blob: a65a1e6bd8d265f4e5394656656794a840e246b7 [file] [log] [blame]
Pablo Tello299025a2017-09-29 11:30:12 +01001/*
SiCong Li11ab4512023-11-07 12:04:59 +00002 * Copyright (c) 2017-2024 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 */
SiCong Li11ab4512023-11-07 12:04:59 +000024#ifndef ACL_TESTS_VALIDATION_FIXTURES_GEMMLOWPFIXTURE_H
25#define ACL_TESTS_VALIDATION_FIXTURES_GEMMLOWPFIXTURE_H
Pablo Tello299025a2017-09-29 11:30:12 +010026
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +000027#include "arm_compute/core/utils/quantization/AsymmHelpers.h"
SiCong Li11ab4512023-11-07 12:04:59 +000028#include "src/core/utils/quantization/AsymmHelpers.h"
29#include "tests/validation/Helpers.h"
Pablo Tello299025a2017-09-29 11:30:12 +010030#include "tests/framework/Fixture.h"
Freddie Liardete572dff2022-05-16 14:09:10 +010031#include "tests/validation/Validation.h"
Ramy Elgammala77c6d72022-09-08 11:30:08 +010032#include "tests/validation/reference/GEMMLowp.h"
Pablo Tello299025a2017-09-29 11:30:12 +010033
SiCong Li11ab4512023-11-07 12:04:59 +000034#include <cstdint>
35#include <vector>
36
Pablo Tello299025a2017-09-29 11:30:12 +010037namespace arm_compute
38{
39namespace test
40{
41namespace validation
42{
George Wort2d7e6832019-02-22 16:37:41 +000043namespace
44{
SiCong Li11ab4512023-11-07 12:04:59 +000045
George Wort2d7e6832019-02-22 16:37:41 +000046template <typename U>
47void fill(U &&tensor, int i)
48{
SiCong Li11ab4512023-11-07 12:04:59 +000049 ARM_COMPUTE_ASSERT(is_data_type_quantized(tensor.data_type()));
50 library->fill_tensor_uniform(tensor, i);
George Wort2d7e6832019-02-22 16:37:41 +000051}
52
SiCong Li11ab4512023-11-07 12:04:59 +000053template <typename U>
54void fill_bias_s32(U &&tensor, int i, int32_t min, int32_t max)
George Wort2d7e6832019-02-22 16:37:41 +000055{
SiCong Li11ab4512023-11-07 12:04:59 +000056 ARM_COMPUTE_ASSERT(tensor.data_type() == DataType::S32);
57 std::uniform_int_distribution<int32_t> distribution(min, max);
58 library->fill(tensor, distribution, i);
59}
60
61/** Information about how to fill tensors */
62struct TensorFillInfo
63{
64 // Bias fill range. Default values are arbitrary
65 int32_t min_bias {-20000};
66 int32_t max_bias {20000};
67 // Optional extra hash to randomize tensor filling
68 int32_t hash {0};
69};
70
71template <typename TensorType, typename AccessorType, typename FunctionType, bool reinterpret_input_as_3d, bool reinterpret_output_as_3d, typename OutputType, bool is_fused = false, bool run_twice = false>
72TensorType compute_gemmlowp_target(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &shape_output, const QuantizationInfo& a_qinfo, const QuantizationInfo& b_qinfo,
73 const QuantizationInfo& output_qinfo, DataType data_type_a = DataType::QASYMM8, DataType data_type_b = DataType::QASYMM8,
74 GEMMLowpOutputStageInfo output_stage = GEMMLowpOutputStageInfo(), bool reshape_b_only_on_first_run = false, const TensorFillInfo& finfo = TensorFillInfo() )
75{
76 ARM_COMPUTE_ASSERT(is_data_type_quantized_asymmetric(data_type_a));
77 ARM_COMPUTE_ASSERT(data_type_a == data_type_b);
George Wort2d7e6832019-02-22 16:37:41 +000078 // Create tensors
SiCong Li11ab4512023-11-07 12:04:59 +000079 const DataType data_type_output = output_stage.type == GEMMLowpOutputStageType::NONE ? DataType::S32 : data_type_a;
Manuel Bottini959c26d2019-12-02 16:22:35 +000080
SiCong Li11ab4512023-11-07 12:04:59 +000081 TensorType a = create_tensor<TensorType>(shape_a, data_type_a, 1, a_qinfo);
82 TensorType b = create_tensor<TensorType>(shape_b, data_type_b, 1, b_qinfo); // gemm output before output stage mismatch if i pass data_layout_output here. to be investigated
83 TensorType output = create_tensor<TensorType>(shape_output, data_type_output, 1, output_qinfo /* output_qinfo will be ignored when output stage type is None */);
George Wort2d7e6832019-02-22 16:37:41 +000084
George Wort2d7e6832019-02-22 16:37:41 +000085 TensorType bias;
86 if(is_fused)
87 {
88 TensorShape bias_shape(shape_b[0]);
89 bias = create_tensor<TensorType>(bias_shape, DataType::S32, 1);
90 }
91
92 // Create and configure function
93 // The GEMMinfo includes the values of the depth in case of reinterpreted 3d input/output
94 FunctionType gemmlowp;
Giorgio Arena5f6fdc12021-06-09 15:23:06 +010095 gemmlowp.configure(&a, &b, is_fused ? &bias : nullptr, &output, GEMMInfo(false, false, reshape_b_only_on_first_run, (reinterpret_output_as_3d ? shape_output[2] : 0), reinterpret_input_as_3d, false,
96 output_stage));
George Wort2d7e6832019-02-22 16:37:41 +000097
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +010098 ARM_COMPUTE_ASSERT(a.info()->is_resizable());
99 ARM_COMPUTE_ASSERT(b.info()->is_resizable());
100 ARM_COMPUTE_ASSERT(output.info()->is_resizable());
George Wort2d7e6832019-02-22 16:37:41 +0000101
Giorgio Arena63825e82021-03-25 14:54:50 +0000102 add_padding_x({ &a, &b, &output });
103
George Wort2d7e6832019-02-22 16:37:41 +0000104 // Allocate tensors
105 a.allocator()->allocate();
106 b.allocator()->allocate();
107 output.allocator()->allocate();
108
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100109 ARM_COMPUTE_ASSERT(!a.info()->is_resizable());
110 ARM_COMPUTE_ASSERT(!b.info()->is_resizable());
111 ARM_COMPUTE_ASSERT(!output.info()->is_resizable());
George Wort2d7e6832019-02-22 16:37:41 +0000112
113 // Fill tensors
SiCong Li11ab4512023-11-07 12:04:59 +0000114 fill(AccessorType(a), 0 + finfo.hash);
115 fill(AccessorType(b), 1 + finfo.hash);
George Wort2d7e6832019-02-22 16:37:41 +0000116
117 if(is_fused)
118 {
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100119 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
George Wort2d7e6832019-02-22 16:37:41 +0000120 bias.allocator()->allocate();
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100121 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
SiCong Li11ab4512023-11-07 12:04:59 +0000122 fill_bias_s32(AccessorType(bias), 2 + finfo.hash, finfo.min_bias, finfo.max_bias);
George Wort2d7e6832019-02-22 16:37:41 +0000123 }
Ramy Elgammala77c6d72022-09-08 11:30:08 +0100124
125 // Run with variable inputs.
126 if(run_twice)
127 {
128 gemmlowp.run();
SiCong Li11ab4512023-11-07 12:04:59 +0000129 fill(AccessorType(a), 3 + finfo.hash); // Fill tensors with new seed after run
130 fill(AccessorType(b), 4 + finfo.hash);
Ramy Elgammala77c6d72022-09-08 11:30:08 +0100131 if(is_fused)
132 {
SiCong Li11ab4512023-11-07 12:04:59 +0000133 fill_bias_s32(AccessorType(bias), 5 + finfo.hash, finfo.min_bias, finfo.max_bias);
Ramy Elgammala77c6d72022-09-08 11:30:08 +0100134 }
135 }
136
George Wort2d7e6832019-02-22 16:37:41 +0000137 // Compute GEMM function
138 gemmlowp.run();
139 return output;
140}
141
Ramy Elgammala77c6d72022-09-08 11:30:08 +0100142template <bool reinterpret_input_as_3d, typename TI = uint8_t, typename TW = uint8_t, bool pretranspose_A = false, bool pretranspose_B = false, bool run_twice = false>
SiCong Li11ab4512023-11-07 12:04:59 +0000143SimpleTensor<int32_t> compute_gemmlowp_reference(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &shape_output, const QuantizationInfo& a_qinfo, const QuantizationInfo& b_qinfo,
144 DataType data_type_a = DataType::QASYMM8, DataType data_type_b = DataType::QASYMM8, const TensorFillInfo& finfo = TensorFillInfo())
George Wort2d7e6832019-02-22 16:37:41 +0000145{
SiCong Li11ab4512023-11-07 12:04:59 +0000146 ARM_COMPUTE_ASSERT(is_data_type_quantized_asymmetric(data_type_a));
147 ARM_COMPUTE_ASSERT(data_type_a == data_type_b);
George Wort2d7e6832019-02-22 16:37:41 +0000148 TensorShape shape_a_to_use = shape_a;
149 if(reinterpret_input_as_3d)
150 {
151 // Collapse the second and third dimension if the input is 3D
152 shape_a_to_use.collapse(2U, 1U);
153 }
154
155 // Create reference
SiCong Li11ab4512023-11-07 12:04:59 +0000156 SimpleTensor<TI> a{ shape_a_to_use, data_type_a, 1, a_qinfo };
157 SimpleTensor<TW> b{ shape_b, data_type_b, 1, b_qinfo };
George Wort2d7e6832019-02-22 16:37:41 +0000158
Adnan AlSinanc5849582022-05-05 11:13:19 +0100159 TensorShape shape_a_to_use_transposed{ shape_a_to_use };
160 TensorShape shape_b_transposed{ shape_b };
161
162 shape_a_to_use_transposed.set(0, shape_a_to_use[1]);
163 shape_a_to_use_transposed.set(1, shape_a_to_use[0]);
164 shape_b_transposed.set(0, shape_b[1]);
165 shape_b_transposed.set(1, shape_b[0]);
166
SiCong Li11ab4512023-11-07 12:04:59 +0000167 SimpleTensor<TI> a_transposed{ shape_a_to_use_transposed, data_type_a, 1, a_qinfo };
168 SimpleTensor<TW> b_transposed{ shape_b_transposed, data_type_b, 1, b_qinfo };
Adnan AlSinanc5849582022-05-05 11:13:19 +0100169
George Wort2d7e6832019-02-22 16:37:41 +0000170 // Fill reference
SiCong Li11ab4512023-11-07 12:04:59 +0000171 fill(a, 0 + finfo.hash);
172 fill(b, 1 + finfo.hash);
Adnan AlSinanc5849582022-05-05 11:13:19 +0100173
174 // Transpose reference if required
Adnan AlSinan3bb72b62022-05-06 12:10:11 +0100175 /* Note: Assuming the usual batch matmul dimensions A = (B x M x K), B = (B x K x N), if pretranspose_A is set to true, then A is assumed to be (B x K x M),
176 therefore, A must be pre-transposed before passing it to the fixture. And, we transpose A again in the fixture to make it (B x M x K)
177 in order to be able to call reference implementation that works with (B x M x K) input.
178 Similarly, if pretranspose_B is set to true, then B is assumed to be (B x N x K), B must be pre-transposed before passing it to the fixture. */
Adnan AlSinanc5849582022-05-05 11:13:19 +0100179 if(pretranspose_A)
180 {
181 transpose_matrix<TI>(a, a_transposed);
182 }
183
184 if(pretranspose_B)
185 {
186 transpose_matrix<TW>(b, b_transposed);
187 }
188
Ramy Elgammala77c6d72022-09-08 11:30:08 +0100189 // Run with variable inputs.
SiCong Li11ab4512023-11-07 12:04:59 +0000190 const int32_t a_offset = a_qinfo.uniform().offset;
191 const int32_t b_offset = b_qinfo.uniform().offset;
Ramy Elgammala77c6d72022-09-08 11:30:08 +0100192 if(run_twice)
193 {
194 reference::gemmlowp_matrix_multiply_core<int32_t, TI, TW>((pretranspose_A ? a_transposed : a), (pretranspose_B ? b_transposed : b), shape_output, a_offset, b_offset);
SiCong Li11ab4512023-11-07 12:04:59 +0000195 fill((pretranspose_A) ? a_transposed : a, 3 + finfo.hash);
196 fill((pretranspose_B) ? b_transposed : b, 4 + finfo.hash);
Ramy Elgammala77c6d72022-09-08 11:30:08 +0100197 }
198
Adnan AlSinanc5849582022-05-05 11:13:19 +0100199 return reference::gemmlowp_matrix_multiply_core<int32_t, TI, TW>((pretranspose_A ? a_transposed : a), (pretranspose_B ? b_transposed : b), shape_output, a_offset, b_offset);
George Wort2d7e6832019-02-22 16:37:41 +0000200}
SiCong Li11ab4512023-11-07 12:04:59 +0000201} // namespace
George Wort2d7e6832019-02-22 16:37:41 +0000202
Ramy Elgammala77c6d72022-09-08 11:30:08 +0100203template <typename TensorType, typename AccessorType, typename FunctionType, bool reinterpret_input_as_3d = false, bool reinterpret_output_as_3d = false, bool run_twice = false>
Gian Marcoe75a02b2017-11-08 12:24:09 +0000204class GEMMLowpMatrixMultiplyCoreValidationFixture : public framework::Fixture
Pablo Tello299025a2017-09-29 11:30:12 +0100205{
206public:
George Wort2d7e6832019-02-22 16:37:41 +0000207 void setup(TensorShape shape_a, TensorShape shape_b, TensorShape shape_output, int32_t a_offset, int32_t b_offset)
Pablo Tello299025a2017-09-29 11:30:12 +0100208 {
SiCong Li11ab4512023-11-07 12:04:59 +0000209 const auto a_qinfo = QuantizationInfo(1.0f / 255, a_offset);
210 const auto b_qinfo = QuantizationInfo(1.0f / 255, b_offset);
211 _target = compute_target(shape_a, shape_b, shape_output, a_qinfo, b_qinfo);
212 _reference = compute_reference(shape_a, shape_b, shape_output, a_qinfo, b_qinfo);
Pablo Tello299025a2017-09-29 11:30:12 +0100213 }
214
215protected:
SiCong Li11ab4512023-11-07 12:04:59 +0000216 TensorType compute_target(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &shape_output, const QuantizationInfo& a_qinfo, const QuantizationInfo& b_qinfo)
Pablo Tello299025a2017-09-29 11:30:12 +0100217 {
SiCong Li11ab4512023-11-07 12:04:59 +0000218 const auto output_qinfo = QuantizationInfo(); // No output stage
219 return compute_gemmlowp_target<TensorType, AccessorType, FunctionType, reinterpret_input_as_3d, reinterpret_output_as_3d, int32_t, false, run_twice>(shape_a, shape_b, shape_output, a_qinfo, b_qinfo, output_qinfo);
Pablo Tello299025a2017-09-29 11:30:12 +0100220 }
221
SiCong Li11ab4512023-11-07 12:04:59 +0000222 SimpleTensor<int32_t> compute_reference(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &shape_output, const QuantizationInfo& a_qinfo, const QuantizationInfo& b_qinfo)
Pablo Tello299025a2017-09-29 11:30:12 +0100223 {
SiCong Li11ab4512023-11-07 12:04:59 +0000224 return compute_gemmlowp_reference<reinterpret_input_as_3d, uint8_t, uint8_t, false, false, run_twice>(shape_a, shape_b, shape_output, a_qinfo, b_qinfo);
Pablo Tellobf2fb952017-09-29 16:43:25 +0100225 }
226
Pablo Tello6ff12a02017-11-02 16:09:35 +0000227 TensorType _target{};
228 SimpleTensor<int32_t> _reference{};
Pablo Tellobf2fb952017-09-29 16:43:25 +0100229};
230
Mohammed Suhail Munshi97a609b2022-10-21 11:15:54 +0100231template <typename TensorType, typename AccessorType, typename FunctionType, bool reinterpret_input_as_3d = false, bool reinterpret_output_as_3d = false, typename TI = uint8_t, typename TW = uint8_t, bool run_twice = false>
Giorgio Arena5f6fdc12021-06-09 15:23:06 +0100232class GEMMLowpMatrixMultiplyCoreFusedOffsetOutputGenericValidationFixture : public framework::Fixture
George Wort2d7e6832019-02-22 16:37:41 +0000233{
234public:
SiCong Li11ab4512023-11-07 12:04:59 +0000235 /** Dynamically initialize the quantization info with saturation awareness
236 */
237 template <typename T>
238 static void setup_quantization(DataType data_type, const TensorShape& shape_a, const TensorShape& shape_b, QuantizationInfo& a_qinfo, QuantizationInfo& b_qinfo, QuantizationInfo& output_qinfo, TensorFillInfo& finfo)
239 {
240 // This hash is used by random generators. There may be hash collisions but
241 // this is intentional as it's a very easy way to make the the current
242 // random generation process almost different for many test configurations,
243 // which were using the same set of values before.
244 finfo.hash = shape_a[0] + shape_a[1] + shape_b[0] + shape_b[1];
245
246 const int32_t t_max = static_cast<int32_t>(std::numeric_limits<T>::max());
247 const int32_t t_min = static_cast<int32_t>(std::numeric_limits<T>::min());
248
249 std::mt19937 generator(library->seed() + finfo.hash);
250 std::uniform_real_distribution<float> distribution_float(-5.0f, 3.0f);
251 std::uniform_int_distribution<int32_t> distribution_t(t_min, t_max);
252
253 const float scale_lhs = pow(2, distribution_float(generator)); // [2^-5, 2^3]
254 const float scale_rhs = pow(2, distribution_float(generator)); // [2^-5, 2^3]
255
256 const int32_t offset_lhs = distribution_t(generator);
257 const int32_t offset_rhs = distribution_t(generator);
258
259 a_qinfo = QuantizationInfo(scale_lhs, offset_lhs);
260 b_qinfo = QuantizationInfo(scale_rhs, offset_rhs);
261
262 // reinterpret_input_as_3d or reinterpret_output_as_3d can be ignored, as the underlying gemm / matmul computation
263 // is equivalent to a standard 2D one with m-n-k dimensions
264 const int m = shape_a.y();
265 const int n = shape_b.x();
266 const int k = shape_a.x();
267
268 const float bias_fraction = 0.5f; // We enabled is_fused in compute_gemmlowp_target below, thus bias is included
269
270 QuantizationHint q_hint = suggest_matmul_dst_q_info_and_bias(a_qinfo, b_qinfo, m, n, k, data_type, bias_fraction);
271 output_qinfo = q_hint.q_info;
272 finfo.min_bias = q_hint.bias_min;
273 finfo.max_bias = q_hint.bias_max;
274
275 // Both target and reference implementations use negated offsets, i.e.
276 // float_val = (int_val + offset) * scale
277 // instead of
278 // float_val = (int_val - offset) * scale
279 // as usual. Therefore, after calculating the output quantization above, we
280 // negate the offsets of inputs' offsets.
281 a_qinfo = QuantizationInfo(scale_lhs, -offset_lhs);
282 b_qinfo = QuantizationInfo(scale_rhs, -offset_rhs);
283 }
284
285 /** Initialize output stage info from quantization info */
286 static Status init_gemmlowp_output_stage_info(
287 DataType data_type,
288 const QuantizationInfo& a_qinfo,
289 const QuantizationInfo& b_qinfo,
290 const QuantizationInfo& output_qinfo,
291 GEMMLowpOutputStageType type,
292 GEMMLowpOutputStageInfo &gemmlowp_output_stage_info)
293 {
294 ARM_COMPUTE_RETURN_ERROR_ON(!is_data_type_quantized_asymmetric(data_type));
295
296 const UniformQuantizationInfo aq_unif = a_qinfo.uniform();
297 const UniformQuantizationInfo bq_unif = b_qinfo.uniform();
298 const UniformQuantizationInfo oq_unif = output_qinfo.uniform();
299
300 float multiplier = (aq_unif.scale * bq_unif.scale) / oq_unif.scale;
301 int32_t int_multiplier;
302 int32_t shift;
303
304 ARM_COMPUTE_RETURN_ON_ERROR(
305 quantization::calculate_quantized_multiplier(multiplier, &int_multiplier, &shift));
306
307 int32_t type_min = 0;
308 int32_t type_max = 0;
309 std::tie(type_min, type_max) = quantization::get_quantized_asymmetric_output_min_max(output_qinfo, ActivationLayerInfo(), data_type);
310
311 gemmlowp_output_stage_info.gemmlowp_real_multiplier = multiplier;
312 gemmlowp_output_stage_info.gemmlowp_multiplier = int_multiplier;
313 gemmlowp_output_stage_info.gemmlowp_multipliers = { int_multiplier };
314 gemmlowp_output_stage_info.gemmlowp_shift = shift;
315 gemmlowp_output_stage_info.gemmlowp_shifts = { shift };
316 gemmlowp_output_stage_info.gemmlowp_offset = oq_unif.offset;
317 gemmlowp_output_stage_info.type = type;
318 gemmlowp_output_stage_info.gemmlowp_min_bound = type_min;
319 gemmlowp_output_stage_info.gemmlowp_max_bound = type_max;
320
321 return Status{};
322 }
323
324 /** Currently this fixture only tests the following data type configurations:
325 *
326 * 1. a and b are of the same data type
327 * 2. The data type is quantized asymmetric
328 *
329 */
330 void setup(TensorShape shape_a, TensorShape shape_b, TensorShape shape_output, GEMMLowpOutputStageType output_stage_type, DataType data_type,
Giorgio Arena5f6fdc12021-06-09 15:23:06 +0100331 bool reshape_b_only_on_first_run)
George Wort2d7e6832019-02-22 16:37:41 +0000332 {
SiCong Li11ab4512023-11-07 12:04:59 +0000333 ARM_COMPUTE_ASSERT(output_stage_type != GEMMLowpOutputStageType::NONE);
334 ARM_COMPUTE_ASSERT(is_data_type_quantized_asymmetric(data_type));
Manuel Bottini959c26d2019-12-02 16:22:35 +0000335
SiCong Li11ab4512023-11-07 12:04:59 +0000336 // Randomized dynamic quantization: randomize quantization info in a way that ensures no result saturation
337 // most of the time
338 QuantizationInfo a_qinfo;
339 QuantizationInfo b_qinfo;
340 QuantizationInfo output_qinfo;
341 TensorFillInfo finfo;
342 setup_quantization<TI>(data_type, shape_a, shape_b, a_qinfo, b_qinfo, output_qinfo, finfo);
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +0000343
SiCong Li11ab4512023-11-07 12:04:59 +0000344 GEMMLowpOutputStageInfo output_stage;
345 init_gemmlowp_output_stage_info(data_type, a_qinfo, b_qinfo, output_qinfo, output_stage_type, output_stage);
346
347 _reference = compute_reference(shape_a, shape_b, shape_output, a_qinfo, b_qinfo, data_type, data_type, output_stage, finfo);
348 _target = compute_target(shape_a, shape_b, shape_output, a_qinfo, b_qinfo, output_qinfo, data_type, data_type, output_stage, reshape_b_only_on_first_run, finfo);
George Wort2d7e6832019-02-22 16:37:41 +0000349 }
350
351protected:
SiCong Li11ab4512023-11-07 12:04:59 +0000352 TensorType compute_target(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &shape_output, const QuantizationInfo& a_qinfo, const QuantizationInfo& b_qinfo, const QuantizationInfo& output_qinfo,
353 DataType data_type_a, DataType data_type_b, const GEMMLowpOutputStageInfo& output_stage, bool reshape_b_only_on_first_run = false, const TensorFillInfo& finfo = TensorFillInfo())
George Wort2d7e6832019-02-22 16:37:41 +0000354 {
SiCong Li11ab4512023-11-07 12:04:59 +0000355 return compute_gemmlowp_target<TensorType, AccessorType, FunctionType, reinterpret_input_as_3d, reinterpret_output_as_3d, qasymm8_t, true, run_twice>(shape_a, shape_b, shape_output, a_qinfo,
356 b_qinfo, output_qinfo, data_type_a, data_type_b, output_stage, reshape_b_only_on_first_run, finfo);
George Wort2d7e6832019-02-22 16:37:41 +0000357 }
358
SiCong Li11ab4512023-11-07 12:04:59 +0000359 SimpleTensor<TI> compute_reference(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &shape_output, const QuantizationInfo& a_qinfo, const QuantizationInfo& b_qinfo,
360 DataType data_type_a, DataType data_type_b, const GEMMLowpOutputStageInfo& output_stage, const TensorFillInfo& finfo = TensorFillInfo())
George Wort2d7e6832019-02-22 16:37:41 +0000361 {
SiCong Li11ab4512023-11-07 12:04:59 +0000362 SimpleTensor<int32_t> output = compute_gemmlowp_reference<reinterpret_input_as_3d, TI, TW, false, false, run_twice>(shape_a, shape_b, shape_output, a_qinfo, b_qinfo, data_type_a, data_type_b, finfo);
George Wort2d7e6832019-02-22 16:37:41 +0000363
364 TensorShape bias_shape(shape_b[0]);
365 SimpleTensor<int32_t> bias{ bias_shape, DataType::S32, 1 };
SiCong Li11ab4512023-11-07 12:04:59 +0000366 (run_twice) ? fill_bias_s32(bias, 5 + finfo.hash, finfo.min_bias, finfo.max_bias) : fill_bias_s32(bias, 2 + finfo.hash, finfo.min_bias, finfo.max_bias); // Fill bias with same seed as last run of gemmlowp_target
George Wort2d7e6832019-02-22 16:37:41 +0000367
368 switch(output_stage.type)
369 {
370 case GEMMLowpOutputStageType::QUANTIZE_DOWN:
Manuel Bottini959c26d2019-12-02 16:22:35 +0000371 return reference::gemmlowp_quantize_down_scale<int32_t, TW>(output, bias,
372 output_stage.gemmlowp_offset, output_stage.gemmlowp_multipliers, output_stage.gemmlowp_shifts, output_stage.gemmlowp_min_bound, output_stage.gemmlowp_max_bound);
George Wort2d7e6832019-02-22 16:37:41 +0000373 break;
374 case GEMMLowpOutputStageType::QUANTIZE_DOWN_FIXEDPOINT:
Manuel Bottini959c26d2019-12-02 16:22:35 +0000375 return reference::gemmlowp_quantize_down_scale_by_fixedpoint<int32_t, TW>(output, bias,
376 output_stage.gemmlowp_multipliers, output_stage.gemmlowp_shifts, output_stage.gemmlowp_offset, output_stage.gemmlowp_min_bound, output_stage.gemmlowp_max_bound);
George Wort2d7e6832019-02-22 16:37:41 +0000377 break;
378 default:
379 ARM_COMPUTE_ERROR("Not Supported!");
380 }
381 }
382
Manuel Bottini959c26d2019-12-02 16:22:35 +0000383 TensorType _target{};
384 SimpleTensor<TI> _reference{};
George Wort2d7e6832019-02-22 16:37:41 +0000385};
386
Giorgio Arena5f6fdc12021-06-09 15:23:06 +0100387template <typename TensorType, typename AccessorType, typename FunctionType, bool reinterpret_input_as_3d = false, bool reinterpret_output_as_3d = false, typename TI = uint8_t, typename TW = uint8_t>
388class GEMMLowpMatrixMultiplyCoreFusedOffsetOutputValidationFixture : public
389 GEMMLowpMatrixMultiplyCoreFusedOffsetOutputGenericValidationFixture<TensorType, AccessorType, FunctionType, reinterpret_input_as_3d, reinterpret_output_as_3d, TI, TW>
390{
391public:
SiCong Li11ab4512023-11-07 12:04:59 +0000392 void setup(TensorShape shape_a, TensorShape shape_b, TensorShape shape_output, GEMMLowpOutputStageType output_stage_type, DataType data_type)
Giorgio Arena5f6fdc12021-06-09 15:23:06 +0100393 {
394 GEMMLowpMatrixMultiplyCoreFusedOffsetOutputGenericValidationFixture<TensorType, AccessorType, FunctionType, reinterpret_input_as_3d, reinterpret_output_as_3d, TI, TW>::setup(shape_a, shape_b,
SiCong Li11ab4512023-11-07 12:04:59 +0000395 shape_output, output_stage_type, data_type, false /* reshape_b_only_on_first_run */);
Giorgio Arena5f6fdc12021-06-09 15:23:06 +0100396 }
397};
398
Gian Marcoe75a02b2017-11-08 12:24:09 +0000399template <typename TensorType, typename AccessorType, typename FunctionType>
400class GEMMLowpQuantizeDownInt32ToUint8ScaleValidationFixture : public framework::Fixture
401{
402public:
Gian Marco6b77e912017-11-17 09:27:57 +0000403 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 +0000404 {
Gian Marco6b77e912017-11-17 09:27:57 +0000405 _target = compute_target(shape, result_offset, result_mult_int, result_shift, min, max, add_bias);
406 _reference = compute_reference(shape, result_offset, result_mult_int, result_shift, min, max, add_bias);
Gian Marcoe75a02b2017-11-08 12:24:09 +0000407 }
408
409protected:
410 template <typename U>
411 void fill(U &&tensor, int i)
412 {
413 std::uniform_int_distribution<> distribution(-6000, 6000);
414 library->fill(tensor, distribution, i);
415 }
416
Gian Marco6b77e912017-11-17 09:27:57 +0000417 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 +0000418 {
Gian Marco6b77e912017-11-17 09:27:57 +0000419 TensorShape shape_bias(shape[0]);
420
Gian Marcoe75a02b2017-11-08 12:24:09 +0000421 // Create tensors
422 TensorType a = create_tensor<TensorType>(shape, DataType::S32, 1);
Gian Marco6b77e912017-11-17 09:27:57 +0000423 TensorType b = create_tensor<TensorType>(shape_bias, DataType::S32, 1);
424 TensorType c = create_tensor<TensorType>(shape, DataType::QASYMM8, 1);
Gian Marcoe75a02b2017-11-08 12:24:09 +0000425
426 // Create and configure function
Luca Foschiani4b869532020-02-13 15:07:36 +0000427 FunctionType output_stage;
428 GEMMLowpOutputStageInfo output_stage_info = GEMMLowpOutputStageInfo();
429 output_stage_info.type = GEMMLowpOutputStageType::QUANTIZE_DOWN;
430 output_stage_info.gemmlowp_offset = result_offset;
431 output_stage_info.gemmlowp_multiplier = result_mult_int;
432 output_stage_info.gemmlowp_shift = result_shift;
433 output_stage_info.gemmlowp_min_bound = min;
434 output_stage_info.gemmlowp_max_bound = max;
435 output_stage_info.output_data_type = DataType::QASYMM8;
436 output_stage.configure(&a, add_bias ? &b : nullptr, &c, output_stage_info);
Gian Marcoe75a02b2017-11-08 12:24:09 +0000437
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100438 ARM_COMPUTE_ASSERT(a.info()->is_resizable());
439 ARM_COMPUTE_ASSERT(c.info()->is_resizable());
Gian Marcoe75a02b2017-11-08 12:24:09 +0000440
441 // Allocate tensors
442 a.allocator()->allocate();
Gian Marco6b77e912017-11-17 09:27:57 +0000443 c.allocator()->allocate();
Gian Marcoe75a02b2017-11-08 12:24:09 +0000444
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100445 ARM_COMPUTE_ASSERT(!a.info()->is_resizable());
446 ARM_COMPUTE_ASSERT(!c.info()->is_resizable());
Gian Marcoe75a02b2017-11-08 12:24:09 +0000447
Gian Marco6b77e912017-11-17 09:27:57 +0000448 // Fill tensor
Gian Marcoe75a02b2017-11-08 12:24:09 +0000449 fill(AccessorType(a), 0);
450
Gian Marco6b77e912017-11-17 09:27:57 +0000451 if(add_bias)
452 {
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100453 ARM_COMPUTE_ASSERT(b.info()->is_resizable());
Gian Marco6b77e912017-11-17 09:27:57 +0000454
455 // Allocate bias tensor
456 b.allocator()->allocate();
457
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100458 ARM_COMPUTE_ASSERT(!b.info()->is_resizable());
Gian Marco6b77e912017-11-17 09:27:57 +0000459
460 // Fill tensor
461 fill(AccessorType(b), 1);
462 }
463
Gian Marcoe75a02b2017-11-08 12:24:09 +0000464 // Compute GEMM function
465 output_stage.run();
Gian Marco6b77e912017-11-17 09:27:57 +0000466 return c;
Gian Marcoe75a02b2017-11-08 12:24:09 +0000467 }
468
Gian Marco6b77e912017-11-17 09:27:57 +0000469 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 +0000470 {
471 // Create reference
Gian Marco6b77e912017-11-17 09:27:57 +0000472 TensorShape shape_bias(shape[0]);
473
Gian Marcoe75a02b2017-11-08 12:24:09 +0000474 SimpleTensor<int32_t> a{ shape, DataType::S32, 1 };
Gian Marco6b77e912017-11-17 09:27:57 +0000475 SimpleTensor<int32_t> b{ shape_bias, DataType::S32, 1 };
Gian Marcoe75a02b2017-11-08 12:24:09 +0000476
477 // Fill reference
478 fill(a, 0);
479
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +0000480 const std::vector<int32_t> result_mult_int_vec = { result_mult_int };
481 const std::vector<int32_t> result_shift_vec = { result_shift };
482
Gian Marco6b77e912017-11-17 09:27:57 +0000483 if(add_bias)
484 {
485 // Fill bias
486 fill(b, 1);
487
Manuel Bottini959c26d2019-12-02 16:22:35 +0000488 return reference::gemmlowp_quantize_down_scale<int32_t, uint8_t>(a, b, result_offset, result_mult_int_vec, result_shift_vec, min, max);
Gian Marco6b77e912017-11-17 09:27:57 +0000489 }
490 else
491 {
Manuel Bottini959c26d2019-12-02 16:22:35 +0000492 return reference::gemmlowp_quantize_down_scale<int32_t, uint8_t>(a, result_offset, result_mult_int_vec, result_shift_vec, min, max);
Gian Marco6b77e912017-11-17 09:27:57 +0000493 }
Gian Marcoe75a02b2017-11-08 12:24:09 +0000494 }
495
496 TensorType _target{};
497 SimpleTensor<uint8_t> _reference{};
498};
Gian Marco58c57942017-11-28 09:10:03 +0000499
500template <typename TensorType, typename AccessorType, typename FunctionType>
Luca Foschiani4b869532020-02-13 15:07:36 +0000501class GEMMLowpQuantizeDownInt32ToInt8ScaleValidationFixture : public framework::Fixture
502{
503public:
Luca Foschiani4b869532020-02-13 15:07:36 +0000504 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)
505 {
506 _target = compute_target(shape, result_offset, result_mult_int, result_shift, min, max, add_bias);
507 _reference = compute_reference(shape, result_offset, result_mult_int, result_shift, min, max, add_bias);
508 }
509
510protected:
511 template <typename U>
512 void fill(U &&tensor, int i)
513 {
514 std::uniform_int_distribution<> distribution(-6000, 6000);
515 library->fill(tensor, distribution, i);
516 }
517
518 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)
519 {
520 TensorShape shape_bias(shape[0]);
521
522 // Create tensors
523 TensorType a = create_tensor<TensorType>(shape, DataType::S32, 1);
524 TensorType b = create_tensor<TensorType>(shape_bias, DataType::S32, 1);
525 TensorType c = create_tensor<TensorType>(shape, DataType::QASYMM8_SIGNED, 1);
526
527 // Create and configure function
528 FunctionType output_stage;
529 GEMMLowpOutputStageInfo output_stage_info = GEMMLowpOutputStageInfo();
530 output_stage_info.type = GEMMLowpOutputStageType::QUANTIZE_DOWN;
531 output_stage_info.gemmlowp_offset = result_offset;
532 output_stage_info.gemmlowp_multiplier = result_mult_int;
533 output_stage_info.gemmlowp_shift = result_shift;
534 output_stage_info.gemmlowp_min_bound = min;
535 output_stage_info.gemmlowp_max_bound = max;
536 output_stage_info.output_data_type = DataType::QASYMM8_SIGNED;
537 output_stage.configure(&a, add_bias ? &b : nullptr, &c, output_stage_info);
538
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100539 ARM_COMPUTE_ASSERT(a.info()->is_resizable());
540 ARM_COMPUTE_ASSERT(c.info()->is_resizable());
Luca Foschiani4b869532020-02-13 15:07:36 +0000541
542 // Allocate tensors
543 a.allocator()->allocate();
544 c.allocator()->allocate();
545
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100546 ARM_COMPUTE_ASSERT(!a.info()->is_resizable());
547 ARM_COMPUTE_ASSERT(!c.info()->is_resizable());
Luca Foschiani4b869532020-02-13 15:07:36 +0000548
549 // Fill tensor
550 fill(AccessorType(a), 0);
551
552 if(add_bias)
553 {
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100554 ARM_COMPUTE_ASSERT(b.info()->is_resizable());
Luca Foschiani4b869532020-02-13 15:07:36 +0000555
556 // Allocate bias tensor
557 b.allocator()->allocate();
558
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100559 ARM_COMPUTE_ASSERT(!b.info()->is_resizable());
Luca Foschiani4b869532020-02-13 15:07:36 +0000560
561 // Fill tensor
562 fill(AccessorType(b), 1);
563 }
564
565 // Compute GEMM function
566 output_stage.run();
567 return c;
568 }
569
570 SimpleTensor<int8_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)
571 {
572 // Create reference
573 TensorShape shape_bias(shape[0]);
574
575 SimpleTensor<int32_t> a{ shape, DataType::S32, 1 };
576 SimpleTensor<int32_t> b{ shape_bias, DataType::S32, 1 };
577
578 // Fill reference
579 fill(a, 0);
580
581 const std::vector<int32_t> result_mult_int_vec = { result_mult_int };
582 const std::vector<int32_t> result_shift_vec = { result_shift };
583
584 if(add_bias)
585 {
586 // Fill bias
587 fill(b, 1);
588
589 return reference::gemmlowp_quantize_down_scale<int32_t, int8_t>(a, b, result_offset, result_mult_int_vec, result_shift_vec, min, max);
590 }
591 else
592 {
593 return reference::gemmlowp_quantize_down_scale<int32_t, int8_t>(a, result_offset, result_mult_int_vec, result_shift_vec, min, max);
594 }
595 }
596
597 TensorType _target{};
598 SimpleTensor<int8_t> _reference{};
599};
600
601template <typename TensorType, typename AccessorType, typename FunctionType>
Georgios Pinitas448a81f2019-11-21 14:10:25 +0000602class GEMMLowpQuantizeDownInt32ToInt8ScaleByFixedPointValidationFixture : public framework::Fixture
603{
604public:
Georgios Pinitas448a81f2019-11-21 14:10:25 +0000605 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)
606 {
607 _target = compute_target(shape, result_fixedpoint_multiplier, result_shift, result_offset_after_shift, min, max, add_bias);
608 _reference = compute_reference(shape, result_fixedpoint_multiplier, result_shift, result_offset_after_shift, min, max, add_bias);
609 }
610
611protected:
612 template <typename U>
613 void fill(U &&tensor, int i)
614 {
615 std::uniform_int_distribution<> distribution(-6000, 6000);
616 library->fill(tensor, distribution, i);
617 }
618
619 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)
620 {
621 TensorShape shape_bias(shape[0]);
622
623 // Create tensors
624 TensorType a = create_tensor<TensorType>(shape, DataType::S32, 1);
625 TensorType b = create_tensor<TensorType>(shape_bias, DataType::S32, 1);
626 TensorType c = create_tensor<TensorType>(shape, DataType::QASYMM8_SIGNED, 1);
627
628 // Create and configure function
629 FunctionType output_stage;
630 output_stage.configure(&a, add_bias ? &b : nullptr, &c, result_fixedpoint_multiplier, result_shift, result_offset_after_shift, min, max);
631
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100632 ARM_COMPUTE_ASSERT(a.info()->is_resizable());
633 ARM_COMPUTE_ASSERT(c.info()->is_resizable());
Georgios Pinitas448a81f2019-11-21 14:10:25 +0000634
635 // Allocate tensors
636 a.allocator()->allocate();
637 c.allocator()->allocate();
638
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100639 ARM_COMPUTE_ASSERT(!a.info()->is_resizable());
640 ARM_COMPUTE_ASSERT(!c.info()->is_resizable());
Georgios Pinitas448a81f2019-11-21 14:10:25 +0000641
642 // Fill tensor
643 fill(AccessorType(a), 0);
644
645 if(add_bias)
646 {
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100647 ARM_COMPUTE_ASSERT(b.info()->is_resizable());
Georgios Pinitas448a81f2019-11-21 14:10:25 +0000648
649 // Allocate bias tensor
650 b.allocator()->allocate();
651
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100652 ARM_COMPUTE_ASSERT(!b.info()->is_resizable());
Georgios Pinitas448a81f2019-11-21 14:10:25 +0000653
654 // Fill tensor
655 fill(AccessorType(b), 1);
656 }
657
658 // Compute GEMM function
659 output_stage.run();
660 return c;
661 }
662
663 SimpleTensor<int8_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,
664 bool add_bias)
665 {
666 // Create reference
667 TensorShape shape_bias(shape[0]);
668
669 SimpleTensor<int32_t> a{ shape, DataType::S32, 1 };
670 SimpleTensor<int32_t> b{ shape_bias, DataType::S32, 1 };
671
672 // Fill reference
673 fill(a, 0);
674
675 const std::vector<int32_t> result_fixed_point_multiplier_vec = { result_fixed_point_multiplier };
676 const std::vector<int32_t> result_shift_vec = { result_shift };
677
678 if(add_bias)
679 {
680 // Fill bias
681 fill(b, 1);
682
683 return reference::gemmlowp_quantize_down_scale_by_fixedpoint<int32_t, int8_t>(a, b, result_fixed_point_multiplier_vec, result_shift_vec, result_offset_after_shift, min, max);
684 }
685 else
686 {
687 return reference::gemmlowp_quantize_down_scale_by_fixedpoint<int32_t, int8_t>(a, result_fixed_point_multiplier_vec, result_shift_vec, result_offset_after_shift, min, max);
688 }
689 }
690
691 TensorType _target{};
692 SimpleTensor<int8_t> _reference{};
693};
694
695template <typename TensorType, typename AccessorType, typename FunctionType>
Gian Marco58c57942017-11-28 09:10:03 +0000696class GEMMLowpQuantizeDownInt32ToUint8ScaleByFixedPointValidationFixture : public framework::Fixture
697{
698public:
Gian Marco58c57942017-11-28 09:10:03 +0000699 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)
700 {
701 _target = compute_target(shape, result_fixedpoint_multiplier, result_shift, result_offset_after_shift, min, max, add_bias);
702 _reference = compute_reference(shape, result_fixedpoint_multiplier, result_shift, result_offset_after_shift, min, max, add_bias);
703 }
704
705protected:
706 template <typename U>
707 void fill(U &&tensor, int i)
708 {
709 std::uniform_int_distribution<> distribution(-6000, 6000);
710 library->fill(tensor, distribution, i);
711 }
712
713 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)
714 {
715 TensorShape shape_bias(shape[0]);
716
717 // Create tensors
718 TensorType a = create_tensor<TensorType>(shape, DataType::S32, 1);
719 TensorType b = create_tensor<TensorType>(shape_bias, DataType::S32, 1);
720 TensorType c = create_tensor<TensorType>(shape, DataType::QASYMM8, 1);
721
722 // Create and configure function
723 FunctionType output_stage;
724 output_stage.configure(&a, add_bias ? &b : nullptr, &c, result_fixedpoint_multiplier, result_shift, result_offset_after_shift, min, max);
725
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100726 ARM_COMPUTE_ASSERT(a.info()->is_resizable());
727 ARM_COMPUTE_ASSERT(c.info()->is_resizable());
Gian Marco58c57942017-11-28 09:10:03 +0000728
729 // Allocate tensors
730 a.allocator()->allocate();
731 c.allocator()->allocate();
732
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100733 ARM_COMPUTE_ASSERT(!a.info()->is_resizable());
734 ARM_COMPUTE_ASSERT(!c.info()->is_resizable());
Gian Marco58c57942017-11-28 09:10:03 +0000735
736 // Fill tensor
737 fill(AccessorType(a), 0);
738
739 if(add_bias)
740 {
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100741 ARM_COMPUTE_ASSERT(b.info()->is_resizable());
Gian Marco58c57942017-11-28 09:10:03 +0000742
743 // Allocate bias tensor
744 b.allocator()->allocate();
745
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100746 ARM_COMPUTE_ASSERT(!b.info()->is_resizable());
Gian Marco58c57942017-11-28 09:10:03 +0000747
748 // Fill tensor
749 fill(AccessorType(b), 1);
750 }
751
752 // Compute GEMM function
753 output_stage.run();
754 return c;
755 }
756
757 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,
758 bool add_bias)
759 {
760 // Create reference
761 TensorShape shape_bias(shape[0]);
762
763 SimpleTensor<int32_t> a{ shape, DataType::S32, 1 };
764 SimpleTensor<int32_t> b{ shape_bias, DataType::S32, 1 };
765
766 // Fill reference
767 fill(a, 0);
768
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +0000769 const std::vector<int32_t> result_fixed_point_multiplier_vec = { result_fixed_point_multiplier };
770 const std::vector<int32_t> result_shift_vec = { result_shift };
771
Gian Marco58c57942017-11-28 09:10:03 +0000772 if(add_bias)
773 {
774 // Fill bias
775 fill(b, 1);
776
Georgios Pinitas448a81f2019-11-21 14:10:25 +0000777 return reference::gemmlowp_quantize_down_scale_by_fixedpoint<int32_t, uint8_t>(a, b, result_fixed_point_multiplier_vec, result_shift_vec, result_offset_after_shift, min, max);
Gian Marco58c57942017-11-28 09:10:03 +0000778 }
779 else
780 {
Georgios Pinitas448a81f2019-11-21 14:10:25 +0000781 return reference::gemmlowp_quantize_down_scale_by_fixedpoint<int32_t, uint8_t>(a, result_fixed_point_multiplier_vec, result_shift_vec, result_offset_after_shift, min, max);
Gian Marco58c57942017-11-28 09:10:03 +0000782 }
783 }
784
785 TensorType _target{};
786 SimpleTensor<uint8_t> _reference{};
787};
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +0000788
Sheri Zhang1b14c752020-03-09 14:29:52 +0000789template <typename TensorType, typename AccessorType, typename FunctionType, typename T>
790class GEMMLowpQuantizeDownInt32ScaleByFloatValidationFixture : public framework::Fixture
791{
792public:
Sheri Zhang1b14c752020-03-09 14:29:52 +0000793 void setup(DataType data_type, TensorShape shape, float result_real_multiplier, int32_t result_offset, int32_t min, int32_t max, bool add_bias)
794 {
795 _target = compute_target(data_type, shape, result_real_multiplier, result_offset, min, max, add_bias);
796 _reference = compute_reference(shape, result_real_multiplier, result_offset, min, max, add_bias);
797 }
798
799protected:
800 template <typename U>
801 void fill(U &&tensor, int i)
802 {
803 // To avoid data all being clampped
804 std::uniform_int_distribution<> distribution(-500, 500);
805 library->fill(tensor, distribution, i);
806 }
807
808 TensorType compute_target(DataType data_type, const TensorShape &shape, float result_multiplier, int32_t result_offset, int32_t min, int32_t max, bool add_bias)
809 {
810 TensorShape shape_bias(shape[0]);
811
812 // Create tensors
813 TensorType a = create_tensor<TensorType>(shape, DataType::S32, 1);
814 TensorType b = create_tensor<TensorType>(shape_bias, DataType::S32, 1);
815 TensorType c = create_tensor<TensorType>(shape, data_type, 1);
816
817 // create output stage info
818 GEMMLowpOutputStageInfo info;
819 info.gemmlowp_max_bound = max;
820 info.gemmlowp_min_bound = min;
821 info.gemmlowp_real_multiplier = result_multiplier;
822 info.gemmlowp_offset = result_offset;
823 info.type = GEMMLowpOutputStageType::QUANTIZE_DOWN_FLOAT;
824 info.output_data_type = data_type;
825
826 // Create and configure function
827 FunctionType output_stage;
828 output_stage.configure(&a, add_bias ? &b : nullptr, &c, info);
829
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100830 ARM_COMPUTE_ASSERT(a.info()->is_resizable());
831 ARM_COMPUTE_ASSERT(c.info()->is_resizable());
Sheri Zhang1b14c752020-03-09 14:29:52 +0000832
833 // Allocate tensors
834 a.allocator()->allocate();
835 c.allocator()->allocate();
836
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100837 ARM_COMPUTE_ASSERT(!a.info()->is_resizable());
838 ARM_COMPUTE_ASSERT(!c.info()->is_resizable());
Sheri Zhang1b14c752020-03-09 14:29:52 +0000839
840 // Fill tensor
841 fill(AccessorType(a), 0);
842
843 if(add_bias)
844 {
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100845 ARM_COMPUTE_ASSERT(b.info()->is_resizable());
Sheri Zhang1b14c752020-03-09 14:29:52 +0000846
847 // Allocate bias tensor
848 b.allocator()->allocate();
849
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100850 ARM_COMPUTE_ASSERT(!b.info()->is_resizable());
Sheri Zhang1b14c752020-03-09 14:29:52 +0000851
852 // Fill tensor
853 fill(AccessorType(b), 1);
854 }
855
856 // Compute GEMM function
857 output_stage.run();
858 return c;
859 }
860
861 SimpleTensor<T> compute_reference(const TensorShape &shape, float_t result_real_multiplier, int32_t result_offset, int32_t min, int32_t max, bool add_bias)
862 {
863 // Create reference
864 TensorShape shape_bias(shape[0]);
865
866 SimpleTensor<int32_t> a{ shape, DataType::S32, 1 };
867 SimpleTensor<int32_t> b{ shape_bias, DataType::S32, 1 };
868
869 // Fill reference
870 fill(a, 0);
871
872 const std::vector<float_t> result_float_multiplier_vec = { result_real_multiplier };
873
874 if(add_bias)
875 {
876 // Fill bias
877 fill(b, 1);
878
879 return reference::gemmlowp_quantize_down_scale_by_float<int32_t, T>(a, b, result_float_multiplier_vec, result_offset, min, max);
880 }
881 else
882 {
883 return reference::gemmlowp_quantize_down_scale_by_float<int32_t, T>(a, result_float_multiplier_vec, result_offset, min, max);
884 }
885 }
886
887 TensorType _target{};
888 SimpleTensor<T> _reference{};
889};
890
Gian Marco Iodicebc415af2019-06-13 15:58:32 +0100891template <typename TensorType, typename AccessorType, typename FunctionType>
892class GEMMLowpQuantizeDownInt32ToInt16ScaleByFixedPointValidationFixture : public framework::Fixture
893{
894public:
Gian Marco Iodicebc415af2019-06-13 15:58:32 +0100895 void setup(TensorShape shape, int32_t result_fixedpoint_multiplier, int32_t result_shift, int32_t min, int32_t max, bool add_bias)
896 {
897 _target = compute_target(shape, result_fixedpoint_multiplier, result_shift, min, max, add_bias);
898 _reference = compute_reference(shape, result_fixedpoint_multiplier, result_shift, min, max, add_bias);
899 }
900
901protected:
902 template <typename U>
903 void fill(U &&tensor, int i)
904 {
905 std::uniform_int_distribution<> distribution(-6000, 6000);
906 library->fill(tensor, distribution, i);
907 }
908
909 TensorType compute_target(const TensorShape &shape, int32_t result_fixedpoint_multiplier, int32_t result_shift, int32_t min, int32_t max, bool add_bias)
910 {
911 TensorShape shape_bias(shape[0]);
912
913 // Create tensors
914 TensorType a = create_tensor<TensorType>(shape, DataType::S32, 1);
915 TensorType b = create_tensor<TensorType>(shape_bias, DataType::S32, 1);
916 TensorType c = create_tensor<TensorType>(shape, DataType::QSYMM16, 1);
917
918 // Create and configure function
919 FunctionType output_stage;
920 output_stage.configure(&a, add_bias ? &b : nullptr, &c, result_fixedpoint_multiplier, result_shift, min, max);
921
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100922 ARM_COMPUTE_ASSERT(a.info()->is_resizable());
923 ARM_COMPUTE_ASSERT(c.info()->is_resizable());
Gian Marco Iodicebc415af2019-06-13 15:58:32 +0100924
925 // Allocate tensors
926 a.allocator()->allocate();
927 c.allocator()->allocate();
928
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100929 ARM_COMPUTE_ASSERT(!a.info()->is_resizable());
930 ARM_COMPUTE_ASSERT(!c.info()->is_resizable());
Gian Marco Iodicebc415af2019-06-13 15:58:32 +0100931
932 // Fill tensor
933 fill(AccessorType(a), 0);
934
935 if(add_bias)
936 {
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100937 ARM_COMPUTE_ASSERT(b.info()->is_resizable());
Gian Marco Iodicebc415af2019-06-13 15:58:32 +0100938
939 // Allocate bias tensor
940 b.allocator()->allocate();
941
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100942 ARM_COMPUTE_ASSERT(!b.info()->is_resizable());
Gian Marco Iodicebc415af2019-06-13 15:58:32 +0100943
944 // Fill tensor
945 fill(AccessorType(b), 1);
946 }
947
948 // Compute GEMM function
949 output_stage.run();
950 return c;
951 }
952
953 SimpleTensor<int16_t> compute_reference(const TensorShape &shape, int32_t result_fixed_point_multiplier, int32_t result_shift, int32_t min, int32_t max,
954 bool add_bias)
955 {
956 // Create reference
957 TensorShape shape_bias(shape[0]);
958
959 SimpleTensor<int32_t> a{ shape, DataType::S32, 1 };
960 SimpleTensor<int32_t> b{ shape_bias, DataType::S32, 1 };
961
962 // Fill reference
963 fill(a, 0);
964
Georgios Pinitas448a81f2019-11-21 14:10:25 +0000965 const std::vector<int32_t> result_fixed_point_multiplier_vec = { result_fixed_point_multiplier };
966 const std::vector<int32_t> result_shift_vec = { result_shift };
967
Gian Marco Iodicebc415af2019-06-13 15:58:32 +0100968 if(add_bias)
969 {
970 // Fill bias
971 fill(b, 1);
972
Georgios Pinitas448a81f2019-11-21 14:10:25 +0000973 return reference::gemmlowp_quantize_down_scale_by_fixedpoint<int32_t, int16_t>(a, b, result_fixed_point_multiplier_vec, result_shift_vec, 0, min, max);
Gian Marco Iodicebc415af2019-06-13 15:58:32 +0100974 }
975 else
976 {
Georgios Pinitas448a81f2019-11-21 14:10:25 +0000977 return reference::gemmlowp_quantize_down_scale_by_fixedpoint<int32_t, int16_t>(a, result_fixed_point_multiplier_vec, result_shift_vec, 0, min, max);
Gian Marco Iodicebc415af2019-06-13 15:58:32 +0100978 }
979 }
980
981 TensorType _target{};
982 SimpleTensor<int16_t> _reference{};
983};
984
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100985template <typename TensorType, typename AccessorType, typename ReshapeLHSOperatorType, typename ReshapeRHSOperatorType, typename GEMMFunctionType>
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +0000986class GEMMLowpMatrixMultiplyReshapedValidationFixture : public framework::Fixture
987{
988public:
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +0000989 void setup(unsigned int m, unsigned int n, unsigned int k, unsigned int batch_size, unsigned int m0, unsigned int n0, unsigned int k0, unsigned int v0, unsigned int h0, bool interleave_lhs,
Sheri Zhang28287af2020-02-25 14:13:54 +0000990 bool interleave_rhs, DataType data_type)
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +0000991 {
992 GEMMLHSMatrixInfo lhs_info;
993 lhs_info.m0 = m0;
994 lhs_info.k0 = k0;
995 lhs_info.v0 = v0;
996 lhs_info.interleave = interleave_lhs;
997 lhs_info.transpose = false;
998
999 GEMMRHSMatrixInfo rhs_info;
1000 rhs_info.n0 = n0;
1001 rhs_info.k0 = k0;
1002 rhs_info.h0 = h0;
1003 rhs_info.interleave = interleave_rhs;
1004 rhs_info.transpose = true;
1005
1006 // Set the tensor shapes for LHS and RHS matrices
1007 const TensorShape lhs_shape(k, m, batch_size);
1008 const TensorShape rhs_shape(n, k, batch_size);
1009
Sheri Zhang28287af2020-02-25 14:13:54 +00001010 _target = compute_target(lhs_shape, rhs_shape, lhs_info, rhs_info, data_type);
1011 _reference = compute_reference(lhs_shape, rhs_shape, data_type);
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001012 }
1013
1014protected:
1015 template <typename U>
1016 void fill(U &&tensor, int i)
1017 {
Sheri Zhang28287af2020-02-25 14:13:54 +00001018 switch(tensor.data_type())
1019 {
1020 case DataType::QASYMM8:
1021 {
1022 // Between 1 and 254 in order to avoid having -128 and 128 for the DOT product path
1023 std::uniform_int_distribution<> distribution(1, 254);
1024 library->fill(tensor, distribution, i);
1025 }
1026 break;
1027 case DataType::QASYMM8_SIGNED:
1028 {
1029 std::uniform_int_distribution<> distribution(-127, 126);
1030 library->fill(tensor, distribution, i);
1031 }
1032 break;
1033 default:
1034 ARM_COMPUTE_ERROR("Unsupported data type");
1035 }
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001036 }
1037
Sheri Zhang28287af2020-02-25 14:13:54 +00001038 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info, DataType data_type)
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001039 {
1040 // Create tensors
Sheri Zhang28287af2020-02-25 14:13:54 +00001041 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1042 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001043 TensorType lhs_reshaped;
1044 TensorType rhs_reshaped;
1045 TensorType dst;
1046
1047 const unsigned int M = lhs_shape[1];
1048 const unsigned int N = rhs_shape[0];
1049 const unsigned int K = lhs_shape[0];
1050
1051 // The output tensor will be auto-initialized within the function
1052
1053 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001054 ReshapeLHSOperatorType reshape_lhs;
1055 ReshapeRHSOperatorType reshape_rhs;
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001056 GEMMFunctionType gemm;
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001057 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
1058 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
Georgios Pinitas4a578b92021-06-25 12:13:49 +01001059 gemm.configure(lhs_reshaped.info(), rhs_reshaped.info(), dst.info(), lhs_info, rhs_info, GEMMReshapeInfo(M, N, K));
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001060
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001061 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1062 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001063
Giorgio Arena63825e82021-03-25 14:54:50 +00001064 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &dst });
1065
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001066 // Allocate tensors
1067 lhs.allocator()->allocate();
1068 rhs.allocator()->allocate();
1069 lhs_reshaped.allocator()->allocate();
1070 rhs_reshaped.allocator()->allocate();
1071 dst.allocator()->allocate();
1072
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001073 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1074 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1075 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
1076 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1077 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001078
1079 // Fill tensors
1080 fill(AccessorType(lhs), 0);
1081 fill(AccessorType(rhs), 1);
1082
1083 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001084 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
1085 reshape_lhs.run(reshape_lhs_pack);
1086 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1087 reshape_rhs.run(reshape_rhs_pack);
Georgios Pinitas4a578b92021-06-25 12:13:49 +01001088 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped }, { ACL_SRC_1, &rhs_reshaped }, { ACL_DST, &dst } });
1089 gemm.run(gemm_pack);
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001090
1091 return dst;
1092 }
1093
Sheri Zhang28287af2020-02-25 14:13:54 +00001094 SimpleTensor<int32_t> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type)
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001095 {
1096 TensorShape dst_shape = lhs_shape;
1097 dst_shape[0] = rhs_shape[0];
1098 dst_shape[1] = lhs_shape[1];
1099
Sheri Zhang28287af2020-02-25 14:13:54 +00001100 switch(data_type)
1101 {
1102 case DataType::QASYMM8:
1103 {
1104 // Create reference
1105 SimpleTensor<uint8_t> lhs{ lhs_shape, data_type, 1 };
1106 SimpleTensor<uint8_t> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001107
Sheri Zhang28287af2020-02-25 14:13:54 +00001108 // Fill reference
1109 fill(lhs, 0);
1110 fill(rhs, 1);
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001111
Sheri Zhang28287af2020-02-25 14:13:54 +00001112 return reference::gemmlowp_matrix_multiply_core<int32_t, uint8_t>(lhs, rhs, dst_shape, 0, 0);
1113 }
1114 case DataType::QASYMM8_SIGNED:
1115 {
1116 // Create reference
1117 SimpleTensor<int8_t> lhs{ lhs_shape, data_type, 1 };
1118 SimpleTensor<int8_t> rhs{ rhs_shape, data_type, 1 };
1119
1120 // Fill reference
1121 fill(lhs, 0);
1122 fill(rhs, 1);
1123
1124 return reference::gemmlowp_matrix_multiply_core<int32_t, int8_t>(lhs, rhs, dst_shape, 0, 0);
1125 }
1126 default:
1127 ARM_COMPUTE_ERROR("Unsupported data type");
1128 }
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001129 }
1130
1131 TensorType _target{};
1132 SimpleTensor<int32_t> _reference{};
1133};
1134
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001135template <typename TensorType, typename AccessorType, typename ReshapeLHSOperatorType, typename ReshapeRHSOperatorType, typename GEMMFunctionType>
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001136class GEMMLowpMatrixMultiplyReshaped3DValidationFixture : public framework::Fixture
1137{
1138public:
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001139 void setup(unsigned int m_w, unsigned int m_h, unsigned int n, unsigned int k, unsigned int batch_size, unsigned int m0, unsigned int n0, unsigned int k0, unsigned int v0, unsigned int h0,
Sheri Zhang28287af2020-02-25 14:13:54 +00001140 bool interleave_lhs, bool interleave_rhs, DataType data_type)
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001141 {
1142 GEMMLHSMatrixInfo lhs_info;
1143 lhs_info.m0 = m0;
1144 lhs_info.k0 = k0;
1145 lhs_info.v0 = v0;
1146 lhs_info.interleave = interleave_lhs;
1147 lhs_info.transpose = false;
1148
1149 GEMMRHSMatrixInfo rhs_info;
1150 rhs_info.n0 = n0;
1151 rhs_info.k0 = k0;
1152 rhs_info.h0 = h0;
1153 rhs_info.interleave = interleave_rhs;
1154 rhs_info.transpose = true;
1155
1156 // In case of GEMM3D, m is the product between m_w and m_h
1157 const unsigned int m = m_w * m_h;
1158
1159 // Set the tensor shapes for LHS and RHS matrices
1160 const TensorShape lhs_shape(k, m, batch_size);
1161 const TensorShape rhs_shape(n, k, batch_size);
1162
Sheri Zhang28287af2020-02-25 14:13:54 +00001163 _target = compute_target(lhs_shape, rhs_shape, lhs_info, rhs_info, m_h, data_type);
1164 _reference = compute_reference(lhs_shape, rhs_shape, m_h, data_type);
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001165 }
1166
1167protected:
1168 template <typename U>
1169 void fill(U &&tensor, int i)
1170 {
Sheri Zhang28287af2020-02-25 14:13:54 +00001171 switch(tensor.data_type())
1172 {
1173 case DataType::QASYMM8:
1174 {
1175 // Between 1 and 254 in order to avoid having -128 and 128 for the DOT product path
1176 std::uniform_int_distribution<> distribution(1, 254);
1177 library->fill(tensor, distribution, i);
1178 }
1179 break;
1180 case DataType::QASYMM8_SIGNED:
1181 {
1182 std::uniform_int_distribution<> distribution(-127, 126);
1183 library->fill(tensor, distribution, i);
1184 }
1185 break;
1186 default:
1187 ARM_COMPUTE_ERROR("Unsupported data type");
1188 }
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001189 }
1190
Sheri Zhang28287af2020-02-25 14:13:54 +00001191 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info, unsigned int m_h,
1192 DataType data_type)
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001193 {
1194 // Create tensors
Sheri Zhang28287af2020-02-25 14:13:54 +00001195 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1196 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001197 TensorType lhs_reshaped;
1198 TensorType rhs_reshaped;
1199 TensorType dst;
1200
1201 const unsigned int M = lhs_shape[1];
1202 const unsigned int N = rhs_shape[0];
1203 const unsigned int K = lhs_shape[0];
1204
1205 // The output tensor will be auto-initialized within the function
1206
1207 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001208 ReshapeLHSOperatorType reshape_lhs;
1209 ReshapeRHSOperatorType reshape_rhs;
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001210 GEMMFunctionType gemm;
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001211 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
1212 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
Georgios Pinitas4a578b92021-06-25 12:13:49 +01001213 gemm.configure(lhs_reshaped.info(), rhs_reshaped.info(), dst.info(), lhs_info, rhs_info, GEMMReshapeInfo(M, N, K, 1, 1, m_h));
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001214
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001215 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1216 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001217
Giorgio Arena63825e82021-03-25 14:54:50 +00001218 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &dst });
1219
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001220 // Allocate tensors
1221 lhs.allocator()->allocate();
1222 rhs.allocator()->allocate();
1223 lhs_reshaped.allocator()->allocate();
1224 rhs_reshaped.allocator()->allocate();
1225 dst.allocator()->allocate();
1226
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001227 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1228 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1229 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
1230 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1231 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001232
1233 // Fill tensors
1234 fill(AccessorType(lhs), 0);
1235 fill(AccessorType(rhs), 1);
1236
1237 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001238 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
1239 reshape_lhs.run(reshape_lhs_pack);
1240 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1241 reshape_rhs.run(reshape_rhs_pack);
Georgios Pinitas4a578b92021-06-25 12:13:49 +01001242 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped }, { ACL_SRC_1, &rhs_reshaped }, { ACL_DST, &dst } });
1243 gemm.run(gemm_pack);
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001244
1245 return dst;
1246 }
1247
Sheri Zhang28287af2020-02-25 14:13:54 +00001248 SimpleTensor<int32_t> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, unsigned int m_h, DataType data_type)
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001249 {
1250 TensorShape dst_shape = lhs_shape;
1251 dst_shape.set(0, rhs_shape[0]);
1252 dst_shape.set(1, lhs_shape[1] / m_h);
1253 dst_shape.set(2, m_h);
1254 dst_shape.set(3, lhs_shape[2]);
1255
Sheri Zhang28287af2020-02-25 14:13:54 +00001256 switch(data_type)
1257 {
1258 case DataType::QASYMM8:
1259 {
1260 // Create reference
1261 SimpleTensor<uint8_t> lhs{ lhs_shape, data_type, 1 };
1262 SimpleTensor<uint8_t> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001263
Sheri Zhang28287af2020-02-25 14:13:54 +00001264 // Fill reference
1265 fill(lhs, 0);
1266 fill(rhs, 1);
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001267
Sheri Zhang28287af2020-02-25 14:13:54 +00001268 return reference::gemmlowp_matrix_multiply_core<int32_t, uint8_t>(lhs, rhs, dst_shape, 0, 0);
1269 }
1270 case DataType::QASYMM8_SIGNED:
1271 {
1272 // Create reference
1273 SimpleTensor<int8_t> lhs{ lhs_shape, data_type, 1 };
1274 SimpleTensor<int8_t> rhs{ rhs_shape, data_type, 1 };
1275
1276 // Fill reference
1277 fill(lhs, 0);
1278 fill(rhs, 1);
1279
1280 return reference::gemmlowp_matrix_multiply_core<int32_t, int8_t>(lhs, rhs, dst_shape, 0, 0);
1281 }
1282 default:
1283 ARM_COMPUTE_ERROR("Unsupported data type");
1284 }
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001285 }
1286
1287 TensorType _target{};
1288 SimpleTensor<int32_t> _reference{};
1289};
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001290
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001291template <typename TensorType, typename AccessorType, typename ReshapeRHSOperatorType, typename GEMMFunctionType>
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001292class GEMMLowpMatrixMultiplyReshapedOnlyRHSValidationFixture : public framework::Fixture
1293{
1294public:
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001295 void setup(unsigned int m, unsigned int n, unsigned int k, unsigned int batch_size, unsigned int m0, unsigned int n0,
1296 unsigned int k0, unsigned int h0, bool interleave_rhs, bool transpose_rhs, DataType data_type)
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001297 {
1298 GEMMLHSMatrixInfo lhs_info;
1299 lhs_info.m0 = m0;
1300 lhs_info.k0 = k0;
1301
1302 GEMMRHSMatrixInfo rhs_info;
1303 rhs_info.n0 = n0;
1304 rhs_info.k0 = k0;
1305 rhs_info.h0 = h0;
1306 rhs_info.interleave = interleave_rhs;
1307 rhs_info.transpose = transpose_rhs;
1308
1309 // Set the tensor shapes for LHS and RHS matrices
1310 const TensorShape lhs_shape(k, m, batch_size);
1311 const TensorShape rhs_shape(n, k, batch_size);
1312
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001313 _target = compute_target(lhs_shape, rhs_shape, lhs_info, rhs_info, data_type);
1314 _reference = compute_reference(lhs_shape, rhs_shape, data_type);
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001315 }
1316
1317protected:
1318 template <typename U>
1319 void fill(U &&tensor, int i)
1320 {
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001321 switch(tensor.data_type())
1322 {
1323 case DataType::QASYMM8:
1324 {
1325 // Between 1 and 254 in order to avoid having -128 and 128 for the DOT product path
1326 std::uniform_int_distribution<> distribution(1, 254);
1327 library->fill(tensor, distribution, i);
1328 }
1329 break;
1330 case DataType::QASYMM8_SIGNED:
1331 {
1332 std::uniform_int_distribution<> distribution(-127, 126);
1333 library->fill(tensor, distribution, i);
1334 }
1335 break;
1336 default:
1337 ARM_COMPUTE_ERROR("Unsupported data type");
1338 }
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001339 }
1340
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001341 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const GEMMLHSMatrixInfo &lhs_info,
1342 const GEMMRHSMatrixInfo &rhs_info, DataType data_type)
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001343 {
1344 // Create tensors
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001345 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1346 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001347 TensorType rhs_reshaped;
1348 TensorType dst;
1349
1350 const unsigned int M = lhs_shape[1];
1351 const unsigned int N = rhs_shape[0];
1352 const unsigned int K = lhs_shape[0];
1353
Michele Di Giorgiob54ba282020-01-14 15:31:55 +00001354 GEMMKernelInfo gemm_info;
1355 gemm_info.m = M;
1356 gemm_info.n = N;
1357 gemm_info.k = K;
1358 gemm_info.lhs_info = lhs_info;
1359 gemm_info.rhs_info = rhs_info;
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001360 // The output tensor will be auto-initialized within the function
1361
1362 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001363 ReshapeRHSOperatorType reshape_rhs;
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001364 GEMMFunctionType gemm;
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001365 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
Georgios Pinitas4a578b92021-06-25 12:13:49 +01001366 gemm.configure(lhs.info(), rhs_reshaped.info(), dst.info(), gemm_info);
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001367
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001368 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1369 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001370
Giorgio Arena63825e82021-03-25 14:54:50 +00001371 add_padding_x({ &lhs, &rhs, &rhs_reshaped, &dst });
1372
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001373 // Allocate tensors
1374 lhs.allocator()->allocate();
1375 rhs.allocator()->allocate();
1376 rhs_reshaped.allocator()->allocate();
1377 dst.allocator()->allocate();
1378
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001379 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1380 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1381 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1382 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001383
1384 // Fill tensors
1385 fill(AccessorType(lhs), 0);
1386 fill(AccessorType(rhs), 1);
1387
1388 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001389 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1390 reshape_rhs.run(reshape_rhs_pack);
Georgios Pinitas4a578b92021-06-25 12:13:49 +01001391 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs }, { ACL_SRC_1, &rhs_reshaped }, { ACL_DST, &dst } });
1392 gemm.run(gemm_pack);
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001393
1394 return dst;
1395 }
1396
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001397 SimpleTensor<int32_t> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type)
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001398 {
1399 TensorShape dst_shape = lhs_shape;
1400 dst_shape[0] = rhs_shape[0];
1401 dst_shape[1] = lhs_shape[1];
1402
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001403 if(data_type == DataType::QASYMM8)
1404 {
1405 // Create reference
1406 SimpleTensor<uint8_t> lhs{ lhs_shape, data_type, 1 };
1407 SimpleTensor<uint8_t> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001408
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001409 // Fill reference
1410 fill(lhs, 0);
1411 fill(rhs, 1);
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001412
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001413 return reference::gemmlowp_matrix_multiply_core<int32_t, uint8_t>(lhs, rhs, dst_shape, 0, 0);
1414 }
1415 else
1416 {
1417 // Create reference
1418 SimpleTensor<int8_t> lhs{ lhs_shape, data_type, 1 };
1419 SimpleTensor<int8_t> rhs{ rhs_shape, data_type, 1 };
1420
1421 // Fill reference
1422 fill(lhs, 0);
1423 fill(rhs, 1);
1424
1425 return reference::gemmlowp_matrix_multiply_core<int32_t, int8_t>(lhs, rhs, dst_shape, 0, 0);
1426 }
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001427 }
1428
1429 TensorType _target{};
1430 SimpleTensor<int32_t> _reference{};
1431};
1432
Freddie Liardete572dff2022-05-16 14:09:10 +01001433template <typename T, typename TensorType, typename AccessorType, typename ReshapeRHSOperatorType, typename GEMMFunctionType, typename ReduceOperation, typename CastOperation>
1434class GEMMLowpMatrixMultiplyReshapedOnlyRHSMMULOutputStageValidationFixture : public framework::Fixture
1435{
1436public:
Freddie Liardete572dff2022-05-16 14:09:10 +01001437 void setup(unsigned int m, unsigned int n, unsigned int k, unsigned int batch_size, unsigned int m0, unsigned int n0,
1438 unsigned int k0, unsigned int h0, bool interleave_rhs, bool transpose_rhs, bool broadcast_bias, DataType data_type)
1439 {
1440 GEMMLowpOutputStageInfo output_stage;
1441 output_stage.type = GEMMLowpOutputStageType::QUANTIZE_DOWN_FIXEDPOINT;
1442 output_stage.output_data_type = data_type;
1443 output_stage.gemmlowp_multipliers = std::vector<int32_t> { 1 };
1444 output_stage.gemmlowp_shifts = std::vector<int32_t> { 1 };
1445 output_stage.gemmlowp_multipliers[0] = 1;
1446 output_stage.gemmlowp_shifts[0] = 1;
1447 output_stage.gemmlowp_offset = 0;
1448 constexpr float scale = 0.001f;
1449 quantization::calculate_quantized_multiplier(scale, &output_stage.gemmlowp_multipliers[0], &output_stage.gemmlowp_shifts[0]);
1450 output_stage.gemmlowp_min_bound = -100;
1451 output_stage.gemmlowp_max_bound = 100;
1452
1453 GEMMLHSMatrixInfo lhs_info;
1454 lhs_info.m0 = m0;
1455 lhs_info.k0 = k0;
1456
1457 GEMMRHSMatrixInfo rhs_info;
1458 rhs_info.n0 = n0;
1459 rhs_info.k0 = k0;
1460 rhs_info.h0 = h0;
1461 rhs_info.interleave = interleave_rhs;
1462 rhs_info.transpose = transpose_rhs;
1463
1464 int a_offset = 1;
1465 int b_offset = 1;
1466
1467 // Set the tensor shapes for LHS and RHS matrices
1468 const TensorShape lhs_shape(k, m, batch_size);
1469 const TensorShape rhs_shape(n, k, batch_size);
1470 const TensorShape bias_shape(n,
1471 broadcast_bias ? 1 : m,
1472 broadcast_bias ? 1 : batch_size);
1473
Ramy Elgammala77c6d72022-09-08 11:30:08 +01001474 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, output_stage, a_offset, b_offset);
Freddie Liardete572dff2022-05-16 14:09:10 +01001475 if(gemm_validated == true)
1476 {
1477 _reference = compute_reference(lhs_shape, rhs_shape, bias_shape, data_type, output_stage, a_offset, b_offset);
1478 }
1479 }
1480
1481protected:
1482 template <typename U>
1483 void fill(U &&tensor, int i)
1484 {
1485 switch(tensor.data_type())
1486 {
1487 case DataType::QASYMM8:
1488 {
1489 // Between 1 and 254 in order to avoid having -128 and 128 for the DOT product path
1490 std::uniform_int_distribution<> distribution(1, 254);
1491 library->fill(tensor, distribution, i);
1492 }
1493 break;
1494 case DataType::QASYMM8_SIGNED:
1495 {
1496 std::uniform_int_distribution<> distribution(-127, 126);
1497 library->fill(tensor, distribution, i);
1498 }
1499 break;
1500 case DataType::S32:
1501 {
1502 std::uniform_int_distribution<> distribution(-10000, 10000);
1503 library->fill(tensor, distribution, i);
1504 }
1505 break;
1506 default:
1507 ARM_COMPUTE_ERROR("Unsupported data type");
1508 }
1509 }
1510
1511 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info,
1512 const GEMMRHSMatrixInfo &rhs_info, DataType data_type, GEMMLowpOutputStageInfo output_stage, const int a_offset, const int b_offset)
1513 {
1514 // Create tensors
1515 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1, QuantizationInfo(1.0f / 255, a_offset));
1516 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1, QuantizationInfo(1.0f / 255, b_offset));
1517 TensorType bias = create_tensor<TensorType>(bias_shape, DataType::S32, 1);
1518 TensorType dst;
1519 TensorType rhs_reshaped;
1520
1521 const unsigned int M = lhs_shape[1];
1522 const unsigned int N = rhs_shape[0];
1523 const unsigned int K = lhs_shape[0];
1524
1525 // Tensors for precomputing sum of lhs rows / rhs columns
1526 TensorType vec_sum_rows = create_tensor<TensorType>(TensorShape(M, 1, lhs_shape[2]), DataType::S32, 1);
1527 TensorType vec_sum_cols = create_tensor<TensorType>(TensorShape(N, 1, rhs_shape[2]), DataType::S32, 1);
1528
1529 GEMMKernelInfo gemm_info;
1530 gemm_info.m = M;
1531 gemm_info.n = N;
1532 gemm_info.k = K;
1533 gemm_info.lhs_info = lhs_info;
1534 gemm_info.rhs_info = rhs_info;
1535 gemm_info.output_stage = output_stage;
1536 gemm_info.a_offset = a_offset;
1537 gemm_info.b_offset = b_offset;
1538 // The output tensor will be auto-initialized within the function
1539
1540 // Create and configure function
1541 ReshapeRHSOperatorType reshape_rhs;
1542 GEMMFunctionType gemm;
1543 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1544
1545 // If GEMM is not validated, do not try to run. The validation will check
1546 // if the technology supports this extension. If not, the test will be skipped.
1547 // If it supports, the test will fail anyway because target and reference
1548 // will not match.
1549 gemm_validated = bool(gemm.validate(lhs.info(), rhs_reshaped.info(), dst.info(), gemm_info, vec_sum_cols.info(), vec_sum_rows.info(), bias.info()));
1550 if(gemm_validated == true)
1551 {
1552 gemm.configure(lhs.info(), rhs_reshaped.info(), dst.info(), gemm_info, vec_sum_cols.info(), vec_sum_rows.info(), bias.info());
1553
1554 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1555 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1556 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
1557
1558 // Allocate tensors
1559 lhs.allocator()->allocate();
1560 rhs.allocator()->allocate();
1561 rhs_reshaped.allocator()->allocate();
1562 bias.allocator()->allocate();
1563 vec_sum_cols.allocator()->allocate();
1564 vec_sum_rows.allocator()->allocate();
1565 dst.allocator()->allocate();
1566
1567 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1568 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1569 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1570 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1571 ARM_COMPUTE_ASSERT(!vec_sum_cols.info()->is_resizable());
1572 ARM_COMPUTE_ASSERT(!vec_sum_rows.info()->is_resizable());
1573 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
1574
1575 // Fill tensors
1576 fill(AccessorType(lhs), 0);
1577 fill(AccessorType(rhs), 1);
1578 fill(AccessorType(bias), 2);
1579
1580 TensorType lhs_32 = create_tensor<TensorType>(lhs_shape, DataType::S32, 1);
1581 TensorType rhs_32 = create_tensor<TensorType>(rhs_shape, DataType::S32, 1);
1582 CastOperation cast_lhs;
1583 CastOperation cast_rhs;
1584 cast_lhs.configure(&lhs, &lhs_32, ConvertPolicy::SATURATE);
1585 cast_rhs.configure(&rhs, &rhs_32, ConvertPolicy::SATURATE);
1586 lhs_32.allocator()->allocate();
1587 rhs_32.allocator()->allocate();
1588 cast_lhs.run();
1589 cast_rhs.run();
1590
1591 ReduceOperation lhs_sum_rows;
1592 ReduceOperation rhs_sum_cols;
1593
1594 lhs_sum_rows.configure(&lhs_32, &vec_sum_rows, 0, ReductionOperation::SUM, false);
1595 rhs_sum_cols.configure(&rhs_32, &vec_sum_cols, 1, ReductionOperation::SUM);
1596
1597 lhs_sum_rows.run();
1598 rhs_sum_cols.run();
1599
1600 // Compute GEMM
1601 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1602 reshape_rhs.run(reshape_rhs_pack);
1603 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs }, { ACL_SRC_1, &rhs_reshaped }, { ACL_SRC_2, &bias }, { ACL_DST, &dst }, { ACL_VEC_COL_SUM, &vec_sum_cols }, { ACL_VEC_ROW_SUM, &vec_sum_rows } });
1604 gemm.run(gemm_pack);
1605 }
1606
1607 return dst;
1608 }
1609
1610 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, DataType data_type, GEMMLowpOutputStageInfo output_stage,
1611 const int a_offset, const int b_offset)
1612 {
1613 TensorShape dst_shape = lhs_shape;
1614 dst_shape[0] = rhs_shape[0];
1615 dst_shape[1] = lhs_shape[1];
1616
1617 // Create reference
1618 SimpleTensor<T> lhs{ lhs_shape, data_type, 1, QuantizationInfo(1.0f / 255, a_offset) };
1619 SimpleTensor<T> rhs{ rhs_shape, data_type, 1, QuantizationInfo(1.0f / 255, b_offset) };
1620 SimpleTensor<int32_t> bias{ bias_shape, DataType::S32, 1 };
1621 SimpleTensor<int32_t> dst{ dst_shape, DataType::S32, 1 };
1622 SimpleTensor<T> dst_final{ dst_shape, data_type, 1 };
1623
1624 // Fill reference
1625 fill(lhs, 0);
1626 fill(rhs, 1);
1627 fill(bias, 2);
1628
1629 dst = reference::gemmlowp_matrix_multiply_core<int32_t, T>(lhs, rhs, dst_shape, a_offset, b_offset);
1630 dst_final = reference::gemmlowp_quantize_down_scale_by_fixedpoint<int32_t, T>(dst, bias,
1631 output_stage.gemmlowp_multipliers, output_stage.gemmlowp_shifts, output_stage.gemmlowp_offset, output_stage.gemmlowp_min_bound, output_stage.gemmlowp_max_bound);
1632 return dst_final;
1633 }
1634
1635 bool gemm_validated = true;
1636 TensorType _target{};
1637 SimpleTensor<T> _reference{};
1638};
1639
1640template <typename TensorType, typename AccessorType, typename ReshapeRHSOperatorType, typename GEMMFunctionType>
1641class GEMMLowpMatrixMultiplyReshapedOnlyRHSMMULValidationFixture : public framework::Fixture
1642{
1643public:
Freddie Liardete572dff2022-05-16 14:09:10 +01001644 void setup(unsigned int m, unsigned int n, unsigned int k, unsigned int batch_size, unsigned int m0, unsigned int n0,
1645 unsigned int k0, unsigned int h0, bool interleave_rhs, bool transpose_rhs, DataType data_type)
1646 {
1647 GEMMLHSMatrixInfo lhs_info;
1648 lhs_info.m0 = m0;
1649 lhs_info.k0 = k0;
1650
1651 GEMMRHSMatrixInfo rhs_info;
1652 rhs_info.n0 = n0;
1653 rhs_info.k0 = k0;
1654 rhs_info.h0 = h0;
1655 rhs_info.interleave = interleave_rhs;
1656 rhs_info.transpose = transpose_rhs;
1657
1658 // Set the tensor shapes for LHS and RHS matrices
1659 const TensorShape lhs_shape(k, m, batch_size);
1660 const TensorShape rhs_shape(n, k, batch_size);
1661
Ramy Elgammala77c6d72022-09-08 11:30:08 +01001662 _target = compute_target(lhs_shape, rhs_shape, lhs_info, rhs_info, data_type);
Freddie Liardete572dff2022-05-16 14:09:10 +01001663 if(gemm_validated == true)
1664 {
1665 _reference = compute_reference(lhs_shape, rhs_shape, data_type);
1666 }
1667 }
1668
1669protected:
1670 template <typename U>
1671 void fill(U &&tensor, int i)
1672 {
1673 switch(tensor.data_type())
1674 {
1675 case DataType::QASYMM8:
1676 {
1677 // Between 1 and 254 in order to avoid having -128 and 128 for the DOT product path
1678 std::uniform_int_distribution<> distribution(1, 254);
1679 library->fill(tensor, distribution, i);
1680 }
1681 break;
1682 case DataType::QASYMM8_SIGNED:
1683 {
1684 std::uniform_int_distribution<> distribution(-127, 126);
1685 library->fill(tensor, distribution, i);
1686 }
1687 break;
1688 default:
1689 ARM_COMPUTE_ERROR("Unsupported data type");
1690 }
1691 }
1692
1693 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const GEMMLHSMatrixInfo &lhs_info,
1694 const GEMMRHSMatrixInfo &rhs_info, DataType data_type)
1695 {
1696 // Create tensors
1697 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1698 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1699 TensorType rhs_reshaped;
1700 TensorType dst;
1701
1702 const unsigned int M = lhs_shape[1];
1703 const unsigned int N = rhs_shape[0];
1704 const unsigned int K = lhs_shape[0];
1705
1706 GEMMKernelInfo gemm_info;
1707 gemm_info.m = M;
1708 gemm_info.n = N;
1709 gemm_info.k = K;
1710 gemm_info.lhs_info = lhs_info;
1711 gemm_info.rhs_info = rhs_info;
1712 // The output tensor will be auto-initialized within the function
1713
1714 // Create and configure function
1715 ReshapeRHSOperatorType reshape_rhs;
1716 GEMMFunctionType gemm;
1717 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1718
1719 // If GEMM is not validated, do not try to run. The validation will check
1720 // if the technology supports this extension. If not, the test will be skipped.
1721 // If it supports, the test will fail anyway because target and reference
1722 // will not match.
1723 gemm_validated = bool(gemm.validate(lhs.info(), rhs_reshaped.info(), dst.info(), gemm_info, nullptr, nullptr, nullptr));
1724 if(gemm_validated == true)
1725 {
1726 gemm.configure(lhs.info(), rhs_reshaped.info(), dst.info(), gemm_info, nullptr, nullptr, nullptr);
1727
1728 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1729 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1730
1731 // Allocate tensors
1732 lhs.allocator()->allocate();
1733 rhs.allocator()->allocate();
1734 rhs_reshaped.allocator()->allocate();
1735 dst.allocator()->allocate();
1736
1737 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1738 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1739 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1740 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
1741
1742 // Fill tensors
1743 fill(AccessorType(lhs), 0);
1744 fill(AccessorType(rhs), 1);
1745
1746 // Compute GEMM
1747 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1748 reshape_rhs.run(reshape_rhs_pack);
1749 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs }, { ACL_SRC_1, &rhs_reshaped }, { ACL_DST, &dst } });
1750 gemm.run(gemm_pack);
1751 }
1752
1753 return dst;
1754 }
1755
1756 SimpleTensor<int32_t> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type)
1757 {
1758 TensorShape dst_shape = lhs_shape;
1759 dst_shape[0] = rhs_shape[0];
1760 dst_shape[1] = lhs_shape[1];
1761
1762 if(data_type == DataType::QASYMM8)
1763 {
1764 // Create reference
1765 SimpleTensor<uint8_t> lhs{ lhs_shape, data_type, 1 };
1766 SimpleTensor<uint8_t> rhs{ rhs_shape, data_type, 1 };
1767 SimpleTensor<int32_t> dst{ dst_shape, DataType::S32, 1 };
1768
1769 // Fill reference
1770 fill(lhs, 0);
1771 fill(rhs, 1);
1772
1773 return reference::gemmlowp_matrix_multiply_core<int32_t, uint8_t>(lhs, rhs, dst_shape, 0, 0);
1774 }
1775 else
1776 {
1777 // Create reference
1778 SimpleTensor<int8_t> lhs{ lhs_shape, data_type, 1 };
1779 SimpleTensor<int8_t> rhs{ rhs_shape, data_type, 1 };
1780 SimpleTensor<int32_t> dst{ dst_shape, DataType::S32, 1 };
1781
1782 // Fill reference
1783 fill(lhs, 0);
1784 fill(rhs, 1);
1785
1786 return reference::gemmlowp_matrix_multiply_core<int32_t, int8_t>(lhs, rhs, dst_shape, 0, 0);
1787 }
1788 }
1789
1790 bool gemm_validated = true;
1791 TensorType _target{};
1792 SimpleTensor<int32_t> _reference{};
1793};
1794
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001795template <typename TensorType, typename AccessorType, typename ReshapeRHSOperatorType, typename GEMMFunctionType>
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001796class GEMMLowpMatrixMultiplyReshapedOnlyRHS3DValidationFixture : public framework::Fixture
1797{
1798public:
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001799 void setup(unsigned int m_w, unsigned int m_h, unsigned int n, unsigned int k, unsigned int batch_size, unsigned int m0, unsigned int n0,
1800 unsigned int k0, unsigned int h0, bool interleave_rhs, bool transpose_rhs, DataType data_type)
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001801 {
1802 GEMMLHSMatrixInfo lhs_info;
1803 lhs_info.m0 = m0;
1804 lhs_info.k0 = k0;
1805
1806 GEMMRHSMatrixInfo rhs_info;
1807 rhs_info.n0 = n0;
1808 rhs_info.k0 = k0;
1809 rhs_info.h0 = h0;
1810 rhs_info.interleave = interleave_rhs;
1811 rhs_info.transpose = transpose_rhs;
1812
1813 // In case of GEMM3D, m is the product between m_w and m_h
1814 const unsigned int m = m_w * m_h;
1815
1816 // Set the tensor shapes for LHS and RHS matrices
1817 const TensorShape lhs_shape(k, m, batch_size);
1818 const TensorShape rhs_shape(n, k, batch_size);
1819
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001820 _target = compute_target(lhs_shape, rhs_shape, lhs_info, rhs_info, m_h, data_type);
1821 _reference = compute_reference(lhs_shape, rhs_shape, m_h, data_type);
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001822 }
1823
1824protected:
1825 template <typename U>
1826 void fill(U &&tensor, int i)
1827 {
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001828 switch(tensor.data_type())
1829 {
1830 case DataType::QASYMM8:
1831 {
1832 // Between 1 and 254 in order to avoid having -128 and 128 for the DOT product path
1833 std::uniform_int_distribution<> distribution(1, 254);
1834 library->fill(tensor, distribution, i);
1835 }
1836 break;
1837 case DataType::QASYMM8_SIGNED:
1838 {
1839 std::uniform_int_distribution<> distribution(-127, 126);
1840 library->fill(tensor, distribution, i);
1841 }
1842 break;
1843 default:
1844 ARM_COMPUTE_ERROR("Unsupported data type");
1845 }
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001846 }
1847
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001848 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const GEMMLHSMatrixInfo &lhs_info,
1849 const GEMMRHSMatrixInfo &rhs_info, unsigned int m_h, DataType data_type)
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001850 {
1851 // Create tensors
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001852 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1853 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001854 TensorType rhs_reshaped;
1855 TensorType dst;
1856
1857 const unsigned int M = lhs_shape[1];
1858 const unsigned int N = rhs_shape[0];
1859 const unsigned int K = lhs_shape[0];
1860
Michele Di Giorgiob54ba282020-01-14 15:31:55 +00001861 GEMMKernelInfo gemm_info;
1862 gemm_info.m = M;
1863 gemm_info.n = N;
1864 gemm_info.k = K;
1865 gemm_info.depth_output_gemm3d = m_h;
1866 gemm_info.lhs_info = lhs_info;
1867 gemm_info.rhs_info = rhs_info;
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001868 // The output tensor will be auto-initialized within the function
1869
1870 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001871 ReshapeRHSOperatorType reshape_rhs;
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001872 GEMMFunctionType gemm;
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001873 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
Georgios Pinitas4a578b92021-06-25 12:13:49 +01001874 gemm.configure(lhs.info(), rhs_reshaped.info(), dst.info(), gemm_info);
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001875
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001876 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1877 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001878
Giorgio Arena63825e82021-03-25 14:54:50 +00001879 add_padding_x({ &lhs, &rhs, &rhs_reshaped, &dst });
1880
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001881 // Allocate tensors
1882 lhs.allocator()->allocate();
1883 rhs.allocator()->allocate();
1884 rhs_reshaped.allocator()->allocate();
1885 dst.allocator()->allocate();
1886
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001887 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1888 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1889 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1890 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001891
1892 // Fill tensors
1893 fill(AccessorType(lhs), 0);
1894 fill(AccessorType(rhs), 1);
1895
1896 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001897 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1898 reshape_rhs.run(reshape_rhs_pack);
Georgios Pinitas4a578b92021-06-25 12:13:49 +01001899 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs }, { ACL_SRC_1, &rhs_reshaped }, { ACL_DST, &dst } });
1900 gemm.run(gemm_pack);
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001901
1902 return dst;
1903 }
1904
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001905 SimpleTensor<int32_t> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, unsigned int m_h, DataType data_type)
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001906 {
1907 TensorShape dst_shape = lhs_shape;
1908 dst_shape.set(0, rhs_shape[0]);
1909 dst_shape.set(1, lhs_shape[1] / m_h);
1910 dst_shape.set(2, m_h);
1911 dst_shape.set(3, lhs_shape[2]);
1912
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001913 if(data_type == DataType::QASYMM8)
1914 {
1915 // Create reference
1916 SimpleTensor<uint8_t> lhs{ lhs_shape, data_type, 1 };
1917 SimpleTensor<uint8_t> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001918
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001919 // Fill reference
1920 fill(lhs, 0);
1921 fill(rhs, 1);
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001922
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001923 return reference::gemmlowp_matrix_multiply_core<int32_t, uint8_t>(lhs, rhs, dst_shape, 0, 0);
1924 }
1925 else
1926 {
1927 // Create reference
1928 SimpleTensor<int8_t> lhs{ lhs_shape, data_type, 1 };
1929 SimpleTensor<int8_t> rhs{ rhs_shape, data_type, 1 };
1930
1931 // Fill reference
1932 fill(lhs, 0);
1933 fill(rhs, 1);
1934
1935 return reference::gemmlowp_matrix_multiply_core<int32_t, int8_t>(lhs, rhs, dst_shape, 0, 0);
1936 }
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001937 }
1938
1939 TensorType _target{};
1940 SimpleTensor<int32_t> _reference{};
1941};
Gian Marco Iodicee7510622019-06-03 17:28:17 +01001942
1943template <typename TensorType, typename AccessorType, typename GEMMFunctionType>
1944class GEMMLowpMatrixMultiplyNativeValidationFixture : public framework::Fixture
1945{
1946public:
Gian Marco Iodicee7510622019-06-03 17:28:17 +01001947 void setup(unsigned int m, unsigned int n, unsigned int k, unsigned int batch_size, unsigned int m0, unsigned int n0, unsigned int k0)
1948 {
1949 GEMMLHSMatrixInfo lhs_info;
1950 lhs_info.m0 = m0;
1951 lhs_info.k0 = k0;
1952
1953 GEMMRHSMatrixInfo rhs_info;
1954 rhs_info.n0 = n0;
1955 rhs_info.k0 = k0;
1956
1957 // Set the tensor shapes for LHS and RHS matrices
1958 const TensorShape lhs_shape(k, m, batch_size);
1959 const TensorShape rhs_shape(n, k, batch_size);
1960
1961 _target = compute_target(lhs_shape, rhs_shape, lhs_info, rhs_info);
1962 _reference = compute_reference(lhs_shape, rhs_shape);
1963 }
1964
1965protected:
1966 template <typename U>
1967 void fill(U &&tensor, int i)
1968 {
1969 // Between 1 and 254 in order to avoid having -128 and 128 for the DOT product path
1970 std::uniform_int_distribution<> distribution(1, 254);
1971 library->fill(tensor, distribution, i);
1972 }
1973
1974 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info)
1975 {
1976 // Create tensors
1977 TensorType lhs = create_tensor<TensorType>(lhs_shape, DataType::QASYMM8, 1);
1978 TensorType rhs = create_tensor<TensorType>(rhs_shape, DataType::QASYMM8, 1);
1979 TensorType dst;
1980
1981 const unsigned int M = lhs_shape[1];
1982 const unsigned int N = rhs_shape[0];
1983 const unsigned int K = lhs_shape[0];
1984
1985 // The output tensor will be auto-initialized within the function
1986
1987 // Create and configure function
1988 GEMMFunctionType gemm;
Georgios Pinitas4a578b92021-06-25 12:13:49 +01001989 gemm.configure(lhs.info(), rhs.info(), dst.info(), lhs_info, rhs_info, GEMMReshapeInfo(M, N, K));
Gian Marco Iodicee7510622019-06-03 17:28:17 +01001990
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001991 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1992 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
Gian Marco Iodicee7510622019-06-03 17:28:17 +01001993
Giorgio Arena63825e82021-03-25 14:54:50 +00001994 add_padding_x({ &lhs, &rhs, &dst });
1995
Gian Marco Iodicee7510622019-06-03 17:28:17 +01001996 // Allocate tensors
1997 lhs.allocator()->allocate();
1998 rhs.allocator()->allocate();
1999 dst.allocator()->allocate();
2000
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01002001 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
2002 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
2003 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodicee7510622019-06-03 17:28:17 +01002004
2005 // Fill tensors
2006 fill(AccessorType(lhs), 0);
2007 fill(AccessorType(rhs), 1);
2008
2009 // Compute GEMM
Georgios Pinitas4a578b92021-06-25 12:13:49 +01002010 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs }, { ACL_SRC_1, &rhs }, { ACL_DST, &dst } });
2011 gemm.run(gemm_pack);
Gian Marco Iodicee7510622019-06-03 17:28:17 +01002012
2013 return dst;
2014 }
2015
2016 SimpleTensor<int32_t> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape)
2017 {
2018 TensorShape dst_shape = lhs_shape;
2019 dst_shape[0] = rhs_shape[0];
2020 dst_shape[1] = lhs_shape[1];
2021
2022 // Create reference
2023 SimpleTensor<uint8_t> lhs{ lhs_shape, DataType::QASYMM8, 1 };
2024 SimpleTensor<uint8_t> rhs{ rhs_shape, DataType::QASYMM8, 1 };
2025
2026 // Fill reference
2027 fill(lhs, 0);
2028 fill(rhs, 1);
2029
2030 return reference::gemmlowp_matrix_multiply_core<int32_t, uint8_t>(lhs, rhs, dst_shape, 0, 0);
2031 }
2032
2033 TensorType _target{};
2034 SimpleTensor<int32_t> _reference{};
2035};
2036
2037template <typename TensorType, typename AccessorType, typename GEMMFunctionType>
2038class GEMMLowpMatrixMultiplyNative3DValidationFixture : public framework::Fixture
2039{
2040public:
Gian Marco Iodicee7510622019-06-03 17:28:17 +01002041 void setup(unsigned int m_w, unsigned int m_h, unsigned int n, unsigned int k, unsigned int batch_size, unsigned int m0, unsigned int n0, unsigned int k0)
2042 {
2043 GEMMLHSMatrixInfo lhs_info;
2044 lhs_info.m0 = m0;
2045 lhs_info.k0 = k0;
2046
2047 GEMMRHSMatrixInfo rhs_info;
2048 rhs_info.n0 = n0;
2049 rhs_info.k0 = k0;
2050
2051 // In case of GEMM3D, m is the product between m_w and m_h
2052 const unsigned int m = m_w * m_h;
2053
2054 // Set the tensor shapes for LHS and RHS matrices
2055 const TensorShape lhs_shape(k, m, batch_size);
2056 const TensorShape rhs_shape(n, k, batch_size);
2057
2058 _target = compute_target(lhs_shape, rhs_shape, lhs_info, rhs_info, m_h);
2059 _reference = compute_reference(lhs_shape, rhs_shape, m_h);
2060 }
2061
2062protected:
2063 template <typename U>
2064 void fill(U &&tensor, int i)
2065 {
2066 // Between 1 and 254 in order to avoid having -128 and 128 for the DOT product path
2067 std::uniform_int_distribution<> distribution(1, 254);
2068 library->fill(tensor, distribution, i);
2069 }
2070
2071 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info, unsigned int m_h)
2072 {
2073 // Create tensors
2074 TensorType lhs = create_tensor<TensorType>(lhs_shape, DataType::QASYMM8, 1);
2075 TensorType rhs = create_tensor<TensorType>(rhs_shape, DataType::QASYMM8, 1);
2076 TensorType dst;
2077
2078 const unsigned int M = lhs_shape[1];
2079 const unsigned int N = rhs_shape[0];
2080 const unsigned int K = lhs_shape[0];
2081
2082 // The output tensor will be auto-initialized within the function
2083
2084 // Create and configure function
2085 GEMMFunctionType gemm;
Georgios Pinitas4a578b92021-06-25 12:13:49 +01002086 gemm.configure(lhs.info(), rhs.info(), dst.info(), lhs_info, rhs_info, GEMMReshapeInfo(M, N, K, 1, 1, m_h));
Gian Marco Iodicee7510622019-06-03 17:28:17 +01002087
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01002088 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
2089 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
Gian Marco Iodicee7510622019-06-03 17:28:17 +01002090
Giorgio Arena63825e82021-03-25 14:54:50 +00002091 add_padding_x({ &lhs, &rhs, &dst });
2092
Gian Marco Iodicee7510622019-06-03 17:28:17 +01002093 // Allocate tensors
2094 lhs.allocator()->allocate();
2095 rhs.allocator()->allocate();
2096 dst.allocator()->allocate();
2097
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01002098 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
2099 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
2100 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodicee7510622019-06-03 17:28:17 +01002101
2102 // Fill tensors
2103 fill(AccessorType(lhs), 0);
2104 fill(AccessorType(rhs), 1);
2105
2106 // Compute GEMM
Georgios Pinitas4a578b92021-06-25 12:13:49 +01002107 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs }, { ACL_SRC_1, &rhs }, { ACL_DST, &dst } });
2108 gemm.run(gemm_pack);
Gian Marco Iodicee7510622019-06-03 17:28:17 +01002109
2110 return dst;
2111 }
2112
2113 SimpleTensor<int32_t> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, unsigned int m_h)
2114 {
2115 TensorShape dst_shape = lhs_shape;
2116 dst_shape.set(0, rhs_shape[0]);
2117 dst_shape.set(1, lhs_shape[1] / m_h);
2118 dst_shape.set(2, m_h);
2119 dst_shape.set(3, lhs_shape[2]);
2120
2121 // Create reference
2122 SimpleTensor<uint8_t> lhs{ lhs_shape, DataType::QASYMM8, 1 };
2123 SimpleTensor<uint8_t> rhs{ rhs_shape, DataType::QASYMM8, 1 };
2124
2125 // Fill reference
2126 fill(lhs, 0);
2127 fill(rhs, 1);
2128
2129 return reference::gemmlowp_matrix_multiply_core<int32_t, uint8_t>(lhs, rhs, dst_shape, 0, 0);
2130 }
2131
2132 TensorType _target{};
2133 SimpleTensor<int32_t> _reference{};
2134};
Pablo Tello299025a2017-09-29 11:30:12 +01002135} // namespace validation
2136} // namespace test
2137} // namespace arm_compute
SiCong Li11ab4512023-11-07 12:04:59 +00002138#endif // ACL_TESTS_VALIDATION_FIXTURES_GEMMLOWPFIXTURE_H