1 /**
2 * Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved.
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 "utils/kernel_util.h"
18
19 #include <algorithm>
20 #include <map>
21 #include <string>
22 #include <vector>
23
24 #include "inc/cust_cpu_utils.h"
25
26 namespace aicpu {
27 namespace {
28 const std::map<Format, std::string> kFormatToStringMap = {
29 {FORMAT_NCHW, "NCHW"},
30 {FORMAT_NHWC, "NHWC"},
31 {FORMAT_ND, "ND"},
32 {FORMAT_NC1HWC0, "NC1HWC0"},
33 {FORMAT_FRACTAL_Z, "FRACTAL_Z"},
34 {FORMAT_NC1C0HWPAD, "NC1C0HWPAD"},
35 {FORMAT_NHWC1C0, "NHWC1C0"},
36 {FORMAT_FSR_NCHW, "FSR_NCHW"},
37 {FORMAT_FRACTAL_DECONV, "FRACTAL_DECONV"},
38 {FORMAT_C1HWNC0, "C1HWNC0"},
39 {FORMAT_FRACTAL_DECONV_TRANSPOSE, "FRACTAL_DECONV_TRANSPOSE"},
40 {FORMAT_FRACTAL_DECONV_SP_STRIDE_TRANS, "FRACTAL_DECONV_SP_STRIDE_TRANS"},
41 {FORMAT_NC1HWC0_C04, "NC1HWC0_C04"},
42 {FORMAT_FRACTAL_Z_C04, "FRACTAL_Z_C04"},
43 {FORMAT_CHWN, "CHWN"},
44 {FORMAT_FRACTAL_DECONV_SP_STRIDE8_TRANS, "DECONV_SP_STRIDE8_TRANS"},
45 {FORMAT_NC1KHKWHWC0, "NC1KHKWHWC0"},
46 {FORMAT_BN_WEIGHT, "BN_WEIGHT"},
47 {FORMAT_FILTER_HWCK, "FILTER_HWCK"},
48 {FORMAT_HWCN, "HWCN"},
49 {FORMAT_HASHTABLE_LOOKUP_LOOKUPS, "LOOKUP_LOOKUPS"},
50 {FORMAT_HASHTABLE_LOOKUP_KEYS, "LOOKUP_KEYS"},
51 {FORMAT_HASHTABLE_LOOKUP_VALUE, "LOOKUP_VALUE"},
52 {FORMAT_HASHTABLE_LOOKUP_OUTPUT, "LOOKUP_OUTPUT"},
53 {FORMAT_HASHTABLE_LOOKUP_HITS, "LOOKUP_HITS"},
54 {FORMAT_MD, "MD"},
55 {FORMAT_NDHWC, "NDHWC"},
56 {FORMAT_NCDHW, "NCDHW"},
57 {FORMAT_DHWCN, "DHWCN"},
58 {FORMAT_DHWNC, "DHWNC"},
59 {FORMAT_NDC1HWC0, "NDC1HWC0"},
60 {FORMAT_FRACTAL_Z_3D, "FRACTAL_Z_3D"},
61 {FORMAT_FRACTAL_Z_3D_TRANSPOSE, "FRACTAL_Z_3D_TRANSPOSE"},
62 {FORMAT_C1HWNCoC0, "C1HWNCoC0"},
63 {FORMAT_FRACTAL_NZ, "FRACTAL_NZ"},
64 {FORMAT_CN, "CN"},
65 {FORMAT_NC, "NC"},
66 {FORMAT_FRACTAL_ZN_LSTM, "FRACTAL_ZN_LSTM"},
67 {FORMAT_FRACTAL_Z_G, "FRACTAL_Z_G"},
68 {FORMAT_RESERVED, "FORMAT_RESERVED"},
69 {FORMAT_ALL, "ALL"},
70 {FORMAT_NULL, "NULL"}};
71 } // namespace
72
FormatToSerialString(CpuKernelContext & ctx,Format format)73 std::string FormatToSerialString(CpuKernelContext &ctx, Format format) {
74 auto it = kFormatToStringMap.find(static_cast<Format>(GetPrimaryFormat(static_cast<int32_t>(format))));
75 if (it != kFormatToStringMap.end()) {
76 if (HasSubFormat(static_cast<int32_t>(format))) {
77 return it->second + ":" + std::to_string(GetSubFormat(static_cast<int32_t>(format)));
78 }
79 return it->second;
80 } else {
81 CUST_KERNEL_LOG_ERROR(ctx, "Format not support [%u]", format);
82 return "UNDEFINED";
83 }
84 }
85
86 const std::map<std::string, DataType> dtype_maps{{"DT_FLOAT", DT_FLOAT},
87 {"DT_FLOAT16", DT_FLOAT16},
88 {"DT_INT8", DT_INT8},
89 {"DT_INT16", DT_INT16},
90 {"DT_UINT16", DT_UINT16},
91 {"DT_UINT8", DT_UINT8},
92 {"DT_INT32", DT_INT32},
93 {"DT_INT64", DT_INT64},
94 {"DT_UINT32", DT_UINT32},
95 {"DT_UINT64", DT_UINT64},
96 {"DT_BOOL", DT_BOOL},
97 {"DT_DOUBLE", DT_DOUBLE},
98 {"DT_STRING", DT_STRING},
99 {"DT_DUAL_SUB_INT8", DT_DUAL_SUB_INT8},
100 {"DT_DUAL_SUB_UINT8", DT_DUAL_SUB_UINT8},
101 {"DT_COMPLEX64", DT_COMPLEX64},
102 {"DT_COMPLEX128", DT_COMPLEX128},
103 {"DT_QINT8", DT_QINT8},
104 {"DT_QINT16", DT_QINT16},
105 {"DT_QINT32", DT_QINT32},
106 {"DT_QUINT8", DT_QUINT8},
107 {"DT_QUINT16", DT_QUINT16},
108 {"DT_RESOURCE", DT_RESOURCE},
109 {"DT_STRING_REF", DT_STRING_REF},
110 {"DT_DUAL", DT_DUAL},
111 {"DT_UNDEFINED", DT_UNDEFINED}};
112
IsEmptyTensor(Tensor * tensor)113 bool IsEmptyTensor(Tensor *tensor) {
114 auto dims = tensor->GetTensorShape()->GetDimSizes();
115 if (tensor->GetData() == nullptr) {
116 for (uint32_t i = 0; i < dims.size(); i++) {
117 if (dims[i] == 0) {
118 return true;
119 }
120 }
121 }
122 return false;
123 }
124
NormalMathCheck(CpuKernelContext & ctx)125 uint32_t NormalMathCheck(CpuKernelContext &ctx) {
126 const uint32_t kInputNum = 2;
127 const uint32_t kOutputNum = 1;
128
129 if ((ctx.GetInputsSize() != kInputNum) || (ctx.GetOutputsSize() != kOutputNum)) {
130 CUST_KERNEL_LOG_ERROR(ctx,
131 "[%s] Input size or Output size is unexpected,"
132 "expected input size [%u], real input size [%u],"
133 "expected output size [%u], real output size [%u]",
134 ctx.GetOpType().c_str(), kInputNum, ctx.GetInputsSize(), kOutputNum, ctx.GetOutputsSize());
135 return KERNEL_STATUS_PARAM_INVALID;
136 }
137
138 Tensor *input_0 = ctx.Input(kFirstInputIndex);
139 CUST_KERNEL_CHECK_NULLPTR(ctx, input_0, KERNEL_STATUS_PARAM_INVALID, "[%s] Get input[0] failed",
140 ctx.GetOpType().c_str());
141 Tensor *input_1 = ctx.Input(kSecondInputIndex);
142 CUST_KERNEL_CHECK_NULLPTR(ctx, input_1, KERNEL_STATUS_PARAM_INVALID, "[%s] Get input[1] failed",
143 ctx.GetOpType().c_str());
144
145 if (input_0->GetDataType() != input_1->GetDataType()) {
146 CUST_KERNEL_LOG_ERROR(ctx,
147 "[%s] dtype of inputs not matched, input[0] data_type is [%d], "
148 "input[1] data_type is [%d]",
149 ctx.GetOpType().c_str(), input_0->GetDataType(), input_1->GetDataType());
150 return KERNEL_STATUS_PARAM_INVALID;
151 }
152
153 Tensor *output = ctx.Output(kFirstOutputIndex);
154 CUST_KERNEL_CHECK_NULLPTR(ctx, output, KERNEL_STATUS_PARAM_INVALID, "[%s] get output failed",
155 ctx.GetOpType().c_str());
156 return KERNEL_STATUS_OK;
157 }
158
NormalCheck(CpuKernelContext & ctx,const uint32_t inputs_num,const uint32_t outputs_num)159 uint32_t NormalCheck(CpuKernelContext &ctx, const uint32_t inputs_num, const uint32_t outputs_num) {
160 if (inputs_num != kDynamicInput) {
161 CUST_KERNEL_CHECK_FALSE(ctx, (ctx.GetInputsSize() >= inputs_num), KERNEL_STATUS_PARAM_INVALID,
162 "[%s] need [%u] inputs, but got [%u].", ctx.GetOpType().c_str(), inputs_num,
163 ctx.GetInputsSize());
164 for (uint32_t i = 0; i < inputs_num; ++i) {
165 Tensor *input = ctx.Input(i);
166 CUST_KERNEL_CHECK_NULLPTR(ctx, input, KERNEL_STATUS_INNER_ERROR, "[%s] get input[%u] failed.",
167 ctx.GetOpType().c_str(), i);
168 auto input_shape = input->GetTensorShape();
169 CUST_KERNEL_CHECK_NULLPTR(ctx, input_shape, KERNEL_STATUS_PARAM_INVALID, "%s input[%u] tensor shape is nullptr.",
170 ctx.GetOpType().c_str(), i);
171 if (!IsEmptyTensor(input)) {
172 auto input_data = input->GetData();
173 CUST_KERNEL_CHECK_NULLPTR(ctx, input_data, KERNEL_STATUS_PARAM_INVALID, "%s input[%u] tensor data is nullptr.",
174 ctx.GetOpType().c_str(), i);
175 }
176 }
177 }
178
179 if (outputs_num != kDynamicOutput) {
180 CUST_KERNEL_CHECK_FALSE(ctx, (ctx.GetOutputsSize() == outputs_num), KERNEL_STATUS_PARAM_INVALID,
181 "[%s] need [%u] outputs, but got [%u].", ctx.GetOpType().c_str(), outputs_num,
182 ctx.GetOutputsSize());
183 for (uint32_t i = 0; i < outputs_num; ++i) {
184 Tensor *output = ctx.Output(i);
185 CUST_KERNEL_CHECK_NULLPTR(ctx, output, KERNEL_STATUS_INNER_ERROR, "[%s] get output[%u] failed.",
186 ctx.GetOpType().c_str(), i);
187 auto output_shape = output->GetTensorShape();
188 CUST_KERNEL_CHECK_NULLPTR(ctx, output_shape, KERNEL_STATUS_PARAM_INVALID,
189 "%s output[%u] tensor shape is nullptr.", ctx.GetOpType().c_str(), i);
190 if (!IsEmptyTensor(output)) {
191 auto output_data = output->GetData();
192 CUST_KERNEL_CHECK_NULLPTR(ctx, output_data, KERNEL_STATUS_PARAM_INVALID,
193 "%s output[%u] tensor data is nullptr.", ctx.GetOpType().c_str(), i);
194 }
195 }
196 }
197 return KERNEL_STATUS_OK;
198 }
199
NormalCheck(CpuKernelContext & ctx,const uint32_t inputs_num,const uint32_t outputs_num,const std::vector<std::string> & attr_names)200 uint32_t NormalCheck(CpuKernelContext &ctx, const uint32_t inputs_num, const uint32_t outputs_num,
201 const std::vector<std::string> &attr_names) {
202 CUST_KERNEL_HANDLE_ERROR(ctx, NormalCheck(ctx, inputs_num, outputs_num), "Check Greater params failed.");
203 for (auto const &attr_name : attr_names) {
204 auto attr = ctx.GetAttr(attr_name);
205 CUST_KERNEL_CHECK_NULLPTR(ctx, attr, KERNEL_STATUS_PARAM_INVALID, "%s get attr[%s] is nullptr.",
206 ctx.GetOpType().c_str(), attr_name.c_str());
207 }
208 return KERNEL_STATUS_OK;
209 }
210
IsScalar(const std::vector<int64_t> & shape)211 bool IsScalar(const std::vector<int64_t> &shape) { return (shape.size() == 0); }
212
IsVector(const std::vector<int64_t> & shape)213 bool IsVector(const std::vector<int64_t> &shape) { return (shape.size() == 1); }
214
IsMatrix(const std::vector<int64_t> & shape)215 bool IsMatrix(const std::vector<int64_t> &shape) { return (shape.size() == 2); }
216
IsSquareMatrix(const std::vector<int64_t> & shape)217 bool IsSquareMatrix(const std::vector<int64_t> &shape) { return ((shape.size() == 2) && (shape[0] == shape[1])); }
218
AddrAlignedCheck(const void * addr,uint64_t alignment)219 bool AddrAlignedCheck(const void *addr, uint64_t alignment) {
220 return reinterpret_cast<uint64_t>(reinterpret_cast<uintptr_t>(addr)) % alignment == 0;
221 }
222
IsVectorOrHigher(const std::vector<int64_t> & shape)223 bool IsVectorOrHigher(const std::vector<int64_t> &shape) { return (shape.size() >= 1); }
224
DType(std::string dtype_str)225 DataType DType(std::string dtype_str) {
226 auto iter = dtype_maps.find(dtype_str);
227 if (iter != dtype_maps.end()) {
228 return iter->second;
229 } else {
230 return DT_UNDEFINED;
231 }
232 }
233
DTypeStr(DataType dtype)234 std::string DTypeStr(DataType dtype) {
235 auto iter =
236 std::find_if(dtype_maps.begin(), dtype_maps.end(),
237 [dtype](const std::map<std::string, DataType>::value_type &kv) { return (kv.second == dtype); });
238 if (iter != dtype_maps.end()) {
239 return iter->first;
240 } else {
241 return std::string("DT_UNDEFINED");
242 }
243 }
244
CheckTensorTypeSame(CpuKernelContext & ctx,const std::map<std::string,DataType> & types,const DataType & check_type,const std::string & prim_name)245 uint32_t CheckTensorTypeSame(CpuKernelContext &ctx, const std::map<std::string, DataType> &types,
246 const DataType &check_type, const std::string &prim_name) {
247 if (types.empty()) {
248 CUST_KERNEL_LOG_ERROR(ctx, "Trying to use the function to check a empty types map!");
249 return KERNEL_STATUS_PARAM_INVALID;
250 }
251 for (const auto type : types) {
252 auto _type_ = type.second;
253 if (_type_ != check_type) {
254 CUST_KERNEL_LOG_ERROR(ctx,
255 "For primitive[%s]'s input arguments [%s] type should equal to [%s] , "
256 "but get the real type [%s].",
257 prim_name.c_str(), type.first.c_str(), DTypeStr(check_type).c_str(),
258 DTypeStr(_type_).c_str());
259 return KERNEL_STATUS_PARAM_INVALID;
260 }
261 }
262 return KERNEL_STATUS_OK;
263 }
264
CheckTensorShapeSame(CpuKernelContext & ctx,const std::map<std::string,TensorShapePtr> & shapes,const std::vector<int64_t> & check_shape,const std::string & prim_name)265 uint32_t CheckTensorShapeSame(CpuKernelContext &ctx, const std::map<std::string, TensorShapePtr> &shapes,
266 const std::vector<int64_t> &check_shape, const std::string &prim_name) {
267 if (shapes.empty()) {
268 CUST_KERNEL_LOG_ERROR(ctx, "Trying to use the function to check a empty types map!");
269 return KERNEL_STATUS_PARAM_INVALID;
270 }
271 for (const auto shape : shapes) {
272 auto _shape_ptr_ = shape.second;
273 CUST_KERNEL_CHECK_NULLPTR(ctx, _shape_ptr_, KERNEL_STATUS_PARAM_INVALID,
274 "For primitive[%s]'s input arguments [%s] TensorShapePtr "
275 "should not be nullptr.",
276 prim_name.c_str(), shape.first.c_str());
277 auto _shape_ = _shape_ptr_->GetDimSizes();
278 if (!ShapeVectorIsSame(_shape_, check_shape)) {
279 CUST_KERNEL_LOG_ERROR(ctx,
280 "For primitive[%s]'s input arguments [%s] shape should equal to (%s) , "
281 "but get the real shape (%s).",
282 prim_name.c_str(), shape.first.c_str(), VectorToString(check_shape).c_str(),
283 VectorToString(_shape_).c_str());
284 return KERNEL_STATUS_PARAM_INVALID;
285 }
286 }
287 return KERNEL_STATUS_OK;
288 }
289
290 } // namespace aicpu
291