1 /* Copyright 2017 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/kernels/internal/tensor_ctypes.h"
19 #include "tensorflow/lite/micro/kernels/kernel_runner.h"
20 #include "tensorflow/lite/micro/test_helpers.h"
21 #include "tensorflow/lite/micro/testing/micro_test.h"
22
23 namespace tflite {
24 namespace testing {
25 namespace {
26
27 #if !defined(XTENSA) // Needed to avoid build errors from unused variables.
28 constexpr int kMaxFilterChannels = 64;
29 constexpr int kMaxBiasChannels = 64;
30 #endif // !defined(XTENSA)
31
32 // Index of the output tensor in context->tensors, specific to
33 // DepthwiseConv.
34 constexpr int kOutputTensorIndex = 3;
35
36 // Creates a DepthwiseConv opeerator, calls it with the provided input tensors
37 // and some defaults parameters, and compares the output with
38 // expected_output_data.
39 //
40 // The tensors parameter contains both the input tensors as well as a
41 // preallocated output tensor into which the output is stored.
42 template <typename T>
ValidateDepthwiseConvGoldens(const T * expected_output_data,int output_length,TfLiteDepthwiseConvParams * conv_params,float tolerance,int tensors_size,TfLiteTensor * tensors)43 TfLiteStatus ValidateDepthwiseConvGoldens(
44 const T* expected_output_data, int output_length,
45 TfLiteDepthwiseConvParams* conv_params, float tolerance, int tensors_size,
46 TfLiteTensor* tensors) {
47 int inputs_array_data[] = {3, 0, 1, 2};
48 TfLiteIntArray* inputs_array = IntArrayFromInts(inputs_array_data);
49 int outputs_array_data[] = {1, 3};
50 TfLiteIntArray* outputs_array = IntArrayFromInts(outputs_array_data);
51
52 const TfLiteRegistration registration = Register_DEPTHWISE_CONV_2D();
53 micro::KernelRunner runner(registration, tensors, tensors_size, inputs_array,
54 outputs_array,
55 reinterpret_cast<void*>(conv_params));
56
57 int input_depth = tensors[0].dims->data[3];
58 int output_depth = tensors[1].dims->data[3];
59 int depth_mul = output_depth / input_depth;
60
61 conv_params->padding = kTfLitePaddingValid;
62 conv_params->stride_height = 1;
63 conv_params->stride_width = 1;
64 conv_params->depth_multiplier = depth_mul;
65
66 const char* init_data = reinterpret_cast<const char*>(conv_params);
67
68 // TODO(b/154240825): Use a test macro here which fails and returns.
69 TfLiteStatus status = runner.InitAndPrepare(init_data);
70 if (status != kTfLiteOk) {
71 return status;
72 }
73 TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.Invoke());
74
75 const T* output_data = tflite::GetTensorData<T>(&tensors[kOutputTensorIndex]);
76 for (int i = 0; i < output_length; ++i) {
77 TF_LITE_MICRO_EXPECT_NEAR(expected_output_data[i], output_data[i],
78 tolerance);
79 }
80 return kTfLiteOk;
81 }
82
83 #if !defined(XTENSA) // Needed to avoid build errors from unsused functions.
TestDepthwiseConvFloat(const int * input_dims_data,const float * input_data,const int * filter_dims_data,const float * filter_data,const int * bias_dims_data,const float * bias_data,const float * expected_output_data,const int * output_dims_data,TfLiteDepthwiseConvParams * conv_params,float * output_data)84 void TestDepthwiseConvFloat(const int* input_dims_data, const float* input_data,
85 const int* filter_dims_data,
86 const float* filter_data, const int* bias_dims_data,
87 const float* bias_data,
88 const float* expected_output_data,
89 const int* output_dims_data,
90 TfLiteDepthwiseConvParams* conv_params,
91 float* output_data) {
92 TfLiteIntArray* input_dims = IntArrayFromInts(input_dims_data);
93 TfLiteIntArray* filter_dims = IntArrayFromInts(filter_dims_data);
94 TfLiteIntArray* bias_dims = IntArrayFromInts(bias_dims_data);
95 TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
96 const int output_dims_count = ElementCount(*output_dims);
97
98 constexpr int inputs_size = 3;
99 constexpr int outputs_size = 1;
100 constexpr int tensors_size = inputs_size + outputs_size;
101 TfLiteTensor tensors[tensors_size] = {
102 CreateTensor(input_data, input_dims),
103 CreateTensor(filter_data, filter_dims),
104 CreateTensor(bias_data, bias_dims),
105 CreateTensor(output_data, output_dims),
106 };
107
108 ValidateDepthwiseConvGoldens(expected_output_data, output_dims_count,
109 conv_params, 1e-5, tensors_size, tensors);
110 }
111
TestDepthwiseConvQuantizedPerLayer(const int * input_dims_data,const float * input_data,uint8_t * input_quantized,float input_scale,int input_zero_point,const int * filter_dims_data,const float * filter_data,uint8_t * filter_quantized,float filter_scale,int filter_zero_point,const int * bias_dims_data,const float * bias_data,int32_t * bias_quantized,const float * golden,uint8_t * golden_quantized,const int * output_dims_data,uint8_t * output_data,float output_scale,int output_zero_point,TfLiteDepthwiseConvParams * conv_params)112 void TestDepthwiseConvQuantizedPerLayer(
113 const int* input_dims_data, const float* input_data,
114 uint8_t* input_quantized, float input_scale, int input_zero_point,
115 const int* filter_dims_data, const float* filter_data,
116 uint8_t* filter_quantized, float filter_scale, int filter_zero_point,
117 const int* bias_dims_data, const float* bias_data, int32_t* bias_quantized,
118 const float* golden, uint8_t* golden_quantized, const int* output_dims_data,
119 uint8_t* output_data, float output_scale, int output_zero_point,
120 TfLiteDepthwiseConvParams* conv_params) {
121 TfLiteIntArray* input_dims = IntArrayFromInts(input_dims_data);
122 TfLiteIntArray* filter_dims = IntArrayFromInts(filter_dims_data);
123 TfLiteIntArray* bias_dims = IntArrayFromInts(bias_dims_data);
124 TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
125 const int output_dims_count = ElementCount(*output_dims);
126
127 constexpr int inputs_size = 3;
128 constexpr int outputs_size = 1;
129 constexpr int tensors_size = inputs_size + outputs_size;
130 TfLiteTensor tensors[tensors_size] = {
131 tflite::testing::CreateQuantizedTensor(input_data, input_quantized,
132 input_dims, input_scale,
133 input_zero_point),
134 tflite::testing::CreateQuantizedTensor(filter_data, filter_quantized,
135 filter_dims, filter_scale,
136 filter_zero_point),
137 tflite::testing::CreateQuantizedBiasTensor(
138 bias_data, bias_quantized, bias_dims, input_scale, filter_scale),
139 tflite::testing::CreateQuantizedTensor(output_data, output_dims,
140 output_scale, output_zero_point),
141 };
142
143 // TODO(njeff): Affine Quantization Params should be set on tensor creation.
144 float filter_scales[] = {1, filter_scale};
145 int filter_zero_points[] = {1, 128};
146 TfLiteAffineQuantization filter_quant = {FloatArrayFromFloats(filter_scales),
147 IntArrayFromInts(filter_zero_points),
148 0};
149 tensors[1].quantization = {kTfLiteAffineQuantization, &filter_quant};
150
151 float bias_scales[] = {1, filter_scale * input_scale};
152 int bias_zero_points[] = {1, 128};
153 TfLiteAffineQuantization bias_quant = {FloatArrayFromFloats(bias_scales),
154 IntArrayFromInts(bias_zero_points), 0};
155 tensors[2].quantization = {kTfLiteAffineQuantization, &bias_quant};
156
157 Quantize(golden, golden_quantized, output_dims_count, output_scale,
158 output_zero_point);
159 ValidateDepthwiseConvGoldens(golden_quantized, output_dims_count, conv_params,
160 1.0, tensors_size, tensors);
161 }
162
TestDepthwiseConvQuantizedPerChannel(const int * input_dims_data,const float * input_data,int8_t * input_quantized,float input_scale,int input_zero_point,const int * filter_dims_data,const float * filter_data,int8_t * filter_data_quantized,const int * bias_dims_data,const float * bias_data,int32_t * bias_data_quantized,const int * output_dims_data,const float * expected_output_data,int8_t * expected_output_data_quantized,int8_t * output_data,float output_scale,int output_zero_point,TfLiteDepthwiseConvParams * conv_params)163 void TestDepthwiseConvQuantizedPerChannel(
164 const int* input_dims_data, const float* input_data,
165 int8_t* input_quantized, float input_scale, int input_zero_point,
166 const int* filter_dims_data, const float* filter_data,
167 int8_t* filter_data_quantized, const int* bias_dims_data,
168 const float* bias_data, int32_t* bias_data_quantized,
169 const int* output_dims_data, const float* expected_output_data,
170 int8_t* expected_output_data_quantized, int8_t* output_data,
171 float output_scale, int output_zero_point,
172 TfLiteDepthwiseConvParams* conv_params) {
173 TfLiteIntArray* input_dims = IntArrayFromInts(input_dims_data);
174 TfLiteIntArray* filter_dims = IntArrayFromInts(filter_dims_data);
175 TfLiteIntArray* bias_dims = IntArrayFromInts(bias_dims_data);
176 TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
177 const int output_dims_count = ElementCount(*output_dims);
178
179 int filter_zero_points[kMaxFilterChannels];
180 float filter_scales[kMaxFilterChannels];
181 int bias_zero_points[kMaxBiasChannels];
182 float bias_scales[kMaxBiasChannels];
183 TfLiteAffineQuantization filter_quant;
184 TfLiteAffineQuantization bias_quant;
185 TfLiteTensor input_tensor = CreateQuantizedTensor(
186 input_data, input_quantized, input_dims, input_scale, input_zero_point);
187 TfLiteTensor filter_tensor = CreateSymmetricPerChannelQuantizedTensor(
188 filter_data, filter_data_quantized, filter_dims, filter_scales,
189 filter_zero_points, &filter_quant, 3 /* quantized dimension */
190 );
191 TfLiteTensor bias_tensor = CreatePerChannelQuantizedBiasTensor(
192 bias_data, bias_data_quantized, bias_dims, input_scale, &filter_scales[1],
193 bias_scales, bias_zero_points, &bias_quant, 3 /* quantized dimension */
194 );
195 TfLiteTensor output_tensor = CreateQuantizedTensor(
196 output_data, output_dims, output_scale, input_zero_point);
197
198 // TODO(njeff): Affine Quantization Params should be set on tensor creation.
199 float input_scales[] = {1, input_scale};
200 int input_zero_points[] = {1, input_zero_point};
201 TfLiteAffineQuantization input_quant = {FloatArrayFromFloats(input_scales),
202 IntArrayFromInts(input_zero_points),
203 0};
204 input_tensor.quantization = {kTfLiteAffineQuantization, &input_quant};
205
206 float output_scales[] = {1, output_scale};
207 int output_zero_points[] = {1, output_zero_point};
208 TfLiteAffineQuantization output_quant = {FloatArrayFromFloats(output_scales),
209 IntArrayFromInts(output_zero_points),
210 0};
211 output_tensor.quantization = {kTfLiteAffineQuantization, &output_quant};
212
213 constexpr int inputs_size = 3;
214 constexpr int outputs_size = 1;
215 constexpr int tensors_size = inputs_size + outputs_size;
216 TfLiteTensor tensors[tensors_size] = {
217 input_tensor,
218 filter_tensor,
219 bias_tensor,
220 output_tensor,
221 };
222
223 Quantize(expected_output_data, expected_output_data_quantized,
224 output_dims_count, output_scale, output_zero_point);
225
226 TF_LITE_MICRO_EXPECT_EQ(
227 kTfLiteOk, ValidateDepthwiseConvGoldens(expected_output_data_quantized,
228 output_dims_count, conv_params,
229 1.0, tensors_size, tensors));
230 }
231
232 #endif // !defined(XTENSA)
233
234 } // namespace
235 } // namespace testing
236 } // namespace tflite
237
238 TF_LITE_MICRO_TESTS_BEGIN
239
240 #if !defined(XTENSA) // TODO(b/170322965): xtensa kernels are less general than
241 // reference kernels and we ifdef out test cases that are
242 // currently known to fail.
TF_LITE_MICRO_TEST(SimpleTest)243 TF_LITE_MICRO_TEST(SimpleTest) {
244 const int input_shape[] = {4, 1, 3, 2, 2};
245 const float input_values[] = {1, 2, 7, 8, 3, 4, 9, 10, 5, 6, 11, 12};
246 const int filter_shape[] = {4, 1, 2, 2, 4};
247 const float filter_values[] = {1, 2, 3, 4, -9, 10, -11, 12,
248 5, 6, 7, 8, 13, -14, 15, -16};
249 const int bias_shape[] = {4, 1, 1, 1, 4};
250 const float bias_values[] = {1, 2, 3, 4};
251 const float golden[] = {
252 71, -34, 99, -20, 91, -26, 127, -4,
253 };
254 const int output_shape[] = {4, 1, 2, 1, 4};
255 const int output_dims_count = 8;
256 float output_data[output_dims_count];
257
258 TfLiteDepthwiseConvParams conv_params;
259 conv_params.activation = kTfLiteActNone;
260 conv_params.dilation_width_factor = 1;
261 conv_params.dilation_height_factor = 1;
262
263 tflite::testing::TestDepthwiseConvFloat(
264 input_shape, input_values, filter_shape, filter_values, bias_shape,
265 bias_values, golden, output_shape, &conv_params, output_data);
266 }
267
TF_LITE_MICRO_TEST(SimpleTestQuantized)268 TF_LITE_MICRO_TEST(SimpleTestQuantized) {
269 const int input_elements = 12;
270 const int input_shape[] = {4, 1, 3, 2, 2};
271 const float input_values[] = {1, 2, 7, 8, 3, 4, 9, 10, 5, 6, 11, 12};
272 const int filter_elements = 16;
273 const int filter_shape[] = {4, 1, 2, 2, 4};
274 const float filter_values[] = {1, 2, 3, 4, -9, 10, -11, 12,
275 5, 6, 7, 8, 13, -14, 15, -16};
276 const int bias_elements = 4;
277 const int bias_shape[] = {4, 1, 1, 1, 4};
278 const int output_elements = 8;
279 const float bias_values[] = {1, 2, 3, 4};
280 const float golden[] = {
281 71, -34, 99, -20, 91, -26, 127, -4,
282 };
283 const int output_shape[] = {4, 1, 2, 1, 4};
284
285 const float input_scale = 0.5f;
286 const int input_zero_point = 128;
287 const float filter_scale = 0.5f;
288 const int filter_zero_point = 128;
289 const float output_scale = 1.0f;
290 const int output_zero_point = 128;
291
292 uint8_t input_quantized[input_elements];
293 uint8_t filter_quantized[filter_elements];
294 int32_t bias_quantized[bias_elements];
295 uint8_t golden_quantized[output_elements];
296 uint8_t output_data[output_elements];
297
298 TfLiteDepthwiseConvParams conv_params;
299 conv_params.activation = kTfLiteActNone;
300 conv_params.dilation_width_factor = 1;
301 conv_params.dilation_height_factor = 1;
302
303 tflite::testing::TestDepthwiseConvQuantizedPerLayer(
304 input_shape, input_values, input_quantized, input_scale, input_zero_point,
305 filter_shape, filter_values, filter_quantized, filter_scale,
306 filter_zero_point, bias_shape, bias_values, bias_quantized, golden,
307 golden_quantized, output_shape, output_data, output_scale,
308 output_zero_point, &conv_params);
309 }
310
TF_LITE_MICRO_TEST(SimpleTestDilatedQuantized)311 TF_LITE_MICRO_TEST(SimpleTestDilatedQuantized) {
312 const int input_elements = 48;
313 const int input_shape[] = {4, 1, 4, 6, 2};
314 const float input_values[] = {1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, // h = 0
315 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, // h = 1
316 1, 2, 3, 4, 5, 6, 2, 6, 2, 4, 4, 2, // h = 2
317 3, 2, 6, 5, 1, 4, 1, 2, 1, 4, 6, 3}; // h = 3
318 const int filter_elements = 16;
319 const int filter_shape[] = {4, 1, 2, 2, 4};
320 const float filter_values[] = {1, 2, 3, 4, -9, 10, -11, 12,
321 5, 6, 7, 8, 13, -14, 15, -16};
322 const int bias_elements = 4;
323 const int bias_shape[] = {4, 1, 1, 1, 4};
324 const int output_elements = 24;
325 const float bias_values[] = {1, 2, 3, 4};
326 const float golden[] = {
327 15, 2, 88, -48, 25, 14, 72, 0, 61, -2, 56, 48, // h = 0
328 -4, 52, 12, 48, 11, 70, 63, 40, 51, -30, 41, 48 // h = 1
329 };
330 const int output_shape[] = {4, 1, 2, 3, 4};
331
332 const float input_scale = 0.5f;
333 const int input_zero_point = 128;
334 const float filter_scale = 0.5f;
335 const int filter_zero_point = 128;
336 const float output_scale = 1.0f;
337 const int output_zero_point = 128;
338
339 uint8_t input_quantized[input_elements];
340 uint8_t filter_quantized[filter_elements];
341 int32_t bias_quantized[bias_elements];
342 uint8_t golden_quantized[output_elements];
343 uint8_t output_data[output_elements];
344
345 TfLiteDepthwiseConvParams conv_params;
346 conv_params.activation = kTfLiteActNone;
347 conv_params.dilation_width_factor = 3;
348 conv_params.dilation_height_factor = 2;
349
350 tflite::testing::TestDepthwiseConvQuantizedPerLayer(
351 input_shape, input_values, input_quantized, input_scale, input_zero_point,
352 filter_shape, filter_values, filter_quantized, filter_scale,
353 filter_zero_point, bias_shape, bias_values, bias_quantized, golden,
354 golden_quantized, output_shape, output_data, output_scale,
355 output_zero_point, &conv_params);
356 }
357
TF_LITE_MICRO_TEST(SimpleTestRelu)358 TF_LITE_MICRO_TEST(SimpleTestRelu) {
359 const int input_shape[] = {4, 1, 3, 2, 2};
360 const float input_values[] = {1, 2, 7, 8, 3, 4, 9, 10, 5, 6, 11, 12};
361 const int filter_shape[] = {4, 1, 2, 2, 4};
362 const float filter_values[] = {1, 2, 3, 4, -9, 10, -11, 12,
363 5, 6, 7, 8, 13, -14, 15, -16};
364 const int bias_shape[] = {4, 1, 1, 1, 4};
365 const float bias_values[] = {1, 2, 3, 4};
366 const int output_shape[] = {4, 1, 2, 1, 4};
367 const int output_dims_count = 8;
368 const float golden_relu[] = {71, 0, 99, 0, 91, 0, 127, 0};
369 float output_data[output_dims_count];
370
371 TfLiteDepthwiseConvParams conv_params;
372 conv_params.activation = kTfLiteActRelu;
373 conv_params.dilation_width_factor = 1;
374 conv_params.dilation_height_factor = 1;
375
376 tflite::testing::TestDepthwiseConvFloat(
377 input_shape, input_values, filter_shape, filter_values, bias_shape,
378 bias_values, golden_relu, output_shape, &conv_params, output_data);
379 }
380
TF_LITE_MICRO_TEST(SimpleTestReluQuantized)381 TF_LITE_MICRO_TEST(SimpleTestReluQuantized) {
382 const int input_elements = 12;
383 const int input_shape[] = {4, 1, 3, 2, 2};
384 const float input_values[] = {1, 2, 7, 8, 3, 4, 9, 10, 5, 6, 11, 12};
385 const int filter_elements = 16;
386 const int filter_shape[] = {4, 1, 2, 2, 4};
387 const float filter_values[] = {1, 2, 3, 4, -9, 10, -11, 12,
388 5, 6, 7, 8, 13, -14, 15, -16};
389 const int bias_elements = 4;
390 const int bias_shape[] = {4, 1, 1, 1, 4};
391 const int output_elements = 8;
392 const float bias_values[] = {1, 2, 3, 4};
393 const int output_shape[] = {4, 1, 2, 1, 4};
394 const float golden_relu[] = {71, 0, 99, 0, 91, 0, 127, 0};
395
396 const float input_scale = 0.5f;
397 const int input_zero_point = 128;
398 const float filter_scale = 0.5f;
399 const int filter_zero_point = 128;
400 const float output_scale = 1.0f;
401 const int output_zero_point = 128;
402
403 uint8_t input_quantized[input_elements];
404 uint8_t filter_quantized[filter_elements];
405 int32_t bias_quantized[bias_elements];
406 uint8_t golden_quantized[output_elements];
407 uint8_t output_data[output_elements];
408
409 TfLiteDepthwiseConvParams conv_params;
410 conv_params.activation = kTfLiteActRelu;
411 conv_params.dilation_width_factor = 1;
412 conv_params.dilation_height_factor = 1;
413
414 tflite::testing::TestDepthwiseConvQuantizedPerLayer(
415 input_shape, input_values, input_quantized, input_scale, input_zero_point,
416 filter_shape, filter_values, filter_quantized, filter_scale,
417 filter_zero_point, bias_shape, bias_values, bias_quantized, golden_relu,
418 golden_quantized, output_shape, output_data, output_scale,
419 output_zero_point, &conv_params);
420 }
421
TF_LITE_MICRO_TEST(SimpleTestQuantizedOptimizedFilterWidth)422 TF_LITE_MICRO_TEST(SimpleTestQuantizedOptimizedFilterWidth) {
423 const int input_elements = 12;
424 const float input_values[] = {1, 2, 7, 8, 3, 4, 9, 10, 5, 6, 11, 12};
425 const int filter_elements = 16;
426 const float filter_values[] = {1, 2, 3, 4, -9, 10, -11, 12,
427 5, 6, 7, 8, 13, -14, 15, -16};
428 const int bias_elements = 4;
429 const float bias_values[] = {1, 2, 3, 4};
430 const int output_dims_count = 9;
431 const int input_shape[] = {4, 1, 1, 9, 1};
432 const int filter_shape[] = {4, 2, 1, 8, 1};
433 const int bias_shape[] = {1, 1};
434 const float goldens[] = {
435 92, 56, 12, 22, 33, 72, 44, 20, 5,
436 };
437 const int output_shape[] = {4, 1, 1, 9, 1};
438
439 const float input_scale = 1.0f;
440 const int input_zero_point = 128;
441 const float filter_scale = 0.5f;
442 const int filter_zero_point = 128;
443 const float output_scale = 1.0f;
444 const int output_zero_point = 128;
445
446 uint8_t input_quantized[input_elements];
447 uint8_t filter_quantized[filter_elements];
448 int32_t bias_quantized[bias_elements];
449 uint8_t golden_quantized[output_dims_count];
450 uint8_t output_data[output_dims_count];
451
452 TfLiteDepthwiseConvParams conv_params;
453 conv_params.activation = kTfLiteActNone;
454 conv_params.dilation_width_factor = 1;
455 conv_params.dilation_height_factor = 1;
456
457 tflite::testing::TestDepthwiseConvQuantizedPerLayer(
458 input_shape, input_values, input_quantized, input_scale, input_zero_point,
459 filter_shape, filter_values, filter_quantized, filter_scale,
460 filter_zero_point, bias_shape, bias_values, bias_quantized, goldens,
461 golden_quantized, output_shape, output_data, output_scale,
462 output_zero_point, &conv_params);
463 }
464
TF_LITE_MICRO_TEST(SimpleTestQuantizedPerChannel)465 TF_LITE_MICRO_TEST(SimpleTestQuantizedPerChannel) {
466 const int input_elements = 12;
467 const int input_shape[] = {4, 1, 3, 2, 2};
468 const float input_values[] = {1, 2, 7, 8, 3, 4, 9, 10, 5, 6, 11, 12};
469 const int filter_elements = 16;
470 const int filter_shape[] = {4, 1, 2, 2, 4};
471 const float filter_values[] = {1, 2, 3, 4, -9, 10, -11, 12,
472 5, 6, 7, 8, 13, -14, 15, -16};
473 const int bias_elements = 4;
474 const int bias_shape[] = {4, 1, 1, 1, 4};
475 const int output_elements = 8;
476 const float bias_values[] = {1, 2, 3, 4};
477 const float golden[] = {
478 71, -34, 99, -20, 91, -26, 127, -4,
479 };
480 const int output_shape[] = {4, 1, 2, 1, 4};
481 const int output_dims_count = 8;
482 int8_t output_data[output_dims_count];
483
484 const float input_scale = 0.5;
485 const float output_scale = 1.0f;
486 const int input_zero_point = 0;
487 const int output_zero_point = 0;
488
489 int8_t input_quantized[input_elements];
490 int8_t filter_quantized[filter_elements];
491 int32_t bias_quantized[bias_elements];
492 int8_t golden_quantized[output_elements];
493
494 TfLiteDepthwiseConvParams conv_params;
495 conv_params.activation = kTfLiteActNone;
496 conv_params.dilation_width_factor = 1;
497 conv_params.dilation_height_factor = 1;
498
499 tflite::testing::TestDepthwiseConvQuantizedPerChannel(
500 input_shape, input_values, input_quantized, input_scale, input_zero_point,
501 filter_shape, filter_values, filter_quantized, bias_shape, bias_values,
502 bias_quantized, output_shape, golden, golden_quantized, output_data,
503 output_scale, output_zero_point, &conv_params);
504 }
505
TF_LITE_MICRO_TEST(SimpleTestQuantizedPerChannelDepthMultiplier1)506 TF_LITE_MICRO_TEST(SimpleTestQuantizedPerChannelDepthMultiplier1) {
507 const int input_elements = 12;
508 const int input_shape[] = {4, 1, 3, 2, 2};
509 const float input_values[] = {1, 2, 7, 8, 3, 4, 9, 10, 5, 6, 11, 12};
510 const int filter_elements = 8;
511 const int filter_shape[] = {4, 1, 2, 2, 2};
512 const float filter_values[] = {1, 2, 3, 4, -9, 10, -11, 12};
513 const int bias_elements = 2;
514 const int bias_shape[] = {4, 1, 1, 1, 2};
515 const int output_elements = 4;
516 const float bias_values[] = {1, 2};
517 const float golden[] = {
518 -103,
519 127,
520 -128,
521 127,
522 };
523 const int output_shape[] = {4, 1, 2, 1, 2};
524 const int output_dims_count = 4;
525 int8_t output_data[output_dims_count];
526
527 const float input_scale = 1.0f;
528 const float output_scale = 1.0f;
529 const int input_zero_point = 0;
530 const int output_zero_point = 0;
531
532 int8_t input_quantized[input_elements];
533 int8_t filter_quantized[filter_elements];
534 int32_t bias_quantized[bias_elements];
535 int8_t golden_quantized[output_elements];
536
537 TfLiteDepthwiseConvParams conv_params;
538 conv_params.activation = kTfLiteActNone;
539 conv_params.dilation_width_factor = 1;
540 conv_params.dilation_height_factor = 1;
541
542 tflite::testing::TestDepthwiseConvQuantizedPerChannel(
543 input_shape, input_values, input_quantized, input_scale, input_zero_point,
544 filter_shape, filter_values, filter_quantized, bias_shape, bias_values,
545 bias_quantized, output_shape, golden, golden_quantized, output_data,
546 output_scale, output_zero_point, &conv_params);
547 }
548
TF_LITE_MICRO_TEST(TestQuantizedPerChannelDepthMultiplier1Relu6)549 TF_LITE_MICRO_TEST(TestQuantizedPerChannelDepthMultiplier1Relu6) {
550 const int input_elements = 24;
551 const int input_shape[] = {4, 1, 3, 2, 4};
552 const float input_values[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
553 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
554 const int filter_elements = 16;
555 const int filter_shape[] = {4, 1, 2, 2, 4};
556 const float filter_values[] = {0, 1, 8, -2, -1, 2, -10, 0,
557 -1, 3, -18, 0, 0, 4, 20, -3};
558 const int bias_elements = 4;
559 const int bias_shape[] = {4, 1, 1, 1, 4};
560 const int output_elements = 8;
561 const float bias_values[] = {1, 2, 3, 4};
562 const float golden[] = {
563 0, 6, 3, 0, 0, 6, 3, 0,
564 };
565 const int output_shape[] = {4, 1, 2, 1, 4};
566 int8_t output_data[output_elements];
567
568 const float input_scale = 0.023529f;
569 const float output_scale = 0.023529f;
570 const int input_zero_point = -128;
571 const int output_zero_point = -128;
572
573 int8_t input_quantized[input_elements];
574 int8_t filter_quantized[filter_elements];
575 int32_t bias_quantized[bias_elements];
576 int8_t golden_quantized[output_elements];
577
578 TfLiteDepthwiseConvParams conv_params;
579 conv_params.activation = kTfLiteActRelu6;
580 conv_params.dilation_width_factor = 1;
581 conv_params.dilation_height_factor = 1;
582
583 tflite::testing::TestDepthwiseConvQuantizedPerChannel(
584 input_shape, input_values, input_quantized, input_scale, input_zero_point,
585 filter_shape, filter_values, filter_quantized, bias_shape, bias_values,
586 bias_quantized, output_shape, golden, golden_quantized, output_data,
587 output_scale, output_zero_point, &conv_params);
588 }
589
TF_LITE_MICRO_TEST(SimpleTestDilatedQuantizedPerChannel)590 TF_LITE_MICRO_TEST(SimpleTestDilatedQuantizedPerChannel) {
591 const int input_elements = 48;
592 const int input_shape[] = {4, 1, 4, 6, 2};
593 const float input_values[] = {1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, // h = 0
594 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, // h = 1
595 1, 2, 3, 4, 5, 6, 2, 6, 2, 4, 4, 2, // h = 2
596 3, 2, 6, 5, 1, 4, 1, 2, 1, 4, 6, 3}; // h = 3
597 const int filter_elements = 16;
598 const int filter_shape[] = {4, 1, 2, 2, 4};
599 const float filter_values[] = {1, 2, 3, 4, -9, 10, -11, 12,
600 5, 6, 7, 8, 13, -14, 15, -16};
601 const int bias_elements = 4;
602 const int bias_shape[] = {4, 1, 1, 1, 4};
603 const int output_elements = 24;
604 const float bias_values[] = {1, 2, 3, 4};
605 const float golden[] = {
606 15, 2, 88, -48, 25, 14, 72, 0, 61, -2, 56, 48, // h = 0
607 -4, 52, 12, 48, 11, 70, 63, 40, 51, -30, 41, 48 // h = 1
608 };
609 const int output_shape[] = {4, 1, 2, 3, 4};
610 int8_t output_data[output_elements];
611
612 const float input_scale = 0.5;
613 const float output_scale = 1.0f;
614 const int input_zero_point = 0;
615 const int output_zero_point = 0;
616
617 int8_t input_quantized[input_elements];
618 int8_t filter_quantized[filter_elements];
619 int32_t bias_quantized[bias_elements];
620 int8_t golden_quantized[output_elements];
621
622 TfLiteDepthwiseConvParams conv_params;
623 conv_params.activation = kTfLiteActNone;
624 conv_params.dilation_width_factor = 3;
625 conv_params.dilation_height_factor = 2;
626
627 tflite::testing::TestDepthwiseConvQuantizedPerChannel(
628 input_shape, input_values, input_quantized, input_scale, input_zero_point,
629 filter_shape, filter_values, filter_quantized, bias_shape, bias_values,
630 bias_quantized, output_shape, golden, golden_quantized, output_data,
631 output_scale, output_zero_point, &conv_params);
632 }
633
TF_LITE_MICRO_TEST(TestQuantizedPerChannelCompareWithFloat)634 TF_LITE_MICRO_TEST(TestQuantizedPerChannelCompareWithFloat) {
635 const int input_dims[] = {4, 1, 2, 3, 2};
636 const float input_data[] = {3, 2, 1, -1, -2, -3, 4, 3, 2, -2, -3, -4};
637 const int filter_dims[] = {4, 1, 2, 2, 4};
638 const float filter_data[] = {1, 2, 3, 4, 3, 4, 5, 6, 7, 8, 5, 6, 3, 4, 1, 2};
639 const int bias_dims[] = {4, 1, 1, 1, 4};
640 const float bias_data[] = {3, -2, 4, 6};
641 const int output_dims[] = {4, 1, 1, 2, 4};
642 const float golden[] = {43, 48, 18, 22, 3, -4, -28, -36};
643
644 const int input_size = 12;
645 const int filter_size = 16;
646 const int output_size = 8;
647 const int bias_size = 4;
648 int8_t input_quantized[input_size];
649 int8_t filter_quantized[filter_size];
650 int32_t bias_quantized[bias_size];
651 int8_t golden_quantized[output_size];
652 int8_t output_data[output_size];
653 float output_float[output_size];
654
655 const float input_scale = 0.5;
656 const float output_scale = 1.0;
657 const int input_zero_point = 0;
658 const int output_zero_point = 0;
659
660 TfLiteDepthwiseConvParams conv_params;
661 conv_params.activation = kTfLiteActNone;
662 conv_params.dilation_width_factor = 1;
663 conv_params.dilation_height_factor = 1;
664
665 tflite::testing::TestDepthwiseConvQuantizedPerChannel(
666 input_dims, input_data, input_quantized, input_scale, input_zero_point,
667 filter_dims, filter_data, filter_quantized, bias_dims, bias_data,
668 bias_quantized, output_dims, golden, golden_quantized, output_data,
669 output_scale, output_zero_point, &conv_params);
670
671 tflite::testing::TestDepthwiseConvFloat(
672 input_dims, input_data, filter_dims, filter_data, bias_dims, bias_data,
673 golden, output_dims, &conv_params, output_float);
674 }
675
TF_LITE_MICRO_TEST(PerChannelBroadcastQuantizationParams)676 TF_LITE_MICRO_TEST(PerChannelBroadcastQuantizationParams) {
677 const float input_scale = 1.0f;
678 const float filter_scale = 1.0f;
679 const float output_scale = 1.0f;
680
681 const int input_elements = 12;
682 const int input_shape[] = {4, 1, 3, 2, 2};
683 const float input_values[] = {1, 2, 7, 8, 3, 4, 9, 10, 5, 6, 11, 12};
684 const int filter_elements = 16;
685 const int filter_shape[] = {4, 1, 2, 2, 4};
686 const float filter_values[] = {1, 2, 3, 4, -9, 10, -11, 12,
687 5, 6, 7, 8, 13, -14, 15, -16};
688 const int bias_elements = 4;
689 const int bias_shape[] = {4, 1, 1, 1, 4};
690 const int output_elements = 8;
691 const float bias_values[] = {1, 2, 3, 4};
692 const float golden[] = {
693 71, -34, 99, -20, 91, -26, 127, -4,
694 };
695 const int output_shape[] = {4, 1, 2, 1, 4};
696 const int output_dims_count = 8;
697 int8_t output_data[output_dims_count];
698
699 int8_t input_quantized[input_elements];
700 int8_t filter_quantized[filter_elements];
701 int32_t bias_quantized[bias_elements];
702 int8_t golden_quantized[output_elements];
703
704 TfLiteIntArray* input_dims = tflite::testing::IntArrayFromInts(input_shape);
705 TfLiteIntArray* filter_dims = tflite::testing::IntArrayFromInts(filter_shape);
706 TfLiteIntArray* bias_dims = tflite::testing::IntArrayFromInts(bias_shape);
707 TfLiteIntArray* output_dims = tflite::testing::IntArrayFromInts(output_shape);
708
709 // Create per-layer quantized int8_t input tensor.
710 TfLiteTensor input_tensor = tflite::testing::CreateQuantizedTensor(
711 input_values, input_quantized, input_dims, input_scale, 0);
712 int input_zero_points[2] = {1, 0};
713 float input_scales[2] = {1, input_scale};
714 TfLiteAffineQuantization input_quant = {
715 tflite::testing::FloatArrayFromFloats(input_scales),
716 tflite::testing::IntArrayFromInts(input_zero_points), 0};
717 input_tensor.quantization = {kTfLiteAffineQuantization, &input_quant};
718
719 // Create per-layer quantized int8_t filter tensor.
720 TfLiteTensor filter_tensor = tflite::testing::CreateQuantizedTensor(
721 filter_values, filter_quantized, filter_dims, filter_scale, 0);
722 int filter_zero_points[2] = {1, 0};
723 float filter_scales[2] = {1, filter_scale};
724 TfLiteAffineQuantization filter_quant = {
725 tflite::testing::FloatArrayFromFloats(filter_scales),
726 tflite::testing::IntArrayFromInts(filter_zero_points), 0};
727 filter_tensor.quantization = {kTfLiteAffineQuantization, &filter_quant};
728
729 // Create per-layer quantized int32_t bias tensor.
730 tflite::SymmetricQuantize(bias_values, bias_quantized, bias_elements,
731 input_scale * output_scale);
732 TfLiteTensor bias_tensor =
733 tflite::testing::CreateTensor(bias_quantized, bias_dims);
734
735 int bias_zero_points[2] = {1, 0};
736 float bias_scales[2] = {1, input_scale * filter_scale};
737 TfLiteAffineQuantization bias_quant = {
738 tflite::testing::FloatArrayFromFloats(bias_scales),
739 tflite::testing::IntArrayFromInts(bias_zero_points), 0};
740 bias_tensor.quantization = {kTfLiteAffineQuantization, &bias_quant};
741
742 // Create per-layer quantized int8_t output tensor.
743 TfLiteTensor output_tensor = tflite::testing::CreateQuantizedTensor(
744 output_data, output_dims, output_scale, 0);
745 int output_zero_points[2] = {1, 0};
746 float output_scales[2] = {1, output_scale};
747 TfLiteAffineQuantization output_quant = {
748 tflite::testing::FloatArrayFromFloats(output_scales),
749 tflite::testing::IntArrayFromInts(output_zero_points), 0};
750 output_tensor.quantization = {kTfLiteAffineQuantization, &output_quant};
751
752 constexpr int inputs_size = 3;
753 constexpr int outputs_size = 1;
754 constexpr int tensors_size = inputs_size + outputs_size;
755 TfLiteTensor tensors[tensors_size] = {
756 input_tensor,
757 filter_tensor,
758 bias_tensor,
759 output_tensor,
760 };
761
762 tflite::Quantize(golden, golden_quantized, output_dims_count, output_scale,
763 0);
764
765 TfLiteDepthwiseConvParams conv_params;
766 conv_params.activation = kTfLiteActNone;
767 conv_params.dilation_width_factor = 1;
768 conv_params.dilation_height_factor = 1;
769
770 TF_LITE_MICRO_EXPECT_EQ(
771 kTfLiteOk, tflite::testing::ValidateDepthwiseConvGoldens(
772 golden_quantized, output_dims_count, &conv_params, 1e-5,
773 tensors_size, tensors));
774 }
775
776 #endif // !defined(XTENSA)
777
TF_LITE_MICRO_TEST(FilterDimsNotMatchingAffineQuantization)778 TF_LITE_MICRO_TEST(FilterDimsNotMatchingAffineQuantization) {
779 const int input_shape[] = {4, 1, 2, 3, 2};
780 const float input_data[] = {3, 2, 1, -1, -2, -3, 4, 3, 2, -2, -3, -4};
781 const int filter_shape[] = {4, 1, 2, 2, 4};
782 const float filter_data[] = {1, 2, 3, 4, 3, 4, 5, 6, 7, 8, 5, 6, 3, 4, 1, 2};
783 const int bias_shape[] = {4, 1, 1, 1, 4};
784 const float bias_data[] = {3, -2, 4, 6};
785 const int output_shape[] = {4, 1, 1, 2, 4};
786
787 const int input_size = 12;
788 const int filter_size = 16;
789 const int output_size = 8;
790 const int bias_size = 4;
791 int8_t input_quantized[input_size];
792 int8_t filter_quantized[filter_size];
793 int32_t bias_quantized[bias_size];
794 int8_t golden_quantized[output_size];
795 int zero_points[bias_size + 1];
796 float scales[bias_size + 1];
797 int8_t output_data[output_size];
798
799 const float input_scale = 0.5;
800 const float output_scale = 1.0;
801 const int input_zero_point = 0;
802 const int output_zero_point = 0;
803
804 TfLiteIntArray* input_dims = tflite::testing::IntArrayFromInts(input_shape);
805 TfLiteIntArray* filter_dims = tflite::testing::IntArrayFromInts(filter_shape);
806 TfLiteIntArray* bias_dims = tflite::testing::IntArrayFromInts(bias_shape);
807 TfLiteIntArray* output_dims = tflite::testing::IntArrayFromInts(output_shape);
808
809 int filter_zero_points[5];
810 float filter_scales[5];
811 TfLiteAffineQuantization filter_quant;
812 TfLiteAffineQuantization bias_quant;
813 TfLiteTensor input_tensor = tflite::testing::CreateQuantizedTensor(
814 input_data, input_quantized, input_dims, input_scale, input_zero_point);
815 TfLiteTensor filter_tensor =
816 tflite::testing::CreateSymmetricPerChannelQuantizedTensor(
817 filter_data, filter_quantized, filter_dims, filter_scales,
818 filter_zero_points, &filter_quant, 0 /* quantized dimension */);
819 TfLiteTensor bias_tensor =
820 tflite::testing::CreatePerChannelQuantizedBiasTensor(
821 bias_data, bias_quantized, bias_dims, input_scale, &filter_scales[1],
822 scales, zero_points, &bias_quant, 0);
823 TfLiteTensor output_tensor = tflite::testing::CreateQuantizedTensor(
824 output_data, output_dims, output_scale, output_zero_point);
825
826 float input_scales[] = {1, input_scale};
827 int input_zero_points[] = {1, input_zero_point};
828 TfLiteAffineQuantization input_quant = {
829 tflite::testing::FloatArrayFromFloats(input_scales),
830 tflite::testing::IntArrayFromInts(input_zero_points), 0};
831 input_tensor.quantization = {kTfLiteAffineQuantization, &input_quant};
832
833 constexpr int inputs_size = 3;
834 constexpr int outputs_size = 1;
835 constexpr int tensors_size = inputs_size + outputs_size;
836 TfLiteTensor tensors[tensors_size] = {
837 input_tensor,
838 filter_tensor,
839 bias_tensor,
840 output_tensor,
841 };
842
843 TfLiteDepthwiseConvParams conv_params;
844 conv_params.activation = kTfLiteActNone;
845 conv_params.dilation_width_factor = 1;
846 conv_params.dilation_height_factor = 1;
847
848 // Set filter quant to mismatched dimension.
849 TfLiteAffineQuantization* quant = reinterpret_cast<TfLiteAffineQuantization*>(
850 filter_tensor.quantization.params);
851 quant->scale->size = 2;
852 TF_LITE_MICRO_EXPECT_EQ(kTfLiteError,
853 tflite::testing::ValidateDepthwiseConvGoldens(
854 golden_quantized, output_size, &conv_params, 1e-5,
855 tensors_size, tensors));
856
857 // Set scale back to correct dimension, and make zero point array too short.
858 quant->scale->size = filter_shape[0];
859 quant->zero_point->size = 2;
860 TF_LITE_MICRO_EXPECT_EQ(kTfLiteError,
861 tflite::testing::ValidateDepthwiseConvGoldens(
862 golden_quantized, output_size, &conv_params, 1e-5,
863 tensors_size, tensors));
864 }
865
TF_LITE_MICRO_TEST(Int8Input32x4Filter32x4ShouldMatchGolden)866 TF_LITE_MICRO_TEST(Int8Input32x4Filter32x4ShouldMatchGolden) {
867 const int input_elements = 32 * 4;
868 const int filter_elements = 32 * 4;
869 const int bias_elements = 32;
870 const int output_elements = 32;
871 const int input_shape[] = {4, 1, 4, 1, 32};
872 const int filter_shape[] = {4, 1, 4, 1, 32};
873 const int bias_shape[] = {1, 32};
874 const int output_shape[] = {4, 1, 1, 1, 32};
875 const float input_values[] = {
876 11.0589, 10.8824, 11.1766, 11.5295, 10.8236, 9.5295, 9.5295, 10.0001,
877 11.2354, 10.8824, 9.1765, 9.0589, 9.6471, 8.9412, 7.9412, 9.0001,
878 9.3530, 7.5295, 9.2354, 9.5883, 7.5883, 8.1765, 7.5883, 9.2942,
879 9.1177, 8.5883, 8.2354, 8.6471, 8.0589, 8.0001, 7.4118, 7.3530,
880 11.0001, 11.1177, 11.0589, 11.2354, 10.5883, 9.2942, 9.2942, 10.1177,
881 11.2354, 10.8824, 8.9412, 8.8236, 9.2354, 8.8824, 7.0001, 9.1177,
882 9.5883, 8.2354, 9.1765, 9.5295, 7.4118, 8.5883, 8.1177, 9.1765,
883 9.0001, 9.0589, 8.9412, 8.2942, 7.8824, 8.4118, 7.2942, 7.2354,
884 10.4118, 10.8824, 11.1177, 11.0001, 10.0001, 9.7060, 9.7648, 10.1766,
885 11.1766, 10.6471, 8.6471, 8.5295, 9.5295, 9.0001, 7.0001, 9.4118,
886 9.8236, 8.0001, 9.2354, 9.5883, 7.5295, 9.0001, 8.5295, 9.0589,
887 8.9412, 9.1177, 8.9412, 8.0001, 8.0589, 8.8824, 7.0589, 7.3530,
888 11.3530, 11.0589, 10.7060, 10.7648, 9.9413, 9.1177, 9.1177, 9.7648,
889 10.7060, 10.2354, 8.5883, 8.8236, 9.7648, 9.2942, 7.5295, 9.2354,
890 9.7060, 8.1177, 9.2942, 9.5883, 7.7648, 9.6471, 9.1177, 9.4707,
891 9.3530, 8.8236, 8.5295, 8.0589, 8.6471, 9.5883, 7.4118, 7.5883};
892 const float filter_values[] = {
893 -0.1617, -0.1948, 0.1419, -0.2311, -0.0891, 0.1551, 0.0033, 0.3037,
894 -0.1683, 0.1353, 0.1518, -0.1683, -0.1386, 0.1452, 0.1816, 0.1716,
895 -0.1948, 0.2080, 0.2245, -0.1981, -0.2410, 0.1849, 0.1981, 0.1584,
896 0.2509, 0.1783, -0.2146, -0.1518, 0.2080, -0.2872, 0.2014, 0.2476,
897 -0.4126, -0.0561, -0.3235, -0.0594, -0.0957, 0.2014, -0.1056, 0.1386,
898 -0.2542, -0.1617, 0.1287, -0.1816, -0.0363, 0.1419, -0.0594, 0.2344,
899 -0.0099, 0.4192, 0.1287, -0.2311, -0.2212, -0.0528, -0.2080, 0.1816,
900 -0.1452, 0.1221, 0.1254, -0.1056, -0.0759, 0.1221, 0.1023, 0.1485,
901 0.2707, 0.1716, -0.1882, -0.1783, 0.1650, -0.2740, 0.1915, 0.2080,
902 -0.2971, -0.2575, -0.3169, 0.0198, -0.0231, 0.2410, -0.0429, 0.0660,
903 -0.1816, 0.1981, 0.2014, -0.1386, -0.1915, 0.1716, 0.1320, 0.1419,
904 0.1320, 0.1353, -0.1386, -0.1716, 0.1320, -0.1650, 0.1386, 0.0825,
905 -0.1419, -0.1023, 0.1783, 0.0462, 0.2047, -0.2179, -0.1518, -0.1551,
906 0.1518, 0.3334, 0.3103, -0.2047, -0.2047, -0.0957, -0.1650, 0.1221,
907 0.0990, 0.1353, -0.1617, -0.1485, 0.1650, -0.1816, 0.1518, 0.1254,
908 -0.0363, -0.1254, 0.1386, 0.0429, 0.2113, -0.2839, -0.1056, -0.2278};
909 const float bias_values[] = {
910 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
911 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
912 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
913 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000};
914 const float golden[] = {
915 -5.1194, -2.0075, -2.1751, -4.7958, 1.7073, -1.2963, -0.4641, 5.0416,
916 -6.4424, 0.3836, 2.4684, -4.7643, -3.8913, 3.8382, -0.5164, 5.4304,
917 -2.7400, 7.7016, 3.6115, -6.8545, -3.6290, 0.8509, 2.3247, 5.6117,
918 1.8215, 2.7645, -0.7032, -3.2156, 3.9689, -5.4583, 2.4346, 1.7731};
919
920 // Quantization Parameters. All scales except output are 1.0, and all zero
921 // points are 0. This direct-maps the values to floating point and makes it
922 // easy to reson about them.
923 const float input_scale = 0.058824;
924 const float filter_scale = 0.003301;
925 const float output_scale = 0.092596;
926 const int input_zero_point = -128;
927 const int output_zero_point = 0;
928
929 TfLiteIntArray* input_dims = tflite::testing::IntArrayFromInts(input_shape);
930 TfLiteIntArray* filter_dims = tflite::testing::IntArrayFromInts(filter_shape);
931 TfLiteIntArray* bias_dims = tflite::testing::IntArrayFromInts(bias_shape);
932 TfLiteIntArray* output_dims = tflite::testing::IntArrayFromInts(output_shape);
933
934 // Create per-tensor quantized int8_t input tensor.
935 int8_t input_quantized[input_elements];
936 TfLiteTensor input_tensor = tflite::testing::CreateQuantizedTensor(
937 input_values, input_quantized, input_dims, input_scale, input_zero_point);
938
939 // Set zero point and scale arrays with a single element for each.
940 int input_zero_points[] = {1, input_zero_point};
941 float input_scales[] = {1, input_scale};
942 TfLiteAffineQuantization input_quant = {
943 tflite::testing::FloatArrayFromFloats(input_scales),
944 tflite::testing::IntArrayFromInts(input_zero_points), 0};
945 input_tensor.quantization = {kTfLiteAffineQuantization, &input_quant};
946
947 // Create per-tensor quantized int8_t filter tensor.
948 int8_t filter_quantized[filter_elements];
949 TfLiteTensor filter_tensor = tflite::testing::CreateQuantizedTensor(
950 filter_values, filter_quantized, filter_dims, filter_scale, 0);
951
952 // Set zero point and scale arrays with a single element for each.
953 int filter_zero_points[] = {1, 0};
954 float filter_scales[] = {1, filter_scale};
955 TfLiteAffineQuantization filter_quant = {
956 tflite::testing::FloatArrayFromFloats(filter_scales),
957 tflite::testing::IntArrayFromInts(filter_zero_points), 0};
958 filter_tensor.quantization = {kTfLiteAffineQuantization, &filter_quant};
959
960 // Create per-tensor quantized int32_t bias tensor.
961 int32_t bias_quantized[bias_elements];
962 // See https://www.tensorflow.org/lite/performance/quantization_spec for a
963 // detailed explanation of why bias scale is input_scale * filter_scale.
964 tflite::SymmetricQuantize(bias_values, bias_quantized, bias_elements,
965 input_scale * output_scale);
966 TfLiteTensor bias_tensor =
967 tflite::testing::CreateTensor(bias_quantized, bias_dims);
968
969 // Set zero point and scale arrays with a single element for each.
970 int bias_zero_points[] = {1, 0};
971 float bias_scales[] = {1, input_scale * filter_scale};
972 TfLiteAffineQuantization bias_quant = {
973 tflite::testing::FloatArrayFromFloats(bias_scales),
974 tflite::testing::IntArrayFromInts(bias_zero_points), 0};
975 bias_tensor.quantization = {kTfLiteAffineQuantization, &bias_quant};
976
977 // Create per-tensor quantized int8_t output tensor.
978 int8_t output_quantized[output_elements];
979 TfLiteTensor output_tensor = tflite::testing::CreateQuantizedTensor(
980 output_quantized, output_dims, output_scale, output_zero_point);
981
982 // Set zero point and scale arrays with a single element for each.
983 int output_zero_points[] = {1, output_zero_point};
984 float output_scales[] = {1, output_scale};
985 TfLiteAffineQuantization output_quant = {
986 tflite::testing::FloatArrayFromFloats(output_scales),
987 tflite::testing::IntArrayFromInts(output_zero_points), 0};
988 output_tensor.quantization = {kTfLiteAffineQuantization, &output_quant};
989
990 // The 3 inputs include the input, filter and bias tensors.
991 constexpr int kInputsSize = 3;
992 constexpr int kOutputsSize = 1;
993 constexpr int kTensorsSize = kInputsSize + kOutputsSize;
994 TfLiteTensor tensors[kTensorsSize] = {
995 input_tensor,
996 filter_tensor,
997 bias_tensor,
998 output_tensor,
999 };
1000
1001 int8_t golden_quantized[output_elements];
1002 tflite::Quantize(golden, golden_quantized, output_elements, output_scale, 0);
1003
1004 // Errors due to quantization should not exceed 1.
1005 constexpr int kQuantizationTolerance = 1;
1006
1007 TfLiteDepthwiseConvParams conv_params;
1008 conv_params.activation = kTfLiteActNone;
1009 conv_params.dilation_width_factor = 1;
1010 conv_params.dilation_height_factor = 1;
1011 tflite::testing::ValidateDepthwiseConvGoldens(
1012 golden_quantized, output_elements, &conv_params, kQuantizationTolerance,
1013 kTensorsSize, tensors);
1014 }
1015
1016 TF_LITE_MICRO_TESTS_END
1017