• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <stdint.h>
17 
18 #include <initializer_list>
19 
20 #include "tensorflow/lite/c/common.h"
21 #include "tensorflow/lite/kernels/internal/tensor_ctypes.h"
22 #include "tensorflow/lite/micro/kernels/kernel_runner.h"
23 #include "tensorflow/lite/micro/micro_utils.h"
24 #include "tensorflow/lite/micro/test_helpers.h"
25 #include "tensorflow/lite/micro/testing/micro_test.h"
26 
27 namespace tflite {
28 namespace testing {
29 namespace {
30 
31 // TODO(b/162356196): Cleanup this unit test more.
32 
33 template <typename T>
ValidateReshapeGoldens(TfLiteTensor * tensors,int tensors_size,TfLiteIntArray * inputs_array,TfLiteIntArray * outputs_array,const T * expected_output,const size_t expected_output_len,const int * expected_dims,const size_t expected_dims_len,bool expect_failure)34 void ValidateReshapeGoldens(
35     TfLiteTensor* tensors, int tensors_size, TfLiteIntArray* inputs_array,
36     TfLiteIntArray* outputs_array, const T* expected_output,
37     const size_t expected_output_len, const int* expected_dims,
38     const size_t expected_dims_len, bool expect_failure) {
39   const TfLiteRegistration registration =
40       tflite::ops::micro::Register_RESHAPE();
41   micro::KernelRunner runner(registration, tensors, tensors_size, inputs_array,
42                              outputs_array,
43                              /*builtin_data=*/nullptr);
44 
45   if (expect_failure) {
46     TF_LITE_MICRO_EXPECT_NE(kTfLiteOk, runner.InitAndPrepare());
47     return;
48   }
49 
50   TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.InitAndPrepare());
51   TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.Invoke());
52 
53   TfLiteTensor* output_tensor = &tensors[outputs_array->data[0]];
54   const T* output_data = GetTensorData<T>(output_tensor);
55   for (size_t i = 0; i < expected_output_len; ++i) {
56     TF_LITE_MICRO_EXPECT_NEAR(expected_output[i], output_data[i], 1e-5f);
57   }
58   TF_LITE_MICRO_EXPECT_EQ(expected_dims_len,
59                           static_cast<size_t>(output_tensor->dims->size));
60   for (size_t i = 0; i < expected_dims_len; ++i) {
61     TF_LITE_MICRO_EXPECT_EQ(expected_dims[i], output_tensor->dims->data[i]);
62   }
63 }
64 template <typename T>
TestReshapeWithShape(TfLiteTensor * input_tensor,TfLiteTensor * shape_tensor,TfLiteTensor * output_tensor,const T * expected_output,const size_t expected_output_len,const int * expected_dims,const size_t expected_dims_len,bool expect_failure)65 void TestReshapeWithShape(TfLiteTensor* input_tensor,
66                           TfLiteTensor* shape_tensor,
67                           TfLiteTensor* output_tensor, const T* expected_output,
68                           const size_t expected_output_len,
69                           const int* expected_dims,
70                           const size_t expected_dims_len, bool expect_failure) {
71   constexpr int inputs_size = 2;
72   constexpr int outputs_size = 1;
73   constexpr int tensors_size = inputs_size + outputs_size;
74   TfLiteTensor tensors[tensors_size];
75   tensors[0] = *input_tensor;
76   tensors[1] = *shape_tensor;
77   tensors[2] = *output_tensor;
78 
79   int inputs_data[] = {2, 0, 1};
80   TfLiteIntArray* inputs_array = IntArrayFromInts(inputs_data);
81   int outputs_data[] = {1, 2};
82   TfLiteIntArray* outputs_array = IntArrayFromInts(outputs_data);
83 
84   ValidateReshapeGoldens(tensors, tensors_size, inputs_array, outputs_array,
85                          expected_output, expected_output_len, expected_dims,
86                          expected_dims_len, expect_failure);
87 }
88 
89 // If expected output is empty, the test is expected to fail.
90 template <typename T>
TestReshapeWithoutShape(TfLiteTensor * input_tensor,TfLiteTensor * output_tensor,const T * expected_output,const size_t expected_output_len,const int * expected_dims,const size_t expected_dims_len,bool expect_failure)91 void TestReshapeWithoutShape(TfLiteTensor* input_tensor,
92                              TfLiteTensor* output_tensor,
93                              const T* expected_output,
94                              const size_t expected_output_len,
95                              const int* expected_dims,
96                              const size_t expected_dims_len,
97                              bool expect_failure) {
98   constexpr int inputs_size = 1;
99   constexpr int outputs_size = 1;
100   constexpr int tensors_size = inputs_size + outputs_size;
101   TfLiteTensor tensors[tensors_size];
102   tensors[0] = *input_tensor;
103   tensors[1] = *output_tensor;
104 
105   int inputs_data[] = {1, 0};
106   TfLiteIntArray* inputs_array = IntArrayFromInts(inputs_data);
107   int outputs_data[] = {1, 1};
108   TfLiteIntArray* outputs_array = IntArrayFromInts(outputs_data);
109 
110   ValidateReshapeGoldens(tensors, tensors_size, inputs_array, outputs_array,
111                          expected_output, expected_output_len, expected_dims,
112                          expected_dims_len, expect_failure);
113 }
114 
TestReshape(const int * input_dims_data,const float * input_data,const int * shape_dims_data,const int32_t * shape_data,int * output_dims_data,float * output_data,const float * expected_output,const size_t expected_output_len,const int * expected_dims,const size_t expected_dims_len,bool expect_failure=false)115 void TestReshape(const int* input_dims_data, const float* input_data,
116                  const int* shape_dims_data, const int32_t* shape_data,
117                  int* output_dims_data, float* output_data,
118                  const float* expected_output, const size_t expected_output_len,
119                  const int* expected_dims, const size_t expected_dims_len,
120                  bool expect_failure = false) {
121   TfLiteIntArray* input_dims = IntArrayFromInts(input_dims_data);
122   TfLiteIntArray* shape_dims = IntArrayFromInts(shape_dims_data);
123   TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
124   TfLiteTensor input_tensor = CreateTensor(input_data, input_dims);
125   TfLiteTensor shape_tensor = CreateTensor(shape_data, shape_dims);
126   TfLiteTensor output_tensor = CreateTensor(output_data, output_dims);
127 
128   TestReshapeWithShape(&input_tensor, &shape_tensor, &output_tensor,
129                        expected_output, expected_output_len, expected_dims,
130                        expected_dims_len, expect_failure);
131 }
132 
133 template <typename T>
TestReshapeQuantized(const int * input_dims_data,const T * input_data,const int * shape_dims_data,const int32_t * shape_data,int * output_dims_data,T * output_data,const T * expected_output,const size_t expected_output_len,const int * expected_dims,const size_t expected_dims_len,bool expect_failure=false)134 void TestReshapeQuantized(const int* input_dims_data, const T* input_data,
135                           const int* shape_dims_data, const int32_t* shape_data,
136                           int* output_dims_data, T* output_data,
137                           const T* expected_output,
138                           const size_t expected_output_len,
139                           const int* expected_dims,
140                           const size_t expected_dims_len,
141                           bool expect_failure = false) {
142   TfLiteIntArray* input_dims = IntArrayFromInts(input_dims_data);
143   TfLiteIntArray* shape_dims = IntArrayFromInts(shape_dims_data);
144   TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
145   TfLiteTensor input_tensor = CreateQuantizedTensor(
146       input_data, input_dims, /*scale=*/1.f, /*zero_point=*/0);
147   TfLiteTensor shape_tensor = CreateTensor(shape_data, shape_dims);
148   TfLiteTensor output_tensor = CreateQuantizedTensor(
149       output_data, output_dims, /*scale=*/1.f, /*zero_point=*/0);
150 
151   TestReshapeWithShape(&input_tensor, &shape_tensor, &output_tensor,
152                        expected_output, expected_output_len, expected_dims,
153                        expected_dims_len, expect_failure);
154 }
155 }  // namespace
156 }  // namespace testing
157 }  // namespace tflite
158 
159 TF_LITE_MICRO_TESTS_BEGIN
160 
TF_LITE_MICRO_TEST(ReshapeWithMismatchedDimensionsShouldFail)161 TF_LITE_MICRO_TEST(ReshapeWithMismatchedDimensionsShouldFail) {
162   float output_data[32];
163   const int input_dims[] = {4, 1, 2, 4, 1};
164   const float input_data[] = {3};
165   const int shape_dims[] = {1, 2};
166   const int32_t shape_int32[] = {2, 1};
167   int output_dims[] = {2, 2, 1};
168   const int golden_output_len = 0;
169   const float golden_output[] = {};
170   const int golden_dims_len = 0;
171   const int golden_dims[] = {};
172   tflite::testing::TestReshape(
173       input_dims, input_data, shape_dims, shape_int32, output_dims, output_data,
174       golden_output, golden_output_len, golden_dims, golden_dims_len, true);
175 }
176 
TF_LITE_MICRO_TEST(ReshapeWithTooManyDimensionsShouldFail)177 TF_LITE_MICRO_TEST(ReshapeWithTooManyDimensionsShouldFail) {
178   float output_data[32];
179   const int input_dims[] = {9, 1, 1, 2, 1, 1, 1, 1, 1, 1};
180   const float input[] = {3, 2};
181   const int shape_dims[] = {1, 9};
182   const int32_t shape_int32[] = {1, 1, 1, 1, 1, 1, 1, 1, 2};
183   int output_dims[] = {9, 1, 1, 1, 1, 1, 1, 1, 1, 2};
184   const int golden_output_len = 2;
185   const float golden_output[] = {3, 2};
186   const int golden_dims_len = 9;
187   const int golden_dims[] = {1, 1, 1, 1, 1, 1, 1, 1, 2};
188   tflite::testing::TestReshape(
189       input_dims, input, shape_dims, shape_int32, output_dims, output_data,
190       golden_output, golden_output_len, golden_dims, golden_dims_len, false);
191 }
192 
TF_LITE_MICRO_TEST(ReshapeWithTooManySpecialDimensionsShouldFail)193 TF_LITE_MICRO_TEST(ReshapeWithTooManySpecialDimensionsShouldFail) {
194   float output_data[32];
195   const int input_dims[] = {4, 1, 2, 4, 11};
196   const float input[] = {3};
197   const int shape_dims[] = {1, 4};
198   const int32_t shape_int32[] = {-1, -1, 2, 4};
199   int output_dims[] = {4, -1, -1, 2, 4};
200   const int golden_output_len = 2;
201   const float golden_output[] = {};
202   const int golden_dims_len = 9;
203   const int golden_dims[] = {};
204   tflite::testing::TestReshape(
205       input_dims, input, shape_dims, shape_int32, output_dims, output_data,
206       golden_output, golden_output_len, golden_dims, golden_dims_len, true);
207 }
208 
209 // Create the model with a 2x2 shape. Processing still works because the new
210 // shape ends up being hardcoded as a flat vector.
TF_LITE_MICRO_TEST(ReshapeWithInvalidShapeShouldFail)211 TF_LITE_MICRO_TEST(ReshapeWithInvalidShapeShouldFail) {
212   int input_dims_data[] = {3, 1, 2, 2};
213   TfLiteIntArray* input_dims =
214       tflite::testing::IntArrayFromInts(input_dims_data);
215   const float input_data[] = {3.0f};
216   auto input_tensor = tflite::testing::CreateTensor(input_data, input_dims);
217   float output_data[4];
218   int output_dims_data[6] = {2, 2, 1, 2, 2, 1};
219   TfLiteIntArray* output_dims =
220       tflite::testing::IntArrayFromInts(output_dims_data);
221   auto output_tensor = tflite::testing::CreateTensor(output_data, output_dims);
222   const int expected_output[] = {};
223   const int expected_output_len = 0;
224   const int expected_dims[] = {};
225   const int expected_dims_len = 0;
226   tflite::testing::TestReshapeWithoutShape(
227       &input_tensor, &output_tensor, expected_output, expected_output_len,
228       expected_dims, expected_dims_len, true);
229 }
230 
TF_LITE_MICRO_TEST(ReshapeWithRegularShapesShouldSucceed)231 TF_LITE_MICRO_TEST(ReshapeWithRegularShapesShouldSucceed) {
232   float output_data_float[32];
233   int8_t output_data_int8[32];
234   uint8_t output_data_uint8[32];
235   const int input_dims[] = {4, 1, 2, 4, 1};
236   const float input_float[] = {1, 2, 3, 4, 5, 6, 7, 8};
237   const int8_t input_int8[] = {1, 2, 3, 4, 5, 6, 7, 8};
238   const uint8_t input_uint8[] = {1, 2, 3, 4, 5, 6, 7, 8};
239   const int shape_dims[] = {1, 3};
240   const int32_t shape_int32[] = {2, 2, 2};
241   int output_dims[] = {3, 2, 2, 2};
242   const int golden_output_len = 8;
243   const float golden_output_float[] = {1, 2, 3, 4, 5, 6, 7, 8};
244   const int8_t golden_output_int8[] = {1, 2, 3, 4, 5, 6, 7, 8};
245   const uint8_t golden_output_uint8[] = {1, 2, 3, 4, 5, 6, 7, 8};
246   const int golden_dims_len = 3;
247   const int golden_dims[] = {2, 2, 2};
248   tflite::testing::TestReshape(input_dims, input_float, shape_dims, shape_int32,
249                                output_dims, output_data_float,
250                                golden_output_float, golden_output_len,
251                                golden_dims, golden_dims_len, false);
252   tflite::testing::TestReshapeQuantized(
253       input_dims, input_int8, shape_dims, shape_int32, output_dims,
254       output_data_int8, golden_output_int8, golden_output_len, golden_dims,
255       golden_dims_len, false);
256   tflite::testing::TestReshapeQuantized(
257       input_dims, input_uint8, shape_dims, shape_int32, output_dims,
258       output_data_uint8, golden_output_uint8, golden_output_len, golden_dims,
259       golden_dims_len, false);
260 }
261 
262 // Stretch is not supported with TF Micro
TF_LITE_MICRO_TEST(ReshapeWithStretchDimensionShouldSucceed)263 TF_LITE_MICRO_TEST(ReshapeWithStretchDimensionShouldSucceed) {
264   float output_data_float[32];
265   int8_t output_data_int8[32];
266   uint8_t output_data_uint8[32];
267   const int input_dims[] = {4, 1, 2, 4, 1};
268   const float input_float[] = {1, 2, 3, 4, 5, 6, 7, 8};
269   const int8_t input_int8[] = {1, 2, 3, 4, 5, 6, 7, 8};
270   const uint8_t input_uint8[] = {1, 2, 3, 4, 5, 6, 7, 8};
271   const int shape_dims[] = {1, 3};
272   const int32_t shape_int32[] = {2, 1, -1};
273   int output_dims[] = {3, 2, 1, -1};
274   const int golden_output_len = 8;
275   const float golden_output_float[] = {1, 2, 3, 4, 5, 6, 7, 8};
276   const int8_t golden_output_int8[] = {1, 2, 3, 4, 5, 6, 7, 8};
277   const uint8_t golden_output_uint8[] = {1, 2, 3, 4, 5, 6, 7, 8};
278   const int golden_dims_len = 3;
279   const int golden_dims[] = {2, 1, 4};
280   tflite::testing::TestReshape(input_dims, input_float, shape_dims, shape_int32,
281                                output_dims, output_data_float,
282                                golden_output_float, golden_output_len,
283                                golden_dims, golden_dims_len, false);
284   tflite::testing::TestReshapeQuantized(
285       input_dims, input_int8, shape_dims, shape_int32, output_dims,
286       output_data_int8, golden_output_int8, golden_output_len, golden_dims,
287       golden_dims_len, false);
288   tflite::testing::TestReshapeQuantized(
289       input_dims, input_uint8, shape_dims, shape_int32, output_dims,
290       output_data_uint8, golden_output_uint8, golden_output_len, golden_dims,
291       golden_dims_len, false);
292 }
293 
294 // Empty shape indicates scalar output.
TF_LITE_MICRO_TEST(ReshapeWithScalarOutputShouldSucceed)295 TF_LITE_MICRO_TEST(ReshapeWithScalarOutputShouldSucceed) {
296   float output_data_float[4];
297   int8_t output_data_int8[4];
298   uint8_t output_data_uint8[4];
299   const int input_dims[] = {1, 1};
300   const float input_float[] = {3};
301   const int8_t input_int8[] = {3};
302   const uint8_t input_uint8[] = {3};
303   const int shape_dims[] = {0};
304   const int32_t shape_int32[] = {};
305   int output_dims[] = {0};
306   const int golden_output_len = 1;
307   const float golden_output_float[] = {3};
308   const int8_t golden_output_int8[] = {3};
309   const uint8_t golden_output_uint8[] = {3};
310   const int golden_dims_len = 0;
311   const int golden_dims[] = {};
312   tflite::testing::TestReshape(input_dims, input_float, shape_dims, shape_int32,
313                                output_dims, output_data_float,
314                                golden_output_float, golden_output_len,
315                                golden_dims, golden_dims_len, false);
316   tflite::testing::TestReshapeQuantized(
317       input_dims, input_int8, shape_dims, shape_int32, output_dims,
318       output_data_int8, golden_output_int8, golden_output_len, golden_dims,
319       golden_dims_len, false);
320   tflite::testing::TestReshapeQuantized(
321       input_dims, input_uint8, shape_dims, shape_int32, output_dims,
322       output_data_uint8, golden_output_uint8, golden_output_len, golden_dims,
323       golden_dims_len, false);
324 }
325 
326 // Some old models specify '[0]' as the new shape, indicating that both input
327 // and output are scalars.
TF_LITE_MICRO_TEST(ReshapeWithLegacyScalarOutputShouldSucceed)328 TF_LITE_MICRO_TEST(ReshapeWithLegacyScalarOutputShouldSucceed) {
329   using tflite::testing::CreateTensor;
330   using tflite::testing::IntArrayFromInts;
331 
332   int input_dims_data[] = {1, 1};
333   TfLiteIntArray* input_dims = IntArrayFromInts(input_dims_data);
334   const float input_data[] = {3.0f};
335   auto input_tensor = CreateTensor(input_data, input_dims);
336 
337   float output_data[1];
338   int output_dims_data[2] = {1, 0};
339   TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
340   auto output_tensor = CreateTensor(output_data, output_dims);
341 
342   int shape_dims_data[] = {1, 0};
343   TfLiteIntArray* shape_dims = IntArrayFromInts(shape_dims_data);
344 
345   const int32_t shape_data[] = {0};
346   auto shape_tensor = tflite::testing::CreateTensor(shape_data, shape_dims);
347   const float expected_output_with_shape[] = {};
348   const int expected_output_with_shape_len = 0;
349   const float expected_output_no_shape[] = {3};
350   const int expected_output_no_shape_len = 1;
351   const int expected_dims[] = {};
352   const int expected_dims_len = 0;
353   tflite::testing::TestReshapeWithShape<float>(
354       &input_tensor, &shape_tensor, &output_tensor, expected_output_with_shape,
355       expected_output_with_shape_len, expected_dims, expected_dims_len, true);
356 
357   tflite::testing::TestReshapeWithoutShape<float>(
358       &input_tensor, &output_tensor, expected_output_no_shape,
359       expected_output_no_shape_len, expected_dims, expected_dims_len, false);
360 }
361 
362 TF_LITE_MICRO_TESTS_END
363