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/all_ops_resolver.h"
19 #include "tensorflow/lite/micro/kernels/circular_buffer_flexbuffers_generated_data.h"
20 #include "tensorflow/lite/micro/kernels/kernel_runner.h"
21 #include "tensorflow/lite/micro/kernels/micro_ops.h"
22 #include "tensorflow/lite/micro/test_helpers.h"
23 #include "tensorflow/lite/micro/testing/micro_test.h"
24
25 namespace tflite {
26 namespace testing {
27 namespace {
28
29 constexpr int kRunPeriod = 2;
30
31 // TODO(b/149795762): Add this to TfLiteStatus enum.
32 constexpr TfLiteStatus kTfLiteAbort = static_cast<TfLiteStatus>(-9);
33
34 } // namespace
35 } // namespace testing
36 } // namespace tflite
37
38 TF_LITE_MICRO_TESTS_BEGIN
39
TF_LITE_MICRO_TEST(OutputTensorLength4)40 TF_LITE_MICRO_TEST(OutputTensorLength4) {
41 constexpr int depth = 3;
42 constexpr int num_slots = 4;
43 int8_t input_data[depth];
44 int8_t output_data[depth * num_slots];
45
46 memset(output_data, 0, sizeof(output_data));
47
48 // There are four input dimensions - [1, 1, 1, depth].
49 int input_dims[] = {4, 1, 1, 1, depth};
50 // There are four output dimensions - [1, num_slots, 1, depth].
51 int output_dims[] = {4, 1, num_slots, 1, depth};
52
53 TfLiteIntArray* input_tensor_dims =
54 tflite::testing::IntArrayFromInts(input_dims);
55 TfLiteIntArray* output_tensor_dims =
56 tflite::testing::IntArrayFromInts(output_dims);
57
58 const int output_dims_count = tflite::ElementCount(*output_tensor_dims);
59
60 constexpr int inputs_size = 2;
61 constexpr int outputs_size = 1;
62 constexpr int tensors_size = inputs_size + outputs_size;
63 TfLiteTensor tensors[tensors_size] = {
64 tflite::testing::CreateQuantizedTensor(input_data, input_tensor_dims, 1,
65 0),
66 tflite::testing::CreateQuantizedTensor(output_data, output_tensor_dims, 1,
67 0),
68 };
69
70 // There is one input - tensor 0.
71 int inputs_array_data[] = {1, 0};
72 TfLiteIntArray* inputs_array =
73 tflite::testing::IntArrayFromInts(inputs_array_data);
74 // There is one output - tensor 1.
75 int outputs_array_data[] = {1, 1};
76 TfLiteIntArray* outputs_array =
77 tflite::testing::IntArrayFromInts(outputs_array_data);
78
79 const TfLiteRegistration* registration =
80 tflite::ops::micro::Register_CIRCULAR_BUFFER();
81 tflite::micro::KernelRunner runner = tflite::micro::KernelRunner(
82 *registration, tensors, tensors_size, inputs_array, outputs_array,
83 /*builtin_data=*/nullptr);
84 TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.InitAndPrepare());
85
86 const int8_t goldens[5][16] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3},
87 {0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6},
88 {0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
89 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
90 {4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}};
91
92 // Expect the circular buffer to run every other invoke for 4xN output.
93 for (int i = 0; i < 5; i++) {
94 for (int j = 0; j < depth; j++) {
95 input_data[j] = i * depth + j + 1;
96 }
97 TfLiteStatus status = runner.Invoke();
98
99 for (int j = 0; j < output_dims_count; ++j) {
100 TF_LITE_MICRO_EXPECT_EQ(goldens[i][j], output_data[j]);
101 }
102
103 // Every kRunPeriod iterations, the circular buffer should return kTfLiteOk.
104 if (i % tflite::testing::kRunPeriod == tflite::testing::kRunPeriod - 1) {
105 TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, status);
106 } else {
107 TF_LITE_MICRO_EXPECT_EQ(tflite::testing::kTfLiteAbort, status);
108 }
109 }
110 }
111
TF_LITE_MICRO_TEST(OutputTensorOnEveryIterationLength4)112 TF_LITE_MICRO_TEST(OutputTensorOnEveryIterationLength4) {
113 constexpr int depth = 3;
114 constexpr int num_slots = 4;
115 int8_t input_data[depth];
116 int8_t output_data[depth * num_slots];
117
118 memset(output_data, 0, sizeof(output_data));
119
120 // There are four input dimensions - [1, 1, 1, depth].
121 int input_dims[] = {4, 1, 1, 1, depth};
122 // There are four output dimensions - [1, num_slots, 1, depth].
123 int output_dims[] = {4, 1, num_slots, 1, depth};
124
125 TfLiteIntArray* input_tensor_dims =
126 tflite::testing::IntArrayFromInts(input_dims);
127 TfLiteIntArray* output_tensor_dims =
128 tflite::testing::IntArrayFromInts(output_dims);
129
130 const int output_dims_count = tflite::ElementCount(*output_tensor_dims);
131
132 constexpr int inputs_size = 2;
133 constexpr int outputs_size = 1;
134 constexpr int tensors_size = inputs_size + outputs_size;
135 TfLiteTensor tensors[tensors_size] = {
136 tflite::testing::CreateQuantizedTensor(input_data, input_tensor_dims, 1,
137 0),
138 tflite::testing::CreateQuantizedTensor(output_data, output_tensor_dims, 1,
139 0),
140 };
141
142 // There is one input - tensor 0.
143 int inputs_array_data[] = {1, 0};
144 TfLiteIntArray* inputs_array =
145 tflite::testing::IntArrayFromInts(inputs_array_data);
146 // There is one output - tensor 1.
147 int outputs_array_data[] = {1, 1};
148 TfLiteIntArray* outputs_array =
149 tflite::testing::IntArrayFromInts(outputs_array_data);
150
151 const TfLiteRegistration* registration =
152 tflite::ops::micro::Register_CIRCULAR_BUFFER();
153 tflite::micro::KernelRunner runner = tflite::micro::KernelRunner(
154 *registration, tensors, tensors_size, inputs_array, outputs_array,
155 /*builtin_data=*/nullptr);
156
157 TF_LITE_MICRO_EXPECT_EQ(
158 kTfLiteOk, runner.InitAndPrepare(reinterpret_cast<const char*>(
159 g_gen_data_circular_buffer_config),
160 g_gen_data_size_circular_buffer_config));
161
162 const int8_t goldens[5][16] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3},
163 {0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6},
164 {0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
165 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
166 {4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}};
167
168 // Expect the circular buffer to run every other invoke for 4xN output.
169 for (int i = 0; i < 5; i++) {
170 for (int j = 0; j < depth; j++) {
171 input_data[j] = i * depth + j + 1;
172 }
173 TfLiteStatus status = runner.Invoke();
174 TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, status);
175
176 for (int j = 0; j < output_dims_count; ++j) {
177 TF_LITE_MICRO_EXPECT_EQ(goldens[i][j], output_data[j]);
178 }
179 }
180 }
181
TF_LITE_MICRO_TEST(OutputTensorLength5)182 TF_LITE_MICRO_TEST(OutputTensorLength5) {
183 constexpr int depth = 4;
184 constexpr int num_slots = 5;
185 int8_t input_data[depth];
186 int8_t output_data[depth * num_slots];
187
188 memset(output_data, 0, sizeof(output_data));
189 int input_dims[] = {4, 1, 1, 1, depth};
190 int output_dims[] = {4, 1, num_slots, 1, depth};
191 TfLiteIntArray* input_tensor_dims =
192 tflite::testing::IntArrayFromInts(input_dims);
193 TfLiteIntArray* output_tensor_dims =
194 tflite::testing::IntArrayFromInts(output_dims);
195
196 const int output_dims_count = tflite::ElementCount(*output_tensor_dims);
197
198 constexpr int inputs_size = 2;
199 constexpr int outputs_size = 1;
200 constexpr int tensors_size = inputs_size + outputs_size;
201 TfLiteTensor tensors[tensors_size] = {
202 tflite::testing::CreateQuantizedTensor(input_data, input_tensor_dims, 1,
203 0),
204 tflite::testing::CreateQuantizedTensor(output_data, output_tensor_dims, 1,
205 0),
206 };
207
208 // There is one input - tensor 0.
209 int inputs_array_data[] = {1, 0};
210 TfLiteIntArray* inputs_array =
211 tflite::testing::IntArrayFromInts(inputs_array_data);
212 // There is one output - tensor 1.
213 int outputs_array_data[] = {1, 1};
214 TfLiteIntArray* outputs_array =
215 tflite::testing::IntArrayFromInts(outputs_array_data);
216
217 const TfLiteRegistration* registration =
218 tflite::ops::micro::Register_CIRCULAR_BUFFER();
219 tflite::micro::KernelRunner runner = tflite::micro::KernelRunner(
220 *registration, tensors, tensors_size, inputs_array, outputs_array,
221 /*builtin_data=*/nullptr);
222 TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.InitAndPrepare());
223
224 const int8_t goldens[6][20] = {
225 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4},
226 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8},
227 {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
228 {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
229 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
230 {5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
231 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}};
232
233 // Expect circular buffer to run every cycle for 5xN output.
234 for (int i = 0; i < 6; i++) {
235 for (int j = 0; j < depth; j++) {
236 input_data[j] = i * depth + j + 1;
237 }
238 TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.Invoke());
239
240 for (int j = 0; j < output_dims_count; ++j) {
241 TF_LITE_MICRO_EXPECT_EQ(goldens[i][j], output_data[j]);
242 }
243 }
244 }
245
246 TF_LITE_MICRO_TESTS_END
247