• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright 2020-2021 Huawei Technologies Co., Ltd
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/delegate/npu/op/convolution_npu.h"
18 #include "src/delegate/npu/op/convolution_depthwise_npu.h"
19 #include "src/delegate/npu/npu_converter_utils.h"
20 namespace mindspore {
IsSupport(const schema::Primitive * primitive,const std::vector<mindspore::MSTensor> & in_tensors,const std::vector<mindspore::MSTensor> & out_tensors)21 int ConvolutionNPUOp::IsSupport(const schema::Primitive *primitive, const std::vector<mindspore::MSTensor> &in_tensors,
22                                 const std::vector<mindspore::MSTensor> &out_tensors) {
23   auto conv_prim = primitive->value_as_Conv2DFusion();
24   if (conv_prim == nullptr) {
25     MS_LOG(ERROR) << "Get null primitive value for op ." << name_;
26     return RET_ERROR;
27   }
28   auto stride_h = static_cast<int>(*(conv_prim->stride()->begin()));
29   auto stride_w = static_cast<int>(*(conv_prim->stride()->begin() + 1));
30   auto in_shape = in_tensors[0].Shape();  // default format: nhwc, RunPass not called
31   if (stride_h > in_shape[NHWC_H] || stride_w > in_shape[NHWC_W]) {
32     MS_LOG(WARNING) << "Npu convolution does not support stride greater than input size.";
33     return RET_NOT_SUPPORT;
34   }
35   return RET_OK;
36 }
37 
SetConvParam(const schema::Conv2DFusion * conv_prim)38 int ConvolutionNPUOp::SetConvParam(const schema::Conv2DFusion *conv_prim) {
39   auto group = static_cast<int>(conv_prim->group());
40   auto stride_h = static_cast<int>(*(conv_prim->stride()->begin()));
41   auto stride_w = static_cast<int>(*(conv_prim->stride()->begin() + 1));
42   auto dilation_h = static_cast<int>(*(conv_prim->dilation()->begin()));
43   auto dilation_w = static_cast<int>(*(conv_prim->dilation()->begin() + 1));
44   conv_->set_attr_strides(ge::AttrValue::LIST_INT({stride_h, stride_w}));
45   conv_->set_attr_dilations(ge::AttrValue::LIST_INT({dilation_h, dilation_w}));
46   conv_->set_attr_groups(group);
47 
48   if (conv_prim->pad_mode() == schema::PadMode_SAME) {
49     conv_->set_attr_pad_mode(ge::AttrValue::STR{"SAME"});
50     conv_->set_attr_pads(ge::AttrValue::LIST_INT({0, 0, 0, 0}));
51   } else if (conv_prim->pad_mode() == schema::PadMode_VALID) {
52     conv_->set_attr_pad_mode(ge::AttrValue::STR{"VALID"});
53     conv_->set_attr_pads(ge::AttrValue::LIST_INT({0, 0, 0, 0}));
54   } else {
55     conv_->set_attr_pad_mode(ge::AttrValue::STR{"SPECIFIC"});
56     auto pad_u = static_cast<int>(*(conv_prim->pad_list()->begin() + PAD_UP));
57     auto pad_d = static_cast<int>(*(conv_prim->pad_list()->begin() + PAD_DOWN));
58     auto pad_l = static_cast<int>(*(conv_prim->pad_list()->begin() + PAD_LEFT));
59     auto pad_r = static_cast<int>(*(conv_prim->pad_list()->begin() + PAD_RIGHT));
60     conv_->set_attr_pads(ge::AttrValue::LIST_INT({pad_u, pad_d, pad_l, pad_r}));
61   }
62   return RET_OK;
63 }
64 
Init(const schema::Primitive * primitive,const std::vector<mindspore::MSTensor> & in_tensors,const std::vector<mindspore::MSTensor> & out_tensors)65 int ConvolutionNPUOp::Init(const schema::Primitive *primitive, const std::vector<mindspore::MSTensor> &in_tensors,
66                            const std::vector<mindspore::MSTensor> &out_tensors) {
67   // set conv attr param
68   conv_ = new (std::nothrow) hiai::op::Convolution(name_ + "_conv");
69   if (conv_ == nullptr) {
70     MS_LOG(ERROR) << "New convolution operator for convolution op " << name_ << " failed.";
71     return RET_ERROR;
72   }
73   auto conv_prim = primitive->value_as_Conv2DFusion();
74   if (conv_prim == nullptr) {
75     MS_LOG(ERROR) << "Get null primitive value for op ." << name_;
76     return RET_ERROR;
77   }
78   auto ret = SetConvParam(conv_prim);
79   if (ret != RET_OK) {
80     MS_LOG(ERROR) << "Set npu op parameter for convolution op " << name_ << " failed.";
81     return RET_ERROR;
82   }
83   act_type_ = conv_prim->activation_type();
84   if (act_type_ != schema::ActivationType_NO_ACTIVATION) {
85     ret = SetActivation(conv_, act_type_);
86     if (ret != RET_OK) {
87       MS_LOG(ERROR) << "New activation npu operator for op " << name_ << " failed.";
88       return RET_ERROR;
89     }
90   }
91   return RET_OK;
92 }
93 
SetNPUInputs(const std::vector<mindspore::MSTensor> & in_tensors,const std::vector<mindspore::MSTensor> & out_tensors,const std::vector<ge::Operator * > & npu_inputs)94 int ConvolutionNPUOp::SetNPUInputs(const std::vector<mindspore::MSTensor> &in_tensors,
95                                    const std::vector<mindspore::MSTensor> &out_tensors,
96                                    const std::vector<ge::Operator *> &npu_inputs) {
97   auto ret = InitWeightConst(in_tensors);
98   if (ret != RET_OK) {
99     MS_LOG(ERROR) << "Set weight and bias for convolution op " << name_ << " failed when running npu";
100     return RET_ERROR;
101   }
102   conv_->set_input_filter(*weight_);
103   if (in_tensors.size() == CONV_INPUT_SIZE) {
104     ret = InitBiasConst(in_tensors);
105     if (ret != RET_OK) {
106       MS_LOG(ERROR) << "Set bias for convolution op " << name_ << " failed when running npu";
107       return RET_ERROR;
108     }
109     conv_->set_input_bias(*bias_);
110   }
111   conv_->set_input_x(*npu_inputs[0]);
112   return RET_OK;
113 }
114 
SetNPUInputs(const std::vector<mindspore::MSTensor> & in_tensors,const std::vector<mindspore::MSTensor> & out_tensors,const std::vector<ge::Operator * > & npu_inputs,const std::unordered_map<int,std::pair<ge::Operator *,int>> & index2_multi_out_index)115 int ConvolutionNPUOp::SetNPUInputs(
116   const std::vector<mindspore::MSTensor> &in_tensors, const std::vector<mindspore::MSTensor> &out_tensors,
117   const std::vector<ge::Operator *> &npu_inputs,
118   const std::unordered_map<int, std::pair<ge::Operator *, int>> &index2_multi_out_index) {
119   auto ret = InitWeightConst(in_tensors);
120   if (ret != RET_OK) {
121     MS_LOG(ERROR) << "Set weight and bias for convolution op " << name_ << " failed when running npu";
122     return RET_ERROR;
123   }
124   conv_->set_input_filter(*weight_);
125   if (in_tensors.size() == CONV_INPUT_SIZE) {
126     ret = InitBiasConst(in_tensors);
127     if (ret != RET_OK) {
128       MS_LOG(ERROR) << "Set bias for convolution op " << name_ << " failed when running npu";
129       return RET_ERROR;
130     }
131     conv_->set_input_bias(*bias_);
132   }
133 
134   if (!index2_multi_out_index.empty()) {
135     auto itr = index2_multi_out_index.begin();
136     auto in_op = itr->second.first;
137     MS_CHECK_TRUE_RET(in_op != nullptr, RET_ERROR);
138     conv_->SetInput(itr->first, *in_op, itr->second.second);
139   } else {
140     conv_->set_input_x(*npu_inputs[0]);
141   }
142   return RET_OK;
143 }
144 
GetNPUOp()145 ge::Operator *ConvolutionNPUOp::GetNPUOp() {
146   if (act_type_ == schema::ActivationType_NO_ACTIVATION) {
147     return conv_;
148   } else {
149     return act_;
150   }
151 }
152 
~ConvolutionNPUOp()153 ConvolutionNPUOp::~ConvolutionNPUOp() {
154   if (conv_ != nullptr) {
155     delete conv_;
156     conv_ = nullptr;
157   }
158 }
GetNPUConvOp(const schema::Primitive * primitive,const std::vector<mindspore::MSTensor> & in_tensors,const std::vector<mindspore::MSTensor> & out_tensors,std::string name)159 NPUOp *GetNPUConvOp(const schema::Primitive *primitive, const std::vector<mindspore::MSTensor> &in_tensors,
160                     const std::vector<mindspore::MSTensor> &out_tensors, std::string name) {
161   auto shape = out_tensors.front().Shape();
162   if (std::find(shape.begin(), shape.end(), -1) != shape.end()) {
163     MS_LOG(ERROR) << "NPU does not support runtime inference shape.";
164     return nullptr;
165   }
166 
167   if (in_tensors[0].Shape().size() > NPU_SHAPE_SIZE) {
168     MS_LOG(ERROR) << "Npu does not support input tensor dims greater than 4";
169     return nullptr;
170   }
171 
172   if (in_tensors[0].DataType() != DataType::kNumberTypeFloat32 &&
173       in_tensors[0].DataType() != DataType::kNumberTypeFloat16) {
174     MS_LOG(ERROR) << "Npu does not support datatype " << static_cast<int>(in_tensors[0].DataType());
175     return nullptr;
176   }
177 
178   NPUOp *op = nullptr;
179   auto conv_prim = primitive->value_as_Conv2DFusion();
180   auto group = static_cast<int>(conv_prim->group());
181   auto input_channel = in_tensors.front().Shape()[NHWC_C];
182   auto output_channel = out_tensors.front().Shape()[NHWC_C];
183   if (group == input_channel && group == output_channel) {
184     op = new (std::nothrow) ConvolutionDepthwiseNPUOp(primitive, in_tensors, out_tensors, name);
185   } else {
186     op = new (std::nothrow) ConvolutionNPUOp(primitive, in_tensors, out_tensors, name);
187   }
188 
189   if (op == nullptr) {
190     MS_LOG(ERROR) << "create conv op for Npu failed.";
191     return nullptr;
192   }
193 
194   auto ret = op->IsSupport(primitive, in_tensors, out_tensors);
195   if (ret != RET_OK) {
196     delete op;
197     return nullptr;
198   }
199   ret = op->Init(primitive, in_tensors, out_tensors);
200   if (ret != RET_OK) {
201     MS_LOG(ERROR) << "NPU op init failed.";
202     delete op;
203     return nullptr;
204   }
205   return op;
206 }
207 }  // namespace mindspore
208