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