blob: f1ec81aae6f1b7c20e38d68365516b4fa1e7b30f [file] [log] [blame]
Pablo Tello299025a2017-09-29 11:30:12 +01001/*
Adnan AlSinanc5849582022-05-05 11:13:19 +01002 * Copyright (c) 2017-2022 Arm Limited.
Pablo Tello299025a2017-09-29 11:30:12 +01003 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24#ifndef ARM_COMPUTE_TEST_GEMMLOWP_FIXTURE
25#define ARM_COMPUTE_TEST_GEMMLOWP_FIXTURE
26
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +000027#include "arm_compute/core/utils/quantization/AsymmHelpers.h"
Pablo Tello299025a2017-09-29 11:30:12 +010028#include "tests/framework/Fixture.h"
Freddie Liardete572dff2022-05-16 14:09:10 +010029#include "tests/validation/Validation.h"
Ramy Elgammala77c6d72022-09-08 11:30:08 +010030#include "tests/validation/reference/GEMMLowp.h"
Pablo Tello299025a2017-09-29 11:30:12 +010031
32namespace arm_compute
33{
34namespace test
35{
36namespace validation
37{
George Wort2d7e6832019-02-22 16:37:41 +000038namespace
39{
40template <typename U>
41void fill(U &&tensor, int i)
42{
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +000043 switch(tensor.data_type())
44 {
45 case DataType::QSYMM8_PER_CHANNEL:
46 {
47 int min_bound = 128;
48 int max_bound = -127;
49 for(size_t j = 0; j < tensor.quantization_info().scale().size(); j++)
50 {
51 std::pair<int, int> bounds = get_symm_quantized_per_channel_bounds(tensor.quantization_info(), -1.0f, 1.0f, i);
52 if(bounds.first < min_bound)
53 {
54 min_bound = bounds.first;
55 }
56 if(bounds.second > max_bound)
57 {
58 max_bound = bounds.second;
59 }
60 }
Pablo Tello29cab362022-03-10 17:05:34 +000061 std::uniform_int_distribution<int32_t> distribution(min_bound, max_bound);
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +000062 library->fill(tensor, distribution, i);
63 break;
64 }
65 case DataType::QASYMM8:
66 {
Pablo Tello29cab362022-03-10 17:05:34 +000067 std::uniform_int_distribution<uint32_t> distribution(1, 254);
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +000068 library->fill(tensor, distribution, i);
69 break;
70 }
71 case DataType::F16:
Giorgio Arena6aeb2172020-12-15 15:45:43 +000072 {
Giorgio Arenaa8e2aeb2021-01-06 11:34:57 +000073 arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ -1.0f, 1.0f };
Giorgio Arena6aeb2172020-12-15 15:45:43 +000074 library->fill(tensor, distribution, i);
75 break;
76 }
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +000077 case DataType::F32:
78 {
Giorgio Arena6aeb2172020-12-15 15:45:43 +000079 std::uniform_real_distribution<float> distribution(-1.0f, 1.0f);
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +000080 library->fill(tensor, distribution, i);
81 break;
82 }
83 default:
84 library->fill_tensor_uniform(tensor, i);
85 }
George Wort2d7e6832019-02-22 16:37:41 +000086}
87
Ramy Elgammala77c6d72022-09-08 11:30:08 +010088template <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>
George Wort2d7e6832019-02-22 16:37:41 +000089TensorType compute_gemmlowp_target(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &shape_output, int32_t a_offset, int32_t b_offset,
Manuel Bottini959c26d2019-12-02 16:22:35 +000090 GEMMLowpOutputStageInfo output_stage = GEMMLowpOutputStageInfo(), DataType data_type_a = DataType::QASYMM8, DataType data_type_b = DataType::QASYMM8,
Giorgio Arena5f6fdc12021-06-09 15:23:06 +010091 QuantizationInfo b_qinfo = QuantizationInfo(), bool reshape_b_only_on_first_run = false)
George Wort2d7e6832019-02-22 16:37:41 +000092{
93 // Create tensors
Manuel Bottini959c26d2019-12-02 16:22:35 +000094 DataType data_type_output = output_stage.type == GEMMLowpOutputStageType::NONE ? DataType::S32 : data_type_a;
95
96 TensorType a = create_tensor<TensorType>(shape_a, data_type_a, 1);
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +000097 TensorType b = create_tensor<TensorType>(shape_b, data_type_b, 1); // gemm output before output stage mismatch if i pass data_layout_output here. to be investigated
Manuel Bottini959c26d2019-12-02 16:22:35 +000098 TensorType output = create_tensor<TensorType>(shape_output, data_type_output, 1);
George Wort2d7e6832019-02-22 16:37:41 +000099
100 a.info()->set_quantization_info(QuantizationInfo(1.0f / 255, a_offset));
George Wort2d7e6832019-02-22 16:37:41 +0000101
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +0000102 if(data_type_b == DataType::QSYMM8_PER_CHANNEL)
103 {
104 b.info()->set_quantization_info(b_qinfo);
105 }
106 else
107 {
108 b.info()->set_quantization_info(QuantizationInfo(1.0f / 255, b_offset));
109 }
George Wort2d7e6832019-02-22 16:37:41 +0000110 TensorType bias;
111 if(is_fused)
112 {
113 TensorShape bias_shape(shape_b[0]);
114 bias = create_tensor<TensorType>(bias_shape, DataType::S32, 1);
115 }
116
117 // Create and configure function
118 // The GEMMinfo includes the values of the depth in case of reinterpreted 3d input/output
119 FunctionType gemmlowp;
Giorgio Arena5f6fdc12021-06-09 15:23:06 +0100120 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,
121 output_stage));
George Wort2d7e6832019-02-22 16:37:41 +0000122
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100123 ARM_COMPUTE_ASSERT(a.info()->is_resizable());
124 ARM_COMPUTE_ASSERT(b.info()->is_resizable());
125 ARM_COMPUTE_ASSERT(output.info()->is_resizable());
George Wort2d7e6832019-02-22 16:37:41 +0000126
Giorgio Arena63825e82021-03-25 14:54:50 +0000127 add_padding_x({ &a, &b, &output });
128
George Wort2d7e6832019-02-22 16:37:41 +0000129 // Allocate tensors
130 a.allocator()->allocate();
131 b.allocator()->allocate();
132 output.allocator()->allocate();
133
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100134 ARM_COMPUTE_ASSERT(!a.info()->is_resizable());
135 ARM_COMPUTE_ASSERT(!b.info()->is_resizable());
136 ARM_COMPUTE_ASSERT(!output.info()->is_resizable());
George Wort2d7e6832019-02-22 16:37:41 +0000137
138 // Fill tensors
139 fill(AccessorType(a), 0);
140 fill(AccessorType(b), 1);
141
142 if(is_fused)
143 {
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100144 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
George Wort2d7e6832019-02-22 16:37:41 +0000145 bias.allocator()->allocate();
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100146 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
George Wort2d7e6832019-02-22 16:37:41 +0000147 fill(AccessorType(bias), 2);
148 }
Ramy Elgammala77c6d72022-09-08 11:30:08 +0100149
150 // Run with variable inputs.
151 if(run_twice)
152 {
153 gemmlowp.run();
154 fill(AccessorType(a), 3); // Fill tensors with new seed after run
155 fill(AccessorType(b), 4);
156 if(is_fused)
157 {
158 fill(AccessorType(bias), 5);
159 }
160 }
161
George Wort2d7e6832019-02-22 16:37:41 +0000162 // Compute GEMM function
163 gemmlowp.run();
164 return output;
165}
166
Ramy Elgammala77c6d72022-09-08 11:30:08 +0100167template <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>
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +0000168SimpleTensor<int32_t> compute_gemmlowp_reference(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &shape_output, int32_t a_offset, int32_t b_offset,
Manuel Bottini959c26d2019-12-02 16:22:35 +0000169 DataType data_type_a = DataType::QASYMM8, DataType data_type_b = DataType::QASYMM8, QuantizationInfo b_qinfo = QuantizationInfo())
George Wort2d7e6832019-02-22 16:37:41 +0000170{
171 TensorShape shape_a_to_use = shape_a;
172 if(reinterpret_input_as_3d)
173 {
174 // Collapse the second and third dimension if the input is 3D
175 shape_a_to_use.collapse(2U, 1U);
176 }
177
178 // Create reference
Manuel Bottini959c26d2019-12-02 16:22:35 +0000179 SimpleTensor<TI> a{ shape_a_to_use, data_type_a, 1 };
180 SimpleTensor<TW> b{ shape_b, data_type_b, 1, data_type_b == DataType::QSYMM8_PER_CHANNEL ? b_qinfo : QuantizationInfo(1.0f / 255, b_offset) };
George Wort2d7e6832019-02-22 16:37:41 +0000181
Adnan AlSinanc5849582022-05-05 11:13:19 +0100182 TensorShape shape_a_to_use_transposed{ shape_a_to_use };
183 TensorShape shape_b_transposed{ shape_b };
184
185 shape_a_to_use_transposed.set(0, shape_a_to_use[1]);
186 shape_a_to_use_transposed.set(1, shape_a_to_use[0]);
187 shape_b_transposed.set(0, shape_b[1]);
188 shape_b_transposed.set(1, shape_b[0]);
189
190 SimpleTensor<TI> a_transposed{ shape_a_to_use_transposed, data_type_a, 1 };
191 SimpleTensor<TW> b_transposed{ shape_b_transposed, data_type_b, 1, data_type_b == DataType::QSYMM8_PER_CHANNEL ? b_qinfo : QuantizationInfo(1.0f / 255, b_offset) };
192
George Wort2d7e6832019-02-22 16:37:41 +0000193 // Fill reference
194 fill(a, 0);
195 fill(b, 1);
Adnan AlSinanc5849582022-05-05 11:13:19 +0100196
197 // Transpose reference if required
Adnan AlSinan3bb72b62022-05-06 12:10:11 +0100198 /* 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),
199 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)
200 in order to be able to call reference implementation that works with (B x M x K) input.
201 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 +0100202 if(pretranspose_A)
203 {
204 transpose_matrix<TI>(a, a_transposed);
205 }
206
207 if(pretranspose_B)
208 {
209 transpose_matrix<TW>(b, b_transposed);
210 }
211
Ramy Elgammala77c6d72022-09-08 11:30:08 +0100212 // Run with variable inputs.
213 if(run_twice)
214 {
215 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);
216 fill((pretranspose_A) ? a_transposed : a, 3);
217 fill((pretranspose_B) ? b_transposed : b, 4);
218 }
219
Adnan AlSinanc5849582022-05-05 11:13:19 +0100220 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 +0000221}
222}
223
Ramy Elgammala77c6d72022-09-08 11:30:08 +0100224template <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 +0000225class GEMMLowpMatrixMultiplyCoreValidationFixture : public framework::Fixture
Pablo Tello299025a2017-09-29 11:30:12 +0100226{
227public:
228 template <typename...>
George Wort2d7e6832019-02-22 16:37:41 +0000229 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 +0100230 {
George Wort2d7e6832019-02-22 16:37:41 +0000231 _target = compute_target(shape_a, shape_b, shape_output, a_offset, b_offset);
232 _reference = compute_reference(shape_a, shape_b, shape_output, a_offset, b_offset);
Pablo Tello299025a2017-09-29 11:30:12 +0100233 }
234
235protected:
George Wort2d7e6832019-02-22 16:37:41 +0000236 TensorType compute_target(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &shape_output, int32_t a_offset, int32_t b_offset)
Pablo Tello299025a2017-09-29 11:30:12 +0100237 {
Ramy Elgammala77c6d72022-09-08 11:30:08 +0100238 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_offset, b_offset);
Pablo Tello299025a2017-09-29 11:30:12 +0100239 }
240
George Wort2d7e6832019-02-22 16:37:41 +0000241 SimpleTensor<int32_t> compute_reference(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &shape_output, int32_t a_offset, int32_t b_offset)
Pablo Tello299025a2017-09-29 11:30:12 +0100242 {
Ramy Elgammala77c6d72022-09-08 11:30:08 +0100243 return compute_gemmlowp_reference<reinterpret_input_as_3d, uint8_t, uint8_t, false, false, run_twice>(shape_a, shape_b, shape_output, a_offset, b_offset);
Pablo Tellobf2fb952017-09-29 16:43:25 +0100244 }
245
Pablo Tello6ff12a02017-11-02 16:09:35 +0000246 TensorType _target{};
247 SimpleTensor<int32_t> _reference{};
Pablo Tellobf2fb952017-09-29 16:43:25 +0100248};
249
Manuel Bottini959c26d2019-12-02 16:22:35 +0000250template <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>
Giorgio Arena5f6fdc12021-06-09 15:23:06 +0100251class GEMMLowpMatrixMultiplyCoreFusedOffsetOutputGenericValidationFixture : public framework::Fixture
George Wort2d7e6832019-02-22 16:37:41 +0000252{
253public:
254 template <typename...>
Giorgio Arena5f6fdc12021-06-09 15:23:06 +0100255 void setup(TensorShape shape_a, TensorShape shape_b, TensorShape shape_output, int32_t a_offset, int32_t b_offset, GEMMLowpOutputStageInfo output_stage, DataType data_type_b,
256 bool reshape_b_only_on_first_run)
George Wort2d7e6832019-02-22 16:37:41 +0000257 {
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100258 ARM_COMPUTE_ASSERT(output_stage.type != GEMMLowpOutputStageType::NONE);
Manuel Bottini959c26d2019-12-02 16:22:35 +0000259 DataType data_type_a = data_type_b == DataType::QASYMM8_SIGNED ? DataType::QASYMM8_SIGNED : DataType::QASYMM8;
260
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +0000261 if(data_type_b == DataType::QSYMM8_PER_CHANNEL)
262 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000263 output_stage.is_quantized_per_channel = true;
264 const size_t num_channels = shape_b[0];
265 std::vector<float> scales(num_channels);
266 std::uniform_real_distribution<float> distribution(0.f, 1.f);
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +0000267 library->fill(scales, distribution, 0);
268 output_stage.gemmlowp_multipliers.resize(num_channels);
269 output_stage.gemmlowp_shifts.resize(num_channels);
270 for(size_t i = 0; i < num_channels; ++i)
271 {
Michele Di Giorgiof29d1b72019-10-29 10:58:13 +0000272 quantization::calculate_quantized_multiplier(scales[i], &output_stage.gemmlowp_multipliers[i], &output_stage.gemmlowp_shifts[i]);
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +0000273 }
274
Manuel Bottini959c26d2019-12-02 16:22:35 +0000275 _reference = compute_reference(shape_a, shape_b, shape_output, a_offset, 0, output_stage, data_type_a, data_type_b, QuantizationInfo(scales));
Giorgio Arena5f6fdc12021-06-09 15:23:06 +0100276 _target = compute_target(shape_a, shape_b, shape_output, a_offset, 0, output_stage, data_type_a, data_type_b, QuantizationInfo(scales), reshape_b_only_on_first_run);
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +0000277 }
278 else
279 {
Manuel Bottini959c26d2019-12-02 16:22:35 +0000280 _reference = compute_reference(shape_a, shape_b, shape_output, a_offset, b_offset, output_stage, data_type_a, data_type_b, QuantizationInfo());
Giorgio Arena5f6fdc12021-06-09 15:23:06 +0100281 _target = compute_target(shape_a, shape_b, shape_output, a_offset, b_offset, output_stage, data_type_a, data_type_b, QuantizationInfo(), reshape_b_only_on_first_run);
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +0000282 }
George Wort2d7e6832019-02-22 16:37:41 +0000283 }
284
285protected:
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +0000286 TensorType compute_target(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &shape_output, int32_t a_offset, int32_t b_offset, GEMMLowpOutputStageInfo output_stage,
Giorgio Arena5f6fdc12021-06-09 15:23:06 +0100287 DataType data_type_a, DataType data_type_b, QuantizationInfo b_qinfo, bool reshape_b_only_on_first_run = false)
George Wort2d7e6832019-02-22 16:37:41 +0000288 {
289 return compute_gemmlowp_target<TensorType, AccessorType, FunctionType, reinterpret_input_as_3d, reinterpret_output_as_3d, qasymm8_t, true>(shape_a, shape_b, shape_output, a_offset, b_offset,
Giorgio Arena5f6fdc12021-06-09 15:23:06 +0100290 output_stage, data_type_a, data_type_b, b_qinfo, reshape_b_only_on_first_run);
George Wort2d7e6832019-02-22 16:37:41 +0000291 }
292
Manuel Bottini959c26d2019-12-02 16:22:35 +0000293 SimpleTensor<TI> compute_reference(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &shape_output, int32_t a_offset, int32_t b_offset,
294 GEMMLowpOutputStageInfo output_stage, DataType data_type_a, DataType data_type_b, QuantizationInfo b_qinfo)
George Wort2d7e6832019-02-22 16:37:41 +0000295 {
Manuel Bottini959c26d2019-12-02 16:22:35 +0000296 SimpleTensor<int32_t> output = compute_gemmlowp_reference<reinterpret_input_as_3d, TI, TW>(shape_a, shape_b, shape_output, a_offset, b_offset, data_type_a, data_type_b, b_qinfo);
George Wort2d7e6832019-02-22 16:37:41 +0000297
298 TensorShape bias_shape(shape_b[0]);
299 SimpleTensor<int32_t> bias{ bias_shape, DataType::S32, 1 };
300 fill(bias, 2);
301
302 switch(output_stage.type)
303 {
304 case GEMMLowpOutputStageType::QUANTIZE_DOWN:
Manuel Bottini959c26d2019-12-02 16:22:35 +0000305 return reference::gemmlowp_quantize_down_scale<int32_t, TW>(output, bias,
306 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 +0000307 break;
308 case GEMMLowpOutputStageType::QUANTIZE_DOWN_FIXEDPOINT:
Manuel Bottini959c26d2019-12-02 16:22:35 +0000309 return reference::gemmlowp_quantize_down_scale_by_fixedpoint<int32_t, TW>(output, bias,
310 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 +0000311 break;
312 default:
313 ARM_COMPUTE_ERROR("Not Supported!");
314 }
315 }
316
Manuel Bottini959c26d2019-12-02 16:22:35 +0000317 TensorType _target{};
318 SimpleTensor<TI> _reference{};
George Wort2d7e6832019-02-22 16:37:41 +0000319};
320
Giorgio Arena5f6fdc12021-06-09 15:23:06 +0100321template <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>
322class GEMMLowpMatrixMultiplyCoreFusedOffsetOutputValidationFixture : public
323 GEMMLowpMatrixMultiplyCoreFusedOffsetOutputGenericValidationFixture<TensorType, AccessorType, FunctionType, reinterpret_input_as_3d, reinterpret_output_as_3d, TI, TW>
324{
325public:
326 template <typename...>
327 void setup(TensorShape shape_a, TensorShape shape_b, TensorShape shape_output, int32_t a_offset, int32_t b_offset, GEMMLowpOutputStageInfo output_stage, DataType data_type_b)
328 {
329 GEMMLowpMatrixMultiplyCoreFusedOffsetOutputGenericValidationFixture<TensorType, AccessorType, FunctionType, reinterpret_input_as_3d, reinterpret_output_as_3d, TI, TW>::setup(shape_a, shape_b,
330 shape_output, a_offset, b_offset, output_stage, data_type_b, false);
331 }
332};
333
Gian Marcoe75a02b2017-11-08 12:24:09 +0000334template <typename TensorType, typename AccessorType, typename FunctionType>
335class GEMMLowpQuantizeDownInt32ToUint8ScaleValidationFixture : public framework::Fixture
336{
337public:
338 template <typename...>
Gian Marco6b77e912017-11-17 09:27:57 +0000339 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 +0000340 {
Gian Marco6b77e912017-11-17 09:27:57 +0000341 _target = compute_target(shape, result_offset, result_mult_int, result_shift, min, max, add_bias);
342 _reference = compute_reference(shape, result_offset, result_mult_int, result_shift, min, max, add_bias);
Gian Marcoe75a02b2017-11-08 12:24:09 +0000343 }
344
345protected:
346 template <typename U>
347 void fill(U &&tensor, int i)
348 {
349 std::uniform_int_distribution<> distribution(-6000, 6000);
350 library->fill(tensor, distribution, i);
351 }
352
Gian Marco6b77e912017-11-17 09:27:57 +0000353 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 +0000354 {
Gian Marco6b77e912017-11-17 09:27:57 +0000355 TensorShape shape_bias(shape[0]);
356
Gian Marcoe75a02b2017-11-08 12:24:09 +0000357 // Create tensors
358 TensorType a = create_tensor<TensorType>(shape, DataType::S32, 1);
Gian Marco6b77e912017-11-17 09:27:57 +0000359 TensorType b = create_tensor<TensorType>(shape_bias, DataType::S32, 1);
360 TensorType c = create_tensor<TensorType>(shape, DataType::QASYMM8, 1);
Gian Marcoe75a02b2017-11-08 12:24:09 +0000361
362 // Create and configure function
Luca Foschiani4b869532020-02-13 15:07:36 +0000363 FunctionType output_stage;
364 GEMMLowpOutputStageInfo output_stage_info = GEMMLowpOutputStageInfo();
365 output_stage_info.type = GEMMLowpOutputStageType::QUANTIZE_DOWN;
366 output_stage_info.gemmlowp_offset = result_offset;
367 output_stage_info.gemmlowp_multiplier = result_mult_int;
368 output_stage_info.gemmlowp_shift = result_shift;
369 output_stage_info.gemmlowp_min_bound = min;
370 output_stage_info.gemmlowp_max_bound = max;
371 output_stage_info.output_data_type = DataType::QASYMM8;
372 output_stage.configure(&a, add_bias ? &b : nullptr, &c, output_stage_info);
Gian Marcoe75a02b2017-11-08 12:24:09 +0000373
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100374 ARM_COMPUTE_ASSERT(a.info()->is_resizable());
375 ARM_COMPUTE_ASSERT(c.info()->is_resizable());
Gian Marcoe75a02b2017-11-08 12:24:09 +0000376
377 // Allocate tensors
378 a.allocator()->allocate();
Gian Marco6b77e912017-11-17 09:27:57 +0000379 c.allocator()->allocate();
Gian Marcoe75a02b2017-11-08 12:24:09 +0000380
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100381 ARM_COMPUTE_ASSERT(!a.info()->is_resizable());
382 ARM_COMPUTE_ASSERT(!c.info()->is_resizable());
Gian Marcoe75a02b2017-11-08 12:24:09 +0000383
Gian Marco6b77e912017-11-17 09:27:57 +0000384 // Fill tensor
Gian Marcoe75a02b2017-11-08 12:24:09 +0000385 fill(AccessorType(a), 0);
386
Gian Marco6b77e912017-11-17 09:27:57 +0000387 if(add_bias)
388 {
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100389 ARM_COMPUTE_ASSERT(b.info()->is_resizable());
Gian Marco6b77e912017-11-17 09:27:57 +0000390
391 // Allocate bias tensor
392 b.allocator()->allocate();
393
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100394 ARM_COMPUTE_ASSERT(!b.info()->is_resizable());
Gian Marco6b77e912017-11-17 09:27:57 +0000395
396 // Fill tensor
397 fill(AccessorType(b), 1);
398 }
399
Gian Marcoe75a02b2017-11-08 12:24:09 +0000400 // Compute GEMM function
401 output_stage.run();
Gian Marco6b77e912017-11-17 09:27:57 +0000402 return c;
Gian Marcoe75a02b2017-11-08 12:24:09 +0000403 }
404
Gian Marco6b77e912017-11-17 09:27:57 +0000405 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 +0000406 {
407 // Create reference
Gian Marco6b77e912017-11-17 09:27:57 +0000408 TensorShape shape_bias(shape[0]);
409
Gian Marcoe75a02b2017-11-08 12:24:09 +0000410 SimpleTensor<int32_t> a{ shape, DataType::S32, 1 };
Gian Marco6b77e912017-11-17 09:27:57 +0000411 SimpleTensor<int32_t> b{ shape_bias, DataType::S32, 1 };
Gian Marcoe75a02b2017-11-08 12:24:09 +0000412
413 // Fill reference
414 fill(a, 0);
415
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +0000416 const std::vector<int32_t> result_mult_int_vec = { result_mult_int };
417 const std::vector<int32_t> result_shift_vec = { result_shift };
418
Gian Marco6b77e912017-11-17 09:27:57 +0000419 if(add_bias)
420 {
421 // Fill bias
422 fill(b, 1);
423
Manuel Bottini959c26d2019-12-02 16:22:35 +0000424 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 +0000425 }
426 else
427 {
Manuel Bottini959c26d2019-12-02 16:22:35 +0000428 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 +0000429 }
Gian Marcoe75a02b2017-11-08 12:24:09 +0000430 }
431
432 TensorType _target{};
433 SimpleTensor<uint8_t> _reference{};
434};
Gian Marco58c57942017-11-28 09:10:03 +0000435
436template <typename TensorType, typename AccessorType, typename FunctionType>
Luca Foschiani4b869532020-02-13 15:07:36 +0000437class GEMMLowpQuantizeDownInt32ToInt8ScaleValidationFixture : public framework::Fixture
438{
439public:
440 template <typename...>
441 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)
442 {
443 _target = compute_target(shape, result_offset, result_mult_int, result_shift, min, max, add_bias);
444 _reference = compute_reference(shape, result_offset, result_mult_int, result_shift, min, max, add_bias);
445 }
446
447protected:
448 template <typename U>
449 void fill(U &&tensor, int i)
450 {
451 std::uniform_int_distribution<> distribution(-6000, 6000);
452 library->fill(tensor, distribution, i);
453 }
454
455 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)
456 {
457 TensorShape shape_bias(shape[0]);
458
459 // Create tensors
460 TensorType a = create_tensor<TensorType>(shape, DataType::S32, 1);
461 TensorType b = create_tensor<TensorType>(shape_bias, DataType::S32, 1);
462 TensorType c = create_tensor<TensorType>(shape, DataType::QASYMM8_SIGNED, 1);
463
464 // Create and configure function
465 FunctionType output_stage;
466 GEMMLowpOutputStageInfo output_stage_info = GEMMLowpOutputStageInfo();
467 output_stage_info.type = GEMMLowpOutputStageType::QUANTIZE_DOWN;
468 output_stage_info.gemmlowp_offset = result_offset;
469 output_stage_info.gemmlowp_multiplier = result_mult_int;
470 output_stage_info.gemmlowp_shift = result_shift;
471 output_stage_info.gemmlowp_min_bound = min;
472 output_stage_info.gemmlowp_max_bound = max;
473 output_stage_info.output_data_type = DataType::QASYMM8_SIGNED;
474 output_stage.configure(&a, add_bias ? &b : nullptr, &c, output_stage_info);
475
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100476 ARM_COMPUTE_ASSERT(a.info()->is_resizable());
477 ARM_COMPUTE_ASSERT(c.info()->is_resizable());
Luca Foschiani4b869532020-02-13 15:07:36 +0000478
479 // Allocate tensors
480 a.allocator()->allocate();
481 c.allocator()->allocate();
482
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100483 ARM_COMPUTE_ASSERT(!a.info()->is_resizable());
484 ARM_COMPUTE_ASSERT(!c.info()->is_resizable());
Luca Foschiani4b869532020-02-13 15:07:36 +0000485
486 // Fill tensor
487 fill(AccessorType(a), 0);
488
489 if(add_bias)
490 {
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100491 ARM_COMPUTE_ASSERT(b.info()->is_resizable());
Luca Foschiani4b869532020-02-13 15:07:36 +0000492
493 // Allocate bias tensor
494 b.allocator()->allocate();
495
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100496 ARM_COMPUTE_ASSERT(!b.info()->is_resizable());
Luca Foschiani4b869532020-02-13 15:07:36 +0000497
498 // Fill tensor
499 fill(AccessorType(b), 1);
500 }
501
502 // Compute GEMM function
503 output_stage.run();
504 return c;
505 }
506
507 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)
508 {
509 // Create reference
510 TensorShape shape_bias(shape[0]);
511
512 SimpleTensor<int32_t> a{ shape, DataType::S32, 1 };
513 SimpleTensor<int32_t> b{ shape_bias, DataType::S32, 1 };
514
515 // Fill reference
516 fill(a, 0);
517
518 const std::vector<int32_t> result_mult_int_vec = { result_mult_int };
519 const std::vector<int32_t> result_shift_vec = { result_shift };
520
521 if(add_bias)
522 {
523 // Fill bias
524 fill(b, 1);
525
526 return reference::gemmlowp_quantize_down_scale<int32_t, int8_t>(a, b, result_offset, result_mult_int_vec, result_shift_vec, min, max);
527 }
528 else
529 {
530 return reference::gemmlowp_quantize_down_scale<int32_t, int8_t>(a, result_offset, result_mult_int_vec, result_shift_vec, min, max);
531 }
532 }
533
534 TensorType _target{};
535 SimpleTensor<int8_t> _reference{};
536};
537
538template <typename TensorType, typename AccessorType, typename FunctionType>
Georgios Pinitas448a81f2019-11-21 14:10:25 +0000539class GEMMLowpQuantizeDownInt32ToInt8ScaleByFixedPointValidationFixture : public framework::Fixture
540{
541public:
542 template <typename...>
543 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)
544 {
545 _target = compute_target(shape, result_fixedpoint_multiplier, result_shift, result_offset_after_shift, min, max, add_bias);
546 _reference = compute_reference(shape, result_fixedpoint_multiplier, result_shift, result_offset_after_shift, min, max, add_bias);
547 }
548
549protected:
550 template <typename U>
551 void fill(U &&tensor, int i)
552 {
553 std::uniform_int_distribution<> distribution(-6000, 6000);
554 library->fill(tensor, distribution, i);
555 }
556
557 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)
558 {
559 TensorShape shape_bias(shape[0]);
560
561 // Create tensors
562 TensorType a = create_tensor<TensorType>(shape, DataType::S32, 1);
563 TensorType b = create_tensor<TensorType>(shape_bias, DataType::S32, 1);
564 TensorType c = create_tensor<TensorType>(shape, DataType::QASYMM8_SIGNED, 1);
565
566 // Create and configure function
567 FunctionType output_stage;
568 output_stage.configure(&a, add_bias ? &b : nullptr, &c, result_fixedpoint_multiplier, result_shift, result_offset_after_shift, min, max);
569
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100570 ARM_COMPUTE_ASSERT(a.info()->is_resizable());
571 ARM_COMPUTE_ASSERT(c.info()->is_resizable());
Georgios Pinitas448a81f2019-11-21 14:10:25 +0000572
573 // Allocate tensors
574 a.allocator()->allocate();
575 c.allocator()->allocate();
576
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100577 ARM_COMPUTE_ASSERT(!a.info()->is_resizable());
578 ARM_COMPUTE_ASSERT(!c.info()->is_resizable());
Georgios Pinitas448a81f2019-11-21 14:10:25 +0000579
580 // Fill tensor
581 fill(AccessorType(a), 0);
582
583 if(add_bias)
584 {
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100585 ARM_COMPUTE_ASSERT(b.info()->is_resizable());
Georgios Pinitas448a81f2019-11-21 14:10:25 +0000586
587 // Allocate bias tensor
588 b.allocator()->allocate();
589
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100590 ARM_COMPUTE_ASSERT(!b.info()->is_resizable());
Georgios Pinitas448a81f2019-11-21 14:10:25 +0000591
592 // Fill tensor
593 fill(AccessorType(b), 1);
594 }
595
596 // Compute GEMM function
597 output_stage.run();
598 return c;
599 }
600
601 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,
602 bool add_bias)
603 {
604 // Create reference
605 TensorShape shape_bias(shape[0]);
606
607 SimpleTensor<int32_t> a{ shape, DataType::S32, 1 };
608 SimpleTensor<int32_t> b{ shape_bias, DataType::S32, 1 };
609
610 // Fill reference
611 fill(a, 0);
612
613 const std::vector<int32_t> result_fixed_point_multiplier_vec = { result_fixed_point_multiplier };
614 const std::vector<int32_t> result_shift_vec = { result_shift };
615
616 if(add_bias)
617 {
618 // Fill bias
619 fill(b, 1);
620
621 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);
622 }
623 else
624 {
625 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);
626 }
627 }
628
629 TensorType _target{};
630 SimpleTensor<int8_t> _reference{};
631};
632
633template <typename TensorType, typename AccessorType, typename FunctionType>
Gian Marco58c57942017-11-28 09:10:03 +0000634class GEMMLowpQuantizeDownInt32ToUint8ScaleByFixedPointValidationFixture : public framework::Fixture
635{
636public:
637 template <typename...>
638 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)
639 {
640 _target = compute_target(shape, result_fixedpoint_multiplier, result_shift, result_offset_after_shift, min, max, add_bias);
641 _reference = compute_reference(shape, result_fixedpoint_multiplier, result_shift, result_offset_after_shift, min, max, add_bias);
642 }
643
644protected:
645 template <typename U>
646 void fill(U &&tensor, int i)
647 {
648 std::uniform_int_distribution<> distribution(-6000, 6000);
649 library->fill(tensor, distribution, i);
650 }
651
652 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)
653 {
654 TensorShape shape_bias(shape[0]);
655
656 // Create tensors
657 TensorType a = create_tensor<TensorType>(shape, DataType::S32, 1);
658 TensorType b = create_tensor<TensorType>(shape_bias, DataType::S32, 1);
659 TensorType c = create_tensor<TensorType>(shape, DataType::QASYMM8, 1);
660
661 // Create and configure function
662 FunctionType output_stage;
663 output_stage.configure(&a, add_bias ? &b : nullptr, &c, result_fixedpoint_multiplier, result_shift, result_offset_after_shift, min, max);
664
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100665 ARM_COMPUTE_ASSERT(a.info()->is_resizable());
666 ARM_COMPUTE_ASSERT(c.info()->is_resizable());
Gian Marco58c57942017-11-28 09:10:03 +0000667
668 // Allocate tensors
669 a.allocator()->allocate();
670 c.allocator()->allocate();
671
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100672 ARM_COMPUTE_ASSERT(!a.info()->is_resizable());
673 ARM_COMPUTE_ASSERT(!c.info()->is_resizable());
Gian Marco58c57942017-11-28 09:10:03 +0000674
675 // Fill tensor
676 fill(AccessorType(a), 0);
677
678 if(add_bias)
679 {
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100680 ARM_COMPUTE_ASSERT(b.info()->is_resizable());
Gian Marco58c57942017-11-28 09:10:03 +0000681
682 // Allocate bias tensor
683 b.allocator()->allocate();
684
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100685 ARM_COMPUTE_ASSERT(!b.info()->is_resizable());
Gian Marco58c57942017-11-28 09:10:03 +0000686
687 // Fill tensor
688 fill(AccessorType(b), 1);
689 }
690
691 // Compute GEMM function
692 output_stage.run();
693 return c;
694 }
695
696 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,
697 bool add_bias)
698 {
699 // Create reference
700 TensorShape shape_bias(shape[0]);
701
702 SimpleTensor<int32_t> a{ shape, DataType::S32, 1 };
703 SimpleTensor<int32_t> b{ shape_bias, DataType::S32, 1 };
704
705 // Fill reference
706 fill(a, 0);
707
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +0000708 const std::vector<int32_t> result_fixed_point_multiplier_vec = { result_fixed_point_multiplier };
709 const std::vector<int32_t> result_shift_vec = { result_shift };
710
Gian Marco58c57942017-11-28 09:10:03 +0000711 if(add_bias)
712 {
713 // Fill bias
714 fill(b, 1);
715
Georgios Pinitas448a81f2019-11-21 14:10:25 +0000716 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 +0000717 }
718 else
719 {
Georgios Pinitas448a81f2019-11-21 14:10:25 +0000720 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 +0000721 }
722 }
723
724 TensorType _target{};
725 SimpleTensor<uint8_t> _reference{};
726};
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +0000727
Sheri Zhang1b14c752020-03-09 14:29:52 +0000728template <typename TensorType, typename AccessorType, typename FunctionType, typename T>
729class GEMMLowpQuantizeDownInt32ScaleByFloatValidationFixture : public framework::Fixture
730{
731public:
732 template <typename...>
733 void setup(DataType data_type, TensorShape shape, float result_real_multiplier, int32_t result_offset, int32_t min, int32_t max, bool add_bias)
734 {
735 _target = compute_target(data_type, shape, result_real_multiplier, result_offset, min, max, add_bias);
736 _reference = compute_reference(shape, result_real_multiplier, result_offset, min, max, add_bias);
737 }
738
739protected:
740 template <typename U>
741 void fill(U &&tensor, int i)
742 {
743 // To avoid data all being clampped
744 std::uniform_int_distribution<> distribution(-500, 500);
745 library->fill(tensor, distribution, i);
746 }
747
748 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)
749 {
750 TensorShape shape_bias(shape[0]);
751
752 // Create tensors
753 TensorType a = create_tensor<TensorType>(shape, DataType::S32, 1);
754 TensorType b = create_tensor<TensorType>(shape_bias, DataType::S32, 1);
755 TensorType c = create_tensor<TensorType>(shape, data_type, 1);
756
757 // create output stage info
758 GEMMLowpOutputStageInfo info;
759 info.gemmlowp_max_bound = max;
760 info.gemmlowp_min_bound = min;
761 info.gemmlowp_real_multiplier = result_multiplier;
762 info.gemmlowp_offset = result_offset;
763 info.type = GEMMLowpOutputStageType::QUANTIZE_DOWN_FLOAT;
764 info.output_data_type = data_type;
765
766 // Create and configure function
767 FunctionType output_stage;
768 output_stage.configure(&a, add_bias ? &b : nullptr, &c, info);
769
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100770 ARM_COMPUTE_ASSERT(a.info()->is_resizable());
771 ARM_COMPUTE_ASSERT(c.info()->is_resizable());
Sheri Zhang1b14c752020-03-09 14:29:52 +0000772
773 // Allocate tensors
774 a.allocator()->allocate();
775 c.allocator()->allocate();
776
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100777 ARM_COMPUTE_ASSERT(!a.info()->is_resizable());
778 ARM_COMPUTE_ASSERT(!c.info()->is_resizable());
Sheri Zhang1b14c752020-03-09 14:29:52 +0000779
780 // Fill tensor
781 fill(AccessorType(a), 0);
782
783 if(add_bias)
784 {
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100785 ARM_COMPUTE_ASSERT(b.info()->is_resizable());
Sheri Zhang1b14c752020-03-09 14:29:52 +0000786
787 // Allocate bias tensor
788 b.allocator()->allocate();
789
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100790 ARM_COMPUTE_ASSERT(!b.info()->is_resizable());
Sheri Zhang1b14c752020-03-09 14:29:52 +0000791
792 // Fill tensor
793 fill(AccessorType(b), 1);
794 }
795
796 // Compute GEMM function
797 output_stage.run();
798 return c;
799 }
800
801 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)
802 {
803 // Create reference
804 TensorShape shape_bias(shape[0]);
805
806 SimpleTensor<int32_t> a{ shape, DataType::S32, 1 };
807 SimpleTensor<int32_t> b{ shape_bias, DataType::S32, 1 };
808
809 // Fill reference
810 fill(a, 0);
811
812 const std::vector<float_t> result_float_multiplier_vec = { result_real_multiplier };
813
814 if(add_bias)
815 {
816 // Fill bias
817 fill(b, 1);
818
819 return reference::gemmlowp_quantize_down_scale_by_float<int32_t, T>(a, b, result_float_multiplier_vec, result_offset, min, max);
820 }
821 else
822 {
823 return reference::gemmlowp_quantize_down_scale_by_float<int32_t, T>(a, result_float_multiplier_vec, result_offset, min, max);
824 }
825 }
826
827 TensorType _target{};
828 SimpleTensor<T> _reference{};
829};
830
Gian Marco Iodicebc415af2019-06-13 15:58:32 +0100831template <typename TensorType, typename AccessorType, typename FunctionType>
832class GEMMLowpQuantizeDownInt32ToInt16ScaleByFixedPointValidationFixture : public framework::Fixture
833{
834public:
835 template <typename...>
836 void setup(TensorShape shape, int32_t result_fixedpoint_multiplier, int32_t result_shift, int32_t min, int32_t max, bool add_bias)
837 {
838 _target = compute_target(shape, result_fixedpoint_multiplier, result_shift, min, max, add_bias);
839 _reference = compute_reference(shape, result_fixedpoint_multiplier, result_shift, min, max, add_bias);
840 }
841
842protected:
843 template <typename U>
844 void fill(U &&tensor, int i)
845 {
846 std::uniform_int_distribution<> distribution(-6000, 6000);
847 library->fill(tensor, distribution, i);
848 }
849
850 TensorType compute_target(const TensorShape &shape, int32_t result_fixedpoint_multiplier, int32_t result_shift, int32_t min, int32_t max, bool add_bias)
851 {
852 TensorShape shape_bias(shape[0]);
853
854 // Create tensors
855 TensorType a = create_tensor<TensorType>(shape, DataType::S32, 1);
856 TensorType b = create_tensor<TensorType>(shape_bias, DataType::S32, 1);
857 TensorType c = create_tensor<TensorType>(shape, DataType::QSYMM16, 1);
858
859 // Create and configure function
860 FunctionType output_stage;
861 output_stage.configure(&a, add_bias ? &b : nullptr, &c, result_fixedpoint_multiplier, result_shift, min, max);
862
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100863 ARM_COMPUTE_ASSERT(a.info()->is_resizable());
864 ARM_COMPUTE_ASSERT(c.info()->is_resizable());
Gian Marco Iodicebc415af2019-06-13 15:58:32 +0100865
866 // Allocate tensors
867 a.allocator()->allocate();
868 c.allocator()->allocate();
869
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100870 ARM_COMPUTE_ASSERT(!a.info()->is_resizable());
871 ARM_COMPUTE_ASSERT(!c.info()->is_resizable());
Gian Marco Iodicebc415af2019-06-13 15:58:32 +0100872
873 // Fill tensor
874 fill(AccessorType(a), 0);
875
876 if(add_bias)
877 {
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100878 ARM_COMPUTE_ASSERT(b.info()->is_resizable());
Gian Marco Iodicebc415af2019-06-13 15:58:32 +0100879
880 // Allocate bias tensor
881 b.allocator()->allocate();
882
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100883 ARM_COMPUTE_ASSERT(!b.info()->is_resizable());
Gian Marco Iodicebc415af2019-06-13 15:58:32 +0100884
885 // Fill tensor
886 fill(AccessorType(b), 1);
887 }
888
889 // Compute GEMM function
890 output_stage.run();
891 return c;
892 }
893
894 SimpleTensor<int16_t> compute_reference(const TensorShape &shape, int32_t result_fixed_point_multiplier, int32_t result_shift, int32_t min, int32_t max,
895 bool add_bias)
896 {
897 // Create reference
898 TensorShape shape_bias(shape[0]);
899
900 SimpleTensor<int32_t> a{ shape, DataType::S32, 1 };
901 SimpleTensor<int32_t> b{ shape_bias, DataType::S32, 1 };
902
903 // Fill reference
904 fill(a, 0);
905
Georgios Pinitas448a81f2019-11-21 14:10:25 +0000906 const std::vector<int32_t> result_fixed_point_multiplier_vec = { result_fixed_point_multiplier };
907 const std::vector<int32_t> result_shift_vec = { result_shift };
908
Gian Marco Iodicebc415af2019-06-13 15:58:32 +0100909 if(add_bias)
910 {
911 // Fill bias
912 fill(b, 1);
913
Georgios Pinitas448a81f2019-11-21 14:10:25 +0000914 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 +0100915 }
916 else
917 {
Georgios Pinitas448a81f2019-11-21 14:10:25 +0000918 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 +0100919 }
920 }
921
922 TensorType _target{};
923 SimpleTensor<int16_t> _reference{};
924};
925
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100926template <typename TensorType, typename AccessorType, typename ReshapeLHSOperatorType, typename ReshapeRHSOperatorType, typename GEMMFunctionType>
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +0000927class GEMMLowpMatrixMultiplyReshapedValidationFixture : public framework::Fixture
928{
929public:
930 template <typename...>
931 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 +0000932 bool interleave_rhs, DataType data_type)
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +0000933 {
934 GEMMLHSMatrixInfo lhs_info;
935 lhs_info.m0 = m0;
936 lhs_info.k0 = k0;
937 lhs_info.v0 = v0;
938 lhs_info.interleave = interleave_lhs;
939 lhs_info.transpose = false;
940
941 GEMMRHSMatrixInfo rhs_info;
942 rhs_info.n0 = n0;
943 rhs_info.k0 = k0;
944 rhs_info.h0 = h0;
945 rhs_info.interleave = interleave_rhs;
946 rhs_info.transpose = true;
947
948 // Set the tensor shapes for LHS and RHS matrices
949 const TensorShape lhs_shape(k, m, batch_size);
950 const TensorShape rhs_shape(n, k, batch_size);
951
Sheri Zhang28287af2020-02-25 14:13:54 +0000952 _target = compute_target(lhs_shape, rhs_shape, lhs_info, rhs_info, data_type);
953 _reference = compute_reference(lhs_shape, rhs_shape, data_type);
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +0000954 }
955
956protected:
957 template <typename U>
958 void fill(U &&tensor, int i)
959 {
Sheri Zhang28287af2020-02-25 14:13:54 +0000960 switch(tensor.data_type())
961 {
962 case DataType::QASYMM8:
963 {
964 // Between 1 and 254 in order to avoid having -128 and 128 for the DOT product path
965 std::uniform_int_distribution<> distribution(1, 254);
966 library->fill(tensor, distribution, i);
967 }
968 break;
969 case DataType::QASYMM8_SIGNED:
970 {
971 std::uniform_int_distribution<> distribution(-127, 126);
972 library->fill(tensor, distribution, i);
973 }
974 break;
975 default:
976 ARM_COMPUTE_ERROR("Unsupported data type");
977 }
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +0000978 }
979
Sheri Zhang28287af2020-02-25 14:13:54 +0000980 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 +0000981 {
982 // Create tensors
Sheri Zhang28287af2020-02-25 14:13:54 +0000983 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
984 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +0000985 TensorType lhs_reshaped;
986 TensorType rhs_reshaped;
987 TensorType dst;
988
989 const unsigned int M = lhs_shape[1];
990 const unsigned int N = rhs_shape[0];
991 const unsigned int K = lhs_shape[0];
992
993 // The output tensor will be auto-initialized within the function
994
995 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100996 ReshapeLHSOperatorType reshape_lhs;
997 ReshapeRHSOperatorType reshape_rhs;
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +0000998 GEMMFunctionType gemm;
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100999 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
1000 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
Georgios Pinitas4a578b92021-06-25 12:13:49 +01001001 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 +00001002
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001003 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1004 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001005
Giorgio Arena63825e82021-03-25 14:54:50 +00001006 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &dst });
1007
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001008 // Allocate tensors
1009 lhs.allocator()->allocate();
1010 rhs.allocator()->allocate();
1011 lhs_reshaped.allocator()->allocate();
1012 rhs_reshaped.allocator()->allocate();
1013 dst.allocator()->allocate();
1014
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001015 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1016 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1017 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
1018 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1019 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001020
1021 // Fill tensors
1022 fill(AccessorType(lhs), 0);
1023 fill(AccessorType(rhs), 1);
1024
1025 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001026 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
1027 reshape_lhs.run(reshape_lhs_pack);
1028 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1029 reshape_rhs.run(reshape_rhs_pack);
Georgios Pinitas4a578b92021-06-25 12:13:49 +01001030 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped }, { ACL_SRC_1, &rhs_reshaped }, { ACL_DST, &dst } });
1031 gemm.run(gemm_pack);
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001032
1033 return dst;
1034 }
1035
Sheri Zhang28287af2020-02-25 14:13:54 +00001036 SimpleTensor<int32_t> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type)
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001037 {
1038 TensorShape dst_shape = lhs_shape;
1039 dst_shape[0] = rhs_shape[0];
1040 dst_shape[1] = lhs_shape[1];
1041
Sheri Zhang28287af2020-02-25 14:13:54 +00001042 switch(data_type)
1043 {
1044 case DataType::QASYMM8:
1045 {
1046 // Create reference
1047 SimpleTensor<uint8_t> lhs{ lhs_shape, data_type, 1 };
1048 SimpleTensor<uint8_t> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001049
Sheri Zhang28287af2020-02-25 14:13:54 +00001050 // Fill reference
1051 fill(lhs, 0);
1052 fill(rhs, 1);
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001053
Sheri Zhang28287af2020-02-25 14:13:54 +00001054 return reference::gemmlowp_matrix_multiply_core<int32_t, uint8_t>(lhs, rhs, dst_shape, 0, 0);
1055 }
1056 case DataType::QASYMM8_SIGNED:
1057 {
1058 // Create reference
1059 SimpleTensor<int8_t> lhs{ lhs_shape, data_type, 1 };
1060 SimpleTensor<int8_t> rhs{ rhs_shape, data_type, 1 };
1061
1062 // Fill reference
1063 fill(lhs, 0);
1064 fill(rhs, 1);
1065
1066 return reference::gemmlowp_matrix_multiply_core<int32_t, int8_t>(lhs, rhs, dst_shape, 0, 0);
1067 }
1068 default:
1069 ARM_COMPUTE_ERROR("Unsupported data type");
1070 }
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001071 }
1072
1073 TensorType _target{};
1074 SimpleTensor<int32_t> _reference{};
1075};
1076
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001077template <typename TensorType, typename AccessorType, typename ReshapeLHSOperatorType, typename ReshapeRHSOperatorType, typename GEMMFunctionType>
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001078class GEMMLowpMatrixMultiplyReshaped3DValidationFixture : public framework::Fixture
1079{
1080public:
1081 template <typename...>
1082 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 +00001083 bool interleave_lhs, bool interleave_rhs, DataType data_type)
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001084 {
1085 GEMMLHSMatrixInfo lhs_info;
1086 lhs_info.m0 = m0;
1087 lhs_info.k0 = k0;
1088 lhs_info.v0 = v0;
1089 lhs_info.interleave = interleave_lhs;
1090 lhs_info.transpose = false;
1091
1092 GEMMRHSMatrixInfo rhs_info;
1093 rhs_info.n0 = n0;
1094 rhs_info.k0 = k0;
1095 rhs_info.h0 = h0;
1096 rhs_info.interleave = interleave_rhs;
1097 rhs_info.transpose = true;
1098
1099 // In case of GEMM3D, m is the product between m_w and m_h
1100 const unsigned int m = m_w * m_h;
1101
1102 // Set the tensor shapes for LHS and RHS matrices
1103 const TensorShape lhs_shape(k, m, batch_size);
1104 const TensorShape rhs_shape(n, k, batch_size);
1105
Sheri Zhang28287af2020-02-25 14:13:54 +00001106 _target = compute_target(lhs_shape, rhs_shape, lhs_info, rhs_info, m_h, data_type);
1107 _reference = compute_reference(lhs_shape, rhs_shape, m_h, data_type);
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001108 }
1109
1110protected:
1111 template <typename U>
1112 void fill(U &&tensor, int i)
1113 {
Sheri Zhang28287af2020-02-25 14:13:54 +00001114 switch(tensor.data_type())
1115 {
1116 case DataType::QASYMM8:
1117 {
1118 // Between 1 and 254 in order to avoid having -128 and 128 for the DOT product path
1119 std::uniform_int_distribution<> distribution(1, 254);
1120 library->fill(tensor, distribution, i);
1121 }
1122 break;
1123 case DataType::QASYMM8_SIGNED:
1124 {
1125 std::uniform_int_distribution<> distribution(-127, 126);
1126 library->fill(tensor, distribution, i);
1127 }
1128 break;
1129 default:
1130 ARM_COMPUTE_ERROR("Unsupported data type");
1131 }
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001132 }
1133
Sheri Zhang28287af2020-02-25 14:13:54 +00001134 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info, unsigned int m_h,
1135 DataType data_type)
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001136 {
1137 // Create tensors
Sheri Zhang28287af2020-02-25 14:13:54 +00001138 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1139 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001140 TensorType lhs_reshaped;
1141 TensorType rhs_reshaped;
1142 TensorType dst;
1143
1144 const unsigned int M = lhs_shape[1];
1145 const unsigned int N = rhs_shape[0];
1146 const unsigned int K = lhs_shape[0];
1147
1148 // The output tensor will be auto-initialized within the function
1149
1150 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001151 ReshapeLHSOperatorType reshape_lhs;
1152 ReshapeRHSOperatorType reshape_rhs;
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001153 GEMMFunctionType gemm;
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001154 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
1155 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
Georgios Pinitas4a578b92021-06-25 12:13:49 +01001156 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 +00001157
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001158 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1159 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001160
Giorgio Arena63825e82021-03-25 14:54:50 +00001161 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &dst });
1162
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001163 // Allocate tensors
1164 lhs.allocator()->allocate();
1165 rhs.allocator()->allocate();
1166 lhs_reshaped.allocator()->allocate();
1167 rhs_reshaped.allocator()->allocate();
1168 dst.allocator()->allocate();
1169
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001170 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1171 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1172 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
1173 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1174 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001175
1176 // Fill tensors
1177 fill(AccessorType(lhs), 0);
1178 fill(AccessorType(rhs), 1);
1179
1180 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001181 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
1182 reshape_lhs.run(reshape_lhs_pack);
1183 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1184 reshape_rhs.run(reshape_rhs_pack);
Georgios Pinitas4a578b92021-06-25 12:13:49 +01001185 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped }, { ACL_SRC_1, &rhs_reshaped }, { ACL_DST, &dst } });
1186 gemm.run(gemm_pack);
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001187
1188 return dst;
1189 }
1190
Sheri Zhang28287af2020-02-25 14:13:54 +00001191 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 +00001192 {
1193 TensorShape dst_shape = lhs_shape;
1194 dst_shape.set(0, rhs_shape[0]);
1195 dst_shape.set(1, lhs_shape[1] / m_h);
1196 dst_shape.set(2, m_h);
1197 dst_shape.set(3, lhs_shape[2]);
1198
Sheri Zhang28287af2020-02-25 14:13:54 +00001199 switch(data_type)
1200 {
1201 case DataType::QASYMM8:
1202 {
1203 // Create reference
1204 SimpleTensor<uint8_t> lhs{ lhs_shape, data_type, 1 };
1205 SimpleTensor<uint8_t> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001206
Sheri Zhang28287af2020-02-25 14:13:54 +00001207 // Fill reference
1208 fill(lhs, 0);
1209 fill(rhs, 1);
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001210
Sheri Zhang28287af2020-02-25 14:13:54 +00001211 return reference::gemmlowp_matrix_multiply_core<int32_t, uint8_t>(lhs, rhs, dst_shape, 0, 0);
1212 }
1213 case DataType::QASYMM8_SIGNED:
1214 {
1215 // Create reference
1216 SimpleTensor<int8_t> lhs{ lhs_shape, data_type, 1 };
1217 SimpleTensor<int8_t> rhs{ rhs_shape, data_type, 1 };
1218
1219 // Fill reference
1220 fill(lhs, 0);
1221 fill(rhs, 1);
1222
1223 return reference::gemmlowp_matrix_multiply_core<int32_t, int8_t>(lhs, rhs, dst_shape, 0, 0);
1224 }
1225 default:
1226 ARM_COMPUTE_ERROR("Unsupported data type");
1227 }
Gian Marco Iodicedb63b9c2019-01-17 09:47:04 +00001228 }
1229
1230 TensorType _target{};
1231 SimpleTensor<int32_t> _reference{};
1232};
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001233
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001234template <typename TensorType, typename AccessorType, typename ReshapeRHSOperatorType, typename GEMMFunctionType>
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001235class GEMMLowpMatrixMultiplyReshapedOnlyRHSValidationFixture : public framework::Fixture
1236{
1237public:
1238 template <typename...>
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001239 void setup(unsigned int m, unsigned int n, unsigned int k, unsigned int batch_size, unsigned int m0, unsigned int n0,
1240 unsigned int k0, unsigned int h0, bool interleave_rhs, bool transpose_rhs, DataType data_type)
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001241 {
1242 GEMMLHSMatrixInfo lhs_info;
1243 lhs_info.m0 = m0;
1244 lhs_info.k0 = k0;
1245
1246 GEMMRHSMatrixInfo rhs_info;
1247 rhs_info.n0 = n0;
1248 rhs_info.k0 = k0;
1249 rhs_info.h0 = h0;
1250 rhs_info.interleave = interleave_rhs;
1251 rhs_info.transpose = transpose_rhs;
1252
1253 // Set the tensor shapes for LHS and RHS matrices
1254 const TensorShape lhs_shape(k, m, batch_size);
1255 const TensorShape rhs_shape(n, k, batch_size);
1256
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001257 _target = compute_target(lhs_shape, rhs_shape, lhs_info, rhs_info, data_type);
1258 _reference = compute_reference(lhs_shape, rhs_shape, data_type);
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001259 }
1260
1261protected:
1262 template <typename U>
1263 void fill(U &&tensor, int i)
1264 {
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001265 switch(tensor.data_type())
1266 {
1267 case DataType::QASYMM8:
1268 {
1269 // Between 1 and 254 in order to avoid having -128 and 128 for the DOT product path
1270 std::uniform_int_distribution<> distribution(1, 254);
1271 library->fill(tensor, distribution, i);
1272 }
1273 break;
1274 case DataType::QASYMM8_SIGNED:
1275 {
1276 std::uniform_int_distribution<> distribution(-127, 126);
1277 library->fill(tensor, distribution, i);
1278 }
1279 break;
1280 default:
1281 ARM_COMPUTE_ERROR("Unsupported data type");
1282 }
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001283 }
1284
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001285 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const GEMMLHSMatrixInfo &lhs_info,
1286 const GEMMRHSMatrixInfo &rhs_info, DataType data_type)
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001287 {
1288 // Create tensors
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001289 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1290 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001291 TensorType rhs_reshaped;
1292 TensorType dst;
1293
1294 const unsigned int M = lhs_shape[1];
1295 const unsigned int N = rhs_shape[0];
1296 const unsigned int K = lhs_shape[0];
1297
Michele Di Giorgiob54ba282020-01-14 15:31:55 +00001298 GEMMKernelInfo gemm_info;
1299 gemm_info.m = M;
1300 gemm_info.n = N;
1301 gemm_info.k = K;
1302 gemm_info.lhs_info = lhs_info;
1303 gemm_info.rhs_info = rhs_info;
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001304 // The output tensor will be auto-initialized within the function
1305
1306 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001307 ReshapeRHSOperatorType reshape_rhs;
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001308 GEMMFunctionType gemm;
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001309 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
Georgios Pinitas4a578b92021-06-25 12:13:49 +01001310 gemm.configure(lhs.info(), rhs_reshaped.info(), dst.info(), gemm_info);
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001311
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001312 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1313 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001314
Giorgio Arena63825e82021-03-25 14:54:50 +00001315 add_padding_x({ &lhs, &rhs, &rhs_reshaped, &dst });
1316
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001317 // Allocate tensors
1318 lhs.allocator()->allocate();
1319 rhs.allocator()->allocate();
1320 rhs_reshaped.allocator()->allocate();
1321 dst.allocator()->allocate();
1322
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001323 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1324 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1325 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1326 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001327
1328 // Fill tensors
1329 fill(AccessorType(lhs), 0);
1330 fill(AccessorType(rhs), 1);
1331
1332 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001333 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1334 reshape_rhs.run(reshape_rhs_pack);
Georgios Pinitas4a578b92021-06-25 12:13:49 +01001335 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs }, { ACL_SRC_1, &rhs_reshaped }, { ACL_DST, &dst } });
1336 gemm.run(gemm_pack);
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001337
1338 return dst;
1339 }
1340
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001341 SimpleTensor<int32_t> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type)
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001342 {
1343 TensorShape dst_shape = lhs_shape;
1344 dst_shape[0] = rhs_shape[0];
1345 dst_shape[1] = lhs_shape[1];
1346
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001347 if(data_type == DataType::QASYMM8)
1348 {
1349 // Create reference
1350 SimpleTensor<uint8_t> lhs{ lhs_shape, data_type, 1 };
1351 SimpleTensor<uint8_t> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001352
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001353 // Fill reference
1354 fill(lhs, 0);
1355 fill(rhs, 1);
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001356
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001357 return reference::gemmlowp_matrix_multiply_core<int32_t, uint8_t>(lhs, rhs, dst_shape, 0, 0);
1358 }
1359 else
1360 {
1361 // Create reference
1362 SimpleTensor<int8_t> lhs{ lhs_shape, data_type, 1 };
1363 SimpleTensor<int8_t> rhs{ rhs_shape, data_type, 1 };
1364
1365 // Fill reference
1366 fill(lhs, 0);
1367 fill(rhs, 1);
1368
1369 return reference::gemmlowp_matrix_multiply_core<int32_t, int8_t>(lhs, rhs, dst_shape, 0, 0);
1370 }
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001371 }
1372
1373 TensorType _target{};
1374 SimpleTensor<int32_t> _reference{};
1375};
1376
Freddie Liardete572dff2022-05-16 14:09:10 +01001377template <typename T, typename TensorType, typename AccessorType, typename ReshapeRHSOperatorType, typename GEMMFunctionType, typename ReduceOperation, typename CastOperation>
1378class GEMMLowpMatrixMultiplyReshapedOnlyRHSMMULOutputStageValidationFixture : public framework::Fixture
1379{
1380public:
1381 template <typename...>
1382 void setup(unsigned int m, unsigned int n, unsigned int k, unsigned int batch_size, unsigned int m0, unsigned int n0,
1383 unsigned int k0, unsigned int h0, bool interleave_rhs, bool transpose_rhs, bool broadcast_bias, DataType data_type)
1384 {
1385 GEMMLowpOutputStageInfo output_stage;
1386 output_stage.type = GEMMLowpOutputStageType::QUANTIZE_DOWN_FIXEDPOINT;
1387 output_stage.output_data_type = data_type;
1388 output_stage.gemmlowp_multipliers = std::vector<int32_t> { 1 };
1389 output_stage.gemmlowp_shifts = std::vector<int32_t> { 1 };
1390 output_stage.gemmlowp_multipliers[0] = 1;
1391 output_stage.gemmlowp_shifts[0] = 1;
1392 output_stage.gemmlowp_offset = 0;
1393 constexpr float scale = 0.001f;
1394 quantization::calculate_quantized_multiplier(scale, &output_stage.gemmlowp_multipliers[0], &output_stage.gemmlowp_shifts[0]);
1395 output_stage.gemmlowp_min_bound = -100;
1396 output_stage.gemmlowp_max_bound = 100;
1397
1398 GEMMLHSMatrixInfo lhs_info;
1399 lhs_info.m0 = m0;
1400 lhs_info.k0 = k0;
1401
1402 GEMMRHSMatrixInfo rhs_info;
1403 rhs_info.n0 = n0;
1404 rhs_info.k0 = k0;
1405 rhs_info.h0 = h0;
1406 rhs_info.interleave = interleave_rhs;
1407 rhs_info.transpose = transpose_rhs;
1408
1409 int a_offset = 1;
1410 int b_offset = 1;
1411
1412 // Set the tensor shapes for LHS and RHS matrices
1413 const TensorShape lhs_shape(k, m, batch_size);
1414 const TensorShape rhs_shape(n, k, batch_size);
1415 const TensorShape bias_shape(n,
1416 broadcast_bias ? 1 : m,
1417 broadcast_bias ? 1 : batch_size);
1418
Ramy Elgammala77c6d72022-09-08 11:30:08 +01001419 _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 +01001420 if(gemm_validated == true)
1421 {
1422 _reference = compute_reference(lhs_shape, rhs_shape, bias_shape, data_type, output_stage, a_offset, b_offset);
1423 }
1424 }
1425
1426protected:
1427 template <typename U>
1428 void fill(U &&tensor, int i)
1429 {
1430 switch(tensor.data_type())
1431 {
1432 case DataType::QASYMM8:
1433 {
1434 // Between 1 and 254 in order to avoid having -128 and 128 for the DOT product path
1435 std::uniform_int_distribution<> distribution(1, 254);
1436 library->fill(tensor, distribution, i);
1437 }
1438 break;
1439 case DataType::QASYMM8_SIGNED:
1440 {
1441 std::uniform_int_distribution<> distribution(-127, 126);
1442 library->fill(tensor, distribution, i);
1443 }
1444 break;
1445 case DataType::S32:
1446 {
1447 std::uniform_int_distribution<> distribution(-10000, 10000);
1448 library->fill(tensor, distribution, i);
1449 }
1450 break;
1451 default:
1452 ARM_COMPUTE_ERROR("Unsupported data type");
1453 }
1454 }
1455
1456 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info,
1457 const GEMMRHSMatrixInfo &rhs_info, DataType data_type, GEMMLowpOutputStageInfo output_stage, const int a_offset, const int b_offset)
1458 {
1459 // Create tensors
1460 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1, QuantizationInfo(1.0f / 255, a_offset));
1461 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1, QuantizationInfo(1.0f / 255, b_offset));
1462 TensorType bias = create_tensor<TensorType>(bias_shape, DataType::S32, 1);
1463 TensorType dst;
1464 TensorType rhs_reshaped;
1465
1466 const unsigned int M = lhs_shape[1];
1467 const unsigned int N = rhs_shape[0];
1468 const unsigned int K = lhs_shape[0];
1469
1470 // Tensors for precomputing sum of lhs rows / rhs columns
1471 TensorType vec_sum_rows = create_tensor<TensorType>(TensorShape(M, 1, lhs_shape[2]), DataType::S32, 1);
1472 TensorType vec_sum_cols = create_tensor<TensorType>(TensorShape(N, 1, rhs_shape[2]), DataType::S32, 1);
1473
1474 GEMMKernelInfo gemm_info;
1475 gemm_info.m = M;
1476 gemm_info.n = N;
1477 gemm_info.k = K;
1478 gemm_info.lhs_info = lhs_info;
1479 gemm_info.rhs_info = rhs_info;
1480 gemm_info.output_stage = output_stage;
1481 gemm_info.a_offset = a_offset;
1482 gemm_info.b_offset = b_offset;
1483 // The output tensor will be auto-initialized within the function
1484
1485 // Create and configure function
1486 ReshapeRHSOperatorType reshape_rhs;
1487 GEMMFunctionType gemm;
1488 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1489
1490 // If GEMM is not validated, do not try to run. The validation will check
1491 // if the technology supports this extension. If not, the test will be skipped.
1492 // If it supports, the test will fail anyway because target and reference
1493 // will not match.
1494 gemm_validated = bool(gemm.validate(lhs.info(), rhs_reshaped.info(), dst.info(), gemm_info, vec_sum_cols.info(), vec_sum_rows.info(), bias.info()));
1495 if(gemm_validated == true)
1496 {
1497 gemm.configure(lhs.info(), rhs_reshaped.info(), dst.info(), gemm_info, vec_sum_cols.info(), vec_sum_rows.info(), bias.info());
1498
1499 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1500 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1501 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
1502
1503 // Allocate tensors
1504 lhs.allocator()->allocate();
1505 rhs.allocator()->allocate();
1506 rhs_reshaped.allocator()->allocate();
1507 bias.allocator()->allocate();
1508 vec_sum_cols.allocator()->allocate();
1509 vec_sum_rows.allocator()->allocate();
1510 dst.allocator()->allocate();
1511
1512 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1513 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1514 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1515 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1516 ARM_COMPUTE_ASSERT(!vec_sum_cols.info()->is_resizable());
1517 ARM_COMPUTE_ASSERT(!vec_sum_rows.info()->is_resizable());
1518 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
1519
1520 // Fill tensors
1521 fill(AccessorType(lhs), 0);
1522 fill(AccessorType(rhs), 1);
1523 fill(AccessorType(bias), 2);
1524
1525 TensorType lhs_32 = create_tensor<TensorType>(lhs_shape, DataType::S32, 1);
1526 TensorType rhs_32 = create_tensor<TensorType>(rhs_shape, DataType::S32, 1);
1527 CastOperation cast_lhs;
1528 CastOperation cast_rhs;
1529 cast_lhs.configure(&lhs, &lhs_32, ConvertPolicy::SATURATE);
1530 cast_rhs.configure(&rhs, &rhs_32, ConvertPolicy::SATURATE);
1531 lhs_32.allocator()->allocate();
1532 rhs_32.allocator()->allocate();
1533 cast_lhs.run();
1534 cast_rhs.run();
1535
1536 ReduceOperation lhs_sum_rows;
1537 ReduceOperation rhs_sum_cols;
1538
1539 lhs_sum_rows.configure(&lhs_32, &vec_sum_rows, 0, ReductionOperation::SUM, false);
1540 rhs_sum_cols.configure(&rhs_32, &vec_sum_cols, 1, ReductionOperation::SUM);
1541
1542 lhs_sum_rows.run();
1543 rhs_sum_cols.run();
1544
1545 // Compute GEMM
1546 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1547 reshape_rhs.run(reshape_rhs_pack);
1548 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 } });
1549 gemm.run(gemm_pack);
1550 }
1551
1552 return dst;
1553 }
1554
1555 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, DataType data_type, GEMMLowpOutputStageInfo output_stage,
1556 const int a_offset, const int b_offset)
1557 {
1558 TensorShape dst_shape = lhs_shape;
1559 dst_shape[0] = rhs_shape[0];
1560 dst_shape[1] = lhs_shape[1];
1561
1562 // Create reference
1563 SimpleTensor<T> lhs{ lhs_shape, data_type, 1, QuantizationInfo(1.0f / 255, a_offset) };
1564 SimpleTensor<T> rhs{ rhs_shape, data_type, 1, QuantizationInfo(1.0f / 255, b_offset) };
1565 SimpleTensor<int32_t> bias{ bias_shape, DataType::S32, 1 };
1566 SimpleTensor<int32_t> dst{ dst_shape, DataType::S32, 1 };
1567 SimpleTensor<T> dst_final{ dst_shape, data_type, 1 };
1568
1569 // Fill reference
1570 fill(lhs, 0);
1571 fill(rhs, 1);
1572 fill(bias, 2);
1573
1574 dst = reference::gemmlowp_matrix_multiply_core<int32_t, T>(lhs, rhs, dst_shape, a_offset, b_offset);
1575 dst_final = reference::gemmlowp_quantize_down_scale_by_fixedpoint<int32_t, T>(dst, bias,
1576 output_stage.gemmlowp_multipliers, output_stage.gemmlowp_shifts, output_stage.gemmlowp_offset, output_stage.gemmlowp_min_bound, output_stage.gemmlowp_max_bound);
1577 return dst_final;
1578 }
1579
1580 bool gemm_validated = true;
1581 TensorType _target{};
1582 SimpleTensor<T> _reference{};
1583};
1584
1585template <typename TensorType, typename AccessorType, typename ReshapeRHSOperatorType, typename GEMMFunctionType>
1586class GEMMLowpMatrixMultiplyReshapedOnlyRHSMMULValidationFixture : public framework::Fixture
1587{
1588public:
1589 template <typename...>
1590 void setup(unsigned int m, unsigned int n, unsigned int k, unsigned int batch_size, unsigned int m0, unsigned int n0,
1591 unsigned int k0, unsigned int h0, bool interleave_rhs, bool transpose_rhs, DataType data_type)
1592 {
1593 GEMMLHSMatrixInfo lhs_info;
1594 lhs_info.m0 = m0;
1595 lhs_info.k0 = k0;
1596
1597 GEMMRHSMatrixInfo rhs_info;
1598 rhs_info.n0 = n0;
1599 rhs_info.k0 = k0;
1600 rhs_info.h0 = h0;
1601 rhs_info.interleave = interleave_rhs;
1602 rhs_info.transpose = transpose_rhs;
1603
1604 // Set the tensor shapes for LHS and RHS matrices
1605 const TensorShape lhs_shape(k, m, batch_size);
1606 const TensorShape rhs_shape(n, k, batch_size);
1607
Ramy Elgammala77c6d72022-09-08 11:30:08 +01001608 _target = compute_target(lhs_shape, rhs_shape, lhs_info, rhs_info, data_type);
Freddie Liardete572dff2022-05-16 14:09:10 +01001609 if(gemm_validated == true)
1610 {
1611 _reference = compute_reference(lhs_shape, rhs_shape, data_type);
1612 }
1613 }
1614
1615protected:
1616 template <typename U>
1617 void fill(U &&tensor, int i)
1618 {
1619 switch(tensor.data_type())
1620 {
1621 case DataType::QASYMM8:
1622 {
1623 // Between 1 and 254 in order to avoid having -128 and 128 for the DOT product path
1624 std::uniform_int_distribution<> distribution(1, 254);
1625 library->fill(tensor, distribution, i);
1626 }
1627 break;
1628 case DataType::QASYMM8_SIGNED:
1629 {
1630 std::uniform_int_distribution<> distribution(-127, 126);
1631 library->fill(tensor, distribution, i);
1632 }
1633 break;
1634 default:
1635 ARM_COMPUTE_ERROR("Unsupported data type");
1636 }
1637 }
1638
1639 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const GEMMLHSMatrixInfo &lhs_info,
1640 const GEMMRHSMatrixInfo &rhs_info, DataType data_type)
1641 {
1642 // Create tensors
1643 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1644 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1645 TensorType rhs_reshaped;
1646 TensorType dst;
1647
1648 const unsigned int M = lhs_shape[1];
1649 const unsigned int N = rhs_shape[0];
1650 const unsigned int K = lhs_shape[0];
1651
1652 GEMMKernelInfo gemm_info;
1653 gemm_info.m = M;
1654 gemm_info.n = N;
1655 gemm_info.k = K;
1656 gemm_info.lhs_info = lhs_info;
1657 gemm_info.rhs_info = rhs_info;
1658 // The output tensor will be auto-initialized within the function
1659
1660 // Create and configure function
1661 ReshapeRHSOperatorType reshape_rhs;
1662 GEMMFunctionType gemm;
1663 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1664
1665 // If GEMM is not validated, do not try to run. The validation will check
1666 // if the technology supports this extension. If not, the test will be skipped.
1667 // If it supports, the test will fail anyway because target and reference
1668 // will not match.
1669 gemm_validated = bool(gemm.validate(lhs.info(), rhs_reshaped.info(), dst.info(), gemm_info, nullptr, nullptr, nullptr));
1670 if(gemm_validated == true)
1671 {
1672 gemm.configure(lhs.info(), rhs_reshaped.info(), dst.info(), gemm_info, nullptr, nullptr, nullptr);
1673
1674 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1675 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1676
1677 // Allocate tensors
1678 lhs.allocator()->allocate();
1679 rhs.allocator()->allocate();
1680 rhs_reshaped.allocator()->allocate();
1681 dst.allocator()->allocate();
1682
1683 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1684 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1685 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1686 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
1687
1688 // Fill tensors
1689 fill(AccessorType(lhs), 0);
1690 fill(AccessorType(rhs), 1);
1691
1692 // Compute GEMM
1693 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1694 reshape_rhs.run(reshape_rhs_pack);
1695 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs }, { ACL_SRC_1, &rhs_reshaped }, { ACL_DST, &dst } });
1696 gemm.run(gemm_pack);
1697 }
1698
1699 return dst;
1700 }
1701
1702 SimpleTensor<int32_t> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type)
1703 {
1704 TensorShape dst_shape = lhs_shape;
1705 dst_shape[0] = rhs_shape[0];
1706 dst_shape[1] = lhs_shape[1];
1707
1708 if(data_type == DataType::QASYMM8)
1709 {
1710 // Create reference
1711 SimpleTensor<uint8_t> lhs{ lhs_shape, data_type, 1 };
1712 SimpleTensor<uint8_t> rhs{ rhs_shape, data_type, 1 };
1713 SimpleTensor<int32_t> dst{ dst_shape, DataType::S32, 1 };
1714
1715 // Fill reference
1716 fill(lhs, 0);
1717 fill(rhs, 1);
1718
1719 return reference::gemmlowp_matrix_multiply_core<int32_t, uint8_t>(lhs, rhs, dst_shape, 0, 0);
1720 }
1721 else
1722 {
1723 // Create reference
1724 SimpleTensor<int8_t> lhs{ lhs_shape, data_type, 1 };
1725 SimpleTensor<int8_t> rhs{ rhs_shape, data_type, 1 };
1726 SimpleTensor<int32_t> dst{ dst_shape, DataType::S32, 1 };
1727
1728 // Fill reference
1729 fill(lhs, 0);
1730 fill(rhs, 1);
1731
1732 return reference::gemmlowp_matrix_multiply_core<int32_t, int8_t>(lhs, rhs, dst_shape, 0, 0);
1733 }
1734 }
1735
1736 bool gemm_validated = true;
1737 TensorType _target{};
1738 SimpleTensor<int32_t> _reference{};
1739};
1740
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001741template <typename TensorType, typename AccessorType, typename ReshapeRHSOperatorType, typename GEMMFunctionType>
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001742class GEMMLowpMatrixMultiplyReshapedOnlyRHS3DValidationFixture : public framework::Fixture
1743{
1744public:
1745 template <typename...>
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001746 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,
1747 unsigned int k0, unsigned int h0, bool interleave_rhs, bool transpose_rhs, DataType data_type)
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001748 {
1749 GEMMLHSMatrixInfo lhs_info;
1750 lhs_info.m0 = m0;
1751 lhs_info.k0 = k0;
1752
1753 GEMMRHSMatrixInfo rhs_info;
1754 rhs_info.n0 = n0;
1755 rhs_info.k0 = k0;
1756 rhs_info.h0 = h0;
1757 rhs_info.interleave = interleave_rhs;
1758 rhs_info.transpose = transpose_rhs;
1759
1760 // In case of GEMM3D, m is the product between m_w and m_h
1761 const unsigned int m = m_w * m_h;
1762
1763 // Set the tensor shapes for LHS and RHS matrices
1764 const TensorShape lhs_shape(k, m, batch_size);
1765 const TensorShape rhs_shape(n, k, batch_size);
1766
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001767 _target = compute_target(lhs_shape, rhs_shape, lhs_info, rhs_info, m_h, data_type);
1768 _reference = compute_reference(lhs_shape, rhs_shape, m_h, data_type);
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001769 }
1770
1771protected:
1772 template <typename U>
1773 void fill(U &&tensor, int i)
1774 {
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001775 switch(tensor.data_type())
1776 {
1777 case DataType::QASYMM8:
1778 {
1779 // Between 1 and 254 in order to avoid having -128 and 128 for the DOT product path
1780 std::uniform_int_distribution<> distribution(1, 254);
1781 library->fill(tensor, distribution, i);
1782 }
1783 break;
1784 case DataType::QASYMM8_SIGNED:
1785 {
1786 std::uniform_int_distribution<> distribution(-127, 126);
1787 library->fill(tensor, distribution, i);
1788 }
1789 break;
1790 default:
1791 ARM_COMPUTE_ERROR("Unsupported data type");
1792 }
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001793 }
1794
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001795 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const GEMMLHSMatrixInfo &lhs_info,
1796 const GEMMRHSMatrixInfo &rhs_info, unsigned int m_h, DataType data_type)
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001797 {
1798 // Create tensors
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001799 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1800 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001801 TensorType rhs_reshaped;
1802 TensorType dst;
1803
1804 const unsigned int M = lhs_shape[1];
1805 const unsigned int N = rhs_shape[0];
1806 const unsigned int K = lhs_shape[0];
1807
Michele Di Giorgiob54ba282020-01-14 15:31:55 +00001808 GEMMKernelInfo gemm_info;
1809 gemm_info.m = M;
1810 gemm_info.n = N;
1811 gemm_info.k = K;
1812 gemm_info.depth_output_gemm3d = m_h;
1813 gemm_info.lhs_info = lhs_info;
1814 gemm_info.rhs_info = rhs_info;
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001815 // The output tensor will be auto-initialized within the function
1816
1817 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001818 ReshapeRHSOperatorType reshape_rhs;
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001819 GEMMFunctionType gemm;
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001820 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
Georgios Pinitas4a578b92021-06-25 12:13:49 +01001821 gemm.configure(lhs.info(), rhs_reshaped.info(), dst.info(), gemm_info);
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001822
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001823 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1824 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001825
Giorgio Arena63825e82021-03-25 14:54:50 +00001826 add_padding_x({ &lhs, &rhs, &rhs_reshaped, &dst });
1827
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001828 // Allocate tensors
1829 lhs.allocator()->allocate();
1830 rhs.allocator()->allocate();
1831 rhs_reshaped.allocator()->allocate();
1832 dst.allocator()->allocate();
1833
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001834 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1835 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1836 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1837 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001838
1839 // Fill tensors
1840 fill(AccessorType(lhs), 0);
1841 fill(AccessorType(rhs), 1);
1842
1843 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001844 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1845 reshape_rhs.run(reshape_rhs_pack);
Georgios Pinitas4a578b92021-06-25 12:13:49 +01001846 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs }, { ACL_SRC_1, &rhs_reshaped }, { ACL_DST, &dst } });
1847 gemm.run(gemm_pack);
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001848
1849 return dst;
1850 }
1851
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001852 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 +00001853 {
1854 TensorShape dst_shape = lhs_shape;
1855 dst_shape.set(0, rhs_shape[0]);
1856 dst_shape.set(1, lhs_shape[1] / m_h);
1857 dst_shape.set(2, m_h);
1858 dst_shape.set(3, lhs_shape[2]);
1859
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001860 if(data_type == DataType::QASYMM8)
1861 {
1862 // Create reference
1863 SimpleTensor<uint8_t> lhs{ lhs_shape, data_type, 1 };
1864 SimpleTensor<uint8_t> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001865
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001866 // Fill reference
1867 fill(lhs, 0);
1868 fill(rhs, 1);
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001869
Michele Di Giorgiof9179d32019-11-27 16:17:30 +00001870 return reference::gemmlowp_matrix_multiply_core<int32_t, uint8_t>(lhs, rhs, dst_shape, 0, 0);
1871 }
1872 else
1873 {
1874 // Create reference
1875 SimpleTensor<int8_t> lhs{ lhs_shape, data_type, 1 };
1876 SimpleTensor<int8_t> rhs{ rhs_shape, data_type, 1 };
1877
1878 // Fill reference
1879 fill(lhs, 0);
1880 fill(rhs, 1);
1881
1882 return reference::gemmlowp_matrix_multiply_core<int32_t, int8_t>(lhs, rhs, dst_shape, 0, 0);
1883 }
Gian Marco Iodice62251f72019-03-11 16:07:12 +00001884 }
1885
1886 TensorType _target{};
1887 SimpleTensor<int32_t> _reference{};
1888};
Gian Marco Iodicee7510622019-06-03 17:28:17 +01001889
1890template <typename TensorType, typename AccessorType, typename GEMMFunctionType>
1891class GEMMLowpMatrixMultiplyNativeValidationFixture : public framework::Fixture
1892{
1893public:
1894 template <typename...>
1895 void setup(unsigned int m, unsigned int n, unsigned int k, unsigned int batch_size, unsigned int m0, unsigned int n0, unsigned int k0)
1896 {
1897 GEMMLHSMatrixInfo lhs_info;
1898 lhs_info.m0 = m0;
1899 lhs_info.k0 = k0;
1900
1901 GEMMRHSMatrixInfo rhs_info;
1902 rhs_info.n0 = n0;
1903 rhs_info.k0 = k0;
1904
1905 // Set the tensor shapes for LHS and RHS matrices
1906 const TensorShape lhs_shape(k, m, batch_size);
1907 const TensorShape rhs_shape(n, k, batch_size);
1908
1909 _target = compute_target(lhs_shape, rhs_shape, lhs_info, rhs_info);
1910 _reference = compute_reference(lhs_shape, rhs_shape);
1911 }
1912
1913protected:
1914 template <typename U>
1915 void fill(U &&tensor, int i)
1916 {
1917 // Between 1 and 254 in order to avoid having -128 and 128 for the DOT product path
1918 std::uniform_int_distribution<> distribution(1, 254);
1919 library->fill(tensor, distribution, i);
1920 }
1921
1922 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info)
1923 {
1924 // Create tensors
1925 TensorType lhs = create_tensor<TensorType>(lhs_shape, DataType::QASYMM8, 1);
1926 TensorType rhs = create_tensor<TensorType>(rhs_shape, DataType::QASYMM8, 1);
1927 TensorType dst;
1928
1929 const unsigned int M = lhs_shape[1];
1930 const unsigned int N = rhs_shape[0];
1931 const unsigned int K = lhs_shape[0];
1932
1933 // The output tensor will be auto-initialized within the function
1934
1935 // Create and configure function
1936 GEMMFunctionType gemm;
Georgios Pinitas4a578b92021-06-25 12:13:49 +01001937 gemm.configure(lhs.info(), rhs.info(), dst.info(), lhs_info, rhs_info, GEMMReshapeInfo(M, N, K));
Gian Marco Iodicee7510622019-06-03 17:28:17 +01001938
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001939 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1940 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
Gian Marco Iodicee7510622019-06-03 17:28:17 +01001941
Giorgio Arena63825e82021-03-25 14:54:50 +00001942 add_padding_x({ &lhs, &rhs, &dst });
1943
Gian Marco Iodicee7510622019-06-03 17:28:17 +01001944 // Allocate tensors
1945 lhs.allocator()->allocate();
1946 rhs.allocator()->allocate();
1947 dst.allocator()->allocate();
1948
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001949 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1950 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1951 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodicee7510622019-06-03 17:28:17 +01001952
1953 // Fill tensors
1954 fill(AccessorType(lhs), 0);
1955 fill(AccessorType(rhs), 1);
1956
1957 // Compute GEMM
Georgios Pinitas4a578b92021-06-25 12:13:49 +01001958 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs }, { ACL_SRC_1, &rhs }, { ACL_DST, &dst } });
1959 gemm.run(gemm_pack);
Gian Marco Iodicee7510622019-06-03 17:28:17 +01001960
1961 return dst;
1962 }
1963
1964 SimpleTensor<int32_t> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape)
1965 {
1966 TensorShape dst_shape = lhs_shape;
1967 dst_shape[0] = rhs_shape[0];
1968 dst_shape[1] = lhs_shape[1];
1969
1970 // Create reference
1971 SimpleTensor<uint8_t> lhs{ lhs_shape, DataType::QASYMM8, 1 };
1972 SimpleTensor<uint8_t> rhs{ rhs_shape, DataType::QASYMM8, 1 };
1973
1974 // Fill reference
1975 fill(lhs, 0);
1976 fill(rhs, 1);
1977
1978 return reference::gemmlowp_matrix_multiply_core<int32_t, uint8_t>(lhs, rhs, dst_shape, 0, 0);
1979 }
1980
1981 TensorType _target{};
1982 SimpleTensor<int32_t> _reference{};
1983};
1984
1985template <typename TensorType, typename AccessorType, typename GEMMFunctionType>
1986class GEMMLowpMatrixMultiplyNative3DValidationFixture : public framework::Fixture
1987{
1988public:
1989 template <typename...>
1990 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)
1991 {
1992 GEMMLHSMatrixInfo lhs_info;
1993 lhs_info.m0 = m0;
1994 lhs_info.k0 = k0;
1995
1996 GEMMRHSMatrixInfo rhs_info;
1997 rhs_info.n0 = n0;
1998 rhs_info.k0 = k0;
1999
2000 // In case of GEMM3D, m is the product between m_w and m_h
2001 const unsigned int m = m_w * m_h;
2002
2003 // Set the tensor shapes for LHS and RHS matrices
2004 const TensorShape lhs_shape(k, m, batch_size);
2005 const TensorShape rhs_shape(n, k, batch_size);
2006
2007 _target = compute_target(lhs_shape, rhs_shape, lhs_info, rhs_info, m_h);
2008 _reference = compute_reference(lhs_shape, rhs_shape, m_h);
2009 }
2010
2011protected:
2012 template <typename U>
2013 void fill(U &&tensor, int i)
2014 {
2015 // Between 1 and 254 in order to avoid having -128 and 128 for the DOT product path
2016 std::uniform_int_distribution<> distribution(1, 254);
2017 library->fill(tensor, distribution, i);
2018 }
2019
2020 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info, unsigned int m_h)
2021 {
2022 // Create tensors
2023 TensorType lhs = create_tensor<TensorType>(lhs_shape, DataType::QASYMM8, 1);
2024 TensorType rhs = create_tensor<TensorType>(rhs_shape, DataType::QASYMM8, 1);
2025 TensorType dst;
2026
2027 const unsigned int M = lhs_shape[1];
2028 const unsigned int N = rhs_shape[0];
2029 const unsigned int K = lhs_shape[0];
2030
2031 // The output tensor will be auto-initialized within the function
2032
2033 // Create and configure function
2034 GEMMFunctionType gemm;
Georgios Pinitas4a578b92021-06-25 12:13:49 +01002035 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 +01002036
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01002037 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
2038 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
Gian Marco Iodicee7510622019-06-03 17:28:17 +01002039
Giorgio Arena63825e82021-03-25 14:54:50 +00002040 add_padding_x({ &lhs, &rhs, &dst });
2041
Gian Marco Iodicee7510622019-06-03 17:28:17 +01002042 // Allocate tensors
2043 lhs.allocator()->allocate();
2044 rhs.allocator()->allocate();
2045 dst.allocator()->allocate();
2046
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01002047 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
2048 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
2049 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodicee7510622019-06-03 17:28:17 +01002050
2051 // Fill tensors
2052 fill(AccessorType(lhs), 0);
2053 fill(AccessorType(rhs), 1);
2054
2055 // Compute GEMM
Georgios Pinitas4a578b92021-06-25 12:13:49 +01002056 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs }, { ACL_SRC_1, &rhs }, { ACL_DST, &dst } });
2057 gemm.run(gemm_pack);
Gian Marco Iodicee7510622019-06-03 17:28:17 +01002058
2059 return dst;
2060 }
2061
2062 SimpleTensor<int32_t> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, unsigned int m_h)
2063 {
2064 TensorShape dst_shape = lhs_shape;
2065 dst_shape.set(0, rhs_shape[0]);
2066 dst_shape.set(1, lhs_shape[1] / m_h);
2067 dst_shape.set(2, m_h);
2068 dst_shape.set(3, lhs_shape[2]);
2069
2070 // Create reference
2071 SimpleTensor<uint8_t> lhs{ lhs_shape, DataType::QASYMM8, 1 };
2072 SimpleTensor<uint8_t> rhs{ rhs_shape, DataType::QASYMM8, 1 };
2073
2074 // Fill reference
2075 fill(lhs, 0);
2076 fill(rhs, 1);
2077
2078 return reference::gemmlowp_matrix_multiply_core<int32_t, uint8_t>(lhs, rhs, dst_shape, 0, 0);
2079 }
2080
2081 TensorType _target{};
2082 SimpleTensor<int32_t> _reference{};
2083};
Pablo Tello299025a2017-09-29 11:30:12 +01002084} // namespace validation
2085} // namespace test
2086} // namespace arm_compute
George Wort2d7e6832019-02-22 16:37:41 +00002087#endif /* ARM_COMPUTE_TEST_GEMMLOWP_FIXTURE */