• 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_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 CONV2D_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_GET = 1;
33 static constexpr int PAD_LIST_GET = 4;
34 static constexpr int SCALAR_LENGTH = 1;
35 static const std::string OP_NAME = "Conv2D";
36 
Conv2DBuilder()37 Conv2DBuilder::Conv2DBuilder() {}
38 
~Conv2DBuilder()39 Conv2DBuilder::~Conv2DBuilder() {}
40 
SetInputAndOutput(const std::vector<uint32_t> & inputsIndex,const std::vector<uint32_t> & outputsIndex,const std::vector<std::shared_ptr<NNTensor>> & allTensors)41 OH_NN_ReturnCode Conv2DBuilder::SetInputAndOutput(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("[Conv2d] SetInputAndOutput failed, passed invalid input or output index.");
48         return returnCode;
49     }
50 
51     m_inputsIndex = inputsIndex;
52     m_outputsIndex = outputsIndex;
53 
54     return OH_NN_SUCCESS;
55 }
56 
SetChannel(const std::vector<uint32_t> & inputsIndex,const std::vector<std::shared_ptr<NNTensor>> & allTensors)57 OH_NN_ReturnCode Conv2DBuilder::SetChannel(const std::vector<uint32_t>& inputsIndex,
58                                            const std::vector<std::shared_ptr<NNTensor>>& allTensors)
59 {
60     // set inChannel, outChannel, kernelSize
61     auto weightShape = allTensors[inputsIndex[CONV2D_INPUT_WEIGHT]]->GetDimensions();
62     if (weightShape.size() != WEIGHT_SIZE) {
63         LOGE("[Conv2d] SetChannel failed, the dimension of weight should be %d", WEIGHT_SIZE);
64         return OH_NN_INVALID_PARAMETER;
65     }
66 
67     m_inChannel = weightShape[IN_CHANNEL_INDEX];
68     m_outChannel = weightShape[OUT_CHANNEL_INDEX];
69 
70     return OH_NN_SUCCESS;
71 }
72 
SetKernelSize(const std::vector<uint32_t> & inputsIndex,const std::vector<std::shared_ptr<NNTensor>> & allTensors)73 void Conv2DBuilder::SetKernelSize(const std::vector<uint32_t>& inputsIndex,
74                                   const std::vector<std::shared_ptr<NNTensor>>& allTensors)
75 {
76     // set inChannel, outChannel, kernelSize
77     auto weightShape = allTensors[inputsIndex[CONV2D_INPUT_WEIGHT]]->GetDimensions();
78 
79     m_kernelSize.clear();
80     m_kernelSize.emplace_back(weightShape[KERNEL_HEIGHT_INDEX]);
81     m_kernelSize.emplace_back(weightShape[KERNEL_WEIGHT_INDEX]);
82 }
83 
SetStrides(std::shared_ptr<NNTensor> tensor)84 OH_NN_ReturnCode Conv2DBuilder::SetStrides(std::shared_ptr<NNTensor> tensor)
85 {
86     tensor->IdentifyOpParameter();
87     // Set Strides
88     if (tensor->GetDataType() != OH_NN_INT64) {
89         LOGE("[Conv2d] SetStrides failed, the Strides should be type OH_NN_INT64.");
90         return OH_NN_INVALID_PARAMETER;
91     }
92 
93     void* buffer = tensor->GetBuffer();
94     if (buffer == nullptr) {
95         LOGE("[Conv2d] SetStrides GetBuffer return nullptr");
96         return OH_NN_INVALID_PARAMETER;
97     }
98     const int64_t* pStrides = reinterpret_cast<const int64_t*>(buffer);
99     int stridesSize = tensor->GetElementCount();
100     m_strides.assign(pStrides, pStrides + stridesSize);
101 
102     return OH_NN_SUCCESS;
103 }
104 
SetDilation(std::shared_ptr<NNTensor> tensor)105 OH_NN_ReturnCode Conv2DBuilder::SetDilation(std::shared_ptr<NNTensor> tensor)
106 {
107     tensor->IdentifyOpParameter();
108     // Set Dilation
109     if (tensor->GetDataType() != OH_NN_INT64) {
110         LOGE("[Conv2d] SetDilation failed, the Dilation should have type OH_NN_INT64");
111         return OH_NN_INVALID_PARAMETER;
112     }
113 
114     void* buffer = tensor->GetBuffer();
115     if (buffer == nullptr) {
116         LOGE("[Conv2d] SetDilation GetBuffer return nullptr");
117         return OH_NN_INVALID_PARAMETER;
118     }
119     const int64_t* pDilation = reinterpret_cast<const int64_t*>(buffer);
120     int dilationSize = tensor->GetElementCount();
121     m_dilation.assign(pDilation, pDilation + dilationSize);
122 
123     return OH_NN_SUCCESS;
124 }
125 
SetPad(std::shared_ptr<NNTensor> tensor)126 OH_NN_ReturnCode Conv2DBuilder::SetPad(std::shared_ptr<NNTensor> tensor)
127 {
128     tensor->IdentifyOpParameter();
129 
130     bool isPadMode = false;
131     if (tensor->GetElementCount() == PAD_MODE_GET) {
132         isPadMode = true;
133     } else if (tensor->GetElementCount() != PAD_LIST_GET) {
134         LOGE("[Conv2d] SetPad failed, inputs should be 1 for padMode and 4 for padList.");
135         return OH_NN_INVALID_PARAMETER;
136     }
137 
138     void* buffer = tensor->GetBuffer();
139     if (buffer == nullptr) {
140         LOGE("[Conv2d] SetPadList GetBuffer return nullptr");
141         return OH_NN_INVALID_PARAMETER;
142     }
143 
144     // Set PadMode or PadList
145     if (isPadMode) {
146         if (tensor->GetDataType() != OH_NN_INT8) {
147             LOGE("[Conv2d] SetPad failed, the PadMode should have type OH_NN_INT8.");
148             return OH_NN_INVALID_PARAMETER;
149         }
150 
151         int8_t* pPad = static_cast<int8_t*>(buffer);
152         if (!OHOS::NeuralNetworkRuntime::Validation::ValidatePadMode(*pPad)) {
153             LOGE("[Conv2d] SetPad failed, invalid pad mode.");
154             return OH_NN_INVALID_PARAMETER;
155         }
156         m_padMode = NNToMS::TransformPadModeValue(*pPad);
157     } else {
158         if (tensor->GetDataType() != OH_NN_INT64) {
159             LOGE("[Conv2d] SetPad failed, the PadList should have type OH_NN_INT64.");
160             return OH_NN_INVALID_PARAMETER;
161         }
162 
163         int64_t* pPadList = static_cast<int64_t*>(buffer);
164         int padListSize = tensor->GetElementCount();
165         m_pad.assign(pPadList, pPadList + padListSize);
166     }
167 
168     return OH_NN_SUCCESS;
169 }
170 
SetGroup(std::shared_ptr<NNTensor> tensor)171 OH_NN_ReturnCode Conv2DBuilder::SetGroup(std::shared_ptr<NNTensor> tensor)
172 {
173     tensor->IdentifyOpParameter();
174     // Set Group
175     if (tensor->GetElementCount() != SCALAR_LENGTH) {
176         LOGE("[Conv2d] SetGroup failed, The Group shoule be a scalar");
177         return OH_NN_INVALID_PARAMETER;
178     }
179 
180     if (tensor->GetDataType() != OH_NN_INT64) {
181         LOGE("[Conv2d] SetGroup failed, The Group should have type OH_NN_INT64.");
182         return OH_NN_INVALID_PARAMETER;
183     }
184 
185     void* buffer = tensor->GetBuffer();
186     if (buffer == nullptr) {
187         LOGE("[Conv2d] SetGroup GetBuffer return nullptr");
188         return OH_NN_INVALID_PARAMETER;
189     }
190     m_group = *static_cast<int64_t*>(buffer);
191 
192     return OH_NN_SUCCESS;
193 }
194 
SetActavitation(std::shared_ptr<NNTensor> tensor)195 OH_NN_ReturnCode Conv2DBuilder::SetActavitation(std::shared_ptr<NNTensor> tensor)
196 {
197     tensor->IdentifyOpParameter();
198 
199     if (tensor->GetElementCount() != SCALAR_LENGTH) {
200         LOGE("[Conv2d] SetActavitation failed, the ActivationType shoule be a scalar");
201         return OH_NN_INVALID_PARAMETER;
202     }
203 
204     if (tensor->GetDataType() != OH_NN_INT8) {
205         LOGE("[Conv2d] SetActavitation failed, the ActivationType should have type OH_NN_INT8.");
206         return OH_NN_INVALID_PARAMETER;
207     }
208 
209     void* buffer = tensor->GetBuffer();
210     if (buffer == nullptr) {
211         LOGE("[Conv2d] SetGroup GetBuffer return nullptr");
212         return OH_NN_INVALID_PARAMETER;
213     }
214     int8_t* pFuseData = static_cast<int8_t*>(buffer);
215     if (!OHOS::NeuralNetworkRuntime::Validation::ValidateFuseType(static_cast<OH_NN_FuseType>(*pFuseData))) {
216         LOGE("[Conv2d] SetActavitation failed, activation input is invalid.");
217         return OH_NN_INVALID_PARAMETER;
218     }
219     m_activationType = NNToMS::TransfromFusionType((OH_NN_FuseType)(*pFuseData));
220 
221     return OH_NN_SUCCESS;
222 }
223 
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)224 OH_NN_ReturnCode Conv2DBuilder::Build(const std::vector<uint32_t>& paramsIndex,
225     const std::vector<uint32_t>& inputsIndex, const std::vector<uint32_t>& outputsIndex,
226     const std::vector<std::shared_ptr<NNTensor>>& allTensors)
227 {
228     if (m_isBuild) {
229         LOGE("[Conv2d] Build failed, Conv2D operation has been build, cannot build again.");
230         return OH_NN_OPERATION_FORBIDDEN;
231     }
232 
233     OH_NN_ReturnCode returnCode = SetInputAndOutput(inputsIndex, outputsIndex, allTensors);
234     if (returnCode != OH_NN_SUCCESS) {
235         return returnCode;
236     }
237 
238     returnCode = SetChannel(inputsIndex, allTensors);
239     if (returnCode != OH_NN_SUCCESS) {
240         return returnCode;
241     }
242 
243     SetKernelSize(inputsIndex, allTensors);
244 
245     for (int i : paramsIndex) {
246         std::shared_ptr<NNTensor> tensor = allTensors[i];
247         switch (tensor->GetType()) {
248             case OH_NN_CONV2D_STRIDES:
249                 returnCode = SetStrides(tensor);
250                 break;
251             case OH_NN_CONV2D_DILATION:
252                 returnCode = SetDilation(tensor);
253                 break;
254             case OH_NN_CONV2D_PAD_MODE:
255             case OH_NN_CONV2D_PAD:
256                 returnCode = SetPad(tensor);
257                 break;
258             case OH_NN_CONV2D_GROUP:
259                 returnCode = SetGroup(tensor);
260                 break;
261             case OH_NN_CONV2D_ACTIVATION_TYPE:
262                 returnCode = SetActavitation(tensor);
263                 break;
264             default:
265                 LOGE("[Conv2D] Build failed, param invalid, type = %d.", tensor->GetType());
266                 return OH_NN_INVALID_PARAMETER;
267         }
268         if (returnCode != OH_NN_SUCCESS) {
269             LOGE("[Conv2D] Build failed, Passed invalid param.");
270             return returnCode;
271         }
272     }
273 
274     // The quantization type of the first output determinies that of the operator.
275     SetQuantType(outputsIndex, allTensors);
276 
277     m_isBuild = true;
278     m_name = OP_NAME;
279     return OH_NN_SUCCESS;
280 }
281 
GetPrimitive()282 LiteGraphPrimitvePtr Conv2DBuilder::GetPrimitive()
283 {
284     if (!m_isBuild) {
285         LOGE("[Conv2d] GetPrimitive failed, Cannot get primitive before call build.");
286         return {nullptr, DestroyLiteGraphPrimitive};
287     }
288 
289     auto primitive = MindIR_Conv2DFusion_CreatePrimitive(m_kernelSize, m_strides,
290         m_dilation, m_padMode, m_pad, m_group, m_inChannel, m_outChannel, m_activationType);
291     LiteGraphPrimitvePtr  graphPrimitivePtr(primitive, DestroyLiteGraphPrimitive);
292     return graphPrimitivePtr;
293 }
294 
295 REGISTER_OPS(Conv2DBuilder, OH_NN_OPS_CONV2D);
296 } // namespace Ops
297 } // namespace NeuralNetworkRuntime
298 } // namespace OHOS
299