• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
2 
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 #include "tensorflow/lite/c/builtin_op_data.h"
17 #include "tensorflow/lite/c/common.h"
18 #include "tensorflow/lite/micro/kernels/kernel_runner.h"
19 #include "tensorflow/lite/micro/test_helpers.h"
20 #include "tensorflow/lite/micro/testing/micro_test.h"
21 
22 namespace tflite {
23 namespace testing {
24 namespace {
25 
26 template <typename T>
ValidateQuantizeGoldens(TfLiteTensor * tensors,int tensors_size,const float * golden,T * golden_quantized,float scale,int zero_point,int output_len,T * output_data)27 void ValidateQuantizeGoldens(TfLiteTensor* tensors, int tensors_size,
28                              const float* golden, T* golden_quantized,
29                              float scale, int zero_point, int output_len,
30                              T* output_data) {
31   int inputs_array_data[] = {1, 0};
32   TfLiteIntArray* inputs_array = IntArrayFromInts(inputs_array_data);
33   int outputs_array_data[] = {1, 1};
34   TfLiteIntArray* outputs_array = IntArrayFromInts(outputs_array_data);
35 
36   // Version 1 of quantize supports int8_t and uint8_t quantization.
37   const TfLiteRegistration registration = Register_QUANTIZE();
38   micro::KernelRunner runner(registration, tensors, tensors_size, inputs_array,
39                              outputs_array,
40                              /*builtin_data=*/nullptr);
41 
42   TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.InitAndPrepare());
43   TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.Invoke());
44 
45   // Use reference quantization from test utils to compare against op output.
46   Quantize(golden, golden_quantized, output_len, scale, zero_point);
47   for (int i = 0; i < output_len; ++i) {
48     TF_LITE_MICRO_EXPECT_EQ(golden_quantized[i], output_data[i]);
49   }
50 }
51 
52 #if !defined(XTENSA)
53 template <typename T>
TestQuantizeFloat(const int * input_dims_data,const float * input_data,const int * output_dims_data,const float * golden,T * golden_quantized,const float scale,const int zero_point,T * output_data)54 void TestQuantizeFloat(const int* input_dims_data, const float* input_data,
55                        const int* output_dims_data, const float* golden,
56                        T* golden_quantized, const float scale,
57                        const int zero_point, T* output_data) {
58   TfLiteIntArray* input_dims = IntArrayFromInts(input_dims_data);
59   TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
60   const int output_dims_count = ElementCount(*output_dims);
61 
62   TfLiteTensor output_tensor =
63       CreateQuantizedTensor(output_data, output_dims, scale, zero_point);
64 
65   TfLiteAffineQuantization quant;
66   float scales[] = {1, scale};
67   int zero_points[] = {1, zero_point};
68   quant.scale = FloatArrayFromFloats(scales);
69   quant.zero_point = IntArrayFromInts(zero_points);
70   output_tensor.quantization = {kTfLiteAffineQuantization, &quant};
71 
72   // 1 input, 1 output.
73   constexpr int tensors_size = 2;
74   TfLiteTensor tensors[tensors_size] = {
75       CreateTensor(input_data, input_dims),
76       output_tensor,
77   };
78 
79   ValidateQuantizeGoldens(tensors, tensors_size, golden, golden_quantized,
80                           scale, zero_point, output_dims_count, output_data);
81 }
82 #endif  // defined(XTENSA)
83 
84 template <typename InputType, typename OutputType>
TestRequantize(const int * input_dims_data,const float * input_data,InputType * input_quantized,const float input_scale,const int input_zero_point,const int * output_dims_data,const float * golden,OutputType * golden_quantized,const float output_scale,const int output_zero_point,OutputType * output_data)85 void TestRequantize(const int* input_dims_data, const float* input_data,
86                     InputType* input_quantized, const float input_scale,
87                     const int input_zero_point, const int* output_dims_data,
88                     const float* golden, OutputType* golden_quantized,
89                     const float output_scale, const int output_zero_point,
90                     OutputType* output_data) {
91   TfLiteIntArray* input_dims = IntArrayFromInts(input_dims_data);
92   TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
93   const int output_dims_count = ElementCount(*output_dims);
94 
95   TfLiteTensor output_tensor = CreateQuantizedTensor(
96       output_data, output_dims, output_scale, output_zero_point);
97 
98   TfLiteAffineQuantization quant;
99   float scales[] = {1, output_scale};
100   int zero_points[] = {1, output_zero_point};
101   quant.scale = FloatArrayFromFloats(scales);
102   quant.zero_point = IntArrayFromInts(zero_points);
103   output_tensor.quantization = {kTfLiteAffineQuantization, &quant};
104 
105   // 1 input, 1 output.
106   constexpr int tensors_size = 2;
107   TfLiteTensor tensors[tensors_size] = {
108       CreateQuantizedTensor(input_data, input_quantized, input_dims,
109                             input_scale, input_zero_point),
110       output_tensor,
111   };
112 
113   ValidateQuantizeGoldens(tensors, tensors_size, golden, golden_quantized,
114                           output_scale, output_zero_point, output_dims_count,
115                           output_data);
116 }
117 
118 }  // namespace
119 }  // namespace testing
120 }  // namespace tflite
121 
122 TF_LITE_MICRO_TESTS_BEGIN
123 
124 #if !defined(XTENSA)
TF_LITE_MICRO_TEST(QuantizeOpTestUint8)125 TF_LITE_MICRO_TEST(QuantizeOpTestUint8) {
126   const int length = 10;
127   const int dims[] = {2, 2, 5};
128   const float values[] = {-63.5, -63,  -62.5, -62,  -61.5,
129                           62,    62.5, 63,    63.5, 64};
130   const float scale = 0.5;
131   const int zero_point = 127;
132   uint8_t output[length];
133   uint8_t values_quantized[length];
134   tflite::testing::TestQuantizeFloat(
135       dims, values, dims, values, values_quantized, scale, zero_point, output);
136 }
137 
TF_LITE_MICRO_TEST(QuantizeOpTestUint8NoScale)138 TF_LITE_MICRO_TEST(QuantizeOpTestUint8NoScale) {
139   const int length = 10;
140   const int dims[] = {2, 2, 5};
141   const float values[] = {-127, -126, -125, -124, -123,
142                           124,  125,  126,  127,  128};
143   const float scale = 1.0;
144   const int zero_point = 127;
145   uint8_t output[length];
146   uint8_t values_quantized[length];
147   tflite::testing::TestQuantizeFloat(
148       dims, values, dims, values, values_quantized, scale, zero_point, output);
149 }
150 
TF_LITE_MICRO_TEST(QuantizeOpTestInt8)151 TF_LITE_MICRO_TEST(QuantizeOpTestInt8) {
152   const int length = 10;
153   const int dims[] = {2, 2, 5};
154   const float values[] = {-63.5, -63,  -62.5, -62,  -61.5,
155                           62,    62.5, 63,    63.5, 64};
156   const float scale = 0.5;
157   const int zero_point = -1;
158   uint8_t output[length];
159   uint8_t values_quantized[length];
160   tflite::testing::TestQuantizeFloat(
161       dims, values, dims, values, values_quantized, scale, zero_point, output);
162 }
163 
TF_LITE_MICRO_TEST(QuantizeOpTestInt8NoScale)164 TF_LITE_MICRO_TEST(QuantizeOpTestInt8NoScale) {
165   const int length = 10;
166   const int dims[] = {2, 2, 5};
167   const float values[] = {-128, -127, -126, -125, -124,
168                           123,  124,  125,  126,  127};
169   const float scale = 1.0;
170   const int zero_point = 0;
171   uint8_t output[length];
172   uint8_t values_quantized[length];
173   tflite::testing::TestQuantizeFloat(
174       dims, values, dims, values, values_quantized, scale, zero_point, output);
175 }
176 
TF_LITE_MICRO_TEST(QuantizeOpTestInt16)177 TF_LITE_MICRO_TEST(QuantizeOpTestInt16) {
178   const int length = 10;
179   const int dims[] = {2, 2, 5};
180   const float values[] = {-63.5, -63,  -62.5, -62,  -61.5,
181                           62,    62.5, 63,    63.5, 64};
182   const float scale = 0.5;
183   const int zero_point = -1;
184   int16_t output[length];
185   int16_t values_quantized[length];
186   tflite::testing::TestQuantizeFloat(
187       dims, values, dims, values, values_quantized, scale, zero_point, output);
188 }
189 
TF_LITE_MICRO_TEST(QuantizeOpTestInt16NoScale)190 TF_LITE_MICRO_TEST(QuantizeOpTestInt16NoScale) {
191   const int length = 10;
192   const int dims[] = {2, 2, 5};
193   const float values[] = {-128, -127, -126, -125, -124,
194                           123,  124,  125,  126,  127};
195   const float scale = 1.0;
196   const int zero_point = 0;
197   int16_t output[length];
198   int16_t values_quantized[length];
199   tflite::testing::TestQuantizeFloat(
200       dims, values, dims, values, values_quantized, scale, zero_point, output);
201 }
202 
TF_LITE_MICRO_TEST(QuantizeOpTestInt16toInt16)203 TF_LITE_MICRO_TEST(QuantizeOpTestInt16toInt16) {
204   const int length = 10;
205   const int dims[] = {2, 2, 5};
206   const float values[] = {-64, -62, -60, -58, -56, 54, 56, 58, 60, 62};
207   const float input_scale = 2.f;
208   const int input_zero_point = 0;
209   const float output_scale = 0.5;
210   const int output_zero_point = 32;
211   int16_t output_quantized[length];
212   int16_t values_quantized[length];
213   int16_t input_quantized[length];
214   tflite::testing::TestRequantize(dims, values, input_quantized, input_scale,
215                                   input_zero_point, dims, values,
216                                   values_quantized, output_scale,
217                                   output_zero_point, output_quantized);
218 }
219 
TF_LITE_MICRO_TEST(QuantizeOpTestInt16toInt16NoZeroPoint)220 TF_LITE_MICRO_TEST(QuantizeOpTestInt16toInt16NoZeroPoint) {
221   const int length = 10;
222   const int dims[] = {2, 2, 5};
223   const float values[] = {-32, -31, -30, -29, -28, 27, 28, 29, 30, 31};
224   const float input_scale = 1.f;
225   const int input_zero_point = 0;
226   const float output_scale = 0.5;
227   const int output_zero_point = 0;
228   int16_t output_quantized[length];
229   int16_t values_quantized[length];
230   int16_t input_quantized[length];
231   tflite::testing::TestRequantize(dims, values, input_quantized, input_scale,
232                                   input_zero_point, dims, values,
233                                   values_quantized, output_scale,
234                                   output_zero_point, output_quantized);
235 }
236 
TF_LITE_MICRO_TEST(QuantizeOpTestInt8toInt8)237 TF_LITE_MICRO_TEST(QuantizeOpTestInt8toInt8) {
238   const int length = 10;
239   const int dims[] = {2, 2, 5};
240   const float values[] = {-64, -62, -60, -58, -56, 54, 56, 58, 60, 62};
241   const float input_scale = 2.f;
242   const int input_zero_point = 0;
243   const float output_scale = 0.5;
244   const int output_zero_point = 32;
245   int8_t output_quantized[length];
246   int8_t values_quantized[length];
247   int8_t input_quantized[length];
248   tflite::testing::TestRequantize(dims, values, input_quantized, input_scale,
249                                   input_zero_point, dims, values,
250                                   values_quantized, output_scale,
251                                   output_zero_point, output_quantized);
252 }
253 
TF_LITE_MICRO_TEST(QuantizeOpTestInt8toInt8NoZeroPoint)254 TF_LITE_MICRO_TEST(QuantizeOpTestInt8toInt8NoZeroPoint) {
255   const int length = 10;
256   const int dims[] = {2, 2, 5};
257   const float values[] = {-32, -31, -30, -29, -28, 27, 28, 29, 30, 31};
258   const float input_scale = 1.f;
259   const int input_zero_point = 0;
260   const float output_scale = 0.5;
261   const int output_zero_point = 0;
262   int8_t output_quantized[length];
263   int8_t values_quantized[length];
264   int8_t input_quantized[length];
265   tflite::testing::TestRequantize(dims, values, input_quantized, input_scale,
266                                   input_zero_point, dims, values,
267                                   values_quantized, output_scale,
268                                   output_zero_point, output_quantized);
269 }
270 #endif  // defined(XTENSA)
271 
272 #if !defined(XTENSA)
273 // TODO(b/155682734): Hifimini optimized quantize requires input scale to be
274 // smaller then output scale.
TF_LITE_MICRO_TEST(QuantizeOpTestInt16toInt8)275 TF_LITE_MICRO_TEST(QuantizeOpTestInt16toInt8) {
276   const int length = 10;
277   const int dims[] = {2, 2, 5};
278   const float values[] = {-64, -62, -60, -58, -56, 54, 56, 58, 60, 62};
279   const float input_scale = 2.f;
280   const int input_zero_point = 0;
281   const float output_scale = 0.5;
282   const int output_zero_point = 0;
283   int8_t output_quantized[length];
284   int8_t values_quantized[length];
285   int16_t input_quantized[length];
286   tflite::testing::TestRequantize(dims, values, input_quantized, input_scale,
287                                   input_zero_point, dims, values,
288                                   values_quantized, output_scale,
289                                   output_zero_point, output_quantized);
290 }
291 #endif  // defined(XTENSA)
292 
TF_LITE_MICRO_TEST(QuantizeOpTestInt16toInt32)293 TF_LITE_MICRO_TEST(QuantizeOpTestInt16toInt32) {
294   const int length = 10;
295   const int dims[] = {2, 2, 5};
296   const float values[] = {-32, -31, -30, -29, -28, 27, 28, 29, 30, 31};
297   const float input_scale = 1.f;
298   const int input_zero_point = 0;
299   const float output_scale = 0.5;
300   const int output_zero_point = 0;
301   int32_t output_quantized[length];
302   int32_t values_quantized[length];
303   int16_t input_quantized[length];
304   tflite::testing::TestRequantize(dims, values, input_quantized, input_scale,
305                                   input_zero_point, dims, values,
306                                   values_quantized, output_scale,
307                                   output_zero_point, output_quantized);
308 }
309 
TF_LITE_MICRO_TEST(QuantizeOpTestInt16toInt8)310 TF_LITE_MICRO_TEST(QuantizeOpTestInt16toInt8) {
311   constexpr int length = 10;
312   const int dims[] = {2, 2, 5};
313   const float values[] = {-32, -31, -30, -29, -28, 27, 28, 29, 30, 31};
314   // TODO(b/155682734): Input scale must be smaller than output scale for
315   // xtensa.
316   const float input_scale = 0.4f;
317   const int input_zero_point = 0;
318   const float output_scale = 1.0f;
319   const int output_zero_point = 0;
320   int8_t output_quantized[length];
321   int8_t values_quantized[length];
322   int16_t input_quantized[length];
323   tflite::testing::TestRequantize(dims, values, input_quantized, input_scale,
324                                   input_zero_point, dims, values,
325                                   values_quantized, output_scale,
326                                   output_zero_point, output_quantized);
327 }
328 
329 TF_LITE_MICRO_TESTS_END
330