xref: /aosp_15_r20/external/executorch/kernels/test/op_relu_test.cpp (revision 523fa7a60841cd1ecfb9cc4201f1ca8b03ed023a)
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree.
7  */
8 
9 #include <executorch/kernels/test/FunctionHeaderWrapper.h> // Declares the operator
10 #include <executorch/kernels/test/TestUtil.h>
11 #include <executorch/runtime/core/exec_aten/exec_aten.h>
12 #include <executorch/runtime/core/exec_aten/testing_util/tensor_factory.h>
13 #include <executorch/runtime/core/exec_aten/testing_util/tensor_util.h>
14 
15 #include <gtest/gtest.h>
16 
17 using namespace ::testing;
18 using exec_aten::ScalarType;
19 using exec_aten::Tensor;
20 using torch::executor::testing::TensorFactory;
21 
22 class OpReluTest : public OperatorTest {
23  protected:
op_relu_out(const Tensor & self,Tensor & out)24   Tensor& op_relu_out(const Tensor& self, Tensor& out) {
25     return torch::executor::aten::relu_outf(context_, self, out);
26   }
27 
28   // Common testing for relu on two floating point Tensors.
29   template <ScalarType DTYPE>
test_relu_execution_floats()30   void test_relu_execution_floats() {
31     TensorFactory<DTYPE> tf;
32 
33     const std::vector<int32_t> sizes = {3, 2};
34 
35     Tensor in = tf.make(
36         sizes, /*data=*/{-0.4775, 0.2948, -0.3984, 1.8690, -0.4048, 0.0});
37 
38     // Destination for the relu.
39     Tensor out = tf.zeros(sizes);
40 
41     // Run relu.
42     op_relu_out(in, out);
43 
44     // Check that it matches the expected output.
45     EXPECT_TENSOR_EQ(
46         out,
47         tf.make(
48             sizes,
49             /*data=*/
50             {0.0, 0.2948, 0.0, 1.8690, 0.0, 0.0}));
51   }
52 
53   template <ScalarType DTYPE>
test_relu_execution_ints()54   void test_relu_execution_ints() {
55     TensorFactory<DTYPE> tf;
56 
57     const std::vector<int32_t> sizes = {3, 2};
58 
59     Tensor in = tf.make(sizes, /*data=*/{-1, 2, 0, 3, 0, -5});
60 
61     // Destination for the relu.
62     Tensor out = tf.zeros(sizes);
63 
64     // Run relu.
65     op_relu_out(in, out);
66 
67     // Check that it matches the expected output.
68     EXPECT_TENSOR_EQ(
69         out,
70         tf.make(
71             sizes,
72             /*data=*/
73             {0, 2, 0, 3, 0, 0}));
74   }
75 };
76 
TEST_F(OpReluTest,FloatTensors)77 TEST_F(OpReluTest, FloatTensors) {
78   test_relu_execution_floats<ScalarType::Float>();
79 }
80 
TEST_F(OpReluTest,DoubleTensors)81 TEST_F(OpReluTest, DoubleTensors) {
82   test_relu_execution_floats<ScalarType::Double>();
83 }
84 
TEST_F(OpReluTest,ByteTensors)85 TEST_F(OpReluTest, ByteTensors) {
86   TensorFactory<ScalarType::Byte> tf;
87 
88   const std::vector<int32_t> sizes = {3, 2};
89 
90   Tensor in = tf.make(sizes, /*data=*/{1, 2, 0, 3, 0, 5});
91 
92   // Destination for the relu.
93   Tensor out = tf.zeros(sizes);
94 
95   // Run relu.
96   op_relu_out(in, out);
97 
98   // Check that it matches the expected output.
99   EXPECT_TENSOR_EQ(
100       out,
101       tf.make(
102           sizes,
103           /*data=*/
104           {1, 2, 0, 3, 0, 5}));
105 }
106 
TEST_F(OpReluTest,CharTensors)107 TEST_F(OpReluTest, CharTensors) {
108   test_relu_execution_ints<ScalarType::Char>();
109 }
110 
TEST_F(OpReluTest,ShortTensors)111 TEST_F(OpReluTest, ShortTensors) {
112   test_relu_execution_ints<ScalarType::Short>();
113 }
114 
TEST_F(OpReluTest,IntTensors)115 TEST_F(OpReluTest, IntTensors) {
116   test_relu_execution_ints<ScalarType::Int>();
117 }
118 
TEST_F(OpReluTest,LongTensors)119 TEST_F(OpReluTest, LongTensors) {
120   test_relu_execution_ints<ScalarType::Long>();
121 }
122 
TEST_F(OpReluTest,InfAndNanPreserved)123 TEST_F(OpReluTest, InfAndNanPreserved) {
124   TensorFactory<ScalarType::Float> tf;
125 
126   const std::vector<int32_t> sizes = {4, 2};
127 
128   Tensor in = tf.make(
129       sizes,
130       /*data=*/
131       {-0.4775,
132        0.2948,
133        -0.3984,
134        NAN,
135        std::numeric_limits<float>::infinity(),
136        -1 * std::numeric_limits<float>::infinity(),
137        0.3,
138        -0.4848});
139 
140   // Destination for the relu.
141   Tensor out = tf.zeros(sizes);
142 
143   // Run full relu.
144   op_relu_out(in, out);
145 
146   // Check that it matches the expected output.
147   EXPECT_TENSOR_EQ(
148       out,
149       tf.make(
150           sizes,
151           /*data=*/
152           {0.0,
153            0.2948,
154            0.0,
155            NAN,
156            std::numeric_limits<float>::infinity(),
157            0.0,
158            0.3,
159            0.0}));
160 }
161 
TEST_F(OpReluTest,UnhandledDtypeDies)162 TEST_F(OpReluTest, UnhandledDtypeDies) {
163   // relu() doesn't handle Bool.
164   TensorFactory<ScalarType::Bool> tf;
165 
166   const std::vector<int32_t> sizes = {2, 2};
167 
168   Tensor a = tf.make(sizes, /*data=*/{false, true, false, true});
169 
170   // Destination for the relu.
171   Tensor out = tf.zeros(sizes);
172 
173   ET_EXPECT_KERNEL_FAILURE(context_, op_relu_out(a, out));
174 }
175 
176 #if !defined(USE_ATEN_LIB)
TEST_F(OpReluTest,UpperBoundOutTensor)177 TEST_F(OpReluTest, UpperBoundOutTensor) {
178   TensorFactory<ScalarType::Float> tf;
179 
180   const std::vector<int32_t> sizes = {3, 2};
181 
182   Tensor in =
183       tf.make(sizes, /*data=*/{-0.4775, 0.2948, -0.3984, 1.8690, -0.4048, 0.0});
184 
185   // Destination for the relu.
186   Tensor out =
187       tf.zeros({5, 7}, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND);
188 
189   // Run relu.
190   op_relu_out(in, out);
191 
192   // Check that it matches the expected output.
193   EXPECT_TENSOR_EQ(
194       out,
195       tf.make(
196           sizes,
197           /*data=*/
198           {0.0, 0.2948, 0.0, 1.8690, 0.0, 0.0}));
199 }
200 #endif
201 
TEST_F(OpReluTest,SimpleGeneratedCase)202 TEST_F(OpReluTest, SimpleGeneratedCase) {
203   TensorFactory<ScalarType::Float> tf;
204 
205   Tensor x = tf.make(
206       {10, 10},
207       {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
208        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
209        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
210        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
211        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
212        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
213        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
214        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0});
215   Tensor expected_result = tf.make(
216       {10, 10},
217       {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
218        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
219        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
220        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
221        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
222        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
223        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
224        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0});
225 
226   Tensor out = tf.zeros({10, 10});
227   Tensor ret = op_relu_out(x, out);
228   EXPECT_TENSOR_CLOSE(out, expected_result);
229 }
230 
TEST_F(OpReluTest,DynamicShapeUpperBoundSameAsExpected)231 TEST_F(OpReluTest, DynamicShapeUpperBoundSameAsExpected) {
232   TensorFactory<ScalarType::Float> tf;
233 
234   Tensor x = tf.make(
235       {3, 2},
236       {0.676039457321167,
237        0.06196027994155884,
238        0.36154472827911377,
239        0.7953161001205444,
240        0.7633233070373535,
241        0.5809110999107361});
242   Tensor expected_result = tf.make(
243       {3, 2},
244       {0.676039457321167,
245        0.06196027994155884,
246        0.36154472827911377,
247        0.7953161001205444,
248        0.7633233070373535,
249        0.5809110999107361});
250 
251   Tensor out =
252       tf.zeros({3, 2}, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND);
253   Tensor ret = op_relu_out(x, out);
254   EXPECT_TENSOR_CLOSE(out, expected_result);
255 }
256 
TEST_F(OpReluTest,DynamicShapeUpperBoundLargerThanExpected)257 TEST_F(OpReluTest, DynamicShapeUpperBoundLargerThanExpected) {
258   TensorFactory<ScalarType::Float> tf;
259 
260   Tensor x = tf.make(
261       {3, 2},
262       {0.676039457321167,
263        0.06196027994155884,
264        0.36154472827911377,
265        0.7953161001205444,
266        0.7633233070373535,
267        0.5809110999107361});
268   Tensor expected_result = tf.make(
269       {3, 2},
270       {0.676039457321167,
271        0.06196027994155884,
272        0.36154472827911377,
273        0.7953161001205444,
274        0.7633233070373535,
275        0.5809110999107361});
276 
277   Tensor out =
278       tf.zeros({10, 10}, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND);
279   Tensor ret = op_relu_out(x, out);
280   EXPECT_TENSOR_CLOSE(out, expected_result);
281 }
282 
TEST_F(OpReluTest,DynamicShapeUnbound)283 TEST_F(OpReluTest, DynamicShapeUnbound) {
284   GTEST_SKIP() << "Unbound dynamic shape not supported";
285   TensorFactory<ScalarType::Float> tf;
286 
287   Tensor x = tf.make(
288       {3, 2},
289       {0.676039457321167,
290        0.06196027994155884,
291        0.36154472827911377,
292        0.7953161001205444,
293        0.7633233070373535,
294        0.5809110999107361});
295   Tensor expected_result = tf.make(
296       {3, 2},
297       {0.676039457321167,
298        0.06196027994155884,
299        0.36154472827911377,
300        0.7953161001205444,
301        0.7633233070373535,
302        0.5809110999107361});
303 
304   Tensor out =
305       tf.zeros({1, 1}, torch::executor::TensorShapeDynamism::DYNAMIC_UNBOUND);
306   Tensor ret = op_relu_out(x, out);
307   EXPECT_TENSOR_CLOSE(out, expected_result);
308 }
309