1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "conv2d_transpose_builder.h"
17
18 #include "frameworks/native/transform.h"
19 #include "frameworks/native/validation.h"
20
21 namespace OHOS {
22 namespace NeuralNetworkRuntime {
23 namespace Ops {
24 static constexpr int INPUT_NUM = 3;
25 static constexpr int OUTPUT_NUM = 1;
26 static constexpr int INPUT_WEIGHT = 1;
27 static constexpr int WEIGHT_SIZE = 4;
28 static constexpr int OUT_CHANNEL_INDEX = 0;
29 static constexpr int IN_CHANNEL_INDEX = 3;
30 static constexpr int KERNEL_HEIGHT_INDEX = 1;
31 static constexpr int KERNEL_WEIGHT_INDEX = 2;
32 static constexpr int PAD_MODE_PARAM_NUM = 1;
33 static constexpr int PAD_LIST_PARAM_NUM = 4;
34 static constexpr int SCALAR_LENGTH = 1;
35 static const std::string OP_NAME = "Conv2DTranspose";
36
Conv2DTransposeBuilder()37 Conv2DTransposeBuilder::Conv2DTransposeBuilder() {}
38
~Conv2DTransposeBuilder()39 Conv2DTransposeBuilder::~Conv2DTransposeBuilder() {}
40
SetInput(const std::vector<uint32_t> & inputsIndex,const std::vector<uint32_t> & outputsIndex,const std::vector<std::shared_ptr<NNTensor>> & allTensors)41 OH_NN_ReturnCode Conv2DTransposeBuilder::SetInput(const std::vector<uint32_t>& inputsIndex,
42 const std::vector<uint32_t>& outputsIndex,
43 const std::vector<std::shared_ptr<NNTensor>>& allTensors)
44 {
45 OH_NN_ReturnCode returnCode = CheckIOIndex(inputsIndex, outputsIndex, allTensors, INPUT_NUM, OUTPUT_NUM);
46 if (returnCode != OH_NN_SUCCESS) {
47 LOGE("[Conv2dTranspose] SetInput failed, Passed invalid input or output index.");
48 return returnCode;
49 }
50
51 m_inputsIndex = inputsIndex;
52 m_outputsIndex = outputsIndex;
53
54 // set inChannel, outChannel, kernelSize
55 auto weightShape = allTensors[inputsIndex[INPUT_WEIGHT]]->GetDimensions();
56 if (weightShape.size() != WEIGHT_SIZE) {
57 LOGE("[Conv2dTranspose] SetInput failed, the dimension of weight should be %d", WEIGHT_SIZE);
58 return OH_NN_INVALID_PARAMETER;
59 }
60
61 m_inChannel = weightShape[IN_CHANNEL_INDEX];
62 m_outChannel = weightShape[OUT_CHANNEL_INDEX];
63
64 return OH_NN_SUCCESS;
65 }
66
SetKernelSize(const std::vector<uint32_t> & inputsIndex,const std::vector<std::shared_ptr<NNTensor>> & allTensors)67 void Conv2DTransposeBuilder::SetKernelSize(const std::vector<uint32_t>& inputsIndex,
68 const std::vector<std::shared_ptr<NNTensor>>& allTensors)
69 {
70 auto weightShape = allTensors[inputsIndex[INPUT_WEIGHT]]->GetDimensions();
71
72 m_kernelSize.clear();
73 m_kernelSize.emplace_back(weightShape[KERNEL_HEIGHT_INDEX]);
74 m_kernelSize.emplace_back(weightShape[KERNEL_WEIGHT_INDEX]);
75 }
76
SetStrides(std::shared_ptr<NNTensor> tensor)77 OH_NN_ReturnCode Conv2DTransposeBuilder::SetStrides(std::shared_ptr<NNTensor> tensor)
78 {
79 tensor->IdentifyOpParameter();
80 // Set Strides
81 if (tensor->GetDataType() != OH_NN_INT64) {
82 LOGE("[Conv2DTranspose] SetStrides failed, the Strides should be type OH_NN_INT64.");
83 return OH_NN_INVALID_PARAMETER;
84 }
85
86 void* buffer = tensor->GetBuffer();
87 if (buffer == nullptr) {
88 LOGE("[Conv2DTranspose] SetStrides GetBuffer return nullptr");
89 return OH_NN_INVALID_PARAMETER;
90 }
91 const int64_t* pStrides = reinterpret_cast<const int64_t*>(buffer);
92 int elementSize = tensor->GetElementCount();
93 m_strides.assign(pStrides, pStrides + elementSize);
94
95 return OH_NN_SUCCESS;
96 }
97
SetDilation(std::shared_ptr<NNTensor> tensor)98 OH_NN_ReturnCode Conv2DTransposeBuilder::SetDilation(std::shared_ptr<NNTensor> tensor)
99 {
100 tensor->IdentifyOpParameter();
101 // Set Dilation
102 if (tensor->GetDataType() != OH_NN_INT64) {
103 LOGE("[Conv2DTranspose] SetDilation failed, the Dilation should be type OH_NN_INT64");
104 return OH_NN_INVALID_PARAMETER;
105 }
106
107 void* buffer = tensor->GetBuffer();
108 if (buffer == nullptr) {
109 LOGE("[Conv2DTranspose] SetDilation GetBuffer return nullptr");
110 return OH_NN_INVALID_PARAMETER;
111 }
112 const int64_t* pDilation = reinterpret_cast<const int64_t*>(buffer);
113 int dilationSize = tensor->GetElementCount();
114 m_dilation.assign(pDilation, pDilation + dilationSize);
115
116 return OH_NN_SUCCESS;
117 }
118
SetPad(std::shared_ptr<NNTensor> tensor)119 OH_NN_ReturnCode Conv2DTransposeBuilder::SetPad(std::shared_ptr<NNTensor> tensor)
120 {
121 tensor->IdentifyOpParameter();
122
123 bool isPadMode = false;
124 if (tensor->GetElementCount() == PAD_MODE_PARAM_NUM) {
125 isPadMode = true;
126 } else if (tensor->GetElementCount() != PAD_LIST_PARAM_NUM) {
127 LOGE("[Conv2DTranspose] SetPad failed, the inputs should be 1 if using padMode or 4 if using padList.");
128 return OH_NN_INVALID_PARAMETER;
129 }
130
131 void* buffer = tensor->GetBuffer();
132 if (buffer == nullptr) {
133 LOGE("[Conv2DTranspose] SetPadMode GetBuffer return nullptr");
134 return OH_NN_INVALID_PARAMETER;
135 }
136
137 // Set PadMode or PadList
138 if (isPadMode) {
139 if (tensor->GetDataType() != OH_NN_INT8) {
140 LOGE("[Conv2DTranspose] SetPad failed, the PadMode should have type OH_NN_INT8.");
141 return OH_NN_INVALID_PARAMETER;
142 }
143
144 int8_t* pPad = static_cast<int8_t*>(buffer);
145 if (!OHOS::NeuralNetworkRuntime::Validation::ValidatePadMode(*pPad)) {
146 LOGE("[Conv2DTranspose] SetPad failed, invalid pad mode.");
147 return OH_NN_INVALID_PARAMETER;
148 }
149 m_padMode = NNToMS::TransformPadModeValue(*pPad);
150 } else {
151 if (tensor->GetDataType() != OH_NN_INT64) {
152 LOGE("[Conv2DTranspose] SetPad failed, the PadList should have type OH_NN_INT64.");
153 return OH_NN_INVALID_PARAMETER;
154 }
155
156 const int64_t* pPadList = reinterpret_cast<const int64_t*>(buffer);
157 int padListPadSize = tensor->GetElementCount();
158 m_padList.assign(pPadList, pPadList + padListPadSize);
159 }
160
161 return OH_NN_SUCCESS;
162 }
163
SetGroup(std::shared_ptr<NNTensor> tensor)164 OH_NN_ReturnCode Conv2DTransposeBuilder::SetGroup(std::shared_ptr<NNTensor> tensor)
165 {
166 tensor->IdentifyOpParameter();
167 // Set Group
168 if (tensor->GetElementCount() != SCALAR_LENGTH) {
169 LOGE("[Conv2dTranspose] SetGroup failed, the Group shoule be a scalar");
170 return OH_NN_INVALID_PARAMETER;
171 }
172
173 if (tensor->GetDataType() != OH_NN_INT64) {
174 LOGE("[Conv2dTranspose] SetGroup failed, the Group should have type OH_NN_INT64.");
175 return OH_NN_INVALID_PARAMETER;
176 }
177
178 void* buffer = tensor->GetBuffer();
179 if (buffer == nullptr) {
180 LOGE("[Conv2DTranspose] SetGroup GetBuffer return nullptr");
181 return OH_NN_INVALID_PARAMETER;
182 }
183 m_group = *reinterpret_cast<const int64_t*>(buffer);
184
185 return OH_NN_SUCCESS;
186 }
187
SetOutPadding(std::shared_ptr<NNTensor> tensor)188 OH_NN_ReturnCode Conv2DTransposeBuilder::SetOutPadding(std::shared_ptr<NNTensor> tensor)
189 {
190 tensor->IdentifyOpParameter();
191 // Set outputPadding
192 if (tensor->GetDataType() != OH_NN_INT64) {
193 LOGE("[Conv2DTranspose] SetOutPadding failed, the outputPadding should be type OH_NN_INT64.");
194 return OH_NN_INVALID_PARAMETER;
195 }
196
197 void* buffer = tensor->GetBuffer();
198 if (buffer == nullptr) {
199 LOGE("[Conv2DTranspose] SetOutPadding GetBuffer return nullptr");
200 return OH_NN_INVALID_PARAMETER;
201 }
202 const int64_t* pOutputPadding = reinterpret_cast<const int64_t*>(buffer);
203 int outputPadSize = tensor->GetElementCount();
204 m_outputPaddings.assign(pOutputPadding, pOutputPadding + outputPadSize);
205
206 return OH_NN_SUCCESS;
207 }
208
SetActivation(std::shared_ptr<NNTensor> tensor)209 OH_NN_ReturnCode Conv2DTransposeBuilder::SetActivation(std::shared_ptr<NNTensor> tensor)
210 {
211 tensor->IdentifyOpParameter();
212
213 if (tensor->GetElementCount() != SCALAR_LENGTH) {
214 LOGE("[Conv2DTranspose] SetActivation failed, the ActivationType shoule be a scalar");
215 return OH_NN_INVALID_PARAMETER;
216 }
217
218 if (tensor->GetDataType() != OH_NN_INT8) {
219 LOGE("[Conv2DTranspose] SetActivation failed, the ActivationType should have type OH_NN_INT8.");
220 return OH_NN_INVALID_PARAMETER;
221 }
222
223 void* buffer = tensor->GetBuffer();
224 if (buffer == nullptr) {
225 LOGE("[Conv2DTranspose] SetOutPadding GetBuffer return nullptr");
226 return OH_NN_INVALID_PARAMETER;
227 }
228 int8_t* pFuseData = static_cast<int8_t*>(buffer);
229 if (!OHOS::NeuralNetworkRuntime::Validation::ValidateFuseType(static_cast<OH_NN_FuseType>(*pFuseData))) {
230 LOGE("[Conv2DTranspose] SetActivation failed, activation input is invalid.");
231 return OH_NN_INVALID_PARAMETER;
232 }
233 m_activationType = NNToMS::TransfromFusionType((OH_NN_FuseType)(*pFuseData));
234
235 return OH_NN_SUCCESS;
236 }
237
Build(const std::vector<uint32_t> & paramsIndex,const std::vector<uint32_t> & inputsIndex,const std::vector<uint32_t> & outputsIndex,const std::vector<std::shared_ptr<NNTensor>> & allTensors)238 OH_NN_ReturnCode Conv2DTransposeBuilder::Build(const std::vector<uint32_t>& paramsIndex,
239 const std::vector<uint32_t>& inputsIndex,
240 const std::vector<uint32_t>& outputsIndex,
241 const std::vector<std::shared_ptr<NNTensor>>& allTensors)
242 {
243 if (m_isBuild) {
244 LOGE("[Conv2DTranspose] Build failed, conv2DTranspose operation has been build, cannot build again.");
245 return OH_NN_OPERATION_FORBIDDEN;
246 }
247
248 OH_NN_ReturnCode returnCode = SetInput(inputsIndex, outputsIndex, allTensors);
249 if (returnCode != OH_NN_SUCCESS) {
250 return returnCode;
251 }
252
253 SetKernelSize(inputsIndex, allTensors);
254
255 for (int i : paramsIndex) {
256 std::shared_ptr<NNTensor> tensor = allTensors[i]; // 参数 tensor
257 switch (tensor->GetType()) {
258 case OH_NN_CONV2D_TRANSPOSE_STRIDES:
259 returnCode = SetStrides(tensor);
260 break;
261 case OH_NN_CONV2D_TRANSPOSE_DILATION:
262 returnCode = SetDilation(tensor);
263 break;
264 case OH_NN_CONV2D_TRANSPOSE_PAD_MODE:
265 case OH_NN_CONV2D_TRANSPOSE_PAD:
266 returnCode = SetPad(tensor);
267 break;
268 case OH_NN_CONV2D_TRANSPOSE_GROUP:
269 returnCode = SetGroup(tensor);
270 break;
271 case OH_NN_CONV2D_TRANSPOSE_OUTPUT_PADDINGS:
272 returnCode = SetOutPadding(tensor);
273 break;
274 case OH_NN_CONV2D_TRANSPOSE_ACTIVATION_TYPE:
275 returnCode = SetActivation(tensor);
276 break;
277 default:
278 LOGE("[Conv2DTranspose] Build failed, param invalid, type = %d.", tensor->GetType());
279 return OH_NN_INVALID_PARAMETER;
280 }
281
282 if (returnCode != OH_NN_SUCCESS) {
283 LOGE("[Conv2DTranspose] Build failed, passed invalid param.");
284 return returnCode;
285 }
286 }
287
288 // The quantization type of the first output determinies that of the operator.
289 SetQuantType(outputsIndex, allTensors);
290
291 m_isBuild = true;
292 m_name = OP_NAME;
293 return OH_NN_SUCCESS;
294 }
295
GetPrimitive()296 LiteGraphPrimitvePtr Conv2DTransposeBuilder::GetPrimitive()
297 {
298 if (!m_isBuild) {
299 LOGE("[Conv2DTranspose] GetPrimitive failed, cannot get primitive before call build.");
300 return {nullptr, DestroyLiteGraphPrimitive};
301 }
302
303 void* primitive = MindIR_Conv2dTransposeFusion_CreatePrimitive(m_kernelSize,
304 m_strides, m_dilation, m_padMode, m_padList, m_group, m_inChannel, m_outChannel,
305 m_activationType, m_outputPaddings);
306 LiteGraphPrimitvePtr graphPrimitivePtr(primitive, DestroyLiteGraphPrimitive);
307 return graphPrimitivePtr;
308 }
309
310 REGISTER_OPS(Conv2DTransposeBuilder, OH_NN_OPS_CONV2D_TRANSPOSE);
311 } // namespace Ops
312 } // namespace NeuralNetworkRuntime
313 } // namespace OHOS
314