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