• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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