• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/quantized/NativeFunctions.h> // Declares the operator
10 #include <executorch/runtime/core/exec_aten/exec_aten.h>
11 #include <executorch/runtime/core/exec_aten/testing_util/tensor_factory.h>
12 #include <executorch/runtime/core/exec_aten/testing_util/tensor_util.h>
13 #include <executorch/runtime/core/exec_aten/util/scalar_type_util.h>
14 
15 #include <executorch/test/utils/DeathTest.h>
16 
17 #include <gtest/gtest.h>
18 #include <limits>
19 
20 using namespace ::testing;
21 using exec_aten::ArrayRef;
22 using exec_aten::Scalar;
23 using exec_aten::ScalarType;
24 using exec_aten::Tensor;
25 using torch::executor::native::choose_qparams_per_token_asymmetric_out;
26 using torch::executor::native::choose_qparams_tensor_out;
27 using torch::executor::testing::TensorFactory;
28 
29 /// A generic smoke test that works for any dtype that supports ones() and
30 /// zeros().
31 template <ScalarType DTYPE>
test_dtype()32 void test_dtype() {
33   et_pal_init();
34   TensorFactory<ScalarType::Float> tf_float;
35   TensorFactory<ScalarType::Double> tf_double;
36   TensorFactory<ScalarType::Long> tf_long;
37 
38   Tensor input = tf_float.make({2, 2}, {1.0, 2.5, 3.2, 15.4});
39   Tensor scale_out = tf_double.zeros({1});
40   Tensor zero_point_out = tf_long.zeros({1});
41   Tensor expected_scale = tf_double.make({1}, {0.0603922});
42   Tensor expected_zero_point = tf_long.make({1}, {0});
43 
44   int64_t quant_min = 0;
45   int64_t quant_max = 255;
46 
47   choose_qparams_tensor_out(
48       input, quant_min, quant_max, 0.0, DTYPE, scale_out, zero_point_out);
49 
50   EXPECT_TENSOR_CLOSE(scale_out, expected_scale);
51   EXPECT_TENSOR_EQ(zero_point_out, expected_zero_point);
52 }
53 
TEST(OpChooseQparamsPerTokenAsymmetricTensorOutTest,Float)54 TEST(OpChooseQparamsPerTokenAsymmetricTensorOutTest, Float) {
55   et_pal_init();
56   TensorFactory<ScalarType::Float> tf_float;
57   TensorFactory<ScalarType::Double> tf_double;
58   TensorFactory<ScalarType::Long> tf_long;
59 
60   Tensor input = tf_float.make({2, 3}, {-0.5, 0.3, 1.2, 0.1, -0.8, 2.1});
61   Tensor scale_out = tf_double.zeros({2, 1});
62   Tensor zero_point_out = tf_long.zeros({2, 1});
63   Tensor expected_scale = tf_double.make({2, 1}, {0.00666667, 0.0113725485});
64   Tensor expected_zero_point = tf_long.make({2, 1}, {-53, -58});
65 
66   choose_qparams_per_token_asymmetric_out(
67       input, ScalarType::Float, scale_out, zero_point_out);
68 
69   EXPECT_TENSOR_CLOSE_WITH_TOL(scale_out, expected_scale, 1e-4, 1e-4);
70   EXPECT_TENSOR_EQ(zero_point_out, expected_zero_point);
71 }
72 
TEST(OpChooseQparamsPerTokenAsymmetricTensorOutTest,ExtraDimFloat)73 TEST(OpChooseQparamsPerTokenAsymmetricTensorOutTest, ExtraDimFloat) {
74   et_pal_init();
75   TensorFactory<ScalarType::Float> tf_float;
76   TensorFactory<ScalarType::Double> tf_double;
77   TensorFactory<ScalarType::Long> tf_long;
78 
79   Tensor input = tf_float.make({1, 2, 3}, {-0.5, 0.3, 1.2, 0.1, -0.8, 2.1});
80   Tensor scale_out = tf_double.zeros({1, 2, 1});
81   Tensor zero_point_out = tf_long.zeros({1, 2, 1});
82   Tensor expected_scale = tf_double.make({1, 2, 1}, {0.00666667, 0.0113725485});
83   Tensor expected_zero_point = tf_long.make({1, 2, 1}, {-53, -58});
84 
85   choose_qparams_per_token_asymmetric_out(
86       input, ScalarType::Float, scale_out, zero_point_out);
87 
88   EXPECT_TENSOR_CLOSE_WITH_TOL(scale_out, expected_scale, 1e-4, 1e-4);
89   EXPECT_TENSOR_EQ(zero_point_out, expected_zero_point);
90 }
91 
TEST(OpChooseQparamsPerTokenAsymmetricTensorOutTest,LargeArray)92 TEST(OpChooseQparamsPerTokenAsymmetricTensorOutTest, LargeArray) {
93   et_pal_init();
94   TensorFactory<ScalarType::Float> tf_float;
95   TensorFactory<ScalarType::Double> tf_double;
96   TensorFactory<ScalarType::Long> tf_long;
97 
98   Tensor input = tf_float.make(
99       {5, 17},
100       {0.41654,  0.26599, 0.4141,   0.83809,  0.02938,  0.12199, 0.53667,
101        0.799,    0.6606,  0.46657,  0.66142,  0.71787,  0.56098, 0.30202,
102        0.059377, 0.85473, 0.8017,   0.2703,   0.44299,  0.49045, 0.75581,
103        0.24429,  0.43906, 0.78652,  0.83885,  0.31034,  0.76534, 0.74422,
104        0.62549,  0.80006, 0.38144,  0.70652,  0.33553,  0.89136, 0.49126,
105        0.072916, 0.75654, 0.82057,  0.083848, 0.29753,  0.62718, 0.95579,
106        0.83097,  0.47293, 0.15666,  0.6248,   0.21672,  0.14626, 0.71834,
107        0.93664,  0.23382, 0.68931,  0.70866,  0.60545,  0.98648, 0.30335,
108        0.62439,  0.19195, 0.1923,   0.75638,  0.81114,  0.34778, 0.0070671,
109        0.50918,  0.19698, 0.19969,  0.57687,  0.062786, 0.18447, 0.22961,
110        0.29656,  0.25486, 0.75965,  0.11328,  0.86468,  0.21264, 0.99591,
111        0.75231,  0.97834, 0.042441, 0.39978,  0.9633,   0.9297,  0.12188,
112        0.73564});
113   Tensor scale_out = tf_double.zeros({5, 1});
114   Tensor zero_point_out = tf_long.zeros({5, 1});
115   Tensor expected_scale = tf_double.make(
116       {5, 1}, {0.0033519, 0.0034955, 0.0037482, 0.0038685, 0.0039055});
117   Tensor expected_zero_point =
118       tf_long.make({5, 1}, {-128, -128, -128, -128, -128});
119 
120   choose_qparams_per_token_asymmetric_out(
121       input, ScalarType::Float, scale_out, zero_point_out);
122 
123   EXPECT_TENSOR_CLOSE_WITH_TOL(scale_out, expected_scale, 1e-5, 1e-5);
124   EXPECT_TENSOR_EQ(zero_point_out, expected_zero_point);
125 }
126 
TEST(OpChooseQparamsPerTokenAsymmetricTensorOutTest,DynamicShapeFloat)127 TEST(OpChooseQparamsPerTokenAsymmetricTensorOutTest, DynamicShapeFloat) {
128   et_pal_init();
129   TensorFactory<ScalarType::Float> tf_float;
130   TensorFactory<ScalarType::Double> tf_double;
131   TensorFactory<ScalarType::Long> tf_long;
132 
133   Tensor input = tf_float.make({1, 2, 3}, {-0.5, 0.3, 1.2, 0.1, -0.8, 2.1});
134   Tensor scale_out = tf_double.zeros(
135       {1, 5, 1}, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND);
136   Tensor zero_point_out = tf_long.zeros(
137       {1, 5, 1}, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND);
138   Tensor expected_scale = tf_double.make({1, 2, 1}, {0.00666667, 0.0113725485});
139   Tensor expected_zero_point = tf_long.make({1, 2, 1}, {-53, -58});
140 
141   choose_qparams_per_token_asymmetric_out(
142       input, ScalarType::Float, scale_out, zero_point_out);
143 
144   EXPECT_TENSOR_CLOSE_WITH_TOL(scale_out, expected_scale, 1e-4, 1e-4);
145   EXPECT_TENSOR_EQ(zero_point_out, expected_zero_point);
146 
147   Tensor new_input = tf_float.make(
148       {1, 5, 8},
149       {5.2254,   5.6041,   5.7653,   -1.0126,  -0.86126, -0.1606,  -0.99196,
150        -1.067,   5.5913,   5.7713,   5.4901,   -0.43128, -1.1759,  -0.60466,
151        -0.82913, -0.73623, 5.4588,   5.4066,   5.2644,   -0.89692, -0.16866,
152        -0.63169, -0.42352, -0.48866, 5.594,    5.5223,   5.5277,   -0.17658,
153        -0.30669, -1.1777,  -0.65389, -0.36422, 5.6375,   5.1857,   5.0743,
154        -0.46654, -0.43817, -0.41506, -0.94515, -0.60247});
155   Tensor new_expected_scale = tf_double.make(
156       {1, 5, 1}, {0.026793, 0.027244, 0.024924, 0.026556, 0.025814});
157   Tensor new_expected_zero_point =
158       tf_long.make({1, 5, 1}, {-88, -85, -92, -84, -91});
159 
160   choose_qparams_per_token_asymmetric_out(
161       new_input, ScalarType::Float, scale_out, zero_point_out);
162 
163   EXPECT_TENSOR_CLOSE_WITH_TOL(scale_out, new_expected_scale, 1e-4, 1e-4);
164   EXPECT_TENSOR_EQ(zero_point_out, new_expected_zero_point);
165 }
166