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