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