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_TENSOR_MAPPING_H
17 #define TENSORFLOW_LITE_DELEGATES_NNRT_TENSOR_MAPPING_H
18 
19 #include "tensorflow/lite/c/common.h"
20 #include "tensorflow/lite/minimal_logging.h"
21 
22 #include "nnrt_utils.h"
23 
24 namespace tflite {
25 namespace delegate {
26 namespace nnrt {
27 constexpr uint32_t QUANT_NUMBITS = 8;
28 
29 class TensorMapping {
30 public:
31     // Given a TFLite index return the NN index. If it doesn't exist
32     // return -1.
LiteIndexToNn(int32_t index)33     int32_t LiteIndexToNn(int32_t index) const
34     {
35         const int64_t maxSize = m_liteTensorToNnTensor.size();
36         if (index >= 0 && index < maxSize) {
37             return m_liteTensorToNnTensor[index];
38         } else {
39             return INVALID_INDEX;
40         }
41     }
42 
43     // NN API uses non tensor tensors instead of structs. This creates one
44     // and returns the index. It uses a std::vector and resizes it as needed
45     // keeping -1 to unmapped values. Intermediate tensors likely will not
46     // be mapped.
AddNewNonTensorTensor()47     const int32_t AddNewNonTensorTensor()
48     {
49         return m_nextNnTensorIndex++;
50     }
51 
52     // Add a new mapping from `tfliteIndex` and return the NN API tensor index.
AddNewNnTensorIndex(int32_t tfliteIndex)53     int32_t AddNewNnTensorIndex(int32_t tfliteIndex)
54     {
55         const int64_t currentSize = m_liteTensorToNnTensor.size();
56         if (tfliteIndex >= currentSize) {
57             m_liteTensorToNnTensor.resize(tfliteIndex + 1, INVALID_INDEX);
58         }
59         const int32_t newTensorIndex = m_nextNnTensorIndex++;
60         m_liteTensorToNnTensor[tfliteIndex] = newTensorIndex;
61         return newTensorIndex;
62     }
63 
64     // Get nn tensor tensor tensor num.
GetTensorTensorNum()65     int32_t GetTensorTensorNum() const
66     {
67         return m_nextNnTensorIndex;
68     }
69 
70     // Given a TFLite index returns a TFLite type to which a tensor must be
71     // converted during copying the data to the memory allocated for NN API.
72     // kTfLiteNoType means no conversion is needed.
GetEqualLiteTypeFromLiteIndex(int32_t index)73     TfLiteType GetEqualLiteTypeFromLiteIndex(int32_t index) const
74     {
75         const int64_t maxSize = m_indexToTypeConversion.size();
76         if (index >= 0 && index < maxSize)
77             return m_indexToTypeConversion[index];
78         else
79             return kTfLiteNoType;
80     }
81 
82     // Add a new mapping from TFLite index to a type conversion.
AddTypeConversion(int32_t tfliteIndex,TfLiteType tfliteType)83     void AddTypeConversion(int32_t tfliteIndex, TfLiteType tfliteType)
84     {
85         const int64_t currentSize = m_indexToTypeConversion.size();
86         if (tfliteIndex >= currentSize) {
87             m_indexToTypeConversion.resize(tfliteIndex + 1, kTfLiteNoType);
88         }
89         m_indexToTypeConversion[tfliteIndex] = tfliteType;
90     }
91 
92     // Convert TFLite tensor quant params to NNRT tensor quant params
ConvertQuantParams(TfLiteContext * context,int32_t tensorIndex,OH_NN_QuantParam & quantParam)93     TfLiteStatus ConvertQuantParams(TfLiteContext* context, int32_t tensorIndex, OH_NN_QuantParam& quantParam)
94     {
95         TfLiteTensor* tensor = &(context->tensors[tensorIndex]);
96         TfLiteType tfType = tensor->type;
97         if ((tfType != kTfLiteFloat32) && (tfType != kTfLiteFloat16) && (tfType != kTfLiteBool) &&
98             (tfType != kTfLiteInt32) && (tfType != kTfLiteUInt8) && (tfType != kTfLiteInt8)) {
99             TFLITE_LOG_PROD(TFLITE_LOG_ERROR,
100                 "[TENSOR_MAPPING] type %s is not supported.", TfLiteTypeGetName(tensor->type));
101             return kTfLiteError;
102         }
103 
104         if (tensor->quantization.type) {
105             TfLiteAffineQuantization* params = reinterpret_cast<TfLiteAffineQuantization*>(tensor->quantization.params);
106             int number = params->scale->size;
107             std::vector<double> scale;
108             for (int i = 0; i < number; ++i) {
109                 scale.emplace_back(static_cast<double>(params->scale->data[i]));
110             }
111             m_scale.emplace_back(scale);
112             quantParam.scale = m_scale.back().data();
113             quantParam.zeroPoint = params->zero_point->data;
114             quantParam.quantCount = number;
115             m_numBits.emplace_back(number, QUANT_NUMBITS);
116             quantParam.numBits = m_numBits.back().data();
117         } else {
118             quantParam.quantCount = 0;
119         }
120 
121         return kTfLiteOk;
122     }
123 
124     // Convert TFLite tensor type to NNRT tensor type
ConvertType(TfLiteContext * context,int32_t tensorIndex,int32_t tensorFlags,OH_NN_DataType & nnType)125     TfLiteStatus ConvertType(TfLiteContext* context, int32_t tensorIndex, int32_t tensorFlags, OH_NN_DataType& nnType)
126     {
127         const bool scalarAsTensor = tensorFlags & NN_TENSOR_FLAG_SCALAR_AS_TENSOR;
128         TfLiteTensor* tensor = &(context->tensors[tensorIndex]);
129         TfLiteType nnTypeEquivalent = GetEqualLiteTypeFromLiteIndex(tensorIndex);
130         if (tensor->type == kTfLiteFloat32) {
131             nnType = OH_NN_FLOAT32;
132         } else if (tensor->type == kTfLiteFloat16) {
133             nnType = OH_NN_FLOAT16;
134             if (scalarAsTensor) {
135                 nnType = OH_NN_FLOAT32;
136                 AddTypeConversion(tensorIndex, kTfLiteFloat32);
137             }
138         } else if (tensor->type == kTfLiteInt32) {
139             nnType = OH_NN_INT32;
140         } else if (tensor->type == kTfLiteBool) {
141             nnType = OH_NN_INT8;
142         } else if (tensor->type == kTfLiteUInt8) {
143             nnType = (nnTypeEquivalent == kTfLiteInt32) ? OH_NN_INT32 : OH_NN_INT8;
144         } else if (tensor->type == kTfLiteInt8) {
145             nnType = (nnTypeEquivalent == kTfLiteInt32) ? OH_NN_INT32 : OH_NN_UINT8;
146         } else {
147             TFLITE_LOG_PROD(TFLITE_LOG_ERROR,
148                 "[TENSOR_MAPPING] type %s is not supported.", TfLiteTypeGetName(tensor->type));
149             return kTfLiteError;
150         }
151 
152         return kTfLiteOk;
153     }
154 
155 private:
156     // Next index of nnrt tensor
157     int32_t m_nextNnTensorIndex = 0;
158 
159     // Mapping from lite index. Use a std::vector for speed and code size
160     // rather than a map.
161     std::vector<int32_t> m_liteTensorToNnTensor;
162 
163     // Mapping from lite index to a type which tensor must be converted to during
164     // the copying of the data to the memory allocated for NN API. kTfLiteNoType
165     // means no conversion is needed. Use an std::vector for speed and code size
166     // rather than a map.
167     std::vector<TfLiteType> m_indexToTypeConversion;
168 
169     std::vector<std::vector<uint32_t>> m_numBits;
170 
171     std::vector<std::vector<double>> m_scale;
172 };
173 } // namespace nnrt
174 } // namespace delegate
175 } // namespace tflite
176 
177 #endif // TENSORFLOW_LITE_DELEGATES_NNRT_TENSOR_MAPPING_H