• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2020 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/kernels/conv_test.h"
19 #include "tensorflow/lite/micro/kernels/kernel_runner.h"
20 #include "tensorflow/lite/micro/micro_utils.h"
21 #include "tensorflow/lite/micro/test_helpers.h"
22 #include "tensorflow/lite/micro/testing/micro_test.h"
23 
24 namespace tflite {
25 namespace testing {
26 namespace {
27 
28 // Common inputs and outputs.
29 constexpr int kInputElements = 32;
30 static const int kInputShape[] = {4, 1, 4, 4, 2};
31 static const float kInputData[kInputElements] = {
32     1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15, 16,
33     17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32};
34 
35 constexpr int kFilterElements = 18;
36 static const int kFilterShape[] = {4, 1, 3, 3, 2};
37 static const float kFilterData[kFilterElements] = {
38     1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18};
39 
40 constexpr int kBiasElements = 1;
41 static const int kBiasShape[] = {4, 1, 1, 1, 1};
42 static const float kBiasData[kBiasElements] = {0};
43 
44 constexpr int kOutputElements = 16;
45 static const int kOutputShape[] = {4, 1, 4, 4, 1};
46 static const float kGoldenData[kOutputElements] = {
47     184,  412,  568,  528,  678,  1347, 1689, 1434,
48     1494, 2715, 3057, 2442, 1968, 3352, 3652, 2760};
49 
50 // Transpose conv uses TfLiteConvParams.
51 static TfLiteConvParams common_conv_params = {kTfLitePaddingSame,  // padding
52                                               1,  // stride_width
53                                               1,  // stride_height
54                                               kTfLiteActNone,
55                                               1,
56                                               1};
57 
58 template <typename T>
InvokeTransposeConv(TfLiteTensor * tensors,int tensors_size,int output_length,TfLiteConvParams * conv_params,T * output_data)59 TfLiteStatus InvokeTransposeConv(TfLiteTensor* tensors, int tensors_size,
60                                  int output_length,
61                                  TfLiteConvParams* conv_params,
62                                  T* output_data) {
63   int inputs_array_data[] = {4, 0, 1, 2, 3};
64   TfLiteIntArray* inputs_array = IntArrayFromInts(inputs_array_data);
65   int outputs_array_data[] = {1, 4};
66   TfLiteIntArray* outputs_array = IntArrayFromInts(outputs_array_data);
67 
68   const TfLiteRegistration registration = tflite::Register_TRANSPOSE_CONV();
69   micro::KernelRunner runner(registration, tensors, tensors_size, inputs_array,
70                              outputs_array, conv_params);
71 
72   const char* init_data = reinterpret_cast<const char*>(conv_params);
73   TfLiteStatus status = runner.InitAndPrepare(init_data);
74   if (status != kTfLiteOk) {
75     return status;
76   }
77   return runner.Invoke();
78 }
79 
80 template <typename T>
ValidateTransposeConvGoldens(TfLiteTensor * tensors,int tensors_size,const T * expected_output_data,int output_length,TfLiteConvParams * conv_params,T * output_data,float tolerance)81 TfLiteStatus ValidateTransposeConvGoldens(TfLiteTensor* tensors,
82                                           int tensors_size,
83                                           const T* expected_output_data,
84                                           int output_length,
85                                           TfLiteConvParams* conv_params,
86                                           T* output_data, float tolerance) {
87   TfLiteStatus status = InvokeTransposeConv(
88       tensors, tensors_size, output_length, conv_params, output_data);
89   if (status != kTfLiteOk) {
90     return status;
91   }
92   for (int i = 0; i < output_length; ++i) {
93     TF_LITE_MICRO_EXPECT_NEAR(expected_output_data[i], output_data[i],
94                               tolerance);
95   }
96   return kTfLiteOk;
97 }
98 
TestTransposeConvFloat(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 int * output_dims_data,const float * expected_output_data,TfLiteConvParams * conv_params,float * output_data)99 TfLiteStatus TestTransposeConvFloat(
100     const int* input_dims_data, const float* input_data,
101     const int* filter_dims_data, const float* filter_data,
102     const int* bias_dims_data, const float* bias_data,
103     const int* output_dims_data, const float* expected_output_data,
104     TfLiteConvParams* conv_params, float* output_data) {
105   TfLiteIntArray* input_dims = IntArrayFromInts(input_dims_data);
106   TfLiteIntArray* filter_dims = IntArrayFromInts(filter_dims_data);
107   TfLiteIntArray* bias_dims = IntArrayFromInts(bias_dims_data);
108   TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
109   const int output_dims_count = ElementCount(*output_dims);
110 
111   const int output_shape_dims_data[] = {1, 0};
112   int32_t* output_shape = nullptr;
113   TfLiteIntArray* output_shape_dims = IntArrayFromInts(output_shape_dims_data);
114 
115   constexpr int inputs_size = 4;
116   constexpr int outputs_size = 1;
117   constexpr int tensors_size = inputs_size + outputs_size;
118   TfLiteTensor tensors[tensors_size] = {
119       CreateTensor(output_shape, output_shape_dims),
120       CreateTensor(filter_data, filter_dims),
121       CreateTensor(input_data, input_dims),
122       CreateTensor(bias_data, bias_dims),
123       CreateTensor(output_data, output_dims),
124   };
125 
126   return ValidateTransposeConvGoldens(tensors, tensors_size,
127                                       expected_output_data, output_dims_count,
128                                       conv_params, output_data, 0.001f);
129 }
130 
TestTransposeConvQuantized(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_quantized,float filter_scale,const int * bias_dims_data,const float * bias_data,int32_t * bias_quantized,float * bias_scales,int * bias_zero_points,const int * output_dims_data,const float * expected_output_data,int8_t * expected_output_quantized,float output_scale,int output_zero_point,TfLiteConvParams * conv_params,int8_t * output_data)131 TfLiteStatus TestTransposeConvQuantized(
132     const int* input_dims_data, const float* input_data,
133     int8_t* input_quantized, float input_scale, int input_zero_point,
134     const int* filter_dims_data, const float* filter_data,
135     int8_t* filter_quantized, float filter_scale, const int* bias_dims_data,
136     const float* bias_data, int32_t* bias_quantized, float* bias_scales,
137     int* bias_zero_points, const int* output_dims_data,
138     const float* expected_output_data, int8_t* expected_output_quantized,
139     float output_scale, int output_zero_point, TfLiteConvParams* conv_params,
140     int8_t* output_data) {
141   TfLiteIntArray* input_dims = IntArrayFromInts(input_dims_data);
142   TfLiteIntArray* filter_dims = IntArrayFromInts(filter_dims_data);
143   TfLiteIntArray* bias_dims = IntArrayFromInts(bias_dims_data);
144   TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
145   const int output_dims_count = ElementCount(*output_dims);
146 
147   int filter_zero_points[5];
148   float filter_scales[5];
149   TfLiteAffineQuantization filter_quant;
150   TfLiteTensor filter_tensor = CreateSymmetricPerChannelQuantizedTensor(
151       filter_data, filter_quantized, filter_dims, filter_scales,
152       filter_zero_points, &filter_quant, 0 /* quantized dimension */);
153   tflite::Quantize(expected_output_data, expected_output_quantized,
154                    output_dims_count, output_scale, 0);
155 
156   const int output_shape_dims_data[] = {1, 0};
157   int32_t* output_shape = nullptr;
158   TfLiteIntArray* output_shape_dims = IntArrayFromInts(output_shape_dims_data);
159 
160   constexpr int inputs_size = 4;
161   constexpr int outputs_size = 1;
162   constexpr int tensors_size = inputs_size + outputs_size;
163   TfLiteTensor tensors[tensors_size] = {
164       CreateTensor(output_shape, output_shape_dims), filter_tensor,
165       CreateQuantizedTensor(input_data, input_quantized, input_dims,
166                             input_scale, input_zero_point),
167       CreateQuantizedBiasTensor(bias_data, bias_quantized, bias_dims,
168                                 input_scale, filter_scale),
169       CreateQuantizedTensor(output_data, output_dims, output_scale,
170                             output_zero_point)};
171 
172   return ValidateTransposeConvGoldens(
173       tensors, tensors_size, expected_output_quantized, output_dims_count,
174       conv_params, output_data, 1.0f);
175 }
176 }  // namespace
177 }  // namespace testing
178 }  // namespace tflite
179 
180 TF_LITE_MICRO_TESTS_BEGIN
181 
TF_LITE_MICRO_TEST(SimpleTestFloat)182 TF_LITE_MICRO_TEST(SimpleTestFloat) {
183   float output_data[tflite::testing::kOutputElements];
184 
185   TF_LITE_MICRO_EXPECT_EQ(
186       kTfLiteOk,
187       tflite::testing::TestTransposeConvFloat(
188           tflite::testing::kInputShape, tflite::testing::kInputData,
189           tflite::testing::kFilterShape, tflite::testing::kFilterData,
190           tflite::testing::kBiasShape, tflite::testing::kBiasData,
191           tflite::testing::kOutputShape, tflite::testing::kGoldenData,
192           &tflite::testing::common_conv_params, output_data));
193 }
194 
TF_LITE_MICRO_TEST(SimpleTestQuantizedPerChannel)195 TF_LITE_MICRO_TEST(SimpleTestQuantizedPerChannel) {
196   int8_t output_data[tflite::testing::kOutputElements];
197 
198   const float input_scale = 0.5f;
199   const float output_scale = 1.0f;
200   const float filter_scale = 1.0f;
201   const int input_zero_point = 0;
202   const int output_zero_point = 0;
203 
204   int8_t input_quantized[tflite::testing::kInputElements];
205   int8_t filter_quantized[tflite::testing::kFilterElements];
206   int32_t bias_quantized[tflite::testing::kBiasElements];
207   int8_t golden_quantized[tflite::testing::kOutputElements];
208   int zero_points[tflite::testing::kBiasElements + 1];
209   float scales[tflite::testing::kBiasElements + 1];
210 
211   TF_LITE_MICRO_EXPECT_EQ(
212       kTfLiteOk,
213       tflite::testing::TestTransposeConvQuantized(
214           tflite::testing::kInputShape, tflite::testing::kInputData,
215           input_quantized, input_scale, input_zero_point,
216           tflite::testing::kFilterShape, tflite::testing::kFilterData,
217           filter_quantized, filter_scale, tflite::testing::kBiasShape,
218           tflite::testing::kBiasData, bias_quantized, scales, zero_points,
219           tflite::testing::kOutputShape, tflite::testing::kGoldenData,
220           golden_quantized, output_scale, output_zero_point,
221           &tflite::testing::common_conv_params, output_data));
222 }
223 
TF_LITE_MICRO_TEST(InputOutputDifferentTypeIsError)224 TF_LITE_MICRO_TEST(InputOutputDifferentTypeIsError) {
225   using tflite::testing::CreateQuantizedTensor;
226   using tflite::testing::CreateTensor;
227   using tflite::testing::IntArrayFromInts;
228 
229   TfLiteIntArray* input_dims = IntArrayFromInts(tflite::testing::kInputShape);
230   TfLiteIntArray* filter_dims = IntArrayFromInts(tflite::testing::kFilterShape);
231   TfLiteIntArray* bias_dims = IntArrayFromInts(tflite::testing::kBiasShape);
232   TfLiteIntArray* output_dims = IntArrayFromInts(tflite::testing::kOutputShape);
233   const int output_dims_count = tflite::ElementCount(*output_dims);
234   constexpr int inputs_size = 4;
235   constexpr int outputs_size = 1;
236   constexpr int tensors_size = inputs_size + outputs_size;
237 
238   int8_t output_data[tflite::testing::kOutputElements];
239 
240   const int output_shape_dims_data[] = {1, 0};
241   int32_t* output_shape = nullptr;
242   TfLiteIntArray* output_shape_dims = IntArrayFromInts(output_shape_dims_data);
243 
244   TfLiteTensor tensors[tensors_size] = {
245       CreateTensor(output_shape, output_shape_dims),
246       CreateTensor(tflite::testing::kInputData, input_dims),
247       CreateTensor(tflite::testing::kFilterData, filter_dims),
248       CreateTensor(tflite::testing::kBiasData, bias_dims),
249       CreateQuantizedTensor(output_data, output_dims, /*scale=*/1.0f,
250                             /*zero_point=*/0),
251   };
252   TF_LITE_MICRO_EXPECT_EQ(
253       kTfLiteError, tflite::testing::InvokeTransposeConv(
254                         tensors, tensors_size, output_dims_count,
255                         &tflite::testing::common_conv_params, output_data));
256 }
257 
TF_LITE_MICRO_TEST(HybridModeIsError)258 TF_LITE_MICRO_TEST(HybridModeIsError) {
259   using tflite::testing::CreateQuantizedTensor;
260   using tflite::testing::CreateTensor;
261   using tflite::testing::IntArrayFromInts;
262 
263   TfLiteIntArray* input_dims = IntArrayFromInts(tflite::testing::kInputShape);
264   TfLiteIntArray* filter_dims = IntArrayFromInts(tflite::testing::kFilterShape);
265   TfLiteIntArray* bias_dims = IntArrayFromInts(tflite::testing::kBiasShape);
266   TfLiteIntArray* output_dims = IntArrayFromInts(tflite::testing::kOutputShape);
267   const int output_dims_count = tflite::ElementCount(*output_dims);
268 
269   constexpr int inputs_size = 4;
270   constexpr int outputs_size = 1;
271   constexpr int tensors_size = inputs_size + outputs_size;
272 
273   int8_t filter_data[tflite::testing::kFilterElements] = {};
274   float output_data[tflite::testing::kOutputElements];
275 
276   const int output_shape_dims_data[] = {1, 0};
277   int32_t* output_shape = nullptr;
278   TfLiteIntArray* output_shape_dims = IntArrayFromInts(output_shape_dims_data);
279 
280   TfLiteTensor tensors[tensors_size] = {
281       CreateTensor(output_shape, output_shape_dims),
282       CreateTensor(tflite::testing::kInputData, input_dims),
283       CreateQuantizedTensor(filter_data, filter_dims,
284                             /*scale=*/1.0f,
285                             /*zero_point=*/0),
286       CreateTensor(tflite::testing::kBiasData, bias_dims),
287       CreateTensor(output_data, output_dims),
288   };
289 
290   TF_LITE_MICRO_EXPECT_EQ(
291       kTfLiteError, tflite::testing::InvokeTransposeConv(
292                         tensors, tensors_size, output_dims_count,
293                         &tflite::testing::common_conv_params, output_data));
294 }
295 
296 TF_LITE_MICRO_TESTS_END
297