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