• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 
16 #include "tensorflow/lite/c/builtin_op_data.h"
17 #include "tensorflow/lite/c/common.h"
18 #include "tensorflow/lite/micro/all_ops_resolver.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 template <typename T>
ValidatePadGoldens(TfLiteTensor * tensors,int tensors_size,const T * golden,T * output_data,int output_length)28 TfLiteStatus ValidatePadGoldens(TfLiteTensor* tensors, int tensors_size,
29                                 const T* golden, T* output_data,
30                                 int output_length) {
31   int inputs_array_data[] = {2, 0, 1};
32   TfLiteIntArray* inputs_array = IntArrayFromInts(inputs_array_data);
33   int outputs_array_data[] = {1, 2};
34   TfLiteIntArray* outputs_array = IntArrayFromInts(outputs_array_data);
35 
36   const TfLiteRegistration registration = tflite::ops::micro::Register_PAD();
37   micro::KernelRunner runner(registration, tensors, tensors_size, inputs_array,
38                              outputs_array,
39                              /*builtin_data=*/nullptr);
40 
41   // Prepare should catch dimension mismatches.
42   TfLiteStatus prepare_status = runner.InitAndPrepare();
43   if (prepare_status != kTfLiteOk) {
44     return prepare_status;
45   }
46 
47   // Eval should catch quantization mismatches.
48   TfLiteStatus invoke_status = runner.Invoke();
49   if (invoke_status != kTfLiteOk) {
50     return invoke_status;
51   }
52 
53   for (int i = 0; i < output_length; ++i) {
54     TF_LITE_MICRO_EXPECT_EQ(golden[i], output_data[i]);
55   }
56   return kTfLiteOk;
57 }
58 
59 template <typename T>
ValidatePadV2Goldens(TfLiteTensor * tensors,int tensors_size,const T * golden,T * output_data,int output_length)60 TfLiteStatus ValidatePadV2Goldens(TfLiteTensor* tensors, int tensors_size,
61                                   const T* golden, T* output_data,
62                                   int output_length) {
63   int inputs_array_data[] = {3, 0, 1, 2};
64   TfLiteIntArray* inputs_array = IntArrayFromInts(inputs_array_data);
65   int outputs_array_data[] = {1, 3};
66   TfLiteIntArray* outputs_array = IntArrayFromInts(outputs_array_data);
67 
68   const TfLiteRegistration registration = tflite::ops::micro::Register_PADV2();
69   micro::KernelRunner runner(registration, tensors, tensors_size, inputs_array,
70                              outputs_array,
71                              /*builtin_data=*/nullptr);
72 
73   // Prepare should catch dimension mismatches.
74   TfLiteStatus prepare_status = runner.InitAndPrepare();
75   if (prepare_status != kTfLiteOk) {
76     return prepare_status;
77   }
78 
79   // Eval should catch quantization mismatches.
80   TfLiteStatus invoke_status = runner.Invoke();
81   if (invoke_status != kTfLiteOk) {
82     return invoke_status;
83   }
84 
85   for (int i = 0; i < output_length; ++i) {
86     TF_LITE_MICRO_EXPECT_EQ(golden[i], output_data[i]);
87   }
88   return kTfLiteOk;
89 }
90 
91 // output data and golden must be shaped correctly
TestPadFloat(const int * input_dims_data,const float * input_data,const int * pad_dims_data,const int32_t * pad_data,const int * output_dims_data,const float * golden,float * output_data,TfLiteStatus expected_status=kTfLiteOk)92 void TestPadFloat(const int* input_dims_data, const float* input_data,
93                   const int* pad_dims_data, const int32_t* pad_data,
94                   const int* output_dims_data, const float* golden,
95                   float* output_data,
96                   TfLiteStatus expected_status = kTfLiteOk) {
97   TfLiteIntArray* input_dims = IntArrayFromInts(input_dims_data);
98   TfLiteIntArray* pad_dims = IntArrayFromInts(pad_dims_data);
99   TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
100   const int output_dims_count = ElementCount(*output_dims);
101   constexpr int inputs_size = 2;
102   constexpr int outputs_size = 1;
103   constexpr int tensors_size = inputs_size + outputs_size;
104   TfLiteTensor tensors[tensors_size] = {CreateTensor(input_data, input_dims),
105                                         CreateTensor(pad_data, pad_dims),
106                                         CreateTensor(output_data, output_dims)};
107 
108   // Pad tensor must be constant.
109   tensors[1].allocation_type = kTfLiteMmapRo;
110 
111   TF_LITE_MICRO_EXPECT_EQ(expected_status,
112                           ValidatePadGoldens(tensors, tensors_size, golden,
113                                              output_data, output_dims_count));
114 }
115 
116 // output data and golden must be shaped correctly
TestPadV2Float(const int * input_dims_data,const float * input_data,const int * pad_dims_data,const int32_t * pad_data,const float pad_value,const int * output_dims_data,const float * golden,float * output_data,TfLiteStatus expected_status=kTfLiteOk)117 void TestPadV2Float(const int* input_dims_data, const float* input_data,
118                     const int* pad_dims_data, const int32_t* pad_data,
119                     const float pad_value, const int* output_dims_data,
120                     const float* golden, float* output_data,
121                     TfLiteStatus expected_status = kTfLiteOk) {
122   TfLiteIntArray* input_dims = IntArrayFromInts(input_dims_data);
123   TfLiteIntArray* pad_dims = IntArrayFromInts(pad_dims_data);
124   const int pad_value_dims_data[] = {1, 1};  // Only one padding value allowed.
125   TfLiteIntArray* pad_value_dims = IntArrayFromInts(pad_value_dims_data);
126   TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
127   const int output_dims_count = ElementCount(*output_dims);
128   constexpr int inputs_size = 3;
129   constexpr int outputs_size = 1;
130   constexpr int tensors_size = inputs_size + outputs_size;
131   TfLiteTensor tensors[tensors_size] = {
132       CreateTensor(input_data, input_dims), CreateTensor(pad_data, pad_dims),
133       CreateTensor(&pad_value, pad_value_dims),
134       CreateTensor(output_data, output_dims)};
135 
136   // Pad tensor must be constant.
137   tensors[1].allocation_type = kTfLiteMmapRo;
138 
139   TF_LITE_MICRO_EXPECT_EQ(expected_status,
140                           ValidatePadV2Goldens(tensors, tensors_size, golden,
141                                                output_data, output_dims_count));
142 }
143 
144 template <typename T>
TestPadQuantized(const int * input_dims_data,const float * input_data,T * input_quantized,float input_scale,int input_zero_point,const int * pad_dims_data,const int32_t * pad_data,const int * output_dims_data,const float * golden,T * golden_quantized,float output_scale,int output_zero_point,T * output_data,TfLiteStatus expected_status=kTfLiteOk)145 void TestPadQuantized(const int* input_dims_data, const float* input_data,
146                       T* input_quantized, float input_scale,
147                       int input_zero_point, const int* pad_dims_data,
148                       const int32_t* pad_data, const int* output_dims_data,
149                       const float* golden, T* golden_quantized,
150                       float output_scale, int output_zero_point, T* output_data,
151                       TfLiteStatus expected_status = kTfLiteOk) {
152   TfLiteIntArray* input_dims = IntArrayFromInts(input_dims_data);
153   TfLiteIntArray* pad_dims = IntArrayFromInts(pad_dims_data);
154   TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
155   const int output_dims_count = ElementCount(*output_dims);
156   constexpr int inputs_size = 2;
157   constexpr int outputs_size = 1;
158   constexpr int tensors_size = inputs_size + outputs_size;
159   TfLiteTensor tensors[tensors_size] = {
160       CreateQuantizedTensor(input_data, input_quantized, input_dims,
161                             input_scale, input_zero_point),
162       CreateTensor(pad_data, pad_dims),
163       CreateQuantizedTensor(output_data, output_dims, output_scale,
164                             output_zero_point)};
165 
166   // Pad tensor must be constant.
167   tensors[1].allocation_type = kTfLiteMmapRo;
168 
169   tflite::Quantize(golden, golden_quantized, output_dims_count, output_scale,
170                    output_zero_point);
171   TF_LITE_MICRO_EXPECT_EQ(
172       expected_status,
173       ValidatePadGoldens(tensors, tensors_size, golden_quantized, output_data,
174                          output_dims_count));
175 }
176 
177 template <typename T>
TestPadV2Quantized(const int * input_dims_data,const float * input_data,T * input_quantized,float input_scale,int input_zero_point,const int * pad_dims_data,const int32_t * pad_data,const float pad_value,const float pad_value_scale,const int pad_value_zero_point,const int * output_dims_data,const float * golden,T * golden_quantized,float output_scale,int output_zero_point,T * output_data,TfLiteStatus expected_status=kTfLiteOk)178 void TestPadV2Quantized(const int* input_dims_data, const float* input_data,
179                         T* input_quantized, float input_scale,
180                         int input_zero_point, const int* pad_dims_data,
181                         const int32_t* pad_data, const float pad_value,
182                         const float pad_value_scale,
183                         const int pad_value_zero_point,
184                         const int* output_dims_data, const float* golden,
185                         T* golden_quantized, float output_scale,
186                         int output_zero_point, T* output_data,
187                         TfLiteStatus expected_status = kTfLiteOk) {
188   TfLiteIntArray* input_dims = IntArrayFromInts(input_dims_data);
189   TfLiteIntArray* pad_dims = IntArrayFromInts(pad_dims_data);
190   const int pad_value_dims_data[] = {1, 1};  // Only one padding value allowed.
191   TfLiteIntArray* pad_value_dims = IntArrayFromInts(pad_value_dims_data);
192   TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
193   T pad_value_quantized;
194   const int output_dims_count = ElementCount(*output_dims);
195   constexpr int inputs_size = 3;
196   constexpr int outputs_size = 1;
197   constexpr int tensors_size = inputs_size + outputs_size;
198   TfLiteTensor tensors[tensors_size] = {
199       CreateQuantizedTensor(input_data, input_quantized, input_dims,
200                             input_scale, input_zero_point),
201       CreateTensor(pad_data, pad_dims),
202       CreateQuantizedTensor(&pad_value, &pad_value_quantized, pad_value_dims,
203                             pad_value_scale, pad_value_zero_point),
204       CreateQuantizedTensor(output_data, output_dims, output_scale,
205                             output_zero_point)};
206 
207   // Pad tensor must be constant.
208   tensors[1].allocation_type = kTfLiteMmapRo;
209   tensors[2].params.scale = pad_value_scale;
210   tensors[3].params.scale = output_scale;
211 
212   tflite::Quantize(golden, golden_quantized, output_dims_count, output_scale,
213                    output_zero_point);
214   TF_LITE_MICRO_EXPECT_EQ(
215       expected_status,
216       ValidatePadV2Goldens(tensors, tensors_size, golden_quantized, output_data,
217                            output_dims_count));
218 }
219 
220 }  // namespace
221 }  // namespace testing
222 }  // namespace tflite
223 
224 TF_LITE_MICRO_TESTS_BEGIN
225 
TF_LITE_MICRO_TEST(Test2DFloat)226 TF_LITE_MICRO_TEST(Test2DFloat) {
227   const int input_dims[] = {4, 1, 2, 2, 1};
228   const float input_values[] = {1, 2, 3, 4};
229   const int pad_dims[] = {2, 4, 2};
230   const int32_t pad_values[] = {1, 1, 0, 0, 1, 1, 0, 0};
231   const int output_dims[] = {4, 3, 2, 4, 1};
232   const float golden[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0,
233                           0, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0};
234   float output_data[24];
235 
236   tflite::testing::TestPadFloat(input_dims, input_values, pad_dims, pad_values,
237                                 output_dims, golden, output_data);
238 }
239 
TF_LITE_MICRO_TEST(Test4DFloat)240 TF_LITE_MICRO_TEST(Test4DFloat) {
241   const int input_dims[] = {4, 1, 1, 1, 1};
242   const float input_values[] = {42};
243   const int pad_dims[] = {2, 4, 2};
244   const int32_t pad_values[] = {1, 1, 1, 1, 1, 1, 1, 1};
245   const int output_dims[] = {4, 3, 3, 3, 3};
246   const int kOutputLen = 81;  // 3 * 3 * 3 * 3
247   float golden[kOutputLen];
248   for (int i = 0; i < kOutputLen; i++) {
249     golden[i] = 0;
250   }
251   golden[40] = 42;
252   float output_data[kOutputLen];
253 
254   tflite::testing::TestPadFloat(input_dims, input_values, pad_dims, pad_values,
255                                 output_dims, const_cast<const float*>(golden),
256                                 output_data);
257 }
258 
TF_LITE_MICRO_TEST(Test2DFloatV2)259 TF_LITE_MICRO_TEST(Test2DFloatV2) {
260   const int input_dims[] = {4, 1, 2, 2, 1};
261   const float input_values[] = {1, 2, 3, 4};
262   const int pad_dims[] = {2, 4, 2};
263   const int32_t pad_values[] = {1, 1, 0, 0, 1, 1, 0, 0};
264   const float pad_value = 42;
265   const int output_dims[] = {4, 3, 2, 4, 1};
266   const float golden[] = {42, 42, 42, 42, 42, 42, 42, 42, 42, 1,  2,  42,
267                           42, 3,  4,  42, 42, 42, 42, 42, 42, 42, 42, 42};
268   float output_data[24];
269 
270   tflite::testing::TestPadV2Float(input_dims, input_values, pad_dims,
271                                   pad_values, pad_value, output_dims, golden,
272                                   output_data);
273 }
274 
TF_LITE_MICRO_TEST(Test2DUInt8)275 TF_LITE_MICRO_TEST(Test2DUInt8) {
276   const int input_dims[] = {4, 1, 2, 2, 1};
277   const float input_values[] = {1, 2, 3, 4};
278   const float input_scale = 1.0f;
279   const int input_zero_point = 127;
280   const int pad_dims[] = {2, 4, 2};
281   const int32_t pad_values[] = {1, 1, 0, 0, 1, 1, 0, 0};
282   const int output_dims[] = {4, 3, 2, 4, 1};
283   const float golden[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0,
284                           0, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0};
285   const float output_scale = 1.0f;
286   const int output_zero_point = 127;
287   uint8_t output_data[24];
288   uint8_t input_quantized[4];
289   uint8_t golden_quantized[24];
290 
291   tflite::testing::TestPadQuantized(
292       input_dims, input_values, input_quantized, input_scale, input_zero_point,
293       pad_dims, pad_values, output_dims, golden, golden_quantized, output_scale,
294       output_zero_point, output_data);
295 }
296 
TF_LITE_MICRO_TEST(Test2DUInt8V2)297 TF_LITE_MICRO_TEST(Test2DUInt8V2) {
298   const int input_dims[] = {4, 1, 2, 2, 1};
299   const float input_values[] = {1, 2, 3, 4};
300   const float input_scale = 1.0f;
301   const int input_zero_point = 127;
302   const int pad_dims[] = {2, 4, 2};
303   const int32_t pad_values[] = {1, 1, 0, 0, 1, 1, 0, 0};
304   const float pad_value = 42;
305   const float pad_value_scale = 1.0;
306   const float pad_value_zero_point = 127;
307   const int output_dims[] = {4, 3, 2, 4, 1};
308   const float golden[] = {42, 42, 42, 42, 42, 42, 42, 42, 42, 1,  2,  42,
309                           42, 3,  4,  42, 42, 42, 42, 42, 42, 42, 42, 42};
310   const float output_scale = 1.0f;
311   const int output_zero_point = 127;
312   uint8_t output_data[24];
313   uint8_t input_quantized[4];
314   uint8_t golden_quantized[24];
315 
316   tflite::testing::TestPadV2Quantized(
317       input_dims, input_values, input_quantized, input_scale, input_zero_point,
318       pad_dims, pad_values, pad_value, pad_value_scale, pad_value_zero_point,
319       output_dims, golden, golden_quantized, output_scale, output_zero_point,
320       output_data);
321 }
322 
TF_LITE_MICRO_TEST(Test2DInt8)323 TF_LITE_MICRO_TEST(Test2DInt8) {
324   const int input_dims[] = {4, 1, 2, 2, 1};
325   const float input_values[] = {1, 2, 3, 4};
326   const float input_scale = 1.0f;
327   const int input_zero_point = 0;
328   const int pad_dims[] = {2, 4, 2};
329   const int32_t pad_values[] = {1, 1, 0, 0, 1, 1, 0, 0};
330   const int output_dims[] = {4, 3, 2, 4, 1};
331   const float golden[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0,
332                           0, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0};
333   const float output_scale = 1.0f;
334   const int output_zero_point = 0;
335   int8_t output_data[24];
336   int8_t input_quantized[4];
337   int8_t golden_quantized[24];
338 
339   tflite::testing::TestPadQuantized(
340       input_dims, input_values, input_quantized, input_scale, input_zero_point,
341       pad_dims, pad_values, output_dims, golden, golden_quantized, output_scale,
342       output_zero_point, output_data);
343 }
344 
TF_LITE_MICRO_TEST(Test2DInt8V2)345 TF_LITE_MICRO_TEST(Test2DInt8V2) {
346   const int input_dims[] = {4, 1, 2, 2, 1};
347   const float input_values[] = {1, 2, 3, 4};
348   const float input_scale = 1.0f;
349   const int input_zero_point = 0;
350   const int pad_dims[] = {2, 4, 2};
351   const int32_t pad_values[] = {1, 1, 0, 0, 1, 1, 0, 0};
352   const float pad_value = 42;
353   const float pad_value_scale = 1.0;
354   const float pad_value_zero_point = 0;
355   const int output_dims[] = {4, 3, 2, 4, 1};
356   const float golden[] = {42, 42, 42, 42, 42, 42, 42, 42, 42, 1,  2,  42,
357                           42, 3,  4,  42, 42, 42, 42, 42, 42, 42, 42, 42};
358   const float output_scale = 1.0f;
359   const int output_zero_point = 0;
360   int8_t output_data[24];
361   int8_t input_quantized[4];
362   int8_t golden_quantized[24];
363 
364   tflite::testing::TestPadV2Quantized(
365       input_dims, input_values, input_quantized, input_scale, input_zero_point,
366       pad_dims, pad_values, pad_value, pad_value_scale, pad_value_zero_point,
367       output_dims, golden, golden_quantized, output_scale, output_zero_point,
368       output_data);
369 }
370 
TF_LITE_MICRO_TEST(Test2DInt8V2ExpectFailurePadValueQuantizationMismatch)371 TF_LITE_MICRO_TEST(Test2DInt8V2ExpectFailurePadValueQuantizationMismatch) {
372   const int input_dims[] = {4, 1, 2, 2, 1};
373   const float input_values[] = {1, 2, 3, 4};
374   const float input_scale = 1.0f;
375   const int input_zero_point = 0;
376   const int pad_dims[] = {2, 4, 2};
377   const int32_t pad_values[] = {1, 1, 0, 0, 1, 1, 0, 0};
378   const float pad_value = 42;
379   // Causes failure since this is in a different quantization space than input.
380   const float pad_value_scale = .5;
381   const float pad_value_zero_point = 0;
382   const int output_dims[] = {4, 3, 2, 4, 1};
383   const float golden[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
384                           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
385   const float output_scale = 1.0f;
386   const int output_zero_point = 0;
387   int8_t output_data[24] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
388                             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
389   int8_t input_quantized[4];
390   int8_t golden_quantized[24];
391 
392   tflite::testing::TestPadV2Quantized(
393       input_dims, input_values, input_quantized, input_scale, input_zero_point,
394       pad_dims, pad_values, pad_value, pad_value_scale, pad_value_zero_point,
395       output_dims, golden, golden_quantized, output_scale, output_zero_point,
396       output_data, kTfLiteError);
397 }
398 
TF_LITE_MICRO_TEST(Test2DInt8ExpectFailureQuantizationRangeExcludesZero)399 TF_LITE_MICRO_TEST(Test2DInt8ExpectFailureQuantizationRangeExcludesZero) {
400   const int input_dims[] = {4, 1, 2, 2, 1};
401   const float input_values[] = {1, 2, 3, 4};
402   const float input_scale = 1.0f;
403   const int input_zero_point = 0;
404   const int pad_dims[] = {2, 4, 2};
405   const int32_t pad_values[] = {1, 1, 0, 0, 1, 1, 0, 0};
406   const int output_dims[] = {4, 3, 2, 4, 1};
407   const float golden[] = {42, 42, 42, 42, 42, 42, 42, 42, 42, 1,  2,  42,
408                           42, 3,  4,  42, 42, 42, 42, 42, 42, 42, 42, 42};
409   // Causes failure since this quantization zero point excludes zero.
410   const float output_scale = 1.0f;
411   const int output_zero_point = 129;
412   int8_t output_data[24];
413   int8_t input_quantized[4];
414   int8_t golden_quantized[24];
415 
416   tflite::testing::TestPadQuantized(
417       input_dims, input_values, input_quantized, input_scale, input_zero_point,
418       pad_dims, pad_values, output_dims, golden, golden_quantized, output_scale,
419       output_zero_point, output_data, kTfLiteError);
420 }
421 
422 TF_LITE_MICRO_TESTS_END
423