1 /* Copyright 2019 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/debug_log.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
26 template <typename T>
ValidatePackGoldens(TfLiteTensor * tensors,int tensors_size,TfLitePackParams params,TfLiteIntArray * inputs_array,TfLiteIntArray * outputs_array,const T * golden,int output_len,float tolerance,T * output)27 void ValidatePackGoldens(TfLiteTensor* tensors, int tensors_size,
28 TfLitePackParams params, TfLiteIntArray* inputs_array,
29 TfLiteIntArray* outputs_array, const T* golden,
30 int output_len, float tolerance, T* output) {
31 // Place a unique value in the uninitialized output buffer.
32 for (int i = 0; i < output_len; ++i) {
33 output[i] = 23;
34 }
35
36 const TfLiteRegistration registration = tflite::ops::micro::Register_PACK();
37 micro::KernelRunner runner(registration, tensors, tensors_size, inputs_array,
38 outputs_array, reinterpret_cast<void*>(¶ms));
39
40 TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.InitAndPrepare());
41 TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.Invoke());
42
43 for (int i = 0; i < output_len; ++i) {
44 TF_LITE_MICRO_EXPECT_NEAR(golden[i], output[i], tolerance);
45 }
46 }
47
TestPackTwoInputsFloat(const int * input1_dims_data,const float * input1_data,const int * input2_dims_data,const float * input2_data,int axis,const int * output_dims_data,const float * expected_output_data,float * output_data)48 void TestPackTwoInputsFloat(const int* input1_dims_data,
49 const float* input1_data,
50 const int* input2_dims_data,
51 const float* input2_data, int axis,
52 const int* output_dims_data,
53 const float* expected_output_data,
54 float* output_data) {
55 TfLiteIntArray* input1_dims = IntArrayFromInts(input1_dims_data);
56 TfLiteIntArray* input2_dims = IntArrayFromInts(input2_dims_data);
57 TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
58 const int output_dims_count = ElementCount(*output_dims);
59
60 constexpr int input_size = 2;
61 constexpr int output_size = 1;
62 constexpr int tensors_size = input_size + output_size;
63 TfLiteTensor tensors[tensors_size] = {CreateTensor(input1_data, input1_dims),
64 CreateTensor(input2_data, input2_dims),
65 CreateTensor(output_data, output_dims)};
66
67 TfLitePackParams builtin_data = {
68 .values_count = 2,
69 .axis = axis,
70 };
71 int inputs_array_data[] = {2, 0, 1};
72 TfLiteIntArray* inputs_array = IntArrayFromInts(inputs_array_data);
73 int outputs_array_data[] = {1, 2};
74 TfLiteIntArray* outputs_array = IntArrayFromInts(outputs_array_data);
75
76 ValidatePackGoldens(tensors, tensors_size, builtin_data, inputs_array,
77 outputs_array, expected_output_data, output_dims_count,
78 1e-5f, output_data);
79 }
80
TestPackThreeInputsFloat(const int * input1_dims_data,const float * input1_data,const int * input2_dims_data,const float * input2_data,const int * input3_dims_data,const float * input3_data,int axis,const int * output_dims_data,const float * expected_output_data,float * output_data)81 void TestPackThreeInputsFloat(
82 const int* input1_dims_data, const float* input1_data,
83 const int* input2_dims_data, const float* input2_data,
84 const int* input3_dims_data, const float* input3_data, int axis,
85 const int* output_dims_data, const float* expected_output_data,
86 float* output_data) {
87 TfLiteIntArray* input1_dims = IntArrayFromInts(input1_dims_data);
88 TfLiteIntArray* input2_dims = IntArrayFromInts(input2_dims_data);
89 TfLiteIntArray* input3_dims = IntArrayFromInts(input3_dims_data);
90 TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
91 const int output_dims_count = ElementCount(*output_dims);
92
93 constexpr int input_size = 3;
94 constexpr int output_size = 1;
95 constexpr int tensors_size = input_size + output_size;
96 TfLiteTensor tensors[tensors_size] = {CreateTensor(input1_data, input1_dims),
97 CreateTensor(input2_data, input2_dims),
98 CreateTensor(input3_data, input3_dims),
99 CreateTensor(output_data, output_dims)};
100
101 TfLitePackParams builtin_data = {
102 .values_count = 3,
103 .axis = axis,
104 };
105 int inputs_array_data[] = {3, 0, 1, 2};
106 TfLiteIntArray* inputs_array = IntArrayFromInts(inputs_array_data);
107 int outputs_array_data[] = {1, 3};
108 TfLiteIntArray* outputs_array = IntArrayFromInts(outputs_array_data);
109
110 ValidatePackGoldens(tensors, tensors_size, builtin_data, inputs_array,
111 outputs_array, expected_output_data, output_dims_count,
112 1e-5f, output_data);
113 }
114
TestPackTwoInputsQuantized(const int * input1_dims_data,const uint8_t * input1_data,const int * input2_dims_data,const uint8_t * input2_data,int axis,const int * output_dims_data,const uint8_t * expected_output_data,uint8_t * output_data)115 void TestPackTwoInputsQuantized(const int* input1_dims_data,
116 const uint8_t* input1_data,
117 const int* input2_dims_data,
118 const uint8_t* input2_data, int axis,
119 const int* output_dims_data,
120 const uint8_t* expected_output_data,
121 uint8_t* output_data) {
122 TfLiteIntArray* input1_dims = IntArrayFromInts(input1_dims_data);
123 TfLiteIntArray* input2_dims = IntArrayFromInts(input2_dims_data);
124 TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
125 const int output_dims_count = ElementCount(*output_dims);
126
127 constexpr int input_size = 2;
128 constexpr int output_size = 1;
129 constexpr int tensors_size = input_size + output_size;
130 TfLiteTensor tensors[tensors_size] = {
131 // CreateQuantizedTensor needs scale/zero_point values as input, but these
132 // values don't matter as to the functionality of PACK, so just set as 1.0
133 // and 128.
134 CreateQuantizedTensor(input1_data, input1_dims, 1.0, 128),
135 CreateQuantizedTensor(input2_data, input2_dims, 1.0, 128),
136 CreateQuantizedTensor(output_data, output_dims, 1.0, 128)};
137
138 TfLitePackParams builtin_data = {
139 .values_count = 2,
140 .axis = axis,
141 };
142 int inputs_array_data[] = {2, 0, 1};
143 TfLiteIntArray* inputs_array = IntArrayFromInts(inputs_array_data);
144 int outputs_array_data[] = {1, 2};
145 TfLiteIntArray* outputs_array = IntArrayFromInts(outputs_array_data);
146
147 ValidatePackGoldens(tensors, tensors_size, builtin_data, inputs_array,
148 outputs_array, expected_output_data, output_dims_count,
149 1e-5f, output_data);
150 }
151
TestPackTwoInputsQuantized32(const int * input1_dims_data,const int32_t * input1_data,const int * input2_dims_data,const int32_t * input2_data,int axis,const int * output_dims_data,const int32_t * expected_output_data,int32_t * output_data)152 void TestPackTwoInputsQuantized32(const int* input1_dims_data,
153 const int32_t* input1_data,
154 const int* input2_dims_data,
155 const int32_t* input2_data, int axis,
156 const int* output_dims_data,
157 const int32_t* expected_output_data,
158 int32_t* output_data) {
159 TfLiteIntArray* input1_dims = IntArrayFromInts(input1_dims_data);
160 TfLiteIntArray* input2_dims = IntArrayFromInts(input2_dims_data);
161 TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
162 const int output_dims_count = ElementCount(*output_dims);
163
164 constexpr int input_size = 2;
165 constexpr int output_size = 1;
166 constexpr int tensors_size = input_size + output_size;
167 TfLiteTensor tensors[tensors_size] = {CreateTensor(input1_data, input1_dims),
168 CreateTensor(input2_data, input2_dims),
169 CreateTensor(output_data, output_dims)};
170
171 TfLitePackParams builtin_data = {
172 .values_count = 2,
173 .axis = axis,
174 };
175 int inputs_array_data[] = {2, 0, 1};
176 TfLiteIntArray* inputs_array = IntArrayFromInts(inputs_array_data);
177 int outputs_array_data[] = {1, 2};
178 TfLiteIntArray* outputs_array = IntArrayFromInts(outputs_array_data);
179
180 ValidatePackGoldens(tensors, tensors_size, builtin_data, inputs_array,
181 outputs_array, expected_output_data, output_dims_count,
182 1e-5f, output_data);
183 }
184
185 } // namespace testing
186 } // namespace tflite
187
188 TF_LITE_MICRO_TESTS_BEGIN
189
TF_LITE_MICRO_TEST(PackFloatThreeInputs)190 TF_LITE_MICRO_TEST(PackFloatThreeInputs) {
191 const int input_shape[] = {1, 2};
192 const int output_shape[] = {2, 3, 2};
193 const float input1_values[] = {1, 4};
194 const float input2_values[] = {2, 5};
195 const float input3_values[] = {3, 6};
196 const float golden[] = {1, 4, 2, 5, 3, 6};
197 const int axis = 0;
198 constexpr int output_dims_count = 6;
199 float output_data[output_dims_count];
200
201 tflite::testing::TestPackThreeInputsFloat(
202 input_shape, input1_values, input_shape, input2_values, input_shape,
203 input3_values, axis, output_shape, golden, output_data);
204 }
205
TF_LITE_MICRO_TEST(PackFloatThreeInputsDifferentAxis)206 TF_LITE_MICRO_TEST(PackFloatThreeInputsDifferentAxis) {
207 const int input_shape[] = {1, 2};
208 const int output_shape[] = {2, 2, 3};
209 const float input1_values[] = {1, 4};
210 const float input2_values[] = {2, 5};
211 const float input3_values[] = {3, 6};
212 const float golden[] = {1, 2, 3, 4, 5, 6};
213 const int axis = 1;
214 constexpr int output_dims_count = 6;
215 float output_data[output_dims_count];
216
217 tflite::testing::TestPackThreeInputsFloat(
218 input_shape, input1_values, input_shape, input2_values, input_shape,
219 input3_values, axis, output_shape, golden, output_data);
220 }
221
TF_LITE_MICRO_TEST(PackFloatThreeInputsNegativeAxis)222 TF_LITE_MICRO_TEST(PackFloatThreeInputsNegativeAxis) {
223 const int input_shape[] = {1, 2};
224 const int output_shape[] = {2, 2, 3};
225 const float input1_values[] = {1, 4};
226 const float input2_values[] = {2, 5};
227 const float input3_values[] = {3, 6};
228 const float golden[] = {1, 2, 3, 4, 5, 6};
229 const int axis = -1;
230 constexpr int output_dims_count = 6;
231 float output_data[output_dims_count];
232
233 tflite::testing::TestPackThreeInputsFloat(
234 input_shape, input1_values, input_shape, input2_values, input_shape,
235 input3_values, axis, output_shape, golden, output_data);
236 }
237
TF_LITE_MICRO_TEST(PackFloatMultilDimensions)238 TF_LITE_MICRO_TEST(PackFloatMultilDimensions) {
239 const int input_shape[] = {2, 2, 3};
240 const int output_shape[] = {3, 2, 2, 3};
241 const float input1_values[] = {1, 2, 3, 4, 5, 6};
242 const float input2_values[] = {7, 8, 9, 10, 11, 12};
243 const float golden[] = {1, 2, 3, 7, 8, 9, 4, 5, 6, 10, 11, 12};
244 const int axis = 1;
245 constexpr int output_dims_count = 12;
246 float output_data[output_dims_count];
247
248 tflite::testing::TestPackTwoInputsFloat(input_shape, input1_values,
249 input_shape, input2_values, axis,
250 output_shape, golden, output_data);
251 }
252
TF_LITE_MICRO_TEST(PackQuantizedMultilDimensions)253 TF_LITE_MICRO_TEST(PackQuantizedMultilDimensions) {
254 const int input_shape[] = {2, 2, 3};
255 const int output_shape[] = {3, 2, 2, 3};
256 const uint8_t input1_values[] = {1, 2, 3, 4, 5, 6};
257 const uint8_t input2_values[] = {7, 8, 9, 10, 11, 12};
258 const uint8_t golden[] = {1, 2, 3, 7, 8, 9, 4, 5, 6, 10, 11, 12};
259 const int axis = 1;
260 constexpr int output_dims_count = 12;
261 uint8_t output_data[output_dims_count];
262
263 tflite::testing::TestPackTwoInputsQuantized(
264 input_shape, input1_values, input_shape, input2_values, axis,
265 output_shape, golden, output_data);
266 }
267
TF_LITE_MICRO_TEST(PackQuantized32MultilDimensions)268 TF_LITE_MICRO_TEST(PackQuantized32MultilDimensions) {
269 const int input_shape[] = {2, 2, 3};
270 const int output_shape[] = {3, 2, 2, 3};
271 const int32_t input1_values[] = {1, 2, 3, 4, 5, 6};
272 const int32_t input2_values[] = {7, 8, 9, 10, 11, 12};
273 const int32_t golden[] = {1, 2, 3, 7, 8, 9, 4, 5, 6, 10, 11, 12};
274 const int axis = 1;
275 constexpr int output_dims_count = 12;
276 int32_t output_data[output_dims_count];
277
278 tflite::testing::TestPackTwoInputsQuantized32(
279 input_shape, input1_values, input_shape, input2_values, axis,
280 output_shape, golden, output_data);
281 }
282
283 TF_LITE_MICRO_TESTS_END
284