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/litert/delegate/npu/op/deconvolution_npu.h"
18 #include "src/litert/delegate/npu/npu_converter_utils.h"
19 #include "nnacl/op_base.h"
20 #include "src/common/log_util.h"
21
22 namespace mindspore::lite {
IsSupport(const schema::Primitive * primitive,const std::vector<mindspore::MSTensor> & in_tensors,const std::vector<mindspore::MSTensor> & out_tensors)23 int DeconvolutionNPUOp::IsSupport(const schema::Primitive *primitive,
24 const std::vector<mindspore::MSTensor> &in_tensors,
25 const std::vector<mindspore::MSTensor> &out_tensors) {
26 if (!in_tensors[1].IsConst()) {
27 MS_LOG(WARNING) << "NPU convolution does not support dynamic weight.";
28 return RET_NOT_SUPPORT;
29 }
30 auto deconv_prim = primitive->value_as_Conv2dTransposeFusion();
31 if (deconv_prim == nullptr) {
32 MS_LOG(ERROR) << "Get null primitive value for op ." << name_;
33 return RET_ERROR;
34 }
35 if (static_cast<int>(deconv_prim->group()) != 1) {
36 MS_LOG(WARNING) << "Only support group equals 1 for npu deconvolution op";
37 return RET_NOT_SUPPORT;
38 }
39 return RET_OK;
40 }
41
SetDeconvParam(const schema::Conv2dTransposeFusion * conv_prim)42 int DeconvolutionNPUOp::SetDeconvParam(const schema::Conv2dTransposeFusion *conv_prim) {
43 CHECK_NULL_RETURN(conv_prim);
44 CHECK_NULL_RETURN(deconv_);
45
46 auto group = static_cast<int>(conv_prim->group());
47 CHECK_NULL_RETURN(conv_prim->stride());
48 CHECK_LESS_RETURN(conv_prim->stride()->size(), DIMENSION_2D);
49 auto stride_h = static_cast<int>(*(conv_prim->stride()->begin()));
50 auto stride_w = static_cast<int>(*(conv_prim->stride()->begin() + 1));
51 CHECK_NULL_RETURN(conv_prim->dilation());
52 CHECK_LESS_RETURN(conv_prim->dilation()->size(), DIMENSION_2D);
53 auto dilation_h = static_cast<int>(*(conv_prim->dilation()->begin()));
54 auto dilation_w = static_cast<int>(*(conv_prim->dilation()->begin() + 1));
55 deconv_->set_attr_strides(ge::AttrValue::LIST_INT({stride_h, stride_w}));
56 deconv_->set_attr_dilations(ge::AttrValue::LIST_INT({dilation_h, dilation_w}));
57 deconv_->set_attr_groups(group);
58
59 if (conv_prim->pad_mode() == schema::PadMode_SAME) {
60 deconv_->set_attr_pad_mode(ge::AttrValue::STR{"SAME"});
61 deconv_->set_attr_pads(ge::AttrValue::LIST_INT({0, 0, 0, 0}));
62 } else if (conv_prim->pad_mode() == schema::PadMode_VALID) {
63 deconv_->set_attr_pad_mode(ge::AttrValue::STR{"VALID"});
64 deconv_->set_attr_pads(ge::AttrValue::LIST_INT({0, 0, 0, 0}));
65 } else {
66 deconv_->set_attr_pad_mode(ge::AttrValue::STR{"SPECIFIC"});
67 CHECK_NULL_RETURN(conv_prim->pad_list());
68 CHECK_LESS_RETURN(conv_prim->pad_list()->size(), DIMENSION_4D);
69 auto pad_u = static_cast<int>(*(conv_prim->pad_list()->begin() + PAD_UP));
70 auto pad_d = static_cast<int>(*(conv_prim->pad_list()->begin() + PAD_DOWN));
71 auto pad_l = static_cast<int>(*(conv_prim->pad_list()->begin() + PAD_LEFT));
72 auto pad_r = static_cast<int>(*(conv_prim->pad_list()->begin() + PAD_RIGHT));
73 deconv_->set_attr_pads(ge::AttrValue::LIST_INT({pad_u, pad_d, pad_l, pad_r}));
74 }
75 return RET_OK;
76 }
77
Init(const schema::Primitive * primitive,const std::vector<mindspore::MSTensor> & in_tensors,const std::vector<mindspore::MSTensor> & out_tensors)78 int DeconvolutionNPUOp::Init(const schema::Primitive *primitive, const std::vector<mindspore::MSTensor> &in_tensors,
79 const std::vector<mindspore::MSTensor> &out_tensors) {
80 CHECK_NULL_RETURN(primitive);
81
82 // set deconv attr param
83 deconv_ = new (std::nothrow) hiai::op::ConvTranspose(name_ + "_deconv");
84 if (deconv_ == nullptr) {
85 MS_LOG(ERROR) << "New deconvolution operator for deconvolution op " << name_ << " failed.";
86 return RET_ERROR;
87 }
88
89 auto deconv_prim = primitive->value_as_Conv2dTransposeFusion();
90 if (deconv_prim == nullptr) {
91 MS_LOG(ERROR) << "Get null primitive value for op ." << name_;
92 return RET_ERROR;
93 }
94 auto ret = SetDeconvParam(deconv_prim);
95 if (ret != RET_OK) {
96 MS_LOG(ERROR) << "Set npu op parameter for convolution op " << name_ << " failed.";
97 return RET_ERROR;
98 }
99 act_type_ = deconv_prim->activation_type();
100 if (act_type_ != schema::ActivationType_NO_ACTIVATION) {
101 ret = SetActivation(deconv_, act_type_);
102 if (ret != RET_OK) {
103 MS_LOG(ERROR) << "New activation npu operator for op " << name_ << " failed.";
104 return RET_ERROR;
105 }
106 }
107 // The shape should be specified not after op Init method since the tensor shape and format may be changed after pass.
108 auto output_shape = out_tensors.at(0).Shape();
109 auto output_batch = static_cast<int32_t>(output_shape.at(NHWC_N));
110 auto output_channel = static_cast<int32_t>(output_shape.at(NHWC_C));
111 auto output_height = static_cast<int32_t>(output_shape.at(NHWC_H));
112 auto output_width = static_cast<int32_t>(output_shape.at(NHWC_W));
113 out_shape_value_ = {output_batch, output_channel, output_height, output_width};
114 return RET_OK;
115 }
116
SetNPUInputs(const std::vector<mindspore::MSTensor> & in_tensors,const std::vector<mindspore::MSTensor> & out_tensors,const std::vector<ge::Operator * > & npu_inputs)117 int DeconvolutionNPUOp::SetNPUInputs(const std::vector<mindspore::MSTensor> &in_tensors,
118 const std::vector<mindspore::MSTensor> &out_tensors,
119 const std::vector<ge::Operator *> &npu_inputs) {
120 CHECK_NULL_RETURN(deconv_);
121
122 auto ret = InitWeightConst(in_tensors);
123 if (ret != RET_OK) {
124 MS_LOG(ERROR) << "Set weight and bias for deconvolution op " << name_ << " failed when running npu";
125 return RET_ERROR;
126 }
127 CHECK_NULL_RETURN(weight_);
128 deconv_->set_input_filter(*weight_);
129
130 ge::TensorDesc out_shape_desc(ge::Shape({NPU_SHAPE_SIZE}), ge::FORMAT_NCHW, ge::DT_INT32);
131 ge::TensorPtr out_shape_tensor = std::make_shared<hiai::Tensor>(out_shape_desc);
132 out_shape_tensor->SetData(reinterpret_cast<uint8_t *>(out_shape_value_.data()), NPU_SHAPE_SIZE * sizeof(int32_t));
133 out_shape_ = new (std::nothrow) hiai::op::Const(name_ + "_output_shape");
134 if (out_shape_ == nullptr) {
135 MS_LOG(ERROR) << "create const NPU op failed for " << name_ + "_output_shape";
136 return RET_ERROR;
137 }
138 out_shape_->set_attr_value(out_shape_tensor);
139 deconv_->set_input_output_shape(*out_shape_);
140
141 if (in_tensors.size() == CONV_INPUT_SIZE) {
142 ret = InitBiasConst(in_tensors);
143 if (ret != RET_OK) {
144 MS_LOG(ERROR) << "Set bias for deconvolution op " << name_ << " failed when running npu";
145 return RET_ERROR;
146 }
147 CHECK_NULL_RETURN(bias_);
148 deconv_->set_input_bias(*bias_);
149 }
150 CHECK_LESS_RETURN(npu_inputs.size(), 1);
151 deconv_->set_input_x(*npu_inputs[0]);
152 return RET_OK;
153 }
154
GetNPUOp()155 ge::Operator *DeconvolutionNPUOp::GetNPUOp() {
156 if (act_type_ == schema::ActivationType_NO_ACTIVATION) {
157 return deconv_;
158 } else {
159 return act_;
160 }
161 }
162
~DeconvolutionNPUOp()163 DeconvolutionNPUOp::~DeconvolutionNPUOp() {
164 if (deconv_ != nullptr) {
165 delete deconv_;
166 deconv_ = nullptr;
167 }
168 if (out_shape_ != nullptr) {
169 delete out_shape_;
170 out_shape_ = nullptr;
171 }
172 }
173 } // namespace mindspore::lite
174