• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <initializer_list>
16 
17 #include "tensorflow/lite/c/builtin_op_data.h"
18 #include "tensorflow/lite/c/common.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 
TestConcatenateTwoInputs(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)27 void TestConcatenateTwoInputs(const int* input1_dims_data,
28                               const float* input1_data,
29                               const int* input2_dims_data,
30                               const float* input2_data, int axis,
31                               const int* output_dims_data,
32                               const float* expected_output_data,
33                               float* output_data) {
34   TfLiteIntArray* input1_dims = IntArrayFromInts(input1_dims_data);
35   TfLiteIntArray* input2_dims = IntArrayFromInts(input2_dims_data);
36   TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
37 
38   constexpr int input_size = 2;
39   constexpr int output_size = 1;
40   constexpr int tensors_size = input_size + output_size;
41   TfLiteTensor tensors[tensors_size] = {CreateTensor(input1_data, input1_dims),
42                                         CreateTensor(input2_data, input2_dims),
43                                         CreateTensor(output_data, output_dims)};
44 
45   int inputs_array_data[] = {2, 0, 1};
46   TfLiteIntArray* inputs_array = IntArrayFromInts(inputs_array_data);
47   int outputs_array_data[] = {1, 2};
48   TfLiteIntArray* outputs_array = IntArrayFromInts(outputs_array_data);
49 
50   TfLiteConcatenationParams builtin_data = {
51       .axis = axis,
52       .activation = kTfLiteActNone  // Only activation supported in this impl
53   };
54 
55   const TfLiteRegistration registration =
56       tflite::ops::micro::Register_CONCATENATION();
57   micro::KernelRunner runner(registration, tensors, tensors_size, inputs_array,
58                              outputs_array,
59                              reinterpret_cast<void*>(&builtin_data));
60 
61   TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.InitAndPrepare());
62   TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.Invoke());
63 
64   const int output_dims_count = ElementCount(*output_dims);
65   for (int i = 0; i < output_dims_count; ++i) {
66     TF_LITE_MICRO_EXPECT_NEAR(expected_output_data[i], output_data[i], 1e-5f);
67   }
68 }
69 
TestConcatenateQuantizedTwoInputs(const int * input1_dims_data,const uint8_t * input1_data,const int * input2_dims_data,const uint8_t * input2_data,const float input_scale,const int input_zero_point,int axis,const int * output_dims_data,const uint8_t * expected_output_data,const float output_scale,const int output_zero_point,uint8_t * output_data)70 void TestConcatenateQuantizedTwoInputs(
71     const int* input1_dims_data, const uint8_t* input1_data,
72     const int* input2_dims_data, const uint8_t* input2_data,
73     const float input_scale, const int input_zero_point, int axis,
74     const int* output_dims_data, const uint8_t* expected_output_data,
75     const float output_scale, const int output_zero_point,
76     uint8_t* output_data) {
77   TfLiteIntArray* input1_dims = IntArrayFromInts(input1_dims_data);
78   TfLiteIntArray* input2_dims = IntArrayFromInts(input2_dims_data);
79   TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
80 
81   constexpr int input_size = 2;
82   constexpr int output_size = 1;
83   constexpr int tensors_size = input_size + output_size;
84   TfLiteTensor tensors[tensors_size] = {
85       CreateQuantizedTensor(input1_data, input1_dims, input_scale,
86                             input_zero_point),
87       CreateQuantizedTensor(input2_data, input2_dims, input_scale,
88                             input_zero_point),
89       CreateQuantizedTensor(output_data, output_dims, output_scale,
90                             output_zero_point)};
91 
92   int inputs_array_data[] = {2, 0, 1};
93   TfLiteIntArray* inputs_array = IntArrayFromInts(inputs_array_data);
94   int outputs_array_data[] = {1, 2};
95   TfLiteIntArray* outputs_array = IntArrayFromInts(outputs_array_data);
96 
97   TfLiteConcatenationParams builtin_data = {
98       .axis = axis,
99       .activation = kTfLiteActNone  // Only activation supported in this impl
100   };
101 
102   const TfLiteRegistration registration =
103       tflite::ops::micro::Register_CONCATENATION();
104   micro::KernelRunner runner(registration, tensors, tensors_size, inputs_array,
105                              outputs_array,
106                              reinterpret_cast<void*>(&builtin_data));
107 
108   TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.InitAndPrepare());
109   TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.Invoke());
110 
111   const int output_dims_count = ElementCount(*output_dims);
112   for (int i = 0; i < output_dims_count; ++i) {
113     TF_LITE_MICRO_EXPECT_EQ(expected_output_data[i], output_data[i]);
114   }
115 }
116 
117 }  // namespace
118 }  // namespace testing
119 }  // namespace tflite
120 
121 TF_LITE_MICRO_TESTS_BEGIN
122 
TF_LITE_MICRO_TEST(TwoInputsAllAxesCombinations)123 TF_LITE_MICRO_TEST(TwoInputsAllAxesCombinations) {
124   // Concatenate the same two input tensors along all possible axes.
125 
126   const int input_shape[] = {2, 2, 3};
127   const float input1_value[] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f};
128   const float input2_value[] = {7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f};
129 
130   // expected output when concatenating on axis 0
131   const int output_shape_axis0[] = {2, 4, 3};
132   const float output_value_axis0[] = {1.0f, 2.0f, 3.0f, 4.0f,  5.0f,  6.0f,
133                                       7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f};
134 
135   // expected output when concatenating on axis 1
136   const int output_shape_axis1[] = {2, 2, 6};
137   const float output_value_axis1[] = {1.0f, 2.0f, 3.0f, 7.0f,  8.0f,  9.0f,
138                                       4.0f, 5.0f, 6.0f, 10.0f, 11.0f, 12.0f};
139 
140   float output_data[12];
141 
142   // Axis = 0
143   tflite::testing::TestConcatenateTwoInputs(
144       input_shape, input1_value, input_shape, input2_value, /* axis */ 0,
145       output_shape_axis0, output_value_axis0, output_data);
146 
147   // Axis = -2 (equivalent to axis = 0)
148   tflite::testing::TestConcatenateTwoInputs(
149       input_shape, input1_value, input_shape, input2_value, /* axis */ -2,
150       output_shape_axis0, output_value_axis0, output_data);
151 
152   // Axis = 1
153   tflite::testing::TestConcatenateTwoInputs(
154       input_shape, input1_value, input_shape, input2_value, /* axis */ 1,
155       output_shape_axis1, output_value_axis1, output_data);
156 
157   // Axis = -1 (equivalent to axis = 1)
158   tflite::testing::TestConcatenateTwoInputs(
159       input_shape, input1_value, input_shape, input2_value, /* axis */ -1,
160       output_shape_axis1, output_value_axis1, output_data);
161 }
162 
TF_LITE_MICRO_TEST(TwoInputsQuantizedUint8)163 TF_LITE_MICRO_TEST(TwoInputsQuantizedUint8) {
164   const int axis = 2;
165   const int input_shape[] = {3, 2, 1, 2};
166   const int output_shape[] = {3, 2, 1, 4};
167 
168   const float input_scale = 0.1f;
169   const int input_zero_point = 127;
170   const float output_scale = 0.1f;
171   const int output_zero_point = 127;
172 
173   const uint8_t input1_values[] = {137, 157, 167, 197};
174 
175   const uint8_t input2_values[] = {138, 158, 168, 198};
176 
177   const uint8_t output_value[] = {
178       137, 157, 138, 158, 167, 197, 168, 198,
179   };
180 
181   uint8_t output_data[8];
182   tflite::testing::TestConcatenateQuantizedTwoInputs(
183       input_shape, input1_values, input_shape, input2_values, input_scale,
184       input_zero_point, axis, output_shape, output_value, output_scale,
185       output_zero_point, output_data);
186 }
187 
TF_LITE_MICRO_TEST(ThreeDimensionalTwoInputsDifferentShapes)188 TF_LITE_MICRO_TEST(ThreeDimensionalTwoInputsDifferentShapes) {
189   const int axis = 1;
190 
191   const int input1_shape[] = {3, 2, 1, 2};
192   const int input2_shape[] = {3, 2, 3, 2};
193   const int output_shape[] = {3, 2, 4, 2};
194 
195   const float input1_values[] = {1.0f, 3.0f, 4.0f, 7.0f};
196   const float input2_values[] = {1.0f, 2.0f, 3.0f, 4.0f,  5.0f,  6.0f,
197                                  7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f};
198   const float output_values[] = {1.0f, 3.0f,  1.0f,  2.0f, 3.0f, 4.0f,
199                                  5.0f, 6.0f,  4.0f,  7.0f, 7.0f, 8.0f,
200                                  9.0f, 10.0f, 11.0f, 12.0f};
201 
202   float output_data[16];
203   tflite::testing::TestConcatenateTwoInputs(
204       input1_shape, input1_values, input2_shape, input2_values, axis,
205       output_shape, output_values, output_data);
206 }
207 
208 TF_LITE_MICRO_TESTS_END
209