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