• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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