Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
kernel_util.cc
00001 /* Copyright 2017 The TensorFlow Authors. All Rights Reserved. 00002 00003 Licensed under the Apache License, Version 2.0 (the "License"); 00004 you may not use this file except in compliance with the License. 00005 You may obtain a copy of the License at 00006 00007 http://www.apache.org/licenses/LICENSE-2.0 00008 00009 Unless required by applicable law or agreed to in writing, software 00010 distributed under the License is distributed on an "AS IS" BASIS, 00011 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00012 See the License for the specific language governing permissions and 00013 limitations under the License. 00014 ==============================================================================*/ 00015 #include "tensorflow/lite/kernels/kernel_util.h" 00016 00017 #include <algorithm> 00018 #include <cmath> 00019 #include <memory> 00020 00021 #include "tensorflow/lite/kernels/internal/quantization_util.h" 00022 #include "tensorflow/lite/kernels/internal/round.h" 00023 00024 namespace tflite { 00025 00026 TfLiteStatus PopulateConvolutionQuantizationParams( 00027 TfLiteContext* context, const TfLiteTensor* input, 00028 const TfLiteTensor* filter, const TfLiteTensor* bias, TfLiteTensor* output, 00029 const TfLiteFusedActivation& activation, int32_t* multiplier, int* shift, 00030 int32_t* output_activation_min, int32_t* output_activation_max, 00031 int32_t* per_channel_multiplier, int* per_channel_shift) { 00032 TF_LITE_ENSURE_EQ(context, input->quantization.type, 00033 kTfLiteAffineQuantization); 00034 TF_LITE_ENSURE_EQ(context, filter->quantization.type, 00035 kTfLiteAffineQuantization); 00036 // TODO(jianlijianli): Enable bias type check and bias scale == input scale 00037 // * filter scale for each channel in affine quantization once bias 00038 // quantization is properly populated. 00039 // TF_LITE_ENSURE_EQ(context, bias->quantization.type, 00040 // kTfLiteAffineQuantization); 00041 00042 // Check data type. 00043 const auto* affine_quantization = 00044 reinterpret_cast<TfLiteAffineQuantization*>(filter->quantization.params); 00045 TF_LITE_ENSURE(context, affine_quantization); 00046 TF_LITE_ENSURE(context, affine_quantization->scale); 00047 const bool is_per_channel = affine_quantization->scale->size > 1; 00048 if (is_per_channel) { 00049 // Currently only Int8 is supported for per channel quantization. 00050 TF_LITE_ENSURE_EQ(context, input->type, kTfLiteInt8); 00051 TF_LITE_ENSURE_EQ(context, filter->type, kTfLiteInt8); 00052 TF_LITE_ENSURE_EQ( 00053 context, affine_quantization->scale->size, 00054 filter->dims->data[affine_quantization->quantized_dimension]); 00055 } 00056 00057 // Populate multiplier and shift using affine quantization. 00058 const int num_channels = affine_quantization->scale->size; 00059 const float input_scale = input->params.scale; 00060 const float output_scale = output->params.scale; 00061 const float* filter_scales = affine_quantization->scale->data; 00062 for (int i = 0; i < num_channels; ++i) { 00063 const double filter_scale = static_cast<double>(filter_scales[i]); 00064 const double effective_output_scale = static_cast<double>(input_scale) * 00065 filter_scale / 00066 static_cast<double>(output_scale); 00067 int32_t significand; 00068 int shift; 00069 QuantizeMultiplier(effective_output_scale, &significand, &shift); 00070 per_channel_multiplier[i] = significand; 00071 per_channel_shift[i] = shift; 00072 } 00073 00074 // Populate scalar quantization parameters. 00075 // This check on legacy quantization parameters is kept only for backward 00076 // compatibility. 00077 if (input->type == kTfLiteUInt8) { 00078 // Check bias scale == input scale * filter scale. 00079 double real_multiplier = 0.0; 00080 TF_LITE_ENSURE_STATUS(GetQuantizedConvolutionMultipler( 00081 context, input, filter, bias, output, &real_multiplier)); 00082 int exponent; 00083 00084 // Populate quantization parameteters with multiplier and shift. 00085 QuantizeMultiplier(real_multiplier, multiplier, &exponent); 00086 *shift = -exponent; 00087 CalculateActivationRangeUint8(activation, output, output_activation_min, 00088 output_activation_max); 00089 } 00090 return kTfLiteOk; 00091 } 00092 00093 TfLiteStatus GetQuantizedConvolutionMultipler(TfLiteContext* context, 00094 const TfLiteTensor* input, 00095 const TfLiteTensor* filter, 00096 const TfLiteTensor* bias, 00097 TfLiteTensor* output, 00098 double* multiplier) { 00099 const double input_product_scale = input->params.scale * filter->params.scale; 00100 // TODO(ahentz): The following conditions must be guaranteed by the training 00101 // pipeline. 00102 if (bias) { 00103 const double bias_scale = bias->params.scale; 00104 TF_LITE_ENSURE(context, 00105 std::abs(input_product_scale - bias_scale) <= 00106 1e-6 * std::min(input_product_scale, bias_scale)); 00107 } 00108 return GetQuantizedConvolutionMultipler(context, input, filter, output, 00109 multiplier); 00110 } 00111 00112 TfLiteStatus GetQuantizedConvolutionMultipler(TfLiteContext* context, 00113 const TfLiteTensor* input, 00114 const TfLiteTensor* filter, 00115 TfLiteTensor* output, 00116 double* multiplier) { 00117 const double input_product_scale = input->params.scale * filter->params.scale; 00118 TF_LITE_ENSURE(context, input_product_scale >= 0); 00119 *multiplier = input_product_scale / output->params.scale; 00120 00121 return kTfLiteOk; 00122 } 00123 00124 namespace { 00125 void CalculateActivationRangeQuantizedImpl(TfLiteFusedActivation activation, 00126 int32_t qmin, int32_t qmax, 00127 TfLiteTensor* output, 00128 int32_t* act_min, int32_t* act_max) { 00129 const auto scale = output->params.scale; 00130 const auto zero_point = output->params.zero_point; 00131 00132 auto quantize = [scale, zero_point](float f) { 00133 return zero_point + static_cast<int32_t>(TfLiteRound(f / scale)); 00134 }; 00135 00136 if (activation == kTfLiteActRelu) { 00137 *act_min = std::max(qmin, quantize(0.0)); 00138 *act_max = qmax; 00139 } else if (activation == kTfLiteActRelu6) { 00140 *act_min = std::max(qmin, quantize(0.0)); 00141 *act_max = std::min(qmax, quantize(6.0)); 00142 } else if (activation == kTfLiteActRelu1) { 00143 *act_min = std::max(qmin, quantize(-1.0)); 00144 *act_max = std::min(qmax, quantize(1.0)); 00145 } else { 00146 *act_min = qmin; 00147 *act_max = qmax; 00148 } 00149 } 00150 } // namespace 00151 00152 TfLiteStatus CalculateActivationRangeQuantized(TfLiteContext* context, 00153 TfLiteFusedActivation activation, 00154 TfLiteTensor* output, 00155 int32_t* act_min, 00156 int32_t* act_max) { 00157 int32_t qmin = 0; 00158 int32_t qmax = 0; 00159 if (output->type == kTfLiteUInt8) { 00160 qmin = std::numeric_limits<uint8_t>::min(); 00161 qmax = std::numeric_limits<uint8_t>::max(); 00162 } else if (output->type == kTfLiteInt8) { 00163 qmin = std::numeric_limits<int8_t>::min(); 00164 qmax = std::numeric_limits<int8_t>::max(); 00165 } else if (output->type == kTfLiteInt16) { 00166 qmin = std::numeric_limits<int16_t>::min(); 00167 qmax = std::numeric_limits<int16_t>::max(); 00168 } else { 00169 TF_LITE_ENSURE(context, false); 00170 } 00171 00172 CalculateActivationRangeQuantizedImpl(activation, qmin, qmax, output, act_min, 00173 act_max); 00174 return kTfLiteOk; 00175 } 00176 00177 void CalculateActivationRangeUint8(TfLiteFusedActivation activation, 00178 TfLiteTensor* output, int32_t* act_min, 00179 int32_t* act_max) { 00180 const int32_t qmin = std::numeric_limits<uint8_t>::min(); 00181 const int32_t qmax = std::numeric_limits<uint8_t>::max(); 00182 00183 CalculateActivationRangeQuantizedImpl(activation, qmin, qmax, output, act_min, 00184 act_max); 00185 } 00186 00187 void CalculateActivationRangeInt8(TfLiteFusedActivation activation, 00188 TfLiteTensor* output, int32_t* act_min, 00189 int32_t* act_max) { 00190 const int32_t qmin = std::numeric_limits<int8_t>::min(); 00191 const int32_t qmax = std::numeric_limits<int8_t>::max(); 00192 00193 CalculateActivationRangeQuantizedImpl(activation, qmin, qmax, output, act_min, 00194 act_max); 00195 } 00196 00197 bool HaveSameShapes(const TfLiteTensor* input1, const TfLiteTensor* input2) { 00198 return TfLiteIntArrayEqual(input1->dims, input2->dims); 00199 } 00200 00201 // TODO(petewarden): Having macros around this is ugly, look at other strategies 00202 // before replicating this approach elsewhere. 00203 #ifndef TF_LITE_STATIC_MEMORY 00204 TfLiteStatus CalculateShapeForBroadcast(TfLiteContext* context, 00205 const TfLiteTensor* input1, 00206 const TfLiteTensor* input2, 00207 TfLiteIntArray** output_shape) { 00208 int64_t dims1 = NumDimensions(input1); 00209 int64_t dims2 = NumDimensions(input2); 00210 int64_t out_dims = std::max(dims1, dims2); 00211 if (NumElements(input1) == 0) { 00212 *output_shape = TfLiteIntArrayCopy(input1->dims); 00213 return kTfLiteOk; 00214 } 00215 std::unique_ptr<TfLiteIntArray, void (*)(TfLiteIntArray*)> shape( 00216 TfLiteIntArrayCreate(out_dims), TfLiteIntArrayFree); 00217 for (int i = 0; i < out_dims; ++i) { 00218 int64_t d1 = i >= dims1 ? 1 : SizeOfDimension(input1, dims1 - i - 1); 00219 int64_t d2 = i >= dims2 ? 1 : SizeOfDimension(input2, dims2 - i - 1); 00220 TF_LITE_ENSURE(context, d1 == d2 || d1 == 1 || d2 == 1); 00221 shape->data[out_dims - i - 1] = std::max(d1, d2); 00222 } 00223 *output_shape = shape.release(); 00224 return kTfLiteOk; 00225 } 00226 #endif // TF_LITE_STATIC_MEMORY 00227 00228 } // namespace tflite
Generated on Wed Jul 13 2022 16:03:35 by
1.7.2