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 #ifndef TENSORFLOW_LITE_DELEGATES_NNRT_UTILS_H
17 #define TENSORFLOW_LITE_DELEGATES_NNRT_UTILS_H
18 
19 #include <map>
20 #include <vector>
21 #include <unordered_map>
22 
23 #include "nnrt_delegate.h"
24 
25 namespace tflite {
26 constexpr int32_t DEPTHWISE_WEIGHT_BATCH_DIMENSION = 0;
27 constexpr int32_t DEPTHWISE_WEIGHT_HEIGHT_DIMENSION = 1;
28 constexpr int32_t DEPTHWISE_WEIGHT_WIDTH_DIMENSION = 2;
29 constexpr int32_t DEPTHWISE_WEIGHT_CHANNEL_DIMENSION = 3;
30 constexpr int32_t DEPTHWISE_WEIGHT_DIMENSION_COUNT = 4;
31 const std::string NNRT_REFERENCE_DEVICE = "nnrt-reference";
32 
33 // Bit mask for tensor flags.
34 enum BIT_MASK {
35     NN_TENSOR_FLAG_SCALAR_AS_TENSOR = 1U << 0,
36     NN_TENSOR_FLAG_INT8_CONVERSION = 1U << 1,
37     NN_TENSOR_FLAG_USE_INT8_ASYMM_SIGNED = 1U << 2,
38     NN_TENSOR_FLAG_FORCE_PER_CHANNEL = 1U << 3,
39     NN_TENSOR_FLAG_HALF_TO_FLOAT_CONVERSION = 1U << 4,
40 };
41 
42 // Returns the enum name corresponding to the given error code if the given
43 // value corresponds to an of the error codes in the enumeration above or
44 // an message with the unknown code.
45 // LINT.IfChange(NnrtErrorDescription)
46 extern std::string NnrtErrorDescription(int32_t errorCode);
47 
48 #define RETURN_TFLITE_ERROR_IF_NN_ERROR(code, callDesc)                                            \
49     do {                                                                                           \
50         if ((code) != OH_NN_SUCCESS) {                                                             \
51             const auto errorDesc = NnrtErrorDescription((code));                                   \
52             TFLITE_LOG_PROD(TFLITE_LOG_ERROR, "NN API returned error %s at line %d while %s.\n",   \
53                             errorDesc.c_str(), __LINE__, (callDesc));                              \
54             return kTfLiteError;                                                                   \
55         }                                                                                          \
56     } while (0)
57 
58 #define RETURN_TFLITE_ERROR_IF_NN_ERROR_FOR_TENSOR(code, callDesc, pTensor)                                          \
59     do {                                                                                                             \
60         if ((code) != OH_NN_SUCCESS) {                                                                               \
61             const auto errorDesc = NnrtErrorDescription((code));                                                     \
62             TFLITE_LOG_PROD(TFLITE_LOG_ERROR,                                                                        \
63                             "NN API returned error %s at line %d while %s for tensor '%s'.\n", errorDesc.c_str(),    \
64                              __LINE__, (callDesc), (pTensor)->name ? (pTensor)->name : "no-name");                   \
65             return kTfLiteError;                                                                                     \
66         }                                                                                                            \
67     } while (0)
68 
69 // Return true if type is kTfLiteFloat32.
70 extern bool IsFloat(TfLiteType type);
71 
72 // Return true if type is kTfLiteUInt8 or kTfLiteInt8.
73 extern bool IsQuantized(TfLiteType type);
74 
75 // Return true if the operator supports scalar data as input.
76 extern bool IsScalarInputSupported(int32_t builtinCode);
77 
78 // Returns true if this delegate is configured to use a specific set of devices.
79 // If the acceleratorName in the delegate options is equal to "nnrt-reference"
80 // this method will return true only if the excludeNnrtReference is true.
81 extern bool IsUseTargetDevice(
82     NnrtDelegate::Options delegateOptions, bool excludeNnrtReference = false);
83 
84 // Fills the given result vector with the list of devices the given delegate
85 // is referring to.
86 // There are three possible results,
87 // - An empty array (not the full list of available accelerators,
88 //   for efficiency reasons) if no accelerator is chosen and the
89 //   disallowNnrtCpu delegate option is false.
90 // - A single element array with the target processor, if an accelerator name
91 //   is specified in the delegate options.
92 // - The target available device on device.
93 extern TfLiteStatus GetTargetDevice(TfLiteContext* context, TfLiteDelegate* delegate,
94     const NnrtApi* nnrt, size_t& dev);
95 
96 // Transpose demension following fixed axis.
97 // If exist -1  in destAxis, return kTfLiteError.
98 extern TfLiteStatus TransposeDims(TfLiteContext* context, const int32_t* dims, uint32_t dimCount,
99     std::vector<int32_t> destAxis, std::vector<int32_t>& weightDims);
100 
101 // Get Tensor size by byte.
102 // Calculate Tesnorsize by mul all dimension in dims.
103 // Return kTfLiteError if element dimension is less 0.
104 extern TfLiteStatus GetTensorSize(TfLiteContext* context, const int32_t* dims, int32_t dimCount, int64_t& tensorSize);
105 
106 // Transpose dimension for Tensor.
107 // Only change NHWC format tensor to CHWN format tensor, and
108 // the capacity of result vec must equal to input tensor size.
109 template <class T>
TransposeTensor(TfLiteContext * context,int32_t tensorIndex,const int32_t * dims,T * transposeTensor)110 TfLiteStatus TransposeTensor(TfLiteContext* context, int32_t tensorIndex, const int32_t* dims,
111     T* transposeTensor)
112 {
113     TF_LITE_ENSURE_EQ(context, dims != nullptr, true);
114 
115     // NHWC -> CHWN
116     TfLiteTensor* tensor = &(context->tensors[tensorIndex]);
117     const T* tensorData = reinterpret_cast<T*>(tensor->data.data);
118     const int32_t batch = dims[DEPTHWISE_WEIGHT_BATCH_DIMENSION];
119     const int32_t height = dims[DEPTHWISE_WEIGHT_HEIGHT_DIMENSION];
120     const int32_t width = dims[DEPTHWISE_WEIGHT_WIDTH_DIMENSION];
121     const int32_t channel = dims[DEPTHWISE_WEIGHT_CHANNEL_DIMENSION];
122 
123     for (int32_t c = 0; c < channel; ++c) {
124         for (int32_t j = 0; j < height * width; ++j) {
125             for (int32_t n = 0; n < batch; ++n) {
126                 int32_t newPos = c * (height * width) * batch + j * batch + n;
127                 int32_t orgPos = n * (height * width) * channel + j * channel + c;
128                 *(transposeTensor + newPos) = *(tensorData + orgPos);
129             }
130         }
131     }
132 
133     return kTfLiteOk;
134 };
135 
136 namespace delegate {
137 namespace nnrt {
138 using unorderedTypeMap = std::unordered_map<int32_t, int32_t>;
139 
140 extern const std::vector<int32_t> ACTIVATE_FUSE_TYPE_LIST;
141 
142 extern const unorderedTypeMap TFLITE_TYPE_TO_NNRT_TYPE;
143 
144 const int32_t INVALID_INDEX = -1;
145 
146 const int32_t OH_NN_UNSUPPORT_OPS = -1;
147 
148 const int32_t OH_NN_FUSE_UNSUPPORTED = -1;
149 } // namespace nnrt
150 } // namespace delegate
151 } // namespace tflite
152 
153 #endif // TENSORFLOW_LITE_DELEGATES_NNRT_UTILS_H
154