blob: 96debe0eec51d0b0ba78bdfa0bb8655f8af55513 [file] [log] [blame]
Pablo Tello299025a2017-09-29 11:30:12 +01001/*
Georgios Pinitasebf6b8a2018-09-24 16:31:08 +01002 * Copyright (c) 2017-2018 ARM Limited.
Pablo Tello299025a2017-09-29 11:30:12 +01003 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24#ifndef ARM_COMPUTE_TEST_GEMMLOWP_FIXTURE
25#define ARM_COMPUTE_TEST_GEMMLOWP_FIXTURE
26
27#include "arm_compute/core/TensorShape.h"
28#include "arm_compute/core/Types.h"
29#include "tests/AssetsLibrary.h"
30#include "tests/Globals.h"
31#include "tests/IAccessor.h"
32#include "tests/framework/Asserts.h"
33#include "tests/framework/Fixture.h"
Pablo Tello299025a2017-09-29 11:30:12 +010034#include "tests/validation/Helpers.h"
Georgios Pinitas5a7e7762017-12-01 16:27:29 +000035#include "tests/validation/reference/GEMMLowp.h"
Pablo Tello299025a2017-09-29 11:30:12 +010036
37#include <random>
38
39namespace arm_compute
40{
41namespace test
42{
43namespace validation
44{
Georgios Pinitasebf6b8a2018-09-24 16:31:08 +010045template <typename TensorType, typename AccessorType, typename FunctionType, bool reinterpret_input_as_3d = false, bool reinterpret_output_as_3d = false>
Gian Marcoe75a02b2017-11-08 12:24:09 +000046class GEMMLowpMatrixMultiplyCoreValidationFixture : public framework::Fixture
Pablo Tello299025a2017-09-29 11:30:12 +010047{
48public:
49 template <typename...>
Gian Marcoe75a02b2017-11-08 12:24:09 +000050 void setup(TensorShape shape_a, TensorShape shape_b, TensorShape shape_c, int32_t a_offset, int32_t b_offset)
Pablo Tello299025a2017-09-29 11:30:12 +010051 {
Gian Marcoe75a02b2017-11-08 12:24:09 +000052 _target = compute_target(shape_a, shape_b, shape_c, a_offset, b_offset);
53 _reference = compute_reference(shape_a, shape_b, shape_c, a_offset, b_offset);
Pablo Tello299025a2017-09-29 11:30:12 +010054 }
55
56protected:
57 template <typename U>
58 void fill(U &&tensor, int i)
59 {
Gian Marcoe75a02b2017-11-08 12:24:09 +000060 // Between 1 and 254 in order to avoid having -128 and 128 for the DOT product path
61 std::uniform_int_distribution<> distribution(1, 254);
Pablo Tello299025a2017-09-29 11:30:12 +010062 library->fill(tensor, distribution, i);
63 }
64
Georgios Pinitasebf6b8a2018-09-24 16:31:08 +010065 TensorType compute_target(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &shape_c, int32_t a_offset, int32_t b_offset)
Pablo Tello299025a2017-09-29 11:30:12 +010066 {
67 // Create tensors
Gian Marcoe75a02b2017-11-08 12:24:09 +000068 TensorType a = create_tensor<TensorType>(shape_a, DataType::QASYMM8, 1);
69 TensorType b = create_tensor<TensorType>(shape_b, DataType::QASYMM8, 1);
Pablo Tello6ff12a02017-11-02 16:09:35 +000070 TensorType c = create_tensor<TensorType>(shape_c, DataType::S32, 1);
Pablo Tellobf2fb952017-09-29 16:43:25 +010071
Gian Marcoe75a02b2017-11-08 12:24:09 +000072 a.info()->set_quantization_info(QuantizationInfo(1.0f / 255, a_offset));
73 b.info()->set_quantization_info(QuantizationInfo(1.0f / 255, b_offset));
74
Pablo Tellobf2fb952017-09-29 16:43:25 +010075 // Create and configure function
Georgios Pinitasebf6b8a2018-09-24 16:31:08 +010076 // The GEMMinfo includes the values of the depth in case of reinterpreted 3d input/output
Pablo Tellobf2fb952017-09-29 16:43:25 +010077 FunctionType gemmlowp;
Gian Marco Iodice4b908652018-10-18 10:21:02 +010078 // TODO (COMPMID-1672) - Extending the test to validate add bias in offset contribution
Gian Marco Iodice3139f032018-11-05 14:26:32 +000079 gemmlowp.configure(&a, &b, nullptr, &c, GEMMInfo(false, false, false, (reinterpret_output_as_3d ? shape_c[2] : 0), reinterpret_input_as_3d));
Pablo Tellobf2fb952017-09-29 16:43:25 +010080
81 ARM_COMPUTE_EXPECT(a.info()->is_resizable(), framework::LogLevel::ERRORS);
82 ARM_COMPUTE_EXPECT(b.info()->is_resizable(), framework::LogLevel::ERRORS);
83 ARM_COMPUTE_EXPECT(c.info()->is_resizable(), framework::LogLevel::ERRORS);
84
85 // Allocate tensors
86 a.allocator()->allocate();
87 b.allocator()->allocate();
88 c.allocator()->allocate();
89
90 ARM_COMPUTE_EXPECT(!a.info()->is_resizable(), framework::LogLevel::ERRORS);
91 ARM_COMPUTE_EXPECT(!b.info()->is_resizable(), framework::LogLevel::ERRORS);
92 ARM_COMPUTE_EXPECT(!c.info()->is_resizable(), framework::LogLevel::ERRORS);
93
94 // Fill tensors
Gian Marcoe75a02b2017-11-08 12:24:09 +000095 fill(AccessorType(a), 0);
96 fill(AccessorType(b), 1);
Pablo Tellobf2fb952017-09-29 16:43:25 +010097
98 // Compute GEMM function
99 gemmlowp.run();
100 return c;
101 }
102
Georgios Pinitasebf6b8a2018-09-24 16:31:08 +0100103 SimpleTensor<int32_t> compute_reference(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &shape_c, int32_t a_offset, int32_t b_offset)
Pablo Tellobf2fb952017-09-29 16:43:25 +0100104 {
Georgios Pinitasebf6b8a2018-09-24 16:31:08 +0100105 TensorShape shape_a_to_use = shape_a;
106 if(reinterpret_input_as_3d)
107 {
108 // Collapse the second and third dimension if the input is 3D
109 shape_a_to_use.collapse(2U, 1U);
110 }
111
Pablo Tellobf2fb952017-09-29 16:43:25 +0100112 // Create reference
Georgios Pinitasebf6b8a2018-09-24 16:31:08 +0100113 SimpleTensor<uint8_t> a{ shape_a_to_use, DataType::QASYMM8, 1 };
Gian Marcoe75a02b2017-11-08 12:24:09 +0000114 SimpleTensor<uint8_t> b{ shape_b, DataType::QASYMM8, 1 };
Pablo Tellobf2fb952017-09-29 16:43:25 +0100115
116 // Fill reference
Gian Marcoe75a02b2017-11-08 12:24:09 +0000117 fill(a, 0);
118 fill(b, 1);
Pablo Tellobf2fb952017-09-29 16:43:25 +0100119
Georgios Pinitasebf6b8a2018-09-24 16:31:08 +0100120 return reference::gemmlowp_matrix_multiply_core<int32_t, uint8_t>(a, b, shape_c, a_offset, b_offset);
Pablo Tellobf2fb952017-09-29 16:43:25 +0100121 }
122
Pablo Tello6ff12a02017-11-02 16:09:35 +0000123 TensorType _target{};
124 SimpleTensor<int32_t> _reference{};
Pablo Tellobf2fb952017-09-29 16:43:25 +0100125};
126
Gian Marcoe75a02b2017-11-08 12:24:09 +0000127template <typename TensorType, typename AccessorType, typename FunctionType>
128class GEMMLowpQuantizeDownInt32ToUint8ScaleValidationFixture : public framework::Fixture
129{
130public:
131 template <typename...>
Gian Marco6b77e912017-11-17 09:27:57 +0000132 void setup(TensorShape shape, int32_t result_offset, int32_t result_mult_int, int32_t result_shift, int32_t min, int32_t max, bool add_bias)
Gian Marcoe75a02b2017-11-08 12:24:09 +0000133 {
Gian Marco6b77e912017-11-17 09:27:57 +0000134 _target = compute_target(shape, result_offset, result_mult_int, result_shift, min, max, add_bias);
135 _reference = compute_reference(shape, result_offset, result_mult_int, result_shift, min, max, add_bias);
Gian Marcoe75a02b2017-11-08 12:24:09 +0000136 }
137
138protected:
139 template <typename U>
140 void fill(U &&tensor, int i)
141 {
142 std::uniform_int_distribution<> distribution(-6000, 6000);
143 library->fill(tensor, distribution, i);
144 }
145
Gian Marco6b77e912017-11-17 09:27:57 +0000146 TensorType compute_target(const TensorShape &shape, int32_t result_offset, int32_t result_mult_int, int32_t result_shift, int32_t min, int32_t max, bool add_bias)
Gian Marcoe75a02b2017-11-08 12:24:09 +0000147 {
Gian Marco6b77e912017-11-17 09:27:57 +0000148 TensorShape shape_bias(shape[0]);
149
Gian Marcoe75a02b2017-11-08 12:24:09 +0000150 // Create tensors
151 TensorType a = create_tensor<TensorType>(shape, DataType::S32, 1);
Gian Marco6b77e912017-11-17 09:27:57 +0000152 TensorType b = create_tensor<TensorType>(shape_bias, DataType::S32, 1);
153 TensorType c = create_tensor<TensorType>(shape, DataType::QASYMM8, 1);
Gian Marcoe75a02b2017-11-08 12:24:09 +0000154
155 // Create and configure function
156 FunctionType output_stage;
Gian Marco6b77e912017-11-17 09:27:57 +0000157 output_stage.configure(&a, add_bias ? &b : nullptr, &c, result_offset, result_mult_int, result_shift, min, max);
Gian Marcoe75a02b2017-11-08 12:24:09 +0000158
159 ARM_COMPUTE_EXPECT(a.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco6b77e912017-11-17 09:27:57 +0000160 ARM_COMPUTE_EXPECT(c.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marcoe75a02b2017-11-08 12:24:09 +0000161
162 // Allocate tensors
163 a.allocator()->allocate();
Gian Marco6b77e912017-11-17 09:27:57 +0000164 c.allocator()->allocate();
Gian Marcoe75a02b2017-11-08 12:24:09 +0000165
166 ARM_COMPUTE_EXPECT(!a.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco6b77e912017-11-17 09:27:57 +0000167 ARM_COMPUTE_EXPECT(!c.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marcoe75a02b2017-11-08 12:24:09 +0000168
Gian Marco6b77e912017-11-17 09:27:57 +0000169 // Fill tensor
Gian Marcoe75a02b2017-11-08 12:24:09 +0000170 fill(AccessorType(a), 0);
171
Gian Marco6b77e912017-11-17 09:27:57 +0000172 if(add_bias)
173 {
174 ARM_COMPUTE_EXPECT(b.info()->is_resizable(), framework::LogLevel::ERRORS);
175
176 // Allocate bias tensor
177 b.allocator()->allocate();
178
179 ARM_COMPUTE_EXPECT(!b.info()->is_resizable(), framework::LogLevel::ERRORS);
180
181 // Fill tensor
182 fill(AccessorType(b), 1);
183 }
184
Gian Marcoe75a02b2017-11-08 12:24:09 +0000185 // Compute GEMM function
186 output_stage.run();
Gian Marco6b77e912017-11-17 09:27:57 +0000187 return c;
Gian Marcoe75a02b2017-11-08 12:24:09 +0000188 }
189
Gian Marco6b77e912017-11-17 09:27:57 +0000190 SimpleTensor<uint8_t> compute_reference(const TensorShape &shape, int32_t result_offset, int32_t result_mult_int, int32_t result_shift, int32_t min, int32_t max, bool add_bias)
Gian Marcoe75a02b2017-11-08 12:24:09 +0000191 {
192 // Create reference
Gian Marco6b77e912017-11-17 09:27:57 +0000193 TensorShape shape_bias(shape[0]);
194
Gian Marcoe75a02b2017-11-08 12:24:09 +0000195 SimpleTensor<int32_t> a{ shape, DataType::S32, 1 };
Gian Marco6b77e912017-11-17 09:27:57 +0000196 SimpleTensor<int32_t> b{ shape_bias, DataType::S32, 1 };
Gian Marcoe75a02b2017-11-08 12:24:09 +0000197
198 // Fill reference
199 fill(a, 0);
200
Gian Marco6b77e912017-11-17 09:27:57 +0000201 if(add_bias)
202 {
203 // Fill bias
204 fill(b, 1);
205
206 return reference::gemmlowp_quantize_down_int32_to_uint8_scale<int32_t>(a, b, result_offset, result_mult_int, result_shift, min, max);
207 }
208 else
209 {
210 return reference::gemmlowp_quantize_down_int32_to_uint8_scale<int32_t>(a, result_offset, result_mult_int, result_shift, min, max);
211 }
Gian Marcoe75a02b2017-11-08 12:24:09 +0000212 }
213
214 TensorType _target{};
215 SimpleTensor<uint8_t> _reference{};
216};
Gian Marco58c57942017-11-28 09:10:03 +0000217
218template <typename TensorType, typename AccessorType, typename FunctionType>
219class GEMMLowpQuantizeDownInt32ToUint8ScaleByFixedPointValidationFixture : public framework::Fixture
220{
221public:
222 template <typename...>
223 void setup(TensorShape shape, int32_t result_fixedpoint_multiplier, int32_t result_shift, int32_t result_offset_after_shift, int32_t min, int32_t max, bool add_bias)
224 {
225 _target = compute_target(shape, result_fixedpoint_multiplier, result_shift, result_offset_after_shift, min, max, add_bias);
226 _reference = compute_reference(shape, result_fixedpoint_multiplier, result_shift, result_offset_after_shift, min, max, add_bias);
227 }
228
229protected:
230 template <typename U>
231 void fill(U &&tensor, int i)
232 {
233 std::uniform_int_distribution<> distribution(-6000, 6000);
234 library->fill(tensor, distribution, i);
235 }
236
237 TensorType compute_target(const TensorShape &shape, int32_t result_fixedpoint_multiplier, int32_t result_shift, int32_t result_offset_after_shift, int32_t min, int32_t max, bool add_bias)
238 {
239 TensorShape shape_bias(shape[0]);
240
241 // Create tensors
242 TensorType a = create_tensor<TensorType>(shape, DataType::S32, 1);
243 TensorType b = create_tensor<TensorType>(shape_bias, DataType::S32, 1);
244 TensorType c = create_tensor<TensorType>(shape, DataType::QASYMM8, 1);
245
246 // Create and configure function
247 FunctionType output_stage;
248 output_stage.configure(&a, add_bias ? &b : nullptr, &c, result_fixedpoint_multiplier, result_shift, result_offset_after_shift, min, max);
249
250 ARM_COMPUTE_EXPECT(a.info()->is_resizable(), framework::LogLevel::ERRORS);
251 ARM_COMPUTE_EXPECT(c.info()->is_resizable(), framework::LogLevel::ERRORS);
252
253 // Allocate tensors
254 a.allocator()->allocate();
255 c.allocator()->allocate();
256
257 ARM_COMPUTE_EXPECT(!a.info()->is_resizable(), framework::LogLevel::ERRORS);
258 ARM_COMPUTE_EXPECT(!c.info()->is_resizable(), framework::LogLevel::ERRORS);
259
260 // Fill tensor
261 fill(AccessorType(a), 0);
262
263 if(add_bias)
264 {
265 ARM_COMPUTE_EXPECT(b.info()->is_resizable(), framework::LogLevel::ERRORS);
266
267 // Allocate bias tensor
268 b.allocator()->allocate();
269
270 ARM_COMPUTE_EXPECT(!b.info()->is_resizable(), framework::LogLevel::ERRORS);
271
272 // Fill tensor
273 fill(AccessorType(b), 1);
274 }
275
276 // Compute GEMM function
277 output_stage.run();
278 return c;
279 }
280
281 SimpleTensor<uint8_t> compute_reference(const TensorShape &shape, int32_t result_fixed_point_multiplier, int32_t result_shift, int32_t result_offset_after_shift, int32_t min, int32_t max,
282 bool add_bias)
283 {
284 // Create reference
285 TensorShape shape_bias(shape[0]);
286
287 SimpleTensor<int32_t> a{ shape, DataType::S32, 1 };
288 SimpleTensor<int32_t> b{ shape_bias, DataType::S32, 1 };
289
290 // Fill reference
291 fill(a, 0);
292
293 if(add_bias)
294 {
295 // Fill bias
296 fill(b, 1);
297
298 return reference::gemmlowp_quantize_down_int32_to_uint8_scale_by_fixedpoint<int32_t>(a, b, result_fixed_point_multiplier, result_shift, result_offset_after_shift, min, max);
299 }
300 else
301 {
302 return reference::gemmlowp_quantize_down_int32_to_uint8_scale_by_fixedpoint<int32_t>(a, result_fixed_point_multiplier, result_shift, result_offset_after_shift, min, max);
303 }
304 }
305
306 TensorType _target{};
307 SimpleTensor<uint8_t> _reference{};
308};
Pablo Tello299025a2017-09-29 11:30:12 +0100309} // namespace validation
310} // namespace test
311} // namespace arm_compute
Chunosov5124be52017-11-22 20:42:13 +0700312#endif /* ARM_COMPUTE_TEST_GEMMLOWP_FIXTURE */