1 /* Copyright 2020 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/micro/kernels/conv_test.h"
17
18 #include "tensorflow/lite/c/builtin_op_data.h"
19 #include "tensorflow/lite/c/common.h"
20 #include "tensorflow/lite/micro/kernels/kernel_runner.h"
21 #include "tensorflow/lite/micro/micro_utils.h"
22 #include "tensorflow/lite/micro/test_helpers.h"
23 #include "tensorflow/lite/micro/testing/micro_test.h"
24
25 namespace tflite {
26 namespace testing {
27 namespace {
28
29 // Common inputs and outputs.
30 constexpr int kInputElements = 16;
31 static const int kInputShape[] = {4, 2, 2, 4, 1};
32 static const float kInputData[kInputElements] = {1, 1, 1, 1, 2, 2, 2, 2,
33 1, 2, 3, 4, 1, 2, 3, 4};
34
35 constexpr int kFilterElements = 12;
36 static const int kFilterShape[] = {4, 3, 2, 2, 1};
37 static const float kFilterData[kFilterElements] = {1, 2, 3, 4, -1, 1,
38 -1, 1, -1, -1, 1, 1};
39
40 constexpr int kBiasElements = 3;
41 static const int kBiasShape[] = {1, 3};
42 static const float kBiasData[kBiasElements] = {1, 2, 3};
43
44 constexpr int kOutputElements = 12;
45 static const int kOutputShape[] = {4, 2, 1, 2, 3};
46 static const float kGoldenData[kOutputElements] = {18, 2, 5, 18, 2, 5,
47 17, 4, 3, 37, 4, 3};
48
49 static TfLiteConvParams common_conv_params = {
50 kTfLitePaddingValid, // padding
51 2, // stride_width
52 2, // stride_height
53 kTfLiteActNone, // activation
54 1, // dilation_width_factor
55 1, // dilation_height_factor
56 };
57
58 } // namespace
59 } // namespace testing
60 } // namespace tflite
61
62 TF_LITE_MICRO_TESTS_BEGIN
63
64 #if !defined(XTENSA) // TODO(b/170321206): xtensa kernels are less general than
65 // reference kernels and we ifdef out test cases that are
66 // currently known to fail.
TF_LITE_MICRO_TEST(SimpleTestFloat)67 TF_LITE_MICRO_TEST(SimpleTestFloat) {
68 float output_data[tflite::testing::kOutputElements];
69
70 TF_LITE_MICRO_EXPECT_EQ(
71 kTfLiteOk,
72 tflite::testing::TestConvFloat(
73 tflite::testing::kInputShape, tflite::testing::kInputData,
74 tflite::testing::kFilterShape, tflite::testing::kFilterData,
75 tflite::testing::kBiasShape, tflite::testing::kBiasData,
76 tflite::testing::kOutputShape, tflite::testing::kGoldenData,
77 &tflite::testing::common_conv_params, tflite::Register_CONV_2D(),
78 output_data));
79 }
80
TF_LITE_MICRO_TEST(InputAndFilterSameWidthHeight)81 TF_LITE_MICRO_TEST(InputAndFilterSameWidthHeight) {
82 const int output_dims_count = 2;
83 float output_data[output_dims_count];
84
85 const int kFilterShape[] = {4, 1, 2, 4, 1};
86 const float filter_values[] = {1, 2, 3, 4, -1, -1, 1, 1};
87 const int kBiasShape[] = {1, 1};
88 const float bias_values[] = {0};
89 const int kOutputShape[] = {4, 2, 1, 1, 1};
90 const float expected_output[] = {10, 34};
91
92 TF_LITE_MICRO_EXPECT_EQ(
93 kTfLiteOk,
94 tflite::testing::TestConvFloat(
95 tflite::testing::kInputShape, tflite::testing::kInputData,
96 kFilterShape, filter_values, kBiasShape, bias_values, kOutputShape,
97 expected_output, &tflite::testing::common_conv_params,
98 tflite::Register_CONV_2D(), output_data));
99 }
100
TF_LITE_MICRO_TEST(SimpleTestQuantized)101 TF_LITE_MICRO_TEST(SimpleTestQuantized) {
102 const int output_dims_count = 12;
103 uint8_t output_data[output_dims_count];
104
105 const float input_scale = 0.5f;
106 const float filter_scale = 0.5f;
107 const float output_scale = 1.0f;
108
109 uint8_t input_quantized[tflite::testing::kInputElements];
110 uint8_t filter_quantized[tflite::testing::kFilterElements];
111 int32_t bias_quantized[tflite::testing::kBiasElements];
112 uint8_t golden_quantized[tflite::testing::kOutputElements];
113
114 TF_LITE_MICRO_EXPECT_EQ(
115 kTfLiteOk,
116 tflite::testing::TestConvQuantizedPerLayer(
117 tflite::testing::kInputShape, tflite::testing::kInputData,
118 input_quantized, input_scale, tflite::testing::kFilterShape,
119 tflite::testing::kFilterData, filter_quantized, filter_scale,
120 tflite::testing::kBiasShape, tflite::testing::kBiasData,
121 bias_quantized, tflite::testing::kOutputShape,
122 tflite::testing::kGoldenData, golden_quantized, output_scale,
123 &tflite::testing::common_conv_params, tflite::Register_CONV_2D(),
124 output_data));
125 }
126
TF_LITE_MICRO_TEST(InputOutputDifferentTypeIsError)127 TF_LITE_MICRO_TEST(InputOutputDifferentTypeIsError) {
128 using tflite::testing::CreateQuantizedTensor;
129 using tflite::testing::CreateTensor;
130 using tflite::testing::IntArrayFromInts;
131
132 TfLiteIntArray* input_dims = IntArrayFromInts(tflite::testing::kInputShape);
133 TfLiteIntArray* filter_dims = IntArrayFromInts(tflite::testing::kFilterShape);
134 TfLiteIntArray* bias_dims = IntArrayFromInts(tflite::testing::kBiasShape);
135 TfLiteIntArray* output_dims = IntArrayFromInts(tflite::testing::kOutputShape);
136 const int output_dims_count = tflite::ElementCount(*output_dims);
137 constexpr int inputs_size = 3;
138 constexpr int outputs_size = 1;
139 constexpr int tensors_size = inputs_size + outputs_size;
140
141 int8_t output_data[tflite::testing::kOutputElements];
142 TfLiteTensor tensors[tensors_size] = {
143 CreateTensor(tflite::testing::kInputData, input_dims),
144 CreateTensor(tflite::testing::kFilterData, filter_dims),
145 CreateTensor(tflite::testing::kBiasData, bias_dims),
146 CreateQuantizedTensor(output_data, output_dims, /*scale=*/0.0f,
147 /*zero_point=*/0),
148 };
149 TF_LITE_MICRO_EXPECT_EQ(
150 kTfLiteError,
151 tflite::testing::InvokeConv(tensors, tensors_size, output_dims_count,
152 &tflite::testing::common_conv_params,
153 tflite::Register_CONV_2D(), output_data));
154 }
155
TF_LITE_MICRO_TEST(HybridModeIsError)156 TF_LITE_MICRO_TEST(HybridModeIsError) {
157 using tflite::testing::CreateQuantizedTensor;
158 using tflite::testing::CreateTensor;
159 using tflite::testing::IntArrayFromInts;
160
161 TfLiteIntArray* input_dims = IntArrayFromInts(tflite::testing::kInputShape);
162 TfLiteIntArray* filter_dims = IntArrayFromInts(tflite::testing::kFilterShape);
163 TfLiteIntArray* bias_dims = IntArrayFromInts(tflite::testing::kBiasShape);
164 TfLiteIntArray* output_dims = IntArrayFromInts(tflite::testing::kOutputShape);
165 const int output_dims_count = tflite::ElementCount(*output_dims);
166 constexpr int inputs_size = 3;
167 constexpr int outputs_size = 1;
168 constexpr int tensors_size = inputs_size + outputs_size;
169
170 int8_t filter_data[tflite::testing::kFilterElements] = {};
171 float output_data[tflite::testing::kOutputElements];
172 TfLiteTensor tensors[tensors_size] = {
173 CreateTensor(tflite::testing::kInputData, input_dims),
174 CreateQuantizedTensor(filter_data, filter_dims,
175 /*scale=*/0.0f,
176 /*zero_point=*/0),
177 CreateTensor(tflite::testing::kBiasData, bias_dims),
178 CreateTensor(output_data, output_dims),
179 };
180 TF_LITE_MICRO_EXPECT_EQ(
181 kTfLiteError,
182 tflite::testing::InvokeConv(tensors, tensors_size, output_dims_count,
183 &tflite::testing::common_conv_params,
184 tflite::Register_CONV_2D(), output_data));
185 }
186
TF_LITE_MICRO_TEST(SimpleTestDilatedQuantized)187 TF_LITE_MICRO_TEST(SimpleTestDilatedQuantized) {
188 const int output_dims_count = 24;
189 uint8_t output_data[output_dims_count];
190
191 const float input_scale = 0.5f;
192 const float filter_scale = 0.5f;
193 const float output_scale = 1.0f;
194
195 const int input_elements = 48;
196 const int input_shape[] = {4, 2, 4, 6, 1};
197 const float input_data[] = {
198 // b = 0
199 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4,
200 // b = 1
201 1, 2, 3, 4, 5, 6, 2, 6, 2, 4, 4, 2, 3, 2, 6, 5, 1, 4, 1, 2, 1, 4, 6, 3};
202 const int output_elements = 24;
203 const int output_shape[] = {4, 2, 2, 2, 3};
204 const float golden_data[] = {25, 2, 7, 25, 2, 7, 10, 2, -3, 10, 2, -3,
205 39, 7, 6, 50, 3, 4, 14, 4, -5, 15, 0, -7};
206
207 uint8_t input_quantized[input_elements];
208 uint8_t filter_quantized[tflite::testing::kFilterElements];
209 int32_t bias_quantized[tflite::testing::kBiasElements];
210 uint8_t golden_quantized[output_elements];
211
212 TfLiteConvParams conv_params{tflite::testing::common_conv_params};
213 conv_params.dilation_width_factor = 3;
214 conv_params.dilation_height_factor = 2;
215
216 TF_LITE_MICRO_EXPECT_EQ(
217 kTfLiteOk,
218 tflite::testing::TestConvQuantizedPerLayer(
219 input_shape, input_data, input_quantized, input_scale,
220 tflite::testing::kFilterShape, tflite::testing::kFilterData,
221 filter_quantized, filter_scale, tflite::testing::kBiasShape,
222 tflite::testing::kBiasData, bias_quantized, output_shape, golden_data,
223 golden_quantized, output_scale, &conv_params,
224 tflite::Register_CONV_2D(), output_data));
225 }
226
TF_LITE_MICRO_TEST(SimpleTestQuantizedPerChannel)227 TF_LITE_MICRO_TEST(SimpleTestQuantizedPerChannel) {
228 const int output_dims_count = 12;
229 int8_t output_data[output_dims_count];
230
231 const float input_scale = 0.5f;
232 const float output_scale = 1.0f;
233 const int input_zero_point = 0;
234 const int output_zero_point = 0;
235
236 int8_t input_quantized[tflite::testing::kInputElements];
237 int8_t filter_quantized[tflite::testing::kFilterElements];
238 int32_t bias_quantized[tflite::testing::kBiasElements];
239 int8_t golden_quantized[tflite::testing::kOutputElements];
240 int zero_points[tflite::testing::kBiasElements + 1];
241 float scales[tflite::testing::kBiasElements + 1];
242
243 TF_LITE_MICRO_EXPECT_EQ(
244 kTfLiteOk,
245 tflite::testing::TestConvQuantizedPerChannel(
246 tflite::testing::kInputShape, tflite::testing::kInputData,
247 input_quantized, input_scale, input_zero_point,
248 tflite::testing::kFilterShape, tflite::testing::kFilterData,
249 filter_quantized, tflite::testing::kBiasShape,
250 tflite::testing::kBiasData, bias_quantized, scales, zero_points,
251 tflite::testing::kOutputShape, tflite::testing::kGoldenData,
252 golden_quantized, output_scale, output_zero_point,
253 &tflite::testing::common_conv_params, tflite::Register_CONV_2D(),
254 output_data));
255 }
256
TF_LITE_MICRO_TEST(SimpleTestDilatedQuantizedPerChannel)257 TF_LITE_MICRO_TEST(SimpleTestDilatedQuantizedPerChannel) {
258 const int output_dims_count = 24;
259 int8_t output_data[output_dims_count];
260
261 const float input_scale = 0.5f;
262 const float output_scale = 1.0f;
263 const int input_zero_point = 0;
264 const int output_zero_point = 0;
265
266 const int input_elements = 48;
267 const int input_shape[] = {4, 2, 4, 6, 1};
268 const float input_data[] = {
269 // b = 0
270 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4,
271 // b = 1
272 1, 2, 3, 4, 5, 6, 2, 6, 2, 4, 4, 2, 3, 2, 6, 5, 1, 4, 1, 2, 1, 4, 6, 3};
273 const int output_elements = 24;
274 const int output_shape[] = {4, 2, 2, 2, 3};
275 const float golden_data[] = {25, 2, 7, 25, 2, 7, 10, 2, -3, 10, 2, -3,
276 39, 7, 6, 50, 3, 4, 14, 4, -5, 15, 0, -7};
277
278 int8_t input_quantized[input_elements];
279 int8_t filter_quantized[tflite::testing::kFilterElements];
280 int32_t bias_quantized[tflite::testing::kBiasElements];
281 int8_t golden_quantized[output_elements];
282 int zero_points[tflite::testing::kBiasElements + 1];
283 float scales[tflite::testing::kBiasElements + 1];
284
285 TfLiteConvParams conv_params{tflite::testing::common_conv_params};
286 conv_params.dilation_width_factor = 3;
287 conv_params.dilation_height_factor = 2;
288
289 TF_LITE_MICRO_EXPECT_EQ(
290 kTfLiteOk,
291 tflite::testing::TestConvQuantizedPerChannel(
292 input_shape, input_data, input_quantized, input_scale,
293 input_zero_point, tflite::testing::kFilterShape,
294 tflite::testing::kFilterData, filter_quantized,
295 tflite::testing::kBiasShape, tflite::testing::kBiasData,
296 bias_quantized, scales, zero_points, output_shape, golden_data,
297 golden_quantized, output_scale, output_zero_point, &conv_params,
298 tflite::Register_CONV_2D(), output_data));
299 }
300
TF_LITE_MICRO_TEST(SimpleTestQuantizedPerChannelRelu6)301 TF_LITE_MICRO_TEST(SimpleTestQuantizedPerChannelRelu6) {
302 const int output_dims_count = 12;
303 int8_t output_data[output_dims_count];
304
305 const float bias_values[] = {1, 2, -3};
306 const float golden_data[] = {6, 2, 0, 6, 2, 0, 6, 4, 0, 6, 4, 0};
307
308 const float input_scale = 0.023529f;
309 const float output_scale = 0.023529f;
310 const int input_zero_point = -128;
311 const int output_zero_point = -128;
312
313 int8_t input_quantized[tflite::testing::kInputElements];
314 int8_t filter_quantized[tflite::testing::kFilterElements];
315 int32_t bias_quantized[tflite::testing::kBiasElements];
316 int8_t golden_quantized[tflite::testing::kOutputElements];
317 int zero_points[tflite::testing::kBiasElements + 1];
318 float scales[tflite::testing::kBiasElements + 1];
319
320 TF_LITE_MICRO_EXPECT_EQ(
321 kTfLiteOk,
322 tflite::testing::TestConvQuantizedPerChannel(
323 tflite::testing::kInputShape, tflite::testing::kInputData,
324 input_quantized, input_scale, input_zero_point,
325 tflite::testing::kFilterShape, tflite::testing::kFilterData,
326 filter_quantized, tflite::testing::kBiasShape, bias_values,
327 bias_quantized, scales, zero_points, tflite::testing::kOutputShape,
328 golden_data, golden_quantized, output_scale, output_zero_point,
329 &tflite::testing::common_conv_params, tflite::Register_CONV_2D(),
330 output_data));
331 }
332
TF_LITE_MICRO_TEST(Kernel1x1QuantizedPerChannel)333 TF_LITE_MICRO_TEST(Kernel1x1QuantizedPerChannel) {
334 // conv params:
335 // padding, stride_<width,height>, activation, dilation_<width, height>
336 TfLiteConvParams conv_params = {kTfLitePaddingValid, 1, 1,
337 kTfLiteActNone, 1, 1};
338
339 constexpr int input_shape[] = {4, 1, 2, 2, 4}; // [len,N,H,W,C]
340 constexpr int input_elements =
341 input_shape[1] * input_shape[2] * input_shape[3] * input_shape[4];
342 constexpr float input_data[input_elements] = {1, 1, 1, 1, 2, 2, 2, 2,
343 1, 2, 3, 4, 1, 2, 3, 4};
344
345 constexpr int filter_shape[] = {4, 3, 1, 1, 4};
346 constexpr int filter_elements =
347 filter_shape[1] * filter_shape[2] * filter_shape[3] * filter_shape[4];
348 const float filter_data[filter_elements] = {1, 2, 3, 4, -1, 1,
349 -1, 1, -1, -1, 1, 1};
350
351 constexpr int bias_elements = filter_shape[1];
352 constexpr int bias_shape[] = {1, bias_elements};
353 constexpr float bias_data[bias_elements] = {1, 2, 3};
354
355 constexpr int output_shape[] = {4, 1, 2, 2, bias_elements};
356 constexpr int output_elements = 4 * 3;
357 int8_t output_data[output_elements];
358
359 const float golden_data[output_elements] = {11, 2, 3, 21, 2, 3,
360 31, 4, 7, 31, 4, 7};
361
362 const float input_scale = 0.5f;
363 const float output_scale = 1.0f;
364 const int input_zero_point = 0;
365 const int output_zero_point = 0;
366
367 int8_t input_quantized[input_elements];
368 int8_t filter_quantized[filter_elements];
369 int32_t bias_quantized[bias_elements];
370 int8_t golden_quantized[output_elements];
371 int zero_points[bias_elements + 1];
372 float scales[bias_elements + 1];
373
374 TF_LITE_MICRO_EXPECT_EQ(
375 kTfLiteOk, tflite::testing::TestConvQuantizedPerChannel(
376 input_shape, input_data, input_quantized, input_scale,
377 input_zero_point, filter_shape, filter_data,
378 filter_quantized, bias_shape, bias_data, bias_quantized,
379 scales, zero_points, output_shape, golden_data,
380 golden_quantized, output_scale, output_zero_point,
381 &conv_params, tflite::Register_CONV_2D(), output_data));
382 }
383
TF_LITE_MICRO_TEST(Kernel1x1QuantizedPerChannelRelu6)384 TF_LITE_MICRO_TEST(Kernel1x1QuantizedPerChannelRelu6) {
385 // conv params:
386 // padding, stride_<width,height>, activation, dilation_<width, height>
387 TfLiteConvParams conv_params = {kTfLitePaddingValid, 1, 1,
388 kTfLiteActRelu6, 1, 1};
389
390 constexpr int input_shape[] = {4, 1, 2, 2, 4}; // [len,N,H,W,C]
391 constexpr int input_elements =
392 input_shape[1] * input_shape[2] * input_shape[3] * input_shape[4];
393 constexpr float input_data[input_elements] = {1, 1, 1, 1, 2, 2, 2, 2,
394 1, 2, 3, 4, 1, 2, 3, 4};
395
396 constexpr int filter_shape[] = {4, 3, 1, 1, 4};
397 constexpr int filter_elements =
398 filter_shape[1] * filter_shape[2] * filter_shape[3] * filter_shape[4];
399 const float filter_data[filter_elements] = {1, 2, 3, 4, -1, 1,
400 -1, 1, -1, -1, 1, 1};
401
402 constexpr int bias_elements = filter_shape[1];
403 constexpr int bias_shape[] = {1, bias_elements};
404 constexpr float bias_data[bias_elements] = {1, 2, -3};
405
406 constexpr int output_shape[] = {4, 1, 2, 2, bias_elements};
407 constexpr int output_elements = 4 * 3;
408 int8_t output_data[output_elements];
409
410 const float golden_data[output_elements] = {6, 2, 0, 6, 2, 0,
411 6, 4, 1, 6, 4, 1};
412
413 const float input_scale = 0.023529f;
414 const float output_scale = 0.023529f;
415 const int input_zero_point = -128;
416 const int output_zero_point = -128;
417
418 int8_t input_quantized[input_elements];
419 int8_t filter_quantized[filter_elements];
420 int32_t bias_quantized[bias_elements];
421 int8_t golden_quantized[output_elements];
422 int zero_points[bias_elements + 1];
423 float scales[bias_elements + 1];
424
425 TF_LITE_MICRO_EXPECT_EQ(
426 kTfLiteOk, tflite::testing::TestConvQuantizedPerChannel(
427 input_shape, input_data, input_quantized, input_scale,
428 input_zero_point, filter_shape, filter_data,
429 filter_quantized, bias_shape, bias_data, bias_quantized,
430 scales, zero_points, output_shape, golden_data,
431 golden_quantized, output_scale, output_zero_point,
432 &conv_params, tflite::Register_CONV_2D(), output_data));
433 }
434
TF_LITE_MICRO_TEST(BroadcastPerLayerQuantizationToPerChannelShouldMatchGolden)435 TF_LITE_MICRO_TEST(BroadcastPerLayerQuantizationToPerChannelShouldMatchGolden) {
436 const int output_dims_count = 12;
437 int8_t output_data[output_dims_count];
438
439 const float input_scale = 1.0f;
440 const float filter_scale = 1.0f;
441 const float output_scale = 1.0f;
442
443 int8_t input_quantized[tflite::testing::kInputElements];
444 int8_t filter_quantized[tflite::testing::kFilterElements];
445 int32_t bias_quantized[tflite::testing::kBiasElements];
446 int8_t golden_quantized[tflite::testing::kOutputElements];
447
448 TfLiteIntArray* input_dims =
449 tflite::testing::IntArrayFromInts(tflite::testing::kInputShape);
450 TfLiteIntArray* filter_dims =
451 tflite::testing::IntArrayFromInts(tflite::testing::kFilterShape);
452 TfLiteIntArray* bias_dims =
453 tflite::testing::IntArrayFromInts(tflite::testing::kBiasShape);
454 TfLiteIntArray* output_dims =
455 tflite::testing::IntArrayFromInts(tflite::testing::kOutputShape);
456
457 // Create per-layer quantized int8_t input tensor.
458 TfLiteTensor input_tensor = tflite::testing::CreateQuantizedTensor(
459 tflite::testing::kInputData, input_quantized, input_dims, input_scale, 0);
460 int input_zero_points[2] = {1, 0};
461 float input_scales[2] = {1, input_scale};
462 TfLiteAffineQuantization input_quant = {
463 tflite::testing::FloatArrayFromFloats(input_scales),
464 tflite::testing::IntArrayFromInts(input_zero_points), 0};
465 input_tensor.quantization = {kTfLiteAffineQuantization, &input_quant};
466
467 // Create per-layer quantized int8_t filter tensor.
468 TfLiteTensor filter_tensor = tflite::testing::CreateQuantizedTensor(
469 tflite::testing::kFilterData, filter_quantized, filter_dims, filter_scale,
470 0);
471 int filter_zero_points[2] = {1, 0};
472 float filter_scales[2] = {1, filter_scale};
473 TfLiteAffineQuantization filter_quant = {
474 tflite::testing::FloatArrayFromFloats(filter_scales),
475 tflite::testing::IntArrayFromInts(filter_zero_points), 0};
476 filter_tensor.quantization = {kTfLiteAffineQuantization, &filter_quant};
477
478 // Create per-layer quantized int32_t bias tensor.
479 tflite::SymmetricQuantize(tflite::testing::kBiasData, bias_quantized,
480 tflite::testing::kBiasElements,
481 input_scale * output_scale);
482 TfLiteTensor bias_tensor =
483 tflite::testing::CreateTensor(bias_quantized, bias_dims);
484
485 int bias_zero_points[2] = {1, 0};
486 float bias_scales[2] = {1, input_scale * filter_scale};
487 TfLiteAffineQuantization bias_quant = {
488 tflite::testing::FloatArrayFromFloats(bias_scales),
489 tflite::testing::IntArrayFromInts(bias_zero_points), 0};
490 bias_tensor.quantization = {kTfLiteAffineQuantization, &bias_quant};
491
492 // Create per-layer quantized int8_t output tensor.
493 TfLiteTensor output_tensor = tflite::testing::CreateQuantizedTensor(
494 output_data, output_dims, output_scale, 0 /* quantized dimension */);
495 int output_zero_points[2] = {1, 0};
496 float output_scales[2] = {1, output_scale};
497 TfLiteAffineQuantization output_quant = {
498 tflite::testing::FloatArrayFromFloats(output_scales),
499 tflite::testing::IntArrayFromInts(output_zero_points), 0};
500 output_tensor.quantization = {kTfLiteAffineQuantization, &output_quant};
501
502 constexpr int inputs_size = 3;
503 constexpr int outputs_size = 1;
504 constexpr int tensors_size = inputs_size + outputs_size;
505 TfLiteTensor tensors[tensors_size] = {
506 input_tensor,
507 filter_tensor,
508 bias_tensor,
509 output_tensor,
510 };
511
512 tflite::Quantize(tflite::testing::kGoldenData, golden_quantized,
513 output_dims_count, output_scale, 0);
514
515 TF_LITE_MICRO_EXPECT_EQ(
516 kTfLiteOk, tflite::testing::ValidateConvGoldens(
517 tensors, tensors_size, golden_quantized, output_dims_count,
518 &tflite::testing::common_conv_params,
519 tflite::Register_CONV_2D(), output_data));
520 }
521
522 #endif // !defined(XTENSA)
523
TF_LITE_MICRO_TEST(FilterDimsNotMatchingAffineQuantization)524 TF_LITE_MICRO_TEST(FilterDimsNotMatchingAffineQuantization) {
525 const int output_dims_count = 12;
526 int8_t output_data[output_dims_count];
527
528 const float input_scale = 0.5f;
529 const float output_scale = 1.0f;
530
531 int8_t input_quantized[tflite::testing::kInputElements];
532 int8_t filter_quantized[tflite::testing::kFilterElements];
533 int32_t bias_quantized[tflite::testing::kBiasElements];
534 int8_t golden_quantized[tflite::testing::kOutputElements];
535 int zero_points[tflite::testing::kBiasElements + 1];
536 float scales[tflite::testing::kBiasElements + 1];
537
538 TfLiteIntArray* input_dims =
539 tflite::testing::IntArrayFromInts(tflite::testing::kInputShape);
540 TfLiteIntArray* filter_dims =
541 tflite::testing::IntArrayFromInts(tflite::testing::kFilterShape);
542 TfLiteIntArray* bias_dims =
543 tflite::testing::IntArrayFromInts(tflite::testing::kBiasShape);
544 TfLiteIntArray* output_dims =
545 tflite::testing::IntArrayFromInts(tflite::testing::kOutputShape);
546
547 int filter_zero_points[5];
548 float filter_scales[5];
549 TfLiteAffineQuantization filter_quant;
550 TfLiteAffineQuantization bias_quant;
551 TfLiteTensor input_tensor = tflite::testing::CreateQuantizedTensor(
552 tflite::testing::kInputData, input_quantized, input_dims, input_scale, 0);
553 TfLiteTensor filter_tensor =
554 tflite::testing::CreateSymmetricPerChannelQuantizedTensor(
555 tflite::testing::kFilterData, filter_quantized, filter_dims,
556 filter_scales, filter_zero_points, &filter_quant,
557 0 /* quantized dimension */);
558 TfLiteTensor bias_tensor =
559 tflite::testing::CreatePerChannelQuantizedBiasTensor(
560 tflite::testing::kBiasData, bias_quantized, bias_dims, input_scale,
561 &filter_scales[1], scales, zero_points, &bias_quant, 0);
562 TfLiteTensor output_tensor = tflite::testing::CreateQuantizedTensor(
563 output_data, output_dims, output_scale, 0 /* quantized dimension */);
564
565 float input_scales[] = {1, input_scale};
566 int input_zero_points[] = {1, 128};
567 TfLiteAffineQuantization input_quant = {
568 tflite::testing::FloatArrayFromFloats(input_scales),
569 tflite::testing::IntArrayFromInts(input_zero_points), 0};
570 input_tensor.quantization = {kTfLiteAffineQuantization, &input_quant};
571
572 constexpr int inputs_size = 3;
573 constexpr int outputs_size = 1;
574 constexpr int tensors_size = inputs_size + outputs_size;
575 TfLiteTensor tensors[tensors_size] = {
576 input_tensor,
577 filter_tensor,
578 bias_tensor,
579 output_tensor,
580 };
581
582 tflite::Quantize(tflite::testing::kGoldenData, golden_quantized,
583 output_dims_count, output_scale, 0);
584
585 // Set filter quant to mismatched dimension.
586 TfLiteAffineQuantization* quant = reinterpret_cast<TfLiteAffineQuantization*>(
587 filter_tensor.quantization.params);
588
589 // Choose arbitrary incorrect scale and zero point sizes which are neither 1
590 // (for broadcast case) nor the quantized dimension size.
591 quant->scale->size = 2;
592 TF_LITE_MICRO_EXPECT_EQ(
593 kTfLiteError, tflite::testing::ValidateConvGoldens(
594 tensors, tensors_size, golden_quantized,
595 output_dims_count, &tflite::testing::common_conv_params,
596 tflite::Register_CONV_2D(), output_data));
597
598 // Set scale back to correct dimension, and make zero point array too short.
599 quant->scale->size = tflite::testing::kFilterShape[0];
600 quant->zero_point->size = 2;
601 TF_LITE_MICRO_EXPECT_EQ(
602 kTfLiteError, tflite::testing::ValidateConvGoldens(
603 tensors, tensors_size, golden_quantized,
604 output_dims_count, &tflite::testing::common_conv_params,
605 tflite::Register_CONV_2D(), output_data));
606 }
607
TF_LITE_MICRO_TEST(Int8Input32x1Filter32x32ShouldMatchGolden)608 TF_LITE_MICRO_TEST(Int8Input32x1Filter32x32ShouldMatchGolden) {
609 constexpr int kSampleSize = 32;
610 constexpr int kNumFilters = 32;
611 const int input_shape[] = {4, 1, 1, 1, kSampleSize};
612 const int filter_shape[] = {4, kNumFilters, 1, 1, kSampleSize};
613 const int bias_shape[] = {1, kSampleSize};
614 const int output_shape[] = {4, 1, 1, 1, kSampleSize};
615 float filter_values[kNumFilters * kSampleSize];
616 float input_values[kSampleSize];
617 float bias_values[kSampleSize];
618
619 // Generated these outputs using the floating point reference conv kernel.
620 // TODO(b/149942509): Do this comparison automatically on random inputs.
621 float expected_output[kSampleSize] = {
622 5168.000000, 3377.000000, 306.000000, -4045.000000, -4556.000000,
623 -1227.000000, 822.000000, 1591.000000, 5176.000000, 3385.000000,
624 314.000000, -4037.000000, -4548.000000, -1219.000000, 830.000000,
625 1599.000000, 5184.000000, 3393.000000, 322.000000, -4029.000000,
626 -4540.000000, -1211.000000, 838.000000, 1607.000000, 5192.000000,
627 3401.000000, 330.000000, -4021.000000, -4532.000000, -1203.000000,
628 846.000000, 1615.000000};
629
630 for (int i = 0; i < kSampleSize; i++) {
631 bias_values[i] = i;
632 // Generate inputs from -16 to 15.
633 input_values[i] = i - 16;
634 }
635
636 // Generate samples of varying values between -128 and 127.
637 for (int i = 0; i < kNumFilters * kSampleSize; i++) {
638 filter_values[i] = (i * 25) % 256 - 128;
639 }
640
641 TfLiteConvParams conv_params;
642 conv_params.activation = kTfLiteActNone;
643 conv_params.dilation_height_factor = 1;
644 conv_params.dilation_width_factor = 1;
645 conv_params.stride_height = 1;
646 conv_params.stride_width = 1;
647 conv_params.padding = kTfLitePaddingValid;
648
649 TfLiteIntArray* input_dims = tflite::testing::IntArrayFromInts(input_shape);
650 TfLiteIntArray* filter_dims = tflite::testing::IntArrayFromInts(filter_shape);
651 TfLiteIntArray* bias_dims = tflite::testing::IntArrayFromInts(bias_shape);
652 TfLiteIntArray* output_dims = tflite::testing::IntArrayFromInts(output_shape);
653 const int output_dims_count = tflite::ElementCount(*output_dims);
654
655 // Quantization Parameters. All scales except output are 1.0, and all zero
656 // points are 0. This direct-maps the values to floating point and makes it
657 // easy to reson about them.
658 int input_zero_point = 0;
659 float input_scale = 1.0f;
660 int filter_zero_point = 0;
661 float filter_scale = 1.0f;
662 int output_zero_point = 0;
663 // Output scale of 50 is needed to accomodate a float range of [-6400, 6350]
664 float output_scale = 50.0f;
665
666 // Create per-tensor quantized int8_t input tensor.
667 int8_t input_quantized[kSampleSize];
668 TfLiteTensor input_tensor = tflite::testing::CreateQuantizedTensor(
669 input_values, input_quantized, input_dims, input_scale, input_zero_point);
670 // Set zero point and scale arrays with a single element for each.
671 int input_zero_points[] = {1, input_zero_point};
672 float input_scales[] = {1, input_scale};
673 TfLiteAffineQuantization input_quant = {
674 tflite::testing::FloatArrayFromFloats(input_scales),
675 tflite::testing::IntArrayFromInts(input_zero_points), 0};
676 input_tensor.quantization = {kTfLiteAffineQuantization, &input_quant};
677
678 // Create per-tensor quantized int8_t filter tensor.
679 int8_t filter_quantized[kNumFilters * kSampleSize];
680 TfLiteTensor filter_tensor = tflite::testing::CreateQuantizedTensor(
681 filter_values, filter_quantized, filter_dims, filter_scale,
682 filter_zero_point);
683 // Set zero point and scale arrays with a single element for each.
684 int filter_zero_points[] = {1, filter_zero_point};
685 float filter_scales[] = {1, filter_scale};
686 TfLiteAffineQuantization filter_quant = {
687 tflite::testing::FloatArrayFromFloats(filter_scales),
688 tflite::testing::IntArrayFromInts(filter_zero_points), 0};
689 filter_tensor.quantization = {kTfLiteAffineQuantization, &filter_quant};
690
691 // Create per-tensor quantized int32_t bias tensor.
692 int32_t bias_quantized[kSampleSize];
693 tflite::SymmetricQuantize(bias_values, bias_quantized, kSampleSize,
694 input_scale * output_scale);
695 TfLiteTensor bias_tensor =
696 tflite::testing::CreateTensor(bias_quantized, bias_dims);
697
698 // There is a single zero point of 0, and a single scale of
699 // input_scale * filter_scale.
700 int bias_zero_points[] = {1, 0};
701 float bias_scales[] = {1, input_scale * filter_scale};
702 TfLiteAffineQuantization bias_quant = {
703 tflite::testing::FloatArrayFromFloats(bias_scales),
704 tflite::testing::IntArrayFromInts(bias_zero_points), 0};
705 bias_tensor.quantization = {kTfLiteAffineQuantization, &bias_quant};
706
707 // Create per-tensor quantized int8_t output tensor.
708 int8_t output_quantized[kSampleSize];
709 TfLiteTensor output_tensor = tflite::testing::CreateQuantizedTensor(
710 output_quantized, output_dims, output_scale, output_zero_point);
711 // Set zero point and scale arrays with a single element for each.
712 int output_zero_points[] = {1, output_zero_point};
713 float output_scales[] = {1, output_scale};
714 TfLiteAffineQuantization output_quant = {
715 tflite::testing::FloatArrayFromFloats(output_scales),
716 tflite::testing::IntArrayFromInts(output_zero_points), 0};
717 output_tensor.quantization = {kTfLiteAffineQuantization, &output_quant};
718
719 // The 3 inputs include the input, filter and bias tensors.
720 constexpr int kInputsSize = 3;
721 constexpr int kOutputsSize = 1;
722 constexpr int kTensorsSize = kInputsSize + kOutputsSize;
723 TfLiteTensor tensors[kTensorsSize] = {
724 input_tensor,
725 filter_tensor,
726 bias_tensor,
727 output_tensor,
728 };
729
730 int8_t golden_quantized[kSampleSize];
731 tflite::Quantize(expected_output, golden_quantized, output_dims_count,
732 output_scale, output_zero_point);
733
734 // Rounding errors due to quantization should not exceed 1.
735 constexpr int kQuantizationTolerance = 1;
736
737 TF_LITE_MICRO_EXPECT_EQ(
738 kTfLiteOk, tflite::testing::ValidateConvGoldens(
739 tensors, kTensorsSize, golden_quantized, output_dims_count,
740 &conv_params, tflite::Register_CONV_2D(), output_quantized,
741 kQuantizationTolerance));
742 }
743
744 TF_LITE_MICRO_TESTS_END
745