• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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