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