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(int * input_dims_data,const float * input_data,int * output_dims_data,const float * golden,T * golden_quantized,const float scale,const int zero_point,T * output_data)54 void TestQuantizeFloat(int* input_dims_data, const float* input_data,
55 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(int * input_dims_data,const float * input_data,InputType * input_quantized,const float input_scale,const int input_zero_point,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(int* input_dims_data, const float* input_data,
86 InputType* input_quantized, const float input_scale,
87 const int input_zero_point, 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(QuantizeOpTestInt16)125 TF_LITE_MICRO_TEST(QuantizeOpTestInt16) {
126 const int length = 10;
127 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 = -1;
132 int16_t output[length];
133 int16_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(QuantizeOpTestInt16NoScale)138 TF_LITE_MICRO_TEST(QuantizeOpTestInt16NoScale) {
139 const int length = 10;
140 int dims[] = {2, 2, 5};
141 const float values[] = {-128, -127, -126, -125, -124,
142 123, 124, 125, 126, 127};
143 const float scale = 1.0;
144 const int zero_point = 0;
145 int16_t output[length];
146 int16_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(QuantizeOpTestInt16toInt16)151 TF_LITE_MICRO_TEST(QuantizeOpTestInt16toInt16) {
152 const int length = 10;
153 int dims[] = {2, 2, 5};
154 const float values[] = {-64, -62, -60, -58, -56, 54, 56, 58, 60, 62};
155 const float input_scale = 2.f;
156 const int input_zero_point = 0;
157 const float output_scale = 0.5;
158 const int output_zero_point = 32;
159 int16_t output_quantized[length];
160 int16_t values_quantized[length];
161 int16_t input_quantized[length];
162 tflite::testing::TestRequantize(dims, values, input_quantized, input_scale,
163 input_zero_point, dims, values,
164 values_quantized, output_scale,
165 output_zero_point, output_quantized);
166 }
167
TF_LITE_MICRO_TEST(QuantizeOpTestInt16toInt16NoZeroPoint)168 TF_LITE_MICRO_TEST(QuantizeOpTestInt16toInt16NoZeroPoint) {
169 const int length = 10;
170 int dims[] = {2, 2, 5};
171 const float values[] = {-32, -31, -30, -29, -28, 27, 28, 29, 30, 31};
172 const float input_scale = 1.f;
173 const int input_zero_point = 0;
174 const float output_scale = 0.5;
175 const int output_zero_point = 0;
176 int16_t output_quantized[length];
177 int16_t values_quantized[length];
178 int16_t input_quantized[length];
179 tflite::testing::TestRequantize(dims, values, input_quantized, input_scale,
180 input_zero_point, dims, values,
181 values_quantized, output_scale,
182 output_zero_point, output_quantized);
183 }
184
TF_LITE_MICRO_TEST(QuantizeOpTestInt8toInt8)185 TF_LITE_MICRO_TEST(QuantizeOpTestInt8toInt8) {
186 const int length = 10;
187 int dims[] = {2, 2, 5};
188 const float values[] = {-64, -62, -60, -58, -56, 54, 56, 58, 60, 62};
189 const float input_scale = 2.f;
190 const int input_zero_point = 0;
191 const float output_scale = 0.5;
192 const int output_zero_point = 32;
193 int8_t output_quantized[length];
194 int8_t values_quantized[length];
195 int8_t input_quantized[length];
196 tflite::testing::TestRequantize(dims, values, input_quantized, input_scale,
197 input_zero_point, dims, values,
198 values_quantized, output_scale,
199 output_zero_point, output_quantized);
200 }
201
TF_LITE_MICRO_TEST(QuantizeOpTestInt8toInt8NoZeroPoint)202 TF_LITE_MICRO_TEST(QuantizeOpTestInt8toInt8NoZeroPoint) {
203 const int length = 10;
204 int dims[] = {2, 2, 5};
205 const float values[] = {-32, -31, -30, -29, -28, 27, 28, 29, 30, 31};
206 const float input_scale = 1.f;
207 const int input_zero_point = 0;
208 const float output_scale = 0.5;
209 const int output_zero_point = 0;
210 int8_t output_quantized[length];
211 int8_t values_quantized[length];
212 int8_t input_quantized[length];
213 tflite::testing::TestRequantize(dims, values, input_quantized, input_scale,
214 input_zero_point, dims, values,
215 values_quantized, output_scale,
216 output_zero_point, output_quantized);
217 }
218
TF_LITE_MICRO_TEST(QuantizeOpTestInt8toInt16)219 TF_LITE_MICRO_TEST(QuantizeOpTestInt8toInt16) {
220 const int length = 10;
221 int dims[] = {2, 2, 5};
222 const float values[] = {-64, -62, -60, -58, -56, 54, 56, 58, 60, 62};
223 const float input_scale = 2.f;
224 const int input_zero_point = 0;
225 const float output_scale = 0.5;
226 const int output_zero_point = 32;
227 int16_t output_quantized[length];
228 int16_t values_quantized[length];
229 int8_t input_quantized[length];
230 tflite::testing::TestRequantize(dims, values, input_quantized, input_scale,
231 input_zero_point, dims, values,
232 values_quantized, output_scale,
233 output_zero_point, output_quantized);
234 }
235 #endif // defined(XTENSA)
236
237 #if !defined(XTENSA)
238 // TODO(b/155682734): Hifimini optimized quantize requires input scale to be
239 // smaller then output scale.
TF_LITE_MICRO_TEST(QuantizeOpTestInt16toInt8)240 TF_LITE_MICRO_TEST(QuantizeOpTestInt16toInt8) {
241 const int length = 10;
242 int dims[] = {2, 2, 5};
243 const float values[] = {-64, -62, -60, -58, -56, 54, 56, 58, 60, 62};
244 const float input_scale = 2.f;
245 const int input_zero_point = 0;
246 const float output_scale = 0.5;
247 const int output_zero_point = 0;
248 int8_t output_quantized[length];
249 int8_t values_quantized[length];
250 int16_t input_quantized[length];
251 tflite::testing::TestRequantize(dims, values, input_quantized, input_scale,
252 input_zero_point, dims, values,
253 values_quantized, output_scale,
254 output_zero_point, output_quantized);
255 }
256 #endif // defined(XTENSA)
257
TF_LITE_MICRO_TEST(QuantizeOpTestInt8toInt32)258 TF_LITE_MICRO_TEST(QuantizeOpTestInt8toInt32) {
259 const int length = 10;
260 int dims[] = {2, 2, 5};
261 const float values[] = {-32, -31, -30, -29, -28, 27, 28, 29, 30, 31};
262 const float input_scale = 1.f;
263 const int input_zero_point = 0;
264 const float output_scale = 0.5;
265 const int output_zero_point = 0;
266 int32_t output_quantized[length];
267 int32_t values_quantized[length];
268 int8_t input_quantized[length];
269 tflite::testing::TestRequantize(dims, values, input_quantized, input_scale,
270 input_zero_point, dims, values,
271 values_quantized, output_scale,
272 output_zero_point, output_quantized);
273 }
274
TF_LITE_MICRO_TEST(QuantizeOpTestInt16toInt32)275 TF_LITE_MICRO_TEST(QuantizeOpTestInt16toInt32) {
276 const int length = 10;
277 int dims[] = {2, 2, 5};
278 const float values[] = {-32, -31, -30, -29, -28, 27, 28, 29, 30, 31};
279 const float input_scale = 1.f;
280 const int input_zero_point = 0;
281 const float output_scale = 0.5;
282 const int output_zero_point = 0;
283 int32_t output_quantized[length];
284 int32_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
TF_LITE_MICRO_TEST(QuantizeOpTestInt16toInt8)292 TF_LITE_MICRO_TEST(QuantizeOpTestInt16toInt8) {
293 constexpr int length = 10;
294 int dims[] = {2, 2, 5};
295 const float values[] = {-32, -31, -30, -29, -28, 27, 28, 29, 30, 31};
296 // TODO(b/155682734): Input scale must be smaller than output scale for
297 // xtensa.
298 const float input_scale = 0.4f;
299 const int input_zero_point = 0;
300 const float output_scale = 1.0f;
301 const int output_zero_point = 0;
302 int8_t output_quantized[length];
303 int8_t values_quantized[length];
304 int16_t input_quantized[length];
305 tflite::testing::TestRequantize(dims, values, input_quantized, input_scale,
306 input_zero_point, dims, values,
307 values_quantized, output_scale,
308 output_zero_point, output_quantized);
309 }
310
311 TF_LITE_MICRO_TESTS_END
312