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 
16 #include "tensorflow/lite/c/builtin_op_data.h"
17 #include "tensorflow/lite/c/common.h"
18 #include "tensorflow/lite/micro/kernels/kernel_runner.h"
19 #include "tensorflow/lite/micro/test_helpers.h"
20 #include "tensorflow/lite/micro/testing/micro_test.h"
21 
22 namespace tflite {
23 namespace testing {
24 namespace {
25 
26 const int flat_size_simple = 4;
27 const float scale_simple = 0.01;
28 int dims_simple[] = {4, 1, 2, 2, 1};
29 const float input1_simple[] = {-0.8, 0.2, 0.9, 0.7};
30 const float input2_simple[] = {0.6, 0.4, 0.9, 0.8};
31 const float golden_simple[] = {-0.48, 0.08, 0.81, 0.56};
32 const float golden_simple_relu[] = {0.0, 0.08, 0.81, 0.56};
33 
34 const int flat_size_broadcast = 6;
35 const float input_scale_broadcast = 0.05f;
36 const float output_scale_broadcast = 0.01f;
37 int dims_broadcast[] = {4, 1, 3, 1, 2};
38 int dims_scalar_broadcast[] = {1, 1};
39 const float input1_broadcast[] = {-2.0, 0.2, 0.7, 0.8, 1.1, 2.0};
40 const float input2_broadcast[] = {0.1};
41 const float golden_broadcast[] = {-0.2, 0.02, 0.07, 0.08, 0.11, 0.2};
42 const float golden_broadcast_relu[] = {0, 0.02, 0.07, 0.08, 0.11, 0.2};
43 
44 template <typename T>
ValidateMulGoldens(TfLiteTensor * tensors,int tensors_size,TfLiteFusedActivation activation,const T * golden,int output_len,float tolerance,T * output)45 void ValidateMulGoldens(TfLiteTensor* tensors, int tensors_size,
46                         TfLiteFusedActivation activation, const T* golden,
47                         int output_len, float tolerance, T* output) {
48   TfLiteMulParams builtin_data = {
49       .activation = activation,
50   };
51 
52   int inputs_array_data[] = {2, 0, 1};
53   TfLiteIntArray* inputs_array = IntArrayFromInts(inputs_array_data);
54   int outputs_array_data[] = {1, 2};
55   TfLiteIntArray* outputs_array = IntArrayFromInts(outputs_array_data);
56 
57   const TfLiteRegistration registration = tflite::ops::micro::Register_MUL();
58   micro::KernelRunner runner(registration, tensors, tensors_size, inputs_array,
59                              outputs_array,
60                              reinterpret_cast<void*>(&builtin_data));
61 
62   TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.InitAndPrepare());
63   TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.Invoke());
64 
65   for (int i = 0; i < output_len; i++) {
66     TF_LITE_MICRO_EXPECT_NEAR(golden[i], output[i], tolerance);
67   }
68 }
69 
TestMulFloat(int * input1_dims_data,const float * input1_data,int * input2_dims_data,const float * input2_data,int * output_dims_data,const float * golden,float * output_data,TfLiteFusedActivation activation)70 void TestMulFloat(int* input1_dims_data, const float* input1_data,
71                   int* input2_dims_data, const float* input2_data,
72                   int* output_dims_data, const float* golden,
73                   float* output_data, TfLiteFusedActivation activation) {
74   TfLiteIntArray* input1_dims = IntArrayFromInts(input1_dims_data);
75   TfLiteIntArray* input2_dims = IntArrayFromInts(input2_dims_data);
76   TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
77   const int output_dims_count = ElementCount(*output_dims);
78 
79   constexpr int inputs_size = 2;
80   constexpr int outputs_size = 1;
81   constexpr int tensors_size = inputs_size + outputs_size;
82   TfLiteTensor tensors[tensors_size] = {
83       CreateTensor(input1_data, input1_dims),
84       CreateTensor(input2_data, input2_dims),
85       CreateTensor(output_data, output_dims),
86   };
87 
88   ValidateMulGoldens(tensors, tensors_size, activation, golden,
89                      output_dims_count, 1e-5, output_data);
90 }
91 
92 template <typename T>
TestMulQuantized(int * input1_dims_data,const float * input1_data,T * input1_quantized,int * input2_dims_data,const float * input2_data,T * input2_quantized,const float input_scale,const int input_zero_point,int * output_dims_data,const float * golden,T * golden_quantized,const float output_scale,const int output_zero_point,T * output_data,TfLiteFusedActivation activation)93 void TestMulQuantized(int* input1_dims_data, const float* input1_data,
94                       T* input1_quantized, int* input2_dims_data,
95                       const float* input2_data, T* input2_quantized,
96                       const float input_scale, const int input_zero_point,
97                       int* output_dims_data, const float* golden,
98                       T* golden_quantized, const float output_scale,
99                       const int output_zero_point, T* output_data,
100                       TfLiteFusedActivation activation) {
101   TfLiteIntArray* input1_dims = IntArrayFromInts(input1_dims_data);
102   TfLiteIntArray* input2_dims = IntArrayFromInts(input2_dims_data);
103   TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
104   const int output_dims_count = ElementCount(*output_dims);
105 
106   constexpr int inputs_size = 2;
107   constexpr int outputs_size = 1;
108   constexpr int tensors_size = inputs_size + outputs_size;
109   TfLiteTensor tensors[tensors_size] = {
110       CreateQuantizedTensor(input1_data, input1_quantized, input1_dims,
111                             input_scale, input_zero_point),
112       CreateQuantizedTensor(input2_data, input2_quantized, input2_dims,
113                             input_scale, input_zero_point),
114       CreateQuantizedTensor(output_data, output_dims, output_scale,
115                             output_zero_point)};
116 
117   Quantize(golden, golden_quantized, output_dims_count, output_scale,
118            output_zero_point);
119 
120   ValidateMulGoldens(tensors, tensors_size, activation, golden_quantized,
121                      output_dims_count, 1.0f, output_data);
122 }
123 
124 }  // namespace
125 
126 }  // namespace testing
127 }  // namespace tflite
128 
129 TF_LITE_MICRO_TESTS_BEGIN
130 
TF_LITE_MICRO_TEST(SimpleFloatNoAcativationShouldMatchGolden)131 TF_LITE_MICRO_TEST(SimpleFloatNoAcativationShouldMatchGolden) {
132   float output_data[tflite::testing::flat_size_simple];
133 
134   tflite::testing::TestMulFloat(
135       tflite::testing::dims_simple, tflite::testing::input1_simple,
136       tflite::testing::dims_simple, tflite::testing::input2_simple,
137       tflite::testing::dims_simple, tflite::testing::golden_simple, output_data,
138       kTfLiteActNone);
139 }
140 
TF_LITE_MICRO_TEST(SimpleFloatReluShouldMatchGolden)141 TF_LITE_MICRO_TEST(SimpleFloatReluShouldMatchGolden) {
142   float output_data[tflite::testing::flat_size_simple];
143 
144   tflite::testing::TestMulFloat(
145       tflite::testing::dims_simple, tflite::testing::input1_simple,
146       tflite::testing::dims_simple, tflite::testing::input2_simple,
147       tflite::testing::dims_simple, tflite::testing::golden_simple_relu,
148       output_data, kTfLiteActRelu);
149 }
150 
TF_LITE_MICRO_TEST(SimpleInt8NoAcativationShouldMatchGolden)151 TF_LITE_MICRO_TEST(SimpleInt8NoAcativationShouldMatchGolden) {
152   int8_t input1_quantized[tflite::testing::flat_size_simple];
153   int8_t input2_quantized[tflite::testing::flat_size_simple];
154   int8_t golden_quantized[tflite::testing::flat_size_simple];
155   int8_t output_data[tflite::testing::flat_size_simple];
156 
157   tflite::testing::TestMulQuantized(
158       tflite::testing::dims_simple, tflite::testing::input1_simple,
159       input1_quantized, tflite::testing::dims_simple,
160       tflite::testing::input2_simple, input2_quantized,
161       tflite::testing::scale_simple, 0, tflite::testing::dims_simple,
162       tflite::testing::golden_simple, golden_quantized,
163       tflite::testing::scale_simple, 0, output_data, kTfLiteActNone);
164 }
165 
TF_LITE_MICRO_TEST(BroadcastFloatNoActivationShouldMatchGolden)166 TF_LITE_MICRO_TEST(BroadcastFloatNoActivationShouldMatchGolden) {
167   float output_data[tflite::testing::flat_size_broadcast];
168 
169   tflite::testing::TestMulFloat(
170       tflite::testing::dims_broadcast, tflite::testing::input1_broadcast,
171       tflite::testing::dims_scalar_broadcast, tflite::testing::input2_broadcast,
172       tflite::testing::dims_broadcast, tflite::testing::golden_broadcast,
173       output_data, kTfLiteActNone);
174 }
175 
TF_LITE_MICRO_TEST(BroadcastFloatReluShouldMatchGolden)176 TF_LITE_MICRO_TEST(BroadcastFloatReluShouldMatchGolden) {
177   float output_data[tflite::testing::flat_size_broadcast];
178 
179   tflite::testing::TestMulFloat(
180       tflite::testing::dims_broadcast, tflite::testing::input1_broadcast,
181       tflite::testing::dims_scalar_broadcast, tflite::testing::input2_broadcast,
182       tflite::testing::dims_broadcast, tflite::testing::golden_broadcast_relu,
183       output_data, kTfLiteActRelu);
184 }
185 
TF_LITE_MICRO_TEST(BroadcastInt8NoAcativationShouldMatchGolden)186 TF_LITE_MICRO_TEST(BroadcastInt8NoAcativationShouldMatchGolden) {
187   int8_t input1_quantized[tflite::testing::flat_size_broadcast];
188   int8_t input2_quantized[tflite::testing::flat_size_broadcast];
189   int8_t golden_quantized[tflite::testing::flat_size_broadcast];
190   int8_t output_data[tflite::testing::flat_size_broadcast];
191 
192   tflite::testing::TestMulQuantized(
193       tflite::testing::dims_broadcast, tflite::testing::input1_broadcast,
194       input1_quantized, tflite::testing::dims_scalar_broadcast,
195       tflite::testing::input2_broadcast, input2_quantized,
196       tflite::testing::input_scale_broadcast, 0,
197       tflite::testing::dims_broadcast, tflite::testing::golden_broadcast,
198       golden_quantized, tflite::testing::output_scale_broadcast, 0, output_data,
199       kTfLiteActNone);
200 }
201 
202 TF_LITE_MICRO_TESTS_END
203