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/delegates/gpu/gl/kernels/elementwise.h"
17
18 #include <utility>
19
20 #include <gmock/gmock.h>
21 #include <gtest/gtest.h>
22 #include "tensorflow/lite/delegates/gpu/common/operations.h"
23 #include "tensorflow/lite/delegates/gpu/gl/kernels/test_util.h"
24
25 using ::testing::FloatEq;
26 using ::testing::FloatNear;
27 using ::testing::Pointwise;
28
29 namespace tflite {
30 namespace gpu {
31 namespace gl {
32 namespace {
33
GetTensorRef(int ref,const BHWC & shape)34 TensorRef<BHWC> GetTensorRef(int ref, const BHWC& shape) {
35 TensorRef<BHWC> tensor_ref;
36 tensor_ref.type = DataType::FLOAT32;
37 tensor_ref.ref = ref;
38 tensor_ref.shape = shape;
39 return tensor_ref;
40 }
41
TEST(ElementwiseOneArgumentTest,Abs)42 TEST(ElementwiseOneArgumentTest, Abs) {
43 OperationType op_type = OperationType::ABS;
44 const BHWC shape(1, 2, 2, 1);
45 SingleOpModel model({/*type=*/ToString(op_type), /*attributes=*/{}},
46 /*inputs=*/{GetTensorRef(0, shape)},
47 /*outputs=*/{GetTensorRef(1, shape)});
48 ASSERT_TRUE(model.PopulateTensor(0, {0.0, -6.2, 2.0, 4.0}));
49 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
50 EXPECT_THAT(model.GetOutput(0),
51 Pointwise(FloatNear(1e-6), {0.0, 6.2, 2.0, 4.0}));
52 }
53
TEST(ElementwiseOneArgumentTest,Cos)54 TEST(ElementwiseOneArgumentTest, Cos) {
55 OperationType op_type = OperationType::COS;
56 const BHWC shape(1, 2, 2, 1);
57 SingleOpModel model({/*type=*/ToString(op_type), /*attributes=*/{}},
58 /*inputs=*/{GetTensorRef(0, shape)},
59 /*outputs=*/{GetTensorRef(1, shape)});
60 ASSERT_TRUE(model.PopulateTensor(0, {0.0, 3.1415926, -3.1415926, 1}));
61 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
62 EXPECT_THAT(model.GetOutput(0),
63 Pointwise(FloatNear(1e-6), {1.0, -1.0, -1.0, 0.540302}));
64 }
65
TEST(ElementwiseOneArgumentTest,Copy)66 TEST(ElementwiseOneArgumentTest, Copy) {
67 OperationType op_type = OperationType::COPY;
68 const BHWC shape(1, 2, 2, 1);
69 SingleOpModel model({/*type=*/ToString(op_type), /*attributes=*/{}},
70 /*inputs=*/{GetTensorRef(0, shape)},
71 /*outputs=*/{GetTensorRef(1, shape)});
72 ASSERT_TRUE(model.PopulateTensor(0, {0.0, -6.2, 2.0, 4.0}));
73 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
74 EXPECT_THAT(model.GetOutput(0), Pointwise(FloatEq(), {0.0, -6.2, 2.0, 4.0}));
75 }
76
TEST(ElementwiseOneArgumentTest,Elu)77 TEST(ElementwiseOneArgumentTest, Elu) {
78 OperationType op_type = OperationType::ELU;
79 const BHWC shape(1, 1, 1, 7);
80 SingleOpModel model({/*type=*/ToString(op_type), /*attributes=*/{}},
81 /*inputs=*/{GetTensorRef(0, shape)},
82 /*outputs=*/{GetTensorRef(1, shape)});
83 ASSERT_TRUE(model.PopulateTensor(
84 0, {0.0f, 1.0f, -1.0f, 100.0f, -100.0f, 0.01f, -0.01f}));
85 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
86 EXPECT_THAT(model.GetOutput(0),
87 Pointwise(FloatNear(1e-6), {0.0f, 1.0f, std::exp(-1.0f) - 1.0f,
88 100.0f, std::exp(-100.0f) - 1.0f,
89 0.01f, std::exp(-0.01f) - 1.0f}));
90 }
91
TEST(ElementwiseOneArgumentTest,Exp)92 TEST(ElementwiseOneArgumentTest, Exp) {
93 OperationType op_type = OperationType::EXP;
94 const BHWC shape(1, 1, 1, 7);
95 SingleOpModel model({/*type=*/ToString(op_type), /*attributes=*/{}},
96 /*inputs=*/{GetTensorRef(0, shape)},
97 /*outputs=*/{GetTensorRef(1, shape)});
98 ASSERT_TRUE(model.PopulateTensor(
99 0, {0.0f, 1.0f, -1.0f, 100.0f, -100.0f, 0.01f, -0.01f}));
100 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
101 EXPECT_THAT(model.GetOutput(0),
102 Pointwise(FloatNear(1e-6),
103 {std::exp(0.0f), std::exp(1.0f), std::exp(-1.0f),
104 std::exp(100.0f), std::exp(-100.0f), std::exp(0.01f),
105 std::exp(-0.01f)}));
106 }
107
TEST(ElementwiseOneArgumentTest,Floor)108 TEST(ElementwiseOneArgumentTest, Floor) {
109 OperationType op_type = OperationType::FLOOR;
110 const BHWC shape(1, 1, 1, 7);
111 SingleOpModel model({/*type=*/ToString(op_type), /*attributes=*/{}},
112 /*inputs=*/{GetTensorRef(0, shape)},
113 /*outputs=*/{GetTensorRef(1, shape)});
114 ASSERT_TRUE(
115 model.PopulateTensor(0, {-4.5f, -3.0f, -1.5f, 0.0f, 1.5f, 3.0f, 4.5f}));
116 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
117 EXPECT_THAT(model.GetOutput(0),
118 Pointwise(FloatNear(1e-6),
119 {-5.0f, -3.0f, -2.0f, 0.0f, 1.0f, 3.0f, 4.0f}));
120 }
121
TEST(ElementwiseOneArgumentTest,HardSwish)122 TEST(ElementwiseOneArgumentTest, HardSwish) {
123 OperationType op_type = OperationType::HARD_SWISH;
124 const BHWC shape(1, 1, 1, 7);
125 SingleOpModel model({/*type=*/ToString(op_type), /*attributes=*/{}},
126 /*inputs=*/{GetTensorRef(0, shape)},
127 /*outputs=*/{GetTensorRef(1, shape)});
128 ASSERT_TRUE(
129 model.PopulateTensor(0, {-4.5f, -3.0f, -1.5f, 0.0f, 1.5f, 3.0f, 4.5f}));
130 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
131 EXPECT_THAT(model.GetOutput(0),
132 Pointwise(FloatNear(1e-6f),
133 {0.0f, 0.0f, -0.375f, 0.0f, 1.125f, 3.f, 4.5f}));
134 }
135
TEST(ElementwiseOneArgumentTest,Log)136 TEST(ElementwiseOneArgumentTest, Log) {
137 OperationType op_type = OperationType::LOG;
138 const BHWC shape(1, 2, 2, 1);
139 SingleOpModel model({/*type=*/ToString(op_type), /*attributes=*/{}},
140 /*inputs=*/{GetTensorRef(0, shape)},
141 /*outputs=*/{GetTensorRef(1, shape)});
142 ASSERT_TRUE(model.PopulateTensor(0, {1.0, 3.1415926, 1.0, 1.0}));
143 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
144 EXPECT_THAT(model.GetOutput(0),
145 Pointwise(FloatNear(1e-6), {0.0, 1.14473, 0.0, 0.0}));
146 }
147
TEST(ElementwiseOneArgumentTest,Neg)148 TEST(ElementwiseOneArgumentTest, Neg) {
149 OperationType op_type = OperationType::NEG;
150 const BHWC shape(1, 2, 2, 1);
151 SingleOpModel model({/*type=*/ToString(op_type), /*attributes=*/{}},
152 /*inputs=*/{GetTensorRef(0, shape)},
153 /*outputs=*/{GetTensorRef(1, shape)});
154 ASSERT_TRUE(model.PopulateTensor(0, {1.0, -3.1415926, 0.0, 1.0}));
155 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
156 EXPECT_THAT(model.GetOutput(0),
157 Pointwise(FloatNear(1e-6), {-1.0, 3.1415926, 0.0, -1.0}));
158 }
159
TEST(ElementwiseOneArgumentTest,Rsqrt)160 TEST(ElementwiseOneArgumentTest, Rsqrt) {
161 OperationType op_type = OperationType::RSQRT;
162 const BHWC shape(1, 2, 2, 1);
163 SingleOpModel model({/*type=*/ToString(op_type), /*attributes=*/{}},
164 /*inputs=*/{GetTensorRef(0, shape)},
165 /*outputs=*/{GetTensorRef(1, shape)});
166 ASSERT_TRUE(model.PopulateTensor(0, {1.0, 2.0, 4.0, 9.0}));
167 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
168 EXPECT_THAT(model.GetOutput(0),
169 Pointwise(FloatNear(1e-6), {1.0, 0.707106, 0.5, 0.333333}));
170 }
171
TEST(ElementwiseOneArgumentTest,Sigmoid)172 TEST(ElementwiseOneArgumentTest, Sigmoid) {
173 OperationType op_type = OperationType::SIGMOID;
174 const BHWC shape(1, 2, 2, 1);
175 SingleOpModel model({/*type=*/ToString(op_type), /*attributes=*/{}},
176 /*inputs=*/{GetTensorRef(0, shape)},
177 /*outputs=*/{GetTensorRef(1, shape)});
178 ASSERT_TRUE(model.PopulateTensor(0, {0.0, -6.0, 2.0, 4.0}));
179 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
180 EXPECT_THAT(model.GetOutput(0),
181 Pointwise(FloatNear(1e-6), {0.5, 0.002473, 0.880797, 0.982014}));
182 }
183
TEST(ElementwiseOneArgumentTest,Sin)184 TEST(ElementwiseOneArgumentTest, Sin) {
185 OperationType op_type = OperationType::SIN;
186 const BHWC shape(1, 2, 2, 1);
187 SingleOpModel model({/*type=*/ToString(op_type), /*attributes=*/{}},
188 /*inputs=*/{GetTensorRef(0, shape)},
189 /*outputs=*/{GetTensorRef(1, shape)});
190 ASSERT_TRUE(model.PopulateTensor(0, {0.0, 3.1415926, -3.1415926, 1.0}));
191 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
192 EXPECT_THAT(model.GetOutput(0),
193 Pointwise(FloatNear(1e-6), {0.0, 0.0, 0.0, 0.841471}));
194 }
195
TEST(ElementwiseOneArgumentTest,Sqrt)196 TEST(ElementwiseOneArgumentTest, Sqrt) {
197 OperationType op_type = OperationType::SQRT;
198 const BHWC shape(1, 2, 2, 1);
199 SingleOpModel model({/*type=*/ToString(op_type), /*attributes=*/{}},
200 /*inputs=*/{GetTensorRef(0, shape)},
201 /*outputs=*/{GetTensorRef(1, shape)});
202 ASSERT_TRUE(model.PopulateTensor(0, {0.0, 1.0, 2.0, 4.0}));
203 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
204 EXPECT_THAT(model.GetOutput(0),
205 Pointwise(FloatNear(1e-6), {0.0, 1.0, 1.414213, 2.0}));
206 }
207
TEST(ElementwiseOneArgumentTest,Square)208 TEST(ElementwiseOneArgumentTest, Square) {
209 OperationType op_type = OperationType::SQUARE;
210 const BHWC shape(1, 2, 2, 1);
211 SingleOpModel model({/*type=*/ToString(op_type), /*attributes=*/{}},
212 /*inputs=*/{GetTensorRef(0, shape)},
213 /*outputs=*/{GetTensorRef(1, shape)});
214 ASSERT_TRUE(model.PopulateTensor(0, {1.0, 2.0, 0.5, -3.0}));
215 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
216 EXPECT_THAT(model.GetOutput(0),
217 Pointwise(FloatNear(1e-6), {1.0, 4.0, 0.25, 9.0}));
218 }
219
TEST(ElementwiseOneArgumentTest,Tanh)220 TEST(ElementwiseOneArgumentTest, Tanh) {
221 OperationType op_type = OperationType::TANH;
222 const BHWC shape(1, 2, 2, 1);
223 SingleOpModel model({/*type=*/ToString(op_type), /*attributes=*/{}},
224 /*inputs=*/{GetTensorRef(0, shape)},
225 /*outputs=*/{GetTensorRef(1, shape)});
226 ASSERT_TRUE(model.PopulateTensor(0, {0.0, -6.0, 2.0, 4.0}));
227 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
228 EXPECT_THAT(model.GetOutput(0),
229 Pointwise(FloatNear(1e-6), {0.0, -0.999987, 0.964027, 0.999329}));
230 }
231
TEST(ElementwiseTwoArgumentsTest,DivElementwise)232 TEST(ElementwiseTwoArgumentsTest, DivElementwise) {
233 OperationType op_type = OperationType::DIV;
234 const BHWC shape(1, 2, 2, 1);
235 SingleOpModel model(
236 {/*type=*/ToString(op_type), /*attributes=*/{}},
237 /*inputs=*/{GetTensorRef(0, shape), GetTensorRef(1, shape)},
238 /*outputs=*/{GetTensorRef(2, shape)});
239 ASSERT_TRUE(model.PopulateTensor(0, {0.0, -6.2, 2.0, 4.0}));
240 ASSERT_TRUE(model.PopulateTensor(1, {1.0, 2.0, -0.5, 4.0}));
241 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
242 EXPECT_THAT(model.GetOutput(0),
243 Pointwise(FloatNear(1e-6), {0.0, -3.1, -4.0, 1.0}));
244 }
245
TEST(ElementwiseTwoArgumentsTest,DivBroadcast)246 TEST(ElementwiseTwoArgumentsTest, DivBroadcast) {
247 OperationType op_type = OperationType::DIV;
248 const BHWC shape0(1, 2, 1, 2);
249 const BHWC shape1(1, 1, 1, 2);
250 SingleOpModel model(
251 {/*type=*/ToString(op_type), /*attributes=*/{}},
252 /*inputs=*/{GetTensorRef(0, shape0), GetTensorRef(1, shape1)},
253 /*outputs=*/{GetTensorRef(2, shape0)});
254 ASSERT_TRUE(model.PopulateTensor(0, {0.0, 1.0, 2.0, 3.0}));
255 ASSERT_TRUE(model.PopulateTensor(1, {0.5, 0.2}));
256 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
257 EXPECT_THAT(model.GetOutput(0),
258 Pointwise(FloatNear(1e-6), {0.0, 5.0, 4.0, 15.0}));
259 }
260
TEST(ElementwiseTwoArgumentsTest,DivScalar)261 TEST(ElementwiseTwoArgumentsTest, DivScalar) {
262 OperationType op_type = OperationType::DIV;
263 const BHWC shape0(1, 2, 1, 2);
264 ElementwiseAttributes attr;
265 attr.param = static_cast<float>(0.5);
266 SingleOpModel model({/*type=*/ToString(op_type), attr},
267 /*inputs=*/{GetTensorRef(0, shape0)},
268 /*outputs=*/{GetTensorRef(2, shape0)});
269 ASSERT_TRUE(model.PopulateTensor(0, {0.0, 1.0, 2.0, 3.0}));
270 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
271 EXPECT_THAT(model.GetOutput(0),
272 Pointwise(FloatNear(1e-6), {0.0, 2.0, 4.0, 6.0}));
273 }
274
TEST(ElementwiseTwoArgumentsTest,DivConstVector)275 TEST(ElementwiseTwoArgumentsTest, DivConstVector) {
276 OperationType op_type = OperationType::DIV;
277 const BHWC shape0(1, 2, 1, 2);
278
279 ElementwiseAttributes attr;
280 Tensor<Linear, DataType::FLOAT32> param;
281 param.shape = Linear(2);
282 param.id = 1;
283 param.data = {0.4, 0.5};
284 attr.param = std::move(param);
285
286 SingleOpModel model({/*type=*/ToString(op_type), attr},
287 /*inputs=*/{GetTensorRef(0, shape0)},
288 /*outputs=*/{GetTensorRef(2, shape0)});
289 ASSERT_TRUE(model.PopulateTensor(0, {0.0, 1.0, 2.0, 3.0}));
290 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
291 EXPECT_THAT(model.GetOutput(0),
292 Pointwise(FloatNear(1e-6), {0.0, 2.0, 5.0, 6.0}));
293 }
294
TEST(ElementwiseTwoArgumentsTest,FloorDiv)295 TEST(ElementwiseTwoArgumentsTest, FloorDiv) {
296 OperationType op_type = OperationType::FLOOR_DIV;
297 const BHWC shape0(1, 1, 1, 7);
298
299 float scalar = 2.7f;
300 ElementwiseAttributes attr;
301 attr.param = scalar;
302
303 SingleOpModel model({/*type=*/ToString(op_type), attr},
304 /*inputs=*/{GetTensorRef(0, shape0)},
305 /*outputs=*/{GetTensorRef(2, shape0)});
306 ASSERT_TRUE(
307 model.PopulateTensor(0, {-4.5f, -3.0f, -1.5f, 0.0f, 1.5f, 3.0f, 4.5f}));
308 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
309 EXPECT_THAT(model.GetOutput(0),
310 Pointwise(FloatNear(1e-6),
311 {std::floor(-4.5f / scalar), std::floor(-3.0f / scalar),
312 std::floor(-1.5f / scalar), std::floor(0.0f / scalar),
313 std::floor(1.5f / scalar), std::floor(3.0f / scalar),
314 std::floor(4.5f / scalar)}));
315 }
316
TEST(ElementwiseTwoArgumentsTest,FloorMod)317 TEST(ElementwiseTwoArgumentsTest, FloorMod) {
318 OperationType op_type = OperationType::FLOOR_MOD;
319 const BHWC shape0(1, 1, 1, 7);
320
321 float scalar = 2.7f;
322 ElementwiseAttributes attr;
323 attr.param = scalar;
324
325 SingleOpModel model({/*type=*/ToString(op_type), attr},
326 /*inputs=*/{GetTensorRef(0, shape0)},
327 /*outputs=*/{GetTensorRef(2, shape0)});
328 ASSERT_TRUE(
329 model.PopulateTensor(0, {-4.5f, -3.0f, -1.5f, 0.0f, 1.5f, 3.0f, 4.5f}));
330 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
331 EXPECT_THAT(
332 model.GetOutput(0),
333 Pointwise(FloatNear(1e-6), {-4.5f - std::floor(-4.5f / scalar) * scalar,
334 -3.0f - std::floor(-3.0f / scalar) * scalar,
335 -1.5f - std::floor(-1.5f / scalar) * scalar,
336 0.0f - std::floor(0.0f / scalar) * scalar,
337 1.5f - std::floor(1.5f / scalar) * scalar,
338 3.0f - std::floor(3.0f / scalar) * scalar,
339 4.5f - std::floor(4.5f / scalar) * scalar}));
340 }
341
TEST(ElementwiseTwoArgumentsTest,MaximumElementwise)342 TEST(ElementwiseTwoArgumentsTest, MaximumElementwise) {
343 OperationType op_type = OperationType::MAXIMUM;
344 const BHWC shape(1, 2, 2, 1);
345 SingleOpModel model(
346 {/*type=*/ToString(op_type), /*attributes=*/{}},
347 /*inputs=*/{GetTensorRef(0, shape), GetTensorRef(1, shape)},
348 /*outputs=*/{GetTensorRef(2, shape)});
349 ASSERT_TRUE(model.PopulateTensor(0, {0.0, -6.2, 2.0, -3.0}));
350 ASSERT_TRUE(model.PopulateTensor(1, {1.0, 2.0, 3.0, -2.0}));
351 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
352 EXPECT_THAT(model.GetOutput(0),
353 Pointwise(FloatNear(1e-6), {1.0, 2.0, 3.0, -2.0}));
354 }
355
TEST(ElementwiseTwoArgumentsTest,MaximumBroadcast)356 TEST(ElementwiseTwoArgumentsTest, MaximumBroadcast) {
357 OperationType op_type = OperationType::MAXIMUM;
358 const BHWC shape0(1, 2, 1, 2);
359 const BHWC shape1(1, 1, 1, 2);
360 SingleOpModel model(
361 {/*type=*/ToString(op_type), /*attributes=*/{}},
362 /*inputs=*/{GetTensorRef(0, shape0), GetTensorRef(1, shape1)},
363 /*outputs=*/{GetTensorRef(2, shape0)});
364 ASSERT_TRUE(model.PopulateTensor(0, {0.0, 1.0, 2.0, 3.0}));
365 ASSERT_TRUE(model.PopulateTensor(1, {0.5, 0.2}));
366 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
367 EXPECT_THAT(model.GetOutput(0),
368 Pointwise(FloatNear(1e-6), {0.5, 1.0, 2.0, 3.0}));
369 }
370
TEST(ElementwiseTwoArgumentsTest,MaximumScalar)371 TEST(ElementwiseTwoArgumentsTest, MaximumScalar) {
372 OperationType op_type = OperationType::MAXIMUM;
373 const BHWC shape(1, 2, 2, 1);
374 ElementwiseAttributes attr;
375 attr.param = -1.0f;
376 SingleOpModel model(
377 {/*type=*/ToString(op_type), /*attributes=*/std::move(attr)},
378 /*inputs=*/{GetTensorRef(0, shape)},
379 /*outputs=*/{GetTensorRef(2, shape)});
380 ASSERT_TRUE(model.PopulateTensor(0, {0.0, -6.2, 2.0, -3.0}));
381 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
382 EXPECT_THAT(model.GetOutput(0),
383 Pointwise(FloatNear(1e-6), {0.0, -1.0, 2.0, -1.0}));
384 }
385
TEST(ElementwiseTwoArgumentsTest,MaximumConstVector)386 TEST(ElementwiseTwoArgumentsTest, MaximumConstVector) {
387 OperationType op_type = OperationType::MAXIMUM;
388 const BHWC shape0(1, 2, 1, 2);
389
390 ElementwiseAttributes attr;
391 Tensor<Linear, DataType::FLOAT32> param;
392 param.shape = Linear(2);
393 param.id = 1;
394 param.data = {0.4, 0.5};
395 attr.param = std::move(param);
396
397 SingleOpModel model({/*type=*/ToString(op_type), attr},
398 /*inputs=*/{GetTensorRef(0, shape0)},
399 /*outputs=*/{GetTensorRef(2, shape0)});
400 ASSERT_TRUE(model.PopulateTensor(0, {0.0, 1.0, 2.0, 3.0}));
401 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
402 EXPECT_THAT(model.GetOutput(0),
403 Pointwise(FloatNear(1e-6), {0.4, 1.0, 2.0, 3.0}));
404 }
405
TEST(ElementwiseTwoArgumentsTest,MinimumElementwise)406 TEST(ElementwiseTwoArgumentsTest, MinimumElementwise) {
407 OperationType op_type = OperationType::MINIMUM;
408 const BHWC shape(1, 2, 2, 1);
409 SingleOpModel model(
410 {/*type=*/ToString(op_type), /*attributes=*/{}},
411 /*inputs=*/{GetTensorRef(0, shape), GetTensorRef(1, shape)},
412 /*outputs=*/{GetTensorRef(2, shape)});
413 ASSERT_TRUE(model.PopulateTensor(0, {0.0, -6.2, 2.0, -3.0}));
414 ASSERT_TRUE(model.PopulateTensor(1, {1.0, 2.0, 3.0, -2.0}));
415 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
416 EXPECT_THAT(model.GetOutput(0),
417 Pointwise(FloatNear(1e-6), {0.0, -6.2, 2.0, -3.0}));
418 }
419
TEST(ElementwiseTwoArgumentsTest,MinimumBroadcast)420 TEST(ElementwiseTwoArgumentsTest, MinimumBroadcast) {
421 OperationType op_type = OperationType::MINIMUM;
422 const BHWC shape0(1, 2, 1, 2);
423 const BHWC shape1(1, 1, 1, 2);
424 SingleOpModel model(
425 {/*type=*/ToString(op_type), /*attributes=*/{}},
426 /*inputs=*/{GetTensorRef(0, shape0), GetTensorRef(1, shape1)},
427 /*outputs=*/{GetTensorRef(2, shape0)});
428 ASSERT_TRUE(model.PopulateTensor(0, {0.0, 1.0, 2.0, 3.0}));
429 ASSERT_TRUE(model.PopulateTensor(1, {0.5, 0.2}));
430 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
431 EXPECT_THAT(model.GetOutput(0),
432 Pointwise(FloatNear(1e-6), {0.0, 0.2, 0.5, 0.2}));
433 }
434
TEST(ElementwiseTwoArgumentsTest,MinimumScalar)435 TEST(ElementwiseTwoArgumentsTest, MinimumScalar) {
436 OperationType op_type = OperationType::MINIMUM;
437 const BHWC shape(1, 2, 2, 1);
438 ElementwiseAttributes attr;
439 attr.param = -1.0f;
440 SingleOpModel model(
441 {/*type=*/ToString(op_type), /*attributes=*/std::move(attr)},
442 /*inputs=*/{GetTensorRef(0, shape)},
443 /*outputs=*/{GetTensorRef(2, shape)});
444 ASSERT_TRUE(model.PopulateTensor(0, {0.0, -6.2, 2.0, -3.0}));
445 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
446 EXPECT_THAT(model.GetOutput(0),
447 Pointwise(FloatNear(1e-6), {-1.0, -6.2, -1.0, -3.0}));
448 }
449
TEST(ElementwiseTwoArgumentsTest,MinimumConstVector)450 TEST(ElementwiseTwoArgumentsTest, MinimumConstVector) {
451 OperationType op_type = OperationType::MINIMUM;
452 const BHWC shape0(1, 2, 1, 2);
453
454 ElementwiseAttributes attr;
455 Tensor<Linear, DataType::FLOAT32> param;
456 param.shape = Linear(2);
457 param.id = 1;
458 param.data = {0.5, 0.2};
459 attr.param = std::move(param);
460
461 SingleOpModel model({/*type=*/ToString(op_type), attr},
462 /*inputs=*/{GetTensorRef(0, shape0)},
463 /*outputs=*/{GetTensorRef(2, shape0)});
464 ASSERT_TRUE(model.PopulateTensor(0, {0.0, 1.0, 2.0, 3.0}));
465 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
466 EXPECT_THAT(model.GetOutput(0),
467 Pointwise(FloatNear(1e-6), {0.0, 0.2, 0.5, 0.2}));
468 }
469
TEST(ElementwiseTwoArgumentsTest,PowElementwise)470 TEST(ElementwiseTwoArgumentsTest, PowElementwise) {
471 OperationType op_type = OperationType::POW;
472 const BHWC shape(1, 2, 2, 1);
473 SingleOpModel model(
474 {/*type=*/ToString(op_type), /*attributes=*/{}},
475 /*inputs=*/{GetTensorRef(0, shape), GetTensorRef(1, shape)},
476 /*outputs=*/{GetTensorRef(2, shape)});
477 ASSERT_TRUE(model.PopulateTensor(0, {0.0, 1.0, 2.0, 4.0}));
478 ASSERT_TRUE(model.PopulateTensor(1, {1.0, 2.0, 3.0, 4.0}));
479 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
480 EXPECT_THAT(model.GetOutput(0),
481 Pointwise(FloatNear(1e-6), {0.0, 1.0, 8.0, 256.0}));
482 }
483
TEST(ElementwiseTwoArgumentsTest,PowBroadcast)484 TEST(ElementwiseTwoArgumentsTest, PowBroadcast) {
485 OperationType op_type = OperationType::POW;
486 const BHWC shape0(1, 2, 1, 2);
487 const BHWC shape1(1, 1, 1, 2);
488 SingleOpModel model(
489 {/*type=*/ToString(op_type), /*attributes=*/{}},
490 /*inputs=*/{GetTensorRef(0, shape0), GetTensorRef(1, shape1)},
491 /*outputs=*/{GetTensorRef(2, shape0)});
492 ASSERT_TRUE(model.PopulateTensor(0, {0.0, 1.0, 2.0, 4.0}));
493 ASSERT_TRUE(model.PopulateTensor(1, {2.0, 0.5}));
494 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
495 EXPECT_THAT(model.GetOutput(0),
496 Pointwise(FloatNear(1e-6), {0.0, 1.0, 4.0, 2.0}));
497 }
498
TEST(ElementwiseTwoArgumentsTest,PowScalar)499 TEST(ElementwiseTwoArgumentsTest, PowScalar) {
500 OperationType op_type = OperationType::POW;
501 const BHWC shape(1, 2, 2, 1);
502 ElementwiseAttributes attr;
503 attr.param = 2.0f;
504 SingleOpModel model(
505 {/*type=*/ToString(op_type), /*attributes=*/std::move(attr)},
506 /*inputs=*/{GetTensorRef(0, shape)},
507 /*outputs=*/{GetTensorRef(2, shape)});
508 ASSERT_TRUE(model.PopulateTensor(0, {0.0, 1.0, 2.0, 4.0}));
509 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
510 EXPECT_THAT(model.GetOutput(0),
511 Pointwise(FloatNear(1e-6), {0.0, 1.0, 4.0, 16.0}));
512 }
513
TEST(ElementwiseTwoArgumentsTest,PowConstVector)514 TEST(ElementwiseTwoArgumentsTest, PowConstVector) {
515 OperationType op_type = OperationType::POW;
516 const BHWC shape0(1, 2, 1, 2);
517
518 ElementwiseAttributes attr;
519 Tensor<Linear, DataType::FLOAT32> param;
520 param.shape = Linear(2);
521 param.id = 1;
522 param.data = {2.0, 0.5};
523 attr.param = std::move(param);
524
525 SingleOpModel model({/*type=*/ToString(op_type), attr},
526 /*inputs=*/{GetTensorRef(0, shape0)},
527 /*outputs=*/{GetTensorRef(2, shape0)});
528 ASSERT_TRUE(model.PopulateTensor(0, {0.0, 1.0, 2.0, 4.0}));
529 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
530 EXPECT_THAT(model.GetOutput(0),
531 Pointwise(FloatNear(1e-6), {0.0, 1.0, 4.0, 2.0}));
532 }
533
TEST(ElementwiseTwoArgumentsTest,SquaredDiffElementwise)534 TEST(ElementwiseTwoArgumentsTest, SquaredDiffElementwise) {
535 OperationType op_type = OperationType::SQUARED_DIFF;
536 const BHWC shape(1, 2, 2, 1);
537 SingleOpModel model(
538 {/*type=*/ToString(op_type), /*attributes=*/{}},
539 /*inputs=*/{GetTensorRef(0, shape), GetTensorRef(1, shape)},
540 /*outputs=*/{GetTensorRef(2, shape)});
541 ASSERT_TRUE(model.PopulateTensor(0, {0.0, 2.0, 2.0, 4.0}));
542 ASSERT_TRUE(model.PopulateTensor(1, {1.0, 1.0, 5.0, 4.0}));
543 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
544 EXPECT_THAT(model.GetOutput(0),
545 Pointwise(FloatNear(1e-6), {1.0, 1.0, 9.0, 0.0}));
546 }
547
TEST(ElementwiseTwoArgumentsTest,SquaredDiffBroadcast)548 TEST(ElementwiseTwoArgumentsTest, SquaredDiffBroadcast) {
549 OperationType op_type = OperationType::SQUARED_DIFF;
550 const BHWC shape0(1, 2, 1, 2);
551 const BHWC shape1(1, 1, 1, 2);
552 SingleOpModel model(
553 {/*type=*/ToString(op_type), /*attributes=*/{}},
554 /*inputs=*/{GetTensorRef(0, shape0), GetTensorRef(1, shape1)},
555 /*outputs=*/{GetTensorRef(2, shape0)});
556 ASSERT_TRUE(model.PopulateTensor(0, {0.0, 1.0, 2.0, 3.0}));
557 ASSERT_TRUE(model.PopulateTensor(1, {-1.0, 5.0}));
558 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
559 EXPECT_THAT(model.GetOutput(0),
560 Pointwise(FloatNear(1e-6), {1.0, 16.0, 9.0, 4.0}));
561 }
562
TEST(ElementwiseTwoArgumentsTest,SquaredDiffScalar)563 TEST(ElementwiseTwoArgumentsTest, SquaredDiffScalar) {
564 OperationType op_type = OperationType::SQUARED_DIFF;
565 const BHWC shape0(1, 2, 1, 2);
566 ElementwiseAttributes attr;
567 attr.param = static_cast<float>(5.0);
568 SingleOpModel model({/*type=*/ToString(op_type), attr},
569 /*inputs=*/{GetTensorRef(0, shape0)},
570 /*outputs=*/{GetTensorRef(2, shape0)});
571 ASSERT_TRUE(model.PopulateTensor(0, {0.0, 1.0, 2.0, 3.0}));
572 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
573 EXPECT_THAT(model.GetOutput(0),
574 Pointwise(FloatNear(1e-6), {25.0, 16.0, 9.0, 4.0}));
575 }
576
TEST(ElementwiseTwoArgumentsTest,SquaredDiffConstVector)577 TEST(ElementwiseTwoArgumentsTest, SquaredDiffConstVector) {
578 OperationType op_type = OperationType::SQUARED_DIFF;
579 const BHWC shape0(1, 2, 1, 2);
580
581 ElementwiseAttributes attr;
582 Tensor<Linear, DataType::FLOAT32> param;
583 param.shape = Linear(2);
584 param.id = 1;
585 param.data = {-1.0, 5.0};
586 attr.param = std::move(param);
587
588 SingleOpModel model({/*type=*/ToString(op_type), attr},
589 /*inputs=*/{GetTensorRef(0, shape0)},
590 /*outputs=*/{GetTensorRef(2, shape0)});
591 ASSERT_TRUE(model.PopulateTensor(0, {0.0, 1.0, 2.0, 3.0}));
592 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
593 EXPECT_THAT(model.GetOutput(0),
594 Pointwise(FloatNear(1e-6), {1.0, 16.0, 9.0, 4.0}));
595 }
596
TEST(ElementwiseTwoArgumentsTest,SubElementwise)597 TEST(ElementwiseTwoArgumentsTest, SubElementwise) {
598 OperationType op_type = OperationType::SUB;
599 const BHWC shape(1, 2, 2, 1);
600 SingleOpModel model(
601 {/*type=*/ToString(op_type), /*attributes=*/{}},
602 /*inputs=*/{GetTensorRef(0, shape), GetTensorRef(1, shape)},
603 /*outputs=*/{GetTensorRef(2, shape)});
604 ASSERT_TRUE(model.PopulateTensor(0, {0.0, -6.2, 2.0, 4.0}));
605 ASSERT_TRUE(model.PopulateTensor(1, {1.0, 2.0, 3.0, 4.0}));
606 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
607 EXPECT_THAT(model.GetOutput(0),
608 Pointwise(FloatNear(1e-6), {-1.0, -8.2, -1.0, 0.0}));
609 }
610
TEST(ElementwiseTwoArgumentsTest,SubBroadcast)611 TEST(ElementwiseTwoArgumentsTest, SubBroadcast) {
612 OperationType op_type = OperationType::SUB;
613 const BHWC shape0(1, 2, 1, 2);
614 const BHWC shape1(1, 1, 1, 2);
615 SingleOpModel model(
616 {/*type=*/ToString(op_type), /*attributes=*/{}},
617 /*inputs=*/{GetTensorRef(0, shape0), GetTensorRef(1, shape1)},
618 /*outputs=*/{GetTensorRef(2, shape0)});
619 ASSERT_TRUE(model.PopulateTensor(0, {0.0, 1.0, 2.0, 3.0}));
620 ASSERT_TRUE(model.PopulateTensor(1, {0.3, 0.2}));
621 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
622 EXPECT_THAT(model.GetOutput(0),
623 Pointwise(FloatNear(1e-6), {-0.3, 0.8, 1.7, 2.8}));
624 }
625
TEST(ElementwiseTwoArgumentsTest,SubScalar)626 TEST(ElementwiseTwoArgumentsTest, SubScalar) {
627 OperationType op_type = OperationType::SUB;
628 const BHWC shape0(1, 2, 1, 2);
629 ElementwiseAttributes attr;
630 attr.param = static_cast<float>(0.5);
631 SingleOpModel model({/*type=*/ToString(op_type), attr},
632 /*inputs=*/{GetTensorRef(0, shape0)},
633 /*outputs=*/{GetTensorRef(2, shape0)});
634 ASSERT_TRUE(model.PopulateTensor(0, {0.0, 1.0, 2.0, 3.0}));
635 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
636 EXPECT_THAT(model.GetOutput(0),
637 Pointwise(FloatNear(1e-6), {-0.5, 0.5, 1.5, 2.5}));
638 }
639
TEST(ElementwiseTwoArgumentsTest,SubConstVector)640 TEST(ElementwiseTwoArgumentsTest, SubConstVector) {
641 OperationType op_type = OperationType::SUB;
642 const BHWC shape0(1, 2, 1, 2);
643
644 ElementwiseAttributes attr;
645 Tensor<Linear, DataType::FLOAT32> param;
646 param.shape = Linear(2);
647 param.id = 1;
648 param.data = {0.3, 0.2};
649 attr.param = std::move(param);
650
651 SingleOpModel model({/*type=*/ToString(op_type), attr},
652 /*inputs=*/{GetTensorRef(0, shape0)},
653 /*outputs=*/{GetTensorRef(2, shape0)});
654 ASSERT_TRUE(model.PopulateTensor(0, {0.0, 1.0, 2.0, 3.0}));
655 ASSERT_OK(model.Invoke(*NewElementwiseNodeShader(op_type)));
656 EXPECT_THAT(model.GetOutput(0),
657 Pointwise(FloatNear(1e-6), {-0.3, 0.8, 1.7, 2.8}));
658 }
659
660 } // namespace
661 } // namespace gl
662 } // namespace gpu
663 } // namespace tflite
664