blob: 94bedc83e18c10195edfc7532c3afbb320186150 [file] [log] [blame]
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +01001/*
Radu Salavatf1f1f872024-02-27 18:32:26 +00002 * Copyright (c) 2017-2024 Arm Limited.
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +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 */
Jakub Sujak0d27b2e2023-08-24 14:01:20 +010024#ifndef ACL_TESTS_VALIDATION_FIXTURES_GEMMFIXTURE_H
25#define ACL_TESTS_VALIDATION_FIXTURES_GEMMFIXTURE_H
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010026
Gian Marco Iodice7026b302019-06-26 17:18:11 +010027#include "arm_compute/core/KernelDescriptors.h"
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010028#include "arm_compute/core/TensorShape.h"
29#include "arm_compute/core/Types.h"
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010030#include "tests/AssetsLibrary.h"
31#include "tests/Globals.h"
32#include "tests/IAccessor.h"
Moritz Pflanzera09de0c2017-09-01 20:41:12 +010033#include "tests/framework/Asserts.h"
34#include "tests/framework/Fixture.h"
Moritz Pflanzera09de0c2017-09-01 20:41:12 +010035#include "tests/validation/Helpers.h"
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +010036#include "tests/validation/reference/ActivationLayer.h"
SiCongLi1af54162021-10-06 15:25:57 +010037#include "tests/validation/reference/ElementwiseOperations.h"
Georgios Pinitas5a7e7762017-12-01 16:27:29 +000038#include "tests/validation/reference/GEMM.h"
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010039
40#include <random>
41
42namespace arm_compute
43{
44namespace test
45{
46namespace validation
47{
Mohammed Suhail Munshi13a2d002022-09-05 11:57:34 +010048template <typename TensorType, typename AccessorType, typename FunctionType, typename T, bool disable_c = false, bool reinterpret_input_as_3d = false, bool reinterpret_output_as_3d = false, bool pretranspose_a = false, bool pretranspose_b = false, bool run_twice = false>
Radu Salavatf1f1f872024-02-27 18:32:26 +000049class GEMMGenericValidationFixture : public framework::Fixture
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010050{
51public:
Radu Salavatf1f1f872024-02-27 18:32:26 +000052 void setup(TensorShape shape_a, TensorShape shape_b, TensorShape shape_c, TensorShape output_shape, float alpha, float beta, bool pretranspose, DataType data_type, bool accumulate=false)
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010053 {
Michalis Spyrou6bff1952019-10-02 17:22:11 +010054 ARM_COMPUTE_UNUSED(pretranspose);
Radu Salavatf1f1f872024-02-27 18:32:26 +000055 _target = compute_target(shape_a, shape_b, shape_c, output_shape, alpha, beta, data_type, accumulate);
56 _reference = compute_reference(shape_a, shape_b, output_shape, alpha, beta, data_type, accumulate);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010057 }
58
59protected:
60 template <typename U>
Pablo Tello0e37b5c2018-10-30 11:18:37 +000061 void fill(U &&tensor, int i, float lo = -1.f, float hi = 1.f)
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010062 {
63 switch(tensor.data_type())
64 {
65 case DataType::F16:
Giorgio Arena6aeb2172020-12-15 15:45:43 +000066 {
Giorgio Arenaa8e2aeb2021-01-06 11:34:57 +000067 arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ float(lo), float(hi) };
Giorgio Arena6aeb2172020-12-15 15:45:43 +000068 library->fill(tensor, distribution, i);
69 break;
70 }
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010071 case DataType::F32:
72 {
Giorgio Arena6aeb2172020-12-15 15:45:43 +000073 std::uniform_real_distribution<float> distribution(lo, hi);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010074 library->fill(tensor, distribution, i);
75 break;
76 }
77 default:
78 library->fill_tensor_uniform(tensor, i);
79 }
80 }
81
82 TensorType compute_target(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &shape_c, const TensorShape &output_shape, float alpha, float beta,
Radu Salavatf1f1f872024-02-27 18:32:26 +000083 DataType data_type, bool accumulate=false)
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010084 {
85 // Create tensors
Vidhya Sudhan Loganathan014333d2018-07-02 09:13:49 +010086 TensorType a = create_tensor<TensorType>(shape_a, data_type, 1);
87 TensorType b = create_tensor<TensorType>(shape_b, data_type, 1);
88 TensorType c = create_tensor<TensorType>(shape_c, data_type, 1);
89 TensorType dst = create_tensor<TensorType>(output_shape, data_type, 1);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010090
91 // Create and configure function
92 FunctionType gemm;
Isabella Gottardi8e74f442018-03-01 16:42:00 +000093 // The GEMMinfo includes the values of the depth in case of reinterpreted 3d output.
Gian Marco Iodice3139f032018-11-05 14:26:32 +000094 // If the output shape has the same number of dimensions of the input the method called is a 2D matrix multiplication (depth_output_reinterpreted_as_3D = 0),
Isabella Gottardi8e74f442018-03-01 16:42:00 +000095 // in the other case we have to use the reinterpreted version of GEMM (depth_output_reinterpreted_as_3D = depth of the 3D output).
Gian Marco Iodicef3622be2019-07-29 14:27:16 +010096 gemm.configure(&a,
97 &b,
98 (disable_c) ? nullptr : &c,
99 &dst,
100 alpha, beta,
Georgios Pinitas4ee8b152021-07-16 16:16:43 +0100101 GEMMInfo(false, false, false, (reinterpret_output_as_3d ? output_shape[2] : 0), reinterpret_input_as_3d, false, GEMMLowpOutputStageInfo(), false, false, (reinterpret_input_as_3d
Radu Salavatf1f1f872024-02-27 18:32:26 +0000102 || reinterpret_output_as_3d), arm_compute::ActivationLayerInfo(), false /* fixed_format */, arm_compute::WeightFormat::UNSPECIFIED, false /* pretranspose_B */, accumulate));
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100103 ARM_COMPUTE_ASSERT(a.info()->is_resizable());
104 ARM_COMPUTE_ASSERT(b.info()->is_resizable());
105 ARM_COMPUTE_ASSERT(c.info()->is_resizable());
106 ARM_COMPUTE_ASSERT(dst.info()->is_resizable());
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100107
Giorgio Arena63825e82021-03-25 14:54:50 +0000108 add_padding_x({ &a, &b, &c, &dst });
109
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100110 // Allocate tensors
111 a.allocator()->allocate();
112 b.allocator()->allocate();
113 c.allocator()->allocate();
114 dst.allocator()->allocate();
115
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100116 ARM_COMPUTE_ASSERT(!a.info()->is_resizable());
117 ARM_COMPUTE_ASSERT(!b.info()->is_resizable());
118 ARM_COMPUTE_ASSERT(!c.info()->is_resizable());
119 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100120
121 // Fill tensors
122 fill(AccessorType(a), 0);
123 fill(AccessorType(b), 1);
Radu Salavatf1f1f872024-02-27 18:32:26 +0000124 if (accumulate)
125 {
126 fill(AccessorType(dst), 6);
127 }
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000128 if(!disable_c)
129 {
130 fill(AccessorType(c), 2);
131 }
Mohammed Suhail Munshi13a2d002022-09-05 11:57:34 +0100132 // Run with variable inputs.
133 if(run_twice)
134 {
135 gemm.run();
136 fill(AccessorType(a), 3); // Fill tensors with new seed after run
137 fill(AccessorType(b), 4);
138 if(!disable_c)
139 {
140 fill(AccessorType(c), 5);
141 }
142 }
143
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100144 // Compute GEMM function
145 gemm.run();
146
147 return dst;
148 }
149
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100150 SimpleTensor<T> compute_reference(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &output_shape, float alpha, float beta,
Radu Salavatf1f1f872024-02-27 18:32:26 +0000151 DataType data_type, bool accumulate=false)
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100152 {
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100153 TensorShape shape_a_to_use = shape_a;
154 if(reinterpret_input_as_3d)
155 {
156 // Collapse the second and third dimension if the input is 3D
157 shape_a_to_use.collapse(2U, 1U);
158 }
159
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100160 // Create reference
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100161 SimpleTensor<T> a{ shape_a_to_use, data_type, 1 };
Vidhya Sudhan Loganathan014333d2018-07-02 09:13:49 +0100162 SimpleTensor<T> b{ shape_b, data_type, 1 };
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100163 SimpleTensor<T> c{ output_shape, data_type, 1 };
Radu Salavatf1f1f872024-02-27 18:32:26 +0000164 SimpleTensor<T> dst{ output_shape, data_type, 1 };
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100165
166 // Fill reference
167 fill(a, 0);
168 fill(b, 1);
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100169 fill(c, 2);
170
171 if(reinterpret_input_as_3d || reinterpret_output_as_3d)
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000172 {
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100173 const int n = shape_b[0];
174 const int m = reinterpret_output_as_3d ? output_shape[1] * output_shape[2] : output_shape[1];
175 const int batch_size = reinterpret_output_as_3d ? output_shape[3] : output_shape[2];
176
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000177 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100178 for(int i = 1; i < m * batch_size; i++)
179 {
180 memcpy(c.data() + i * n, c.data(), n * sizeof(T));
181 }
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000182 }
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000183
Adnan AlSinan3bb72b62022-05-06 12:10:11 +0100184 /* 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),
185 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)
186 in order to be able to call reference implementation that works with (B x M x K) input.
187 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. */
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000188
Mohammed Suhail Munshibc5c4072022-04-27 13:49:51 +0100189 // Define transposed shapes
190 TensorShape a_transposed_shape(a.shape().y(), a.shape().x());
191 TensorShape b_transposed_shape(b.shape().y(), b.shape().x());
192
193 // Define transposed tensors
194 SimpleTensor<T> a_transposed{ a_transposed_shape, data_type };
195 SimpleTensor<T> b_transposed{ b_transposed_shape, data_type };
196
197 // pretranspose a if necessary
198 if(pretranspose_a)
199 {
200 transpose_matrix<T>(a, a_transposed);
201 }
202
203 // pretranspose b if necessary
204 if(pretranspose_b)
205 {
206 transpose_matrix<T>(b, b_transposed);
207 }
208
Mohammed Suhail Munshi13a2d002022-09-05 11:57:34 +0100209 // Run with variable inputs.
210 if(run_twice)
211 {
212 reference::gemm<T>((pretranspose_a) ? a_transposed : a, (pretranspose_b) ? b_transposed : b, c, alpha, disable_c ? 0.f : beta);
213 fill((pretranspose_a) ? a_transposed : a, 3);
214 fill((pretranspose_b) ? b_transposed : b, 4);
Adnan AlSinan26c9d1a2022-09-07 13:54:53 +0100215 fill(c, 5);
Mohammed Suhail Munshi13a2d002022-09-05 11:57:34 +0100216 }
217
Radu Salavatf1f1f872024-02-27 18:32:26 +0000218 // Do in place summation
219 if (accumulate)
220 {
221 fill(dst, 6);
222 }
223
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100224 // Setting beta to 0 will effectively disable C for the
225 // computation of the reference: alpha * A * B + 0 * C
Mohammed Suhail Munshibc5c4072022-04-27 13:49:51 +0100226 // Use transposed tensors if boolean enabled else use original tensors
Radu Salavatf1f1f872024-02-27 18:32:26 +0000227 if (accumulate)
228 {
229 reference::gemm_accumulate<T>((pretranspose_a) ? a_transposed : a, (pretranspose_b) ? b_transposed : b, c, alpha, disable_c ? 0.f : beta, dst);
230 return dst;
231 }
232 else
233 {
234 return reference::gemm<T>((pretranspose_a) ? a_transposed : a, (pretranspose_b) ? b_transposed : b, c, alpha, disable_c ? 0.f : beta);
235 }
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100236 }
237
238 TensorType _target{};
239 SimpleTensor<T> _reference{};
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100240};
241
Radu Salavatf1f1f872024-02-27 18:32:26 +0000242template <typename TensorType, typename AccessorType, typename FunctionType, typename T, bool disable_c = false, bool reinterpret_input_as_3d = false, bool reinterpret_output_as_3d = false, bool pretranspose_a = false, bool pretranspose_b = false, bool run_twice = false>
243class GEMMValidationFixture : protected GEMMGenericValidationFixture<TensorType, AccessorType, FunctionType, T, disable_c, reinterpret_input_as_3d, reinterpret_output_as_3d, pretranspose_a, pretranspose_b, run_twice>
244{
245public:
246 void setup(TensorShape shape_a, TensorShape shape_b, TensorShape shape_c, TensorShape output_shape, float alpha, float beta, bool pretranspose, DataType data_type)
247 {
248 GEMMGenericValidationFixture<TensorType, AccessorType, FunctionType, T, disable_c, reinterpret_input_as_3d, reinterpret_output_as_3d, pretranspose_a, pretranspose_b, run_twice>::setup(shape_a, shape_b, shape_c, output_shape, alpha, beta, pretranspose, data_type, false /*accumulate*/);
249 }
250};
251
252template <typename TensorType, typename AccessorType, typename FunctionType, typename T, bool disable_c = false, bool reinterpret_input_as_3d = false, bool reinterpret_output_as_3d = false, bool pretranspose_a = false, bool pretranspose_b = false, bool run_twice = false>
253class GEMMAccumulateValidationFixture : protected GEMMGenericValidationFixture<TensorType, AccessorType, FunctionType, T, disable_c, reinterpret_input_as_3d, reinterpret_output_as_3d, pretranspose_a, pretranspose_b, run_twice>
254{
255public:
256 void setup(TensorShape shape_a, TensorShape shape_b, TensorShape shape_c, TensorShape output_shape, float alpha, float beta, bool pretranspose, DataType data_type)
257 {
258 bool accumulate = true;
259 GEMMGenericValidationFixture<TensorType, AccessorType, FunctionType, T, disable_c, reinterpret_input_as_3d, reinterpret_output_as_3d, pretranspose_a, pretranspose_b, run_twice>::setup(shape_a, shape_b, shape_c, output_shape, alpha, beta, pretranspose, data_type, accumulate);
260 }
261};
262
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100263template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100264class GEMMMatrixMultiplyValidationFixture : public framework::Fixture
265{
266public:
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100267 void setup(unsigned int m, unsigned int n, unsigned int k, unsigned int batch_size, float alpha, float beta, bool broadcast_bias, bool fp16_mixed_precision, const ActivationLayerInfo &act_info,
268 DataType data_type, GPUTarget gpu_arch)
269 {
270 // Set the tensor shapes for LHS and RHS matrices
271 const TensorShape lhs_shape(k, m, batch_size);
272 const TensorShape rhs_shape(n, k, batch_size);
273 const TensorShape bias_shape(n,
274 broadcast_bias ? 1 : m,
275 broadcast_bias ? 1 : batch_size);
276
277 _target = compute_target(lhs_shape, rhs_shape, bias_shape, data_type, alpha, beta, broadcast_bias, fp16_mixed_precision, act_info, gpu_arch);
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100278 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100279 }
280
281protected:
282 template <typename U>
283 void fill(U &&tensor, int i)
284 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000285 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
Giorgio Arena33b103b2021-01-08 10:37:15 +0000286 using DistributionType = typename std::conditional<std::is_same<T, half>::value, arm_compute::utils::uniform_real_distribution_16bit<T>, std::uniform_real_distribution<T>>::type;
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000287
288 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100289 library->fill(tensor, distribution, i);
290
291 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000292 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100293 library->fill_borders_with_garbage(tensor, distribution_inf, i);
294 }
295
296 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
297 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
298 {
299 // Create tensors
300 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
301 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
302 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
303 TensorType dst;
304
305 const unsigned int m = lhs_shape[1];
306 const unsigned int n = rhs_shape[0];
307 const unsigned int k = lhs_shape[0];
308 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, 0, false, broadcast_bias);
309
310 // The output tensor will be auto-initialized within the function
311
312 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100313 GEMMOperatorType gemm;
314 gemm.configure(gpu_arch, lhs.info(), rhs.info(), bias.info(), dst.info(), alpha, beta, false, reshape_info, fp16_mixed_precision, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100315
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100316 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
317 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
318 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100319
Giorgio Arena63825e82021-03-25 14:54:50 +0000320 add_padding_x({ &lhs, &rhs, &bias, &dst });
321
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100322 // Allocate tensors
323 lhs.allocator()->allocate();
324 rhs.allocator()->allocate();
325 bias.allocator()->allocate();
326 dst.allocator()->allocate();
327
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100328 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
329 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
330 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
331 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100332
333 // Fill tensors
334 fill(AccessorType(lhs), 0);
335 fill(AccessorType(rhs), 1);
336 fill(AccessorType(bias), 2);
337
338 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100339 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
340 { ACL_SRC_1, &rhs },
341 { ACL_SRC_2, &bias },
Jakub Sujak0d27b2e2023-08-24 14:01:20 +0100342 { ACL_DST, &dst } });
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100343 gemm.run(gemm_pack);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100344
345 return dst;
346 }
347
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100348 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100349 const ActivationLayerInfo &act_info)
350 {
351 TensorShape dst_shape = lhs_shape;
352 dst_shape[0] = rhs_shape[0];
353 dst_shape[1] = lhs_shape[1];
354
355 // Create reference
356 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
357 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
358 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
359
360 const int n = rhs_shape[0];
361 const int m = lhs_shape[1];
362 const int batch_size = lhs_shape[2];
363
364 // Fill reference
365 fill(lhs, 0);
366 fill(rhs, 1);
367 fill(bias, 2);
368
369 if(broadcast_bias)
370 {
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000371 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100372 for(int i = 1; i < m * batch_size; i++)
373 {
374 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
375 }
376 }
377
378 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
379 }
380
381 TensorType _target{};
382 SimpleTensor<T> _reference{};
383};
384
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100385template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100386class GEMMMatrixMultiply3DValidationFixture : public framework::Fixture
387{
388public:
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100389 void setup(unsigned int m_w, unsigned int m_h, unsigned int n, unsigned int k, unsigned int batch_size, float alpha, float beta, bool broadcast_bias, bool fp16_mixed_precision,
390 const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
391 {
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100392 ARM_COMPUTE_UNUSED(broadcast_bias);
393
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100394 // In case of GEMM3D, m is the product between m_w and m_h
395 const unsigned int m = m_w * m_h;
396
397 // Set the tensor shapes for LHS and RHS matrices
398 const TensorShape lhs_shape(k, m, batch_size);
399 const TensorShape rhs_shape(n, k, batch_size);
400 const TensorShape bias_shape(n, 1, 1);
401
402 _target = compute_target(lhs_shape, rhs_shape, bias_shape, data_type, alpha, beta, m_h, fp16_mixed_precision, act_info, gpu_arch);
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100403 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100404 }
405
406protected:
407 template <typename U>
408 void fill(U &&tensor, int i)
409 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000410 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
Giorgio Arena33b103b2021-01-08 10:37:15 +0000411 using DistributionType = typename std::conditional<std::is_same<T, half>::value, arm_compute::utils::uniform_real_distribution_16bit<T>, std::uniform_real_distribution<T>>::type;
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000412
413 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100414 library->fill(tensor, distribution, i);
415 }
416
417 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, DataType data_type, float alpha, float beta, unsigned int m_h,
418 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
419 {
420 // Create tensors
421 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
422 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
423 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
424 TensorType dst;
425
426 const unsigned int m = lhs_shape[1];
427 const unsigned int n = rhs_shape[0];
428 const unsigned int k = lhs_shape[0];
429 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, m_h, false, true);
430
431 // The output tensor will be auto-initialized within the function
432
433 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100434 GEMMOperatorType gemm;
435 gemm.configure(gpu_arch, lhs.info(), rhs.info(), bias.info(), dst.info(), alpha, beta, false, reshape_info, fp16_mixed_precision, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100436
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100437 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
438 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
439 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100440
Giorgio Arena63825e82021-03-25 14:54:50 +0000441 add_padding_x({ &lhs, &rhs, &bias, &dst });
442
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100443 // Allocate tensors
444 lhs.allocator()->allocate();
445 rhs.allocator()->allocate();
446 bias.allocator()->allocate();
447 dst.allocator()->allocate();
448
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100449 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
450 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
451 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
452 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100453
454 // Fill tensors
455 fill(AccessorType(lhs), 0);
456 fill(AccessorType(rhs), 1);
457 fill(AccessorType(bias), 2);
458
459 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100460 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
461 { ACL_SRC_1, &rhs },
462 { ACL_SRC_2, &bias },
Jakub Sujak0d27b2e2023-08-24 14:01:20 +0100463 { ACL_DST, &dst } });
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100464 gemm.run(gemm_pack);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100465
466 return dst;
467 }
468
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100469 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, unsigned int m_h,
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100470 const ActivationLayerInfo &act_info)
471 {
472 TensorShape dst_shape = lhs_shape;
473 dst_shape.set(0, rhs_shape[0]);
474 dst_shape.set(1, lhs_shape[1] / m_h);
475 dst_shape.set(2, m_h);
476 dst_shape.set(3, lhs_shape[2]);
477
478 // Create reference
479 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
480 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
481 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
482
483 const int n = rhs_shape[0];
484 const int m = lhs_shape[1];
485 const int batch_size = lhs_shape[2];
486
487 // Fill reference
488 fill(lhs, 0);
489 fill(rhs, 1);
490 fill(bias, 2);
491
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000492 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100493 for(int i = 1; i < m * batch_size; i++)
494 {
495 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
496 }
497
498 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
499 }
500
501 TensorType _target{};
502 SimpleTensor<T> _reference{};
503};
504
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100505template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSOperatorType, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100506class GEMMMatrixMultiplyInterleavedTransposedValidationFixture : public framework::Fixture
507{
508public:
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100509 void setup(unsigned int m, unsigned int n, unsigned int k, unsigned int batch_size, float alpha, float beta, unsigned int v0, unsigned int h0, bool broadcast_bias, bool fp16_mixed_precision,
510 const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
511 {
512 GEMMLHSMatrixInfo lhs_info;
513 lhs_info.m0 = 4;
514 lhs_info.k0 = 4;
515 lhs_info.v0 = v0;
516 lhs_info.interleave = true;
517 lhs_info.transpose = true;
518
519 GEMMRHSMatrixInfo rhs_info;
520 rhs_info.n0 = 16 / sizeof(T);
521 rhs_info.k0 = 1;
522 rhs_info.h0 = h0;
523 rhs_info.interleave = false;
524 rhs_info.transpose = false;
525
526 // Set the tensor shapes for LHS and RHS matrices
527 const TensorShape lhs_shape(k, m, batch_size);
528 const TensorShape rhs_shape(n, k, batch_size);
529 const TensorShape bias_shape(n,
530 broadcast_bias ? 1 : m,
531 broadcast_bias ? 1 : batch_size);
532
533 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, fp16_mixed_precision, act_info, gpu_arch);
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100534 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100535 }
536
537protected:
538 template <typename U>
539 void fill(U &&tensor, int i)
540 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000541 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
Giorgio Arena33b103b2021-01-08 10:37:15 +0000542 using DistributionType = typename std::conditional<std::is_same<T, half>::value, arm_compute::utils::uniform_real_distribution_16bit<T>, std::uniform_real_distribution<T>>::type;
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000543
544 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100545 library->fill(tensor, distribution, i);
546
547 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000548 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100549 library->fill_borders_with_garbage(tensor, distribution_inf, i);
550 }
551
552 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
553 DataType data_type, float alpha, float beta, bool broadcast_bias, bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
554 {
555 // Create tensors
556 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
557 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
558 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
559 TensorType lhs_reshaped;
560 TensorType rhs_reshaped;
561 TensorType dst;
562
563 const unsigned int m = lhs_shape[1];
564 const unsigned int n = rhs_shape[0];
565 const unsigned int k = lhs_shape[0];
566 GEMMReshapeInfo reshape_info(m, n, k, rhs_info.h0, lhs_info.v0, 0, false, broadcast_bias);
567
568 // The output tensor will be auto-initialized within the function
569
570 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100571 ReshapeLHSOperatorType reshape_lhs;
572 ReshapeRHSOperatorType reshape_rhs;
573 GEMMOperatorType gemm;
574 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
575 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
576 gemm.configure(gpu_arch, lhs_reshaped.info(), rhs_reshaped.info(), bias.info(), dst.info(), alpha, beta, true, reshape_info, fp16_mixed_precision, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100577
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100578 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
579 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
580 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100581
Georgios Pinitas3dca91b2021-04-13 13:35:58 +0100582 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +0000583 if(!rhs_info.export_to_cl_image)
584 {
585 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
586 }
587
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100588 // Allocate tensors
589 lhs.allocator()->allocate();
590 rhs.allocator()->allocate();
591 lhs_reshaped.allocator()->allocate();
592 rhs_reshaped.allocator()->allocate();
593 bias.allocator()->allocate();
594 dst.allocator()->allocate();
595
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100596 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
597 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
598 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
599 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
600 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
601 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100602
603 // Fill tensors
604 fill(AccessorType(lhs), 0);
605 fill(AccessorType(rhs), 1);
606 fill(AccessorType(bias), 2);
607
608 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100609 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
610 reshape_lhs.run(reshape_lhs_pack);
611 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
612 reshape_rhs.run(reshape_rhs_pack);
613 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
614 { ACL_SRC_1, &rhs_reshaped },
615 { ACL_SRC_2, &bias },
Jakub Sujak0d27b2e2023-08-24 14:01:20 +0100616 { ACL_DST, &dst } });
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100617 gemm.run(gemm_pack);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100618
619 return dst;
620 }
621
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100622 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100623 const ActivationLayerInfo &act_info)
624 {
625 TensorShape dst_shape = lhs_shape;
626 dst_shape[0] = rhs_shape[0];
627 dst_shape[1] = lhs_shape[1];
628
629 // Create reference
630 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
631 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
632 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
633
634 const int n = rhs_shape[0];
635 const int m = lhs_shape[1];
636 const int batch_size = lhs_shape[2];
637
638 // Fill reference
639 fill(lhs, 0);
640 fill(rhs, 1);
641 fill(bias, 2);
642
643 if(broadcast_bias)
644 {
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000645 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100646 for(int i = 1; i < m * batch_size; i++)
647 {
648 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
649 }
650 }
651
652 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
653 }
654
655 TensorType _target{};
656 SimpleTensor<T> _reference{};
657};
658
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100659template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSOperatorType, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100660class GEMMMatrixMultiplyInterleavedTransposed3DValidationFixture : public framework::Fixture
661{
662public:
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100663 void setup(unsigned int m_w, unsigned int m_h, unsigned int n, unsigned int k, unsigned int batch_size, float alpha, float beta, unsigned int v0, unsigned int h0, bool broadcast_bias,
664 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
665 {
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100666 ARM_COMPUTE_UNUSED(broadcast_bias);
667
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100668 GEMMLHSMatrixInfo lhs_info;
669 lhs_info.m0 = 4;
670 lhs_info.k0 = 4;
671 lhs_info.v0 = v0;
672 lhs_info.interleave = true;
673 lhs_info.transpose = true;
674
675 GEMMRHSMatrixInfo rhs_info;
676 rhs_info.n0 = 16 / sizeof(T);
677 rhs_info.k0 = 1;
678 rhs_info.h0 = h0;
679 rhs_info.interleave = false;
680 rhs_info.transpose = false;
681
682 // In case of GEMM3D, m is the product between m_w and m_h
683 const unsigned int m = m_w * m_h;
684
685 // Set the tensor shapes for LHS and RHS matrices
686 const TensorShape lhs_shape(k, m, batch_size);
687 const TensorShape rhs_shape(n, k, batch_size);
688 const TensorShape bias_shape(n, 1, 1);
689
690 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, fp16_mixed_precision, act_info, gpu_arch);
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100691 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100692 }
693
694protected:
695 template <typename U>
696 void fill(U &&tensor, int i)
697 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000698 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
Giorgio Arena33b103b2021-01-08 10:37:15 +0000699 using DistributionType = typename std::conditional<std::is_same<T, half>::value, arm_compute::utils::uniform_real_distribution_16bit<T>, std::uniform_real_distribution<T>>::type;
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000700
701 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100702 library->fill(tensor, distribution, i);
703 }
704
705 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
706 DataType data_type, float alpha, float beta, unsigned int m_h, bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
707 {
708 // Create tensors
709 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
710 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
711 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
712 TensorType lhs_reshaped;
713 TensorType rhs_reshaped;
714 TensorType dst;
715
716 const unsigned int m = lhs_shape[1];
717 const unsigned int n = rhs_shape[0];
718 const unsigned int k = lhs_shape[0];
719 GEMMReshapeInfo reshape_info(m, n, k, rhs_info.h0, lhs_info.v0, m_h, false, true);
720
721 // The output tensor will be auto-initialized within the function
722
723 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100724 ReshapeLHSOperatorType reshape_lhs;
725 ReshapeRHSOperatorType reshape_rhs;
726 GEMMOperatorType gemm;
727 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
728 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
729 gemm.configure(gpu_arch, lhs_reshaped.info(), rhs_reshaped.info(), bias.info(), dst.info(), alpha, beta, true, reshape_info, fp16_mixed_precision, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100730
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100731 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
732 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
733 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100734
Georgios Pinitas3dca91b2021-04-13 13:35:58 +0100735 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +0000736 if(!rhs_info.export_to_cl_image)
737 {
738 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
739 }
740
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100741 // Allocate tensors
742 lhs.allocator()->allocate();
743 rhs.allocator()->allocate();
744 lhs_reshaped.allocator()->allocate();
745 rhs_reshaped.allocator()->allocate();
746 bias.allocator()->allocate();
747 dst.allocator()->allocate();
748
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100749 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
750 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
751 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
752 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
753 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
754 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100755
756 // Fill tensors
757 fill(AccessorType(lhs), 0);
758 fill(AccessorType(rhs), 1);
759 fill(AccessorType(bias), 2);
760
761 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100762 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
763 reshape_lhs.run(reshape_lhs_pack);
764 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
765 reshape_rhs.run(reshape_rhs_pack);
766 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
767 { ACL_SRC_1, &rhs_reshaped },
768 { ACL_SRC_2, &bias },
Jakub Sujak0d27b2e2023-08-24 14:01:20 +0100769 { ACL_DST, &dst } });
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100770 gemm.run(gemm_pack);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100771
772 return dst;
773 }
774
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100775 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, unsigned int m_h,
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100776 const ActivationLayerInfo &act_info)
777 {
778 TensorShape dst_shape = lhs_shape;
779 dst_shape.set(0, rhs_shape[0]);
780 dst_shape.set(1, lhs_shape[1] / m_h);
781 dst_shape.set(2, m_h);
782 dst_shape.set(3, lhs_shape[2]);
783
784 // Create reference
785 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
786 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
787 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
788
789 const int n = rhs_shape[0];
790 const int m = lhs_shape[1];
791 const int batch_size = lhs_shape[2];
792
793 // Fill reference
794 fill(lhs, 0);
795 fill(rhs, 1);
796 fill(bias, 2);
797
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000798 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100799 for(int i = 1; i < m * batch_size; i++)
800 {
801 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
802 }
803
804 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
805 }
806
807 TensorType _target{};
808 SimpleTensor<T> _reference{};
809};
810
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100811template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSOperatorType, typename ReshapeRHSOperatorType, typename GEMMOperatorType, bool fp_mixed_precision = false>
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000812class GEMMMatrixMultiplyReshapedValidationFixture : public framework::Fixture
813{
814public:
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000815 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,
Gian Marco Iodicee3a849a2020-06-10 17:59:30 +0100816 bool interleave_rhs, bool export_to_cl_image, DataType data_type, float alpha, float beta, bool broadcast_bias, bool lhs_transpose, const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000817 {
818 GEMMLHSMatrixInfo lhs_info;
819 lhs_info.m0 = m0;
820 lhs_info.k0 = k0;
821 lhs_info.v0 = v0;
822 lhs_info.interleave = interleave_lhs;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100823 lhs_info.transpose = lhs_transpose;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000824
825 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodicee3a849a2020-06-10 17:59:30 +0100826 rhs_info.n0 = n0;
827 rhs_info.k0 = k0;
828 rhs_info.h0 = h0;
829 rhs_info.interleave = interleave_rhs;
830 rhs_info.transpose = !lhs_transpose;
831 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000832
833 // Set the tensor shapes for LHS and RHS matrices
834 const TensorShape lhs_shape(k, m, batch_size);
835 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100836 const TensorShape bias_shape(n,
837 broadcast_bias ? 1 : m,
838 broadcast_bias ? 1 : batch_size);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000839
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000840 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
841 if(validate_result)
842 {
843 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
844 }
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000845 }
846
847protected:
848 template <typename U>
849 void fill(U &&tensor, int i)
850 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000851 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
Giorgio Arena33b103b2021-01-08 10:37:15 +0000852 using DistributionType = typename std::conditional<std::is_same<T, half>::value, arm_compute::utils::uniform_real_distribution_16bit<T>, std::uniform_real_distribution<T>>::type;
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000853
854 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000855 library->fill(tensor, distribution, i);
Gian Marco Iodiceb87b95e2019-01-21 17:14:31 +0000856
857 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000858 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiceb87b95e2019-01-21 17:14:31 +0000859 library->fill_borders_with_garbage(tensor, distribution_inf, i);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000860 }
861
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100862 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100863 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000864 {
865 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100866 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
867 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
868 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000869 TensorType lhs_reshaped;
870 TensorType rhs_reshaped;
871 TensorType dst;
872
873 const unsigned int M = lhs_shape[1];
874 const unsigned int N = rhs_shape[0];
875 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100876 GEMMKernelInfo kernel_info;
877 kernel_info.m = M;
878 kernel_info.n = N;
879 kernel_info.k = K;
880 kernel_info.depth_output_gemm3d = 0;
881 kernel_info.reinterpret_input_as_3d = false;
882 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100883 kernel_info.activation_info = act_info;
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100884 kernel_info.fp_mixed_precision = fp_mixed_precision;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000885
886 // The output tensor will be auto-initialized within the function
887
888 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100889 ReshapeLHSOperatorType reshape_lhs;
890 ReshapeRHSOperatorType reshape_rhs;
891 GEMMOperatorType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000892
893 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
894 validate_result = validate_result || !rhs_info.export_to_cl_image;
895 if(!validate_result)
896 {
897 return nullptr;
898 }
899
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100900 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
901 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
902 gemm.configure(lhs_reshaped.info(), rhs_reshaped.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000903
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100904 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
905 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
906 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000907
Georgios Pinitas3dca91b2021-04-13 13:35:58 +0100908 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +0000909 if(!rhs_info.export_to_cl_image)
910 {
911 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
912 }
913
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000914 // Allocate tensors
915 lhs.allocator()->allocate();
916 rhs.allocator()->allocate();
917 lhs_reshaped.allocator()->allocate();
918 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100919 bias.allocator()->allocate();
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000920 dst.allocator()->allocate();
921
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100922 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
923 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
924 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
925 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
926 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
927 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000928
929 // Fill tensors
930 fill(AccessorType(lhs), 0);
931 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100932 fill(AccessorType(bias), 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000933
934 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100935 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
936 reshape_lhs.run(reshape_lhs_pack);
937 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
938 reshape_rhs.run(reshape_rhs_pack);
939 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
940 { ACL_SRC_1, &rhs_reshaped },
941 { ACL_SRC_2, &bias },
Jakub Sujak0d27b2e2023-08-24 14:01:20 +0100942 { ACL_DST, &dst } });
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100943 gemm.run(gemm_pack);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000944
945 return dst;
946 }
947
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100948 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100949 const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000950 {
951 TensorShape dst_shape = lhs_shape;
952 dst_shape[0] = rhs_shape[0];
953 dst_shape[1] = lhs_shape[1];
954
955 // Create reference
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000956 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
957 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100958 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
959
960 const int n = rhs_shape[0];
961 const int m = lhs_shape[1];
962 const int batch_size = lhs_shape[2];
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000963
964 // Fill reference
965 fill(lhs, 0);
966 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100967 fill(bias, 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000968
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100969 if(broadcast_bias)
970 {
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000971 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100972 for(int i = 1; i < m * batch_size; i++)
973 {
974 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
975 }
976 }
977
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100978 if(fp_mixed_precision)
979 {
980 return reference::activation_layer(reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta), act_info);
981 }
982 else
983 {
984 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
985 }
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000986 }
987
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000988 bool validate_result = true;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000989 TensorType _target{};
990 SimpleTensor<T> _reference{};
991};
992
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100993template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSOperatorType, typename ReshapeRHSOperatorType, typename GEMMOperatorType, bool fp_mixed_precision = false>
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000994class GEMMMatrixMultiplyReshaped3DValidationFixture : public framework::Fixture
995{
996public:
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000997 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,
Gian Marco Iodicee3a849a2020-06-10 17:59:30 +0100998 bool interleave_lhs, bool interleave_rhs, bool export_to_cl_image, DataType data_type, float alpha, float beta, bool lhs_transpose, const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000999 {
1000 GEMMLHSMatrixInfo lhs_info;
1001 lhs_info.m0 = m0;
1002 lhs_info.k0 = k0;
1003 lhs_info.v0 = v0;
1004 lhs_info.interleave = interleave_lhs;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +01001005 lhs_info.transpose = lhs_transpose;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001006
1007 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodicee3a849a2020-06-10 17:59:30 +01001008 rhs_info.n0 = n0;
1009 rhs_info.k0 = k0;
1010 rhs_info.h0 = h0;
1011 rhs_info.interleave = interleave_rhs;
1012 rhs_info.transpose = !lhs_transpose;
1013 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001014
1015 // In case of GEMM3D, m is the product between m_w and m_h
1016 const unsigned int m = m_w * m_h;
1017
1018 // Set the tensor shapes for LHS and RHS matrices
1019 const TensorShape lhs_shape(k, m, batch_size);
1020 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001021 const TensorShape bias_shape(n, 1, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001022
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001023 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info);
1024 if(validate_result)
1025 {
1026 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
1027 }
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001028 }
1029
1030protected:
1031 template <typename U>
1032 void fill(U &&tensor, int i)
1033 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001034 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
Giorgio Arena33b103b2021-01-08 10:37:15 +00001035 using DistributionType = typename std::conditional<std::is_same<T, half>::value, arm_compute::utils::uniform_real_distribution_16bit<T>, std::uniform_real_distribution<T>>::type;
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001036
1037 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001038 library->fill(tensor, distribution, i);
1039 }
1040
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001041 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001042 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001043 {
1044 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001045 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1046 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1047 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001048 TensorType lhs_reshaped;
1049 TensorType rhs_reshaped;
1050 TensorType dst;
1051
1052 const unsigned int M = lhs_shape[1];
1053 const unsigned int N = rhs_shape[0];
1054 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001055 GEMMKernelInfo kernel_info;
1056 kernel_info.m = M;
1057 kernel_info.n = N;
1058 kernel_info.k = K;
1059 kernel_info.depth_output_gemm3d = m_h;
1060 kernel_info.reinterpret_input_as_3d = false;
1061 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001062 kernel_info.activation_info = act_info;
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +01001063 kernel_info.fp_mixed_precision = fp_mixed_precision;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001064
1065 // The output tensor will be auto-initialized within the function
1066
1067 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001068 ReshapeLHSOperatorType reshape_lhs;
1069 ReshapeRHSOperatorType reshape_rhs;
1070 GEMMOperatorType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001071
1072 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1073 validate_result = validate_result || !rhs_info.export_to_cl_image;
1074 if(!validate_result)
1075 {
1076 return nullptr;
1077 }
1078
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001079 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
1080 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1081 gemm.configure(lhs_reshaped.info(), rhs_reshaped.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001082
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001083 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1084 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1085 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001086
Georgios Pinitas3dca91b2021-04-13 13:35:58 +01001087 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +00001088 if(!rhs_info.export_to_cl_image)
1089 {
1090 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
1091 }
1092
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001093 // Allocate tensors
1094 lhs.allocator()->allocate();
1095 rhs.allocator()->allocate();
1096 lhs_reshaped.allocator()->allocate();
1097 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001098 bias.allocator()->allocate();
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001099 dst.allocator()->allocate();
1100
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001101 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1102 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1103 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
1104 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1105 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1106 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001107
1108 // Fill tensors
1109 fill(AccessorType(lhs), 0);
1110 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001111 fill(AccessorType(bias), 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001112
1113 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001114 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
1115 reshape_lhs.run(reshape_lhs_pack);
1116 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1117 reshape_rhs.run(reshape_rhs_pack);
1118 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
1119 { ACL_SRC_1, &rhs_reshaped },
1120 { ACL_SRC_2, &bias },
Jakub Sujak0d27b2e2023-08-24 14:01:20 +01001121 { ACL_DST, &dst } });
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001122 gemm.run(gemm_pack);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001123
1124 return dst;
1125 }
1126
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001127 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, unsigned int m_h,
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001128 const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001129 {
1130 TensorShape dst_shape = lhs_shape;
1131 dst_shape.set(0, rhs_shape[0]);
1132 dst_shape.set(1, lhs_shape[1] / m_h);
1133 dst_shape.set(2, m_h);
1134 dst_shape.set(3, lhs_shape[2]);
1135
1136 // Create reference
1137 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1138 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001139 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1140
1141 const int n = rhs_shape[0];
1142 const int m = lhs_shape[1];
1143 const int batch_size = lhs_shape[2];
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001144
1145 // Fill reference
1146 fill(lhs, 0);
1147 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001148 fill(bias, 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001149
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00001150 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001151 for(int i = 1; i < m * batch_size; i++)
1152 {
1153 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1154 }
1155
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +01001156 if(fp_mixed_precision)
1157 {
1158 return reference::activation_layer(reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta), act_info);
1159 }
1160 else
1161 {
1162 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
1163 }
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001164 }
1165
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001166 bool validate_result = true;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001167 TensorType _target{};
1168 SimpleTensor<T> _reference{};
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +00001169};
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001170
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001171template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001172class GEMMMatrixMultiplyReshapedOnlyRHSValidationFixture : public framework::Fixture
1173{
1174public:
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001175 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 h0,
Gian Marco Iodice781cba72020-06-19 16:56:57 +01001176 bool interleave_rhs, bool transpose_rhs, bool export_to_cl_image, DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001177 {
1178 GEMMLHSMatrixInfo lhs_info;
1179 lhs_info.m0 = m0;
1180 lhs_info.k0 = k0;
1181
1182 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodice781cba72020-06-19 16:56:57 +01001183 rhs_info.n0 = n0;
1184 rhs_info.k0 = k0;
1185 rhs_info.h0 = h0;
1186 rhs_info.interleave = interleave_rhs;
1187 rhs_info.transpose = transpose_rhs;
1188 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001189
1190 // Set the tensor shapes for LHS and RHS matrices
1191 const TensorShape lhs_shape(k, m, batch_size);
1192 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001193 const TensorShape bias_shape(n,
1194 broadcast_bias ? 1 : m,
1195 broadcast_bias ? 1 : batch_size);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001196
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001197 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
1198 if(validate_result)
1199 {
1200 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
1201 }
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001202 }
1203
1204protected:
1205 template <typename U>
1206 void fill(U &&tensor, int i)
1207 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001208 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
Giorgio Arena33b103b2021-01-08 10:37:15 +00001209 using DistributionType = typename std::conditional<std::is_same<T, half>::value, arm_compute::utils::uniform_real_distribution_16bit<T>, std::uniform_real_distribution<T>>::type;
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001210
1211 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001212 library->fill(tensor, distribution, i);
1213
1214 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001215 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001216 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1217 }
1218
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001219 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001220 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001221 {
1222 // Create tensors
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001223 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1224 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1225 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001226 TensorType rhs_reshaped;
1227 TensorType dst;
1228
1229 const unsigned int M = lhs_shape[1];
1230 const unsigned int N = rhs_shape[0];
1231 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001232 GEMMKernelInfo kernel_info;
1233 kernel_info.m = M;
1234 kernel_info.n = N;
1235 kernel_info.k = K;
1236 kernel_info.depth_output_gemm3d = 0;
1237 kernel_info.reinterpret_input_as_3d = false;
1238 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001239 kernel_info.activation_info = act_info;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001240
1241 // The output tensor will be auto-initialized within the function
1242
1243 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001244 ReshapeRHSOperatorType reshape_rhs;
1245 GEMMOperatorType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001246
1247 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1248 validate_result = validate_result || !rhs_info.export_to_cl_image;
1249 if(!validate_result)
1250 {
1251 return nullptr;
1252 }
1253
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001254 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1255 gemm.configure(lhs.info(), rhs_reshaped.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001256
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001257 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1258 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1259 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001260
Georgios Pinitas3dca91b2021-04-13 13:35:58 +01001261 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +00001262 if(!rhs_info.export_to_cl_image)
1263 {
1264 add_padding_x({ &lhs, &rhs, &rhs_reshaped, &bias, &dst });
1265 }
1266
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001267 // Allocate tensors
1268 lhs.allocator()->allocate();
1269 rhs.allocator()->allocate();
1270 rhs_reshaped.allocator()->allocate();
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001271 bias.allocator()->allocate();
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001272 dst.allocator()->allocate();
1273
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001274 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1275 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1276 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1277 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1278 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001279
1280 // Fill tensors
1281 fill(AccessorType(lhs), 0);
1282 fill(AccessorType(rhs), 1);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001283 fill(AccessorType(bias), 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001284
1285 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001286 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1287 reshape_rhs.run(reshape_rhs_pack);
1288 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
1289 { ACL_SRC_1, &rhs_reshaped },
1290 { ACL_SRC_2, &bias },
Jakub Sujak0d27b2e2023-08-24 14:01:20 +01001291 { ACL_DST, &dst } });
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001292 gemm.run(gemm_pack);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001293
1294 return dst;
1295 }
1296
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001297 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001298 const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001299 {
1300 TensorShape dst_shape = lhs_shape;
1301 dst_shape[0] = rhs_shape[0];
1302 dst_shape[1] = lhs_shape[1];
1303
1304 // Create reference
1305 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1306 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001307 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1308
1309 const int n = rhs_shape[0];
1310 const int m = lhs_shape[1];
1311 const int batch_size = lhs_shape[2];
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001312
1313 // Fill reference
1314 fill(lhs, 0);
1315 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001316 fill(bias, 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001317
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001318 if(broadcast_bias)
1319 {
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00001320 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001321 for(int i = 1; i < m * batch_size; i++)
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001322 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001323 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001324 }
1325 }
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001326
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001327 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001328 }
1329
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001330 bool validate_result = true;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001331 TensorType _target{};
1332 SimpleTensor<T> _reference{};
1333};
1334
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001335template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001336class GEMMMatrixMultiplyReshapedOnlyRHS3DValidationFixture : public framework::Fixture
1337{
1338public:
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001339 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 h0,
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001340 bool interleave_rhs, bool transpose_rhs, bool export_to_cl_image, bool has_pad_y, DataType data_type, float alpha, float beta, const ActivationLayerInfo &act_info)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001341 {
1342 GEMMLHSMatrixInfo lhs_info;
1343 lhs_info.m0 = m0;
1344 lhs_info.k0 = k0;
1345
1346 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodice781cba72020-06-19 16:56:57 +01001347 rhs_info.n0 = n0;
1348 rhs_info.k0 = k0;
1349 rhs_info.h0 = h0;
1350 rhs_info.interleave = interleave_rhs;
1351 rhs_info.transpose = transpose_rhs;
1352 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001353
1354 // In case of GEMM3D, m is the product between m_w and m_h
1355 const unsigned int m = m_w * m_h;
1356
1357 // Set the tensor shapes for LHS and RHS matrices
1358 const TensorShape lhs_shape(k, m, batch_size);
1359 const TensorShape rhs_shape(n, k, batch_size);
1360 const TensorShape bias_shape(n, 1, 1);
1361
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001362 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info, has_pad_y);
1363 if(validate_result)
1364 {
1365 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
1366 }
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001367 }
1368
1369protected:
1370 template <typename U>
1371 void fill(U &&tensor, int i)
1372 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001373 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
Giorgio Arena33b103b2021-01-08 10:37:15 +00001374 using DistributionType = typename std::conditional<std::is_same<T, half>::value, arm_compute::utils::uniform_real_distribution_16bit<T>, std::uniform_real_distribution<T>>::type;
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001375
1376 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001377 library->fill(tensor, distribution, i);
1378 }
1379
1380 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
1381 DataType data_type, float alpha, float beta,
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001382 unsigned int m_h, const ActivationLayerInfo &act_info, bool has_pad_y)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001383 {
1384 // Create tensors
1385 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1386 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1387 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
1388 TensorType rhs_reshaped;
1389 TensorType dst;
1390
1391 const unsigned int M = lhs_shape[1];
1392 const unsigned int N = rhs_shape[0];
1393 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001394 GEMMKernelInfo kernel_info;
1395 kernel_info.m = M;
1396 kernel_info.n = N;
1397 kernel_info.k = K;
1398 kernel_info.depth_output_gemm3d = m_h;
1399 kernel_info.reinterpret_input_as_3d = false;
1400 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001401 kernel_info.activation_info = act_info;
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001402 kernel_info.has_pad_y = has_pad_y;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001403
1404 // The output tensor will be auto-initialized within the function
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001405 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001406 ReshapeRHSOperatorType reshape_rhs;
1407 GEMMOperatorType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001408
1409 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1410 validate_result = validate_result || !rhs_info.export_to_cl_image;
1411 if(!validate_result)
1412 {
1413 return nullptr;
1414 }
1415
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001416 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1417 gemm.configure(lhs.info(), rhs_reshaped.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001418
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001419 if(has_pad_y)
1420 {
1421 // Add dummy padding into lhs to validate has_pad_y path
1422 lhs.info()->extend_padding(PaddingSize(2, 0, 2, 0));
1423 dst.info()->extend_padding(PaddingSize(2, 0, 1, 0));
1424 }
1425
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001426 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1427 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1428 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001429
Georgios Pinitas3dca91b2021-04-13 13:35:58 +01001430 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +00001431 if(!rhs_info.export_to_cl_image)
1432 {
1433 add_padding_x({ &lhs, &rhs, &rhs_reshaped, &bias, &dst });
1434 }
1435
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001436 // Allocate tensors
1437 lhs.allocator()->allocate();
1438 rhs.allocator()->allocate();
1439 rhs_reshaped.allocator()->allocate();
1440 bias.allocator()->allocate();
1441 dst.allocator()->allocate();
1442
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001443 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1444 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1445 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1446 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1447 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001448
1449 // Fill tensors
1450 fill(AccessorType(lhs), 0);
1451 fill(AccessorType(rhs), 1);
1452 fill(AccessorType(bias), 2);
1453
1454 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001455 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1456 reshape_rhs.run(reshape_rhs_pack);
1457 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
1458 { ACL_SRC_1, &rhs_reshaped },
1459 { ACL_SRC_2, &bias },
Jakub Sujak0d27b2e2023-08-24 14:01:20 +01001460 { ACL_DST, &dst } });
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001461 gemm.run(gemm_pack);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001462
1463 return dst;
1464 }
1465
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001466 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, unsigned int m_h,
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001467 const ActivationLayerInfo &act_info)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001468 {
1469 TensorShape dst_shape = lhs_shape;
1470 dst_shape.set(0, rhs_shape[0]);
1471 dst_shape.set(1, lhs_shape[1] / m_h);
1472 dst_shape.set(2, m_h);
1473 dst_shape.set(3, lhs_shape[2]);
1474
1475 // Create reference
1476 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1477 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
1478 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1479
1480 const int n = rhs_shape[0];
1481 const int m = lhs_shape[1];
1482 const int batch_size = lhs_shape[2];
1483
1484 // Fill reference
1485 fill(lhs, 0);
1486 fill(rhs, 1);
1487 fill(bias, 2);
1488
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00001489 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001490 for(int i = 1; i < m * batch_size; i++)
1491 {
1492 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1493 }
1494
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001495 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001496 }
1497
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001498 bool validate_result = true;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001499 TensorType _target{};
1500 SimpleTensor<T> _reference{};
1501};
1502
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001503template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
giuros01b3204e72019-04-01 13:50:22 +01001504class GEMMMatrixMultiplyNativeValidationFixture : public framework::Fixture
1505{
1506public:
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001507 void setup(unsigned int m, unsigned int n, unsigned int k, unsigned int batch_size, unsigned int m0, unsigned int n0, unsigned int k0, DataType data_type, float alpha, float beta, bool broadcast_bias,
1508 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001509 {
1510 GEMMLHSMatrixInfo lhs_info;
1511 lhs_info.m0 = m0;
1512 lhs_info.k0 = k0;
1513
1514 GEMMRHSMatrixInfo rhs_info;
1515 rhs_info.n0 = n0;
1516 rhs_info.k0 = k0;
1517
1518 // Set the tensor shapes for LHS and RHS matrices
1519 const TensorShape lhs_shape(k, m, batch_size);
1520 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001521 const TensorShape bias_shape(n,
1522 broadcast_bias ? 1 : m,
1523 broadcast_bias ? 1 : batch_size);
giuros01b3204e72019-04-01 13:50:22 +01001524
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001525 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001526 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
giuros01b3204e72019-04-01 13:50:22 +01001527 }
1528
1529protected:
1530 template <typename U>
1531 void fill(U &&tensor, int i)
1532 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001533 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
Giorgio Arena33b103b2021-01-08 10:37:15 +00001534 using DistributionType = typename std::conditional<std::is_same<T, half>::value, arm_compute::utils::uniform_real_distribution_16bit<T>, std::uniform_real_distribution<T>>::type;
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001535
1536 DistributionType distribution{ T(-1.0f), T(1.0f) };
giuros01b3204e72019-04-01 13:50:22 +01001537 library->fill(tensor, distribution, i);
1538
1539 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001540 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
giuros01b3204e72019-04-01 13:50:22 +01001541 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1542 }
1543
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001544 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001545 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001546 {
1547 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001548 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1549 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1550 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01001551 TensorType dst;
1552
1553 const unsigned int M = lhs_shape[1];
1554 const unsigned int N = rhs_shape[0];
1555 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001556 GEMMKernelInfo kernel_info;
1557 kernel_info.m = M;
1558 kernel_info.n = N;
1559 kernel_info.k = K;
1560 kernel_info.depth_output_gemm3d = 0;
1561 kernel_info.reinterpret_input_as_3d = false;
1562 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001563 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01001564
1565 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001566 GEMMOperatorType gemm;
1567 gemm.configure(lhs.info(), rhs.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01001568
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001569 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1570 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1571 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
giuros01b3204e72019-04-01 13:50:22 +01001572
Giorgio Arena63825e82021-03-25 14:54:50 +00001573 add_padding_x({ &lhs, &rhs, &bias, &dst });
1574
giuros01b3204e72019-04-01 13:50:22 +01001575 // Allocate tensors
1576 lhs.allocator()->allocate();
1577 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001578 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01001579 dst.allocator()->allocate();
1580
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001581 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1582 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1583 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1584 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
giuros01b3204e72019-04-01 13:50:22 +01001585
1586 // Fill tensors
1587 fill(AccessorType(lhs), 0);
1588 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001589 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01001590
1591 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001592 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
1593 { ACL_SRC_1, &rhs },
1594 { ACL_SRC_2, &bias },
Jakub Sujak0d27b2e2023-08-24 14:01:20 +01001595 { ACL_DST, &dst } });
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001596 gemm.run(gemm_pack);
giuros01b3204e72019-04-01 13:50:22 +01001597
1598 return dst;
1599 }
1600
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001601 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001602 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001603 {
1604 TensorShape dst_shape = lhs_shape;
1605 dst_shape[0] = rhs_shape[0];
1606 dst_shape[1] = lhs_shape[1];
1607
1608 // Create reference
1609 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1610 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001611 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1612
1613 const int n = rhs_shape[0];
1614 const int m = lhs_shape[1];
1615 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01001616
1617 // Fill reference
1618 fill(lhs, 0);
1619 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001620 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01001621
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001622 if(broadcast_bias)
1623 {
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00001624 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001625 for(int i = 1; i < m * batch_size; i++)
1626 {
1627 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1628 }
1629 }
1630
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001631 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01001632 }
1633
1634 TensorType _target{};
1635 SimpleTensor<T> _reference{};
1636};
1637
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001638template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
giuros01b3204e72019-04-01 13:50:22 +01001639class GEMMMatrixMultiplyNative3DValidationFixture : public framework::Fixture
1640{
1641public:
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001642 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, DataType data_type, float alpha, float beta,
1643 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001644 {
1645 GEMMLHSMatrixInfo lhs_info;
1646 lhs_info.m0 = m0;
1647 lhs_info.k0 = k0;
1648
1649 GEMMRHSMatrixInfo rhs_info;
1650 rhs_info.n0 = n0;
1651 rhs_info.k0 = k0;
1652
1653 // In case of GEMM3D, m is the product between m_w and m_h
1654 const unsigned int m = m_w * m_h;
1655
1656 // Set the tensor shapes for LHS and RHS matrices
1657 const TensorShape lhs_shape(k, m, batch_size);
1658 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001659 const TensorShape bias_shape(n, 1, 1);
giuros01b3204e72019-04-01 13:50:22 +01001660
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001661 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info);
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001662 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
giuros01b3204e72019-04-01 13:50:22 +01001663 }
1664
1665protected:
1666 template <typename U>
1667 void fill(U &&tensor, int i)
1668 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001669 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
Giorgio Arena33b103b2021-01-08 10:37:15 +00001670 using DistributionType = typename std::conditional<std::is_same<T, half>::value, arm_compute::utils::uniform_real_distribution_16bit<T>, std::uniform_real_distribution<T>>::type;
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001671
1672 DistributionType distribution{ T(-1.0f), T(1.0f) };
giuros01b3204e72019-04-01 13:50:22 +01001673 library->fill(tensor, distribution, i);
1674 }
1675
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001676 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001677 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001678 {
1679 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001680 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1681 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1682 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01001683 TensorType dst;
1684
1685 const unsigned int M = lhs_shape[1];
1686 const unsigned int N = rhs_shape[0];
1687 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001688 GEMMKernelInfo kernel_info;
1689 kernel_info.m = M;
1690 kernel_info.n = N;
1691 kernel_info.k = K;
1692 kernel_info.depth_output_gemm3d = m_h;
1693 kernel_info.reinterpret_input_as_3d = false;
1694 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001695 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01001696
1697 // The output tensor will be auto-initialized within the function
1698
1699 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001700 GEMMOperatorType gemm;
1701 gemm.configure(lhs.info(), rhs.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01001702
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001703 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1704 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1705 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
giuros01b3204e72019-04-01 13:50:22 +01001706
Giorgio Arena63825e82021-03-25 14:54:50 +00001707 add_padding_x({ &lhs, &rhs, &bias, &dst });
1708
giuros01b3204e72019-04-01 13:50:22 +01001709 // Allocate tensors
1710 lhs.allocator()->allocate();
1711 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001712 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01001713 dst.allocator()->allocate();
1714
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001715 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1716 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1717 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1718 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
giuros01b3204e72019-04-01 13:50:22 +01001719
1720 // Fill tensors
1721 fill(AccessorType(lhs), 0);
1722 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001723 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01001724
1725 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001726 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
1727 { ACL_SRC_1, &rhs },
1728 { ACL_SRC_2, &bias },
Jakub Sujak0d27b2e2023-08-24 14:01:20 +01001729 { ACL_DST, &dst } });
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001730 gemm.run(gemm_pack);
giuros01b3204e72019-04-01 13:50:22 +01001731
1732 return dst;
1733 }
1734
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001735 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, unsigned int m_h,
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001736 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001737 {
1738 TensorShape dst_shape = lhs_shape;
1739 dst_shape.set(0, rhs_shape[0]);
1740 dst_shape.set(1, lhs_shape[1] / m_h);
1741 dst_shape.set(2, m_h);
1742 dst_shape.set(3, lhs_shape[2]);
1743
1744 // Create reference
1745 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1746 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001747 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1748
1749 const int n = rhs_shape[0];
1750 const int m = lhs_shape[1];
1751 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01001752
1753 // Fill reference
1754 fill(lhs, 0);
1755 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001756 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01001757
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00001758 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001759 for(int i = 1; i < m * batch_size; i++)
1760 {
1761 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1762 }
1763
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001764 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01001765 }
1766
1767 TensorType _target{};
1768 SimpleTensor<T> _reference{};
1769};
1770
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00001771template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
1772class GEMMMatrixMultiplyReshapedOnlyRhsMMULValidationFixture : public framework::Fixture
1773{
1774public:
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00001775 void setup(unsigned int m, unsigned int n, unsigned int k, unsigned int batch_size, unsigned int m0, unsigned int n0, unsigned int k0, bool export_to_cl_image, DataType data_type, float alpha,
1776 float beta, bool broadcast_bias,
1777 const ActivationLayerInfo &act_info)
1778 {
1779 GEMMLHSMatrixInfo lhs_info;
1780 lhs_info.m0 = m0;
1781 lhs_info.k0 = k0;
1782
1783 GEMMRHSMatrixInfo rhs_info;
1784 rhs_info.n0 = n0;
1785 rhs_info.k0 = k0;
1786 rhs_info.interleave = true;
1787 rhs_info.transpose = false;
1788 rhs_info.h0 = 4;
1789 rhs_info.export_to_cl_image = export_to_cl_image;
1790
1791 // Set the tensor shapes for LHS and RHS matrices
1792 const TensorShape lhs_shape(k, m, batch_size);
1793 const TensorShape rhs_shape(n, k, batch_size);
1794 const TensorShape bias_shape(n,
1795 broadcast_bias ? 1 : m,
1796 broadcast_bias ? 1 : batch_size);
1797
1798 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
1799 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
1800 }
1801
1802protected:
1803 template <typename U>
1804 void fill(U &&tensor, int i)
1805 {
1806 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
1807 using DistributionType = typename std::conditional<std::is_same<T, half>::value, arm_compute::utils::uniform_real_distribution_16bit<T>, std::uniform_real_distribution<T>>::type;
1808
1809 DistributionType distribution{ T(-1.0f), T(1.0f) };
1810 library->fill(tensor, distribution, i);
1811
1812 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
1813 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
1814 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1815 }
1816
1817 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
1818 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
1819 {
1820 // Create tensors
1821 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1822 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1823 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
1824 TensorType rhs_reshaped;
1825 TensorType dst;
1826
1827 const unsigned int M = lhs_shape[1];
1828 const unsigned int N = rhs_shape[0];
1829 const unsigned int K = lhs_shape[0];
1830 GEMMKernelInfo kernel_info;
1831 kernel_info.m = M;
1832 kernel_info.n = N;
1833 kernel_info.k = K;
1834 kernel_info.depth_output_gemm3d = 0;
1835 kernel_info.reinterpret_input_as_3d = false;
1836 kernel_info.broadcast_bias = broadcast_bias;
1837 kernel_info.activation_info = act_info;
1838
1839 // Create and configure function
1840 ReshapeRHSOperatorType reshape_rhs;
1841 GEMMOperatorType gemm;
1842
1843 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1844 if(!validate_result)
1845 {
1846 return nullptr;
1847 }
1848
1849 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1850
1851 validate_result = bool(gemm.validate(lhs.info(), rhs_reshaped.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info));
1852 if(!validate_result)
1853 {
1854 return nullptr;
1855 }
1856
1857 gemm.configure(lhs.info(), rhs_reshaped.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
1858
1859 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1860 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1861 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
1862
1863 // Allocate tensors
1864 lhs.allocator()->allocate();
1865 rhs.allocator()->allocate();
1866 rhs_reshaped.allocator()->allocate();
1867 bias.allocator()->allocate();
1868 dst.allocator()->allocate();
1869
1870 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1871 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1872 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1873 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1874 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
1875
1876 // Fill tensors
1877 fill(AccessorType(lhs), 0);
1878 fill(AccessorType(rhs), 1);
1879 fill(AccessorType(bias), 2);
1880
1881 // Compute GEMM
1882 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1883 reshape_rhs.run(reshape_rhs_pack);
1884 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
1885 { ACL_SRC_1, &rhs_reshaped },
1886 { ACL_SRC_2, &bias },
Jakub Sujak0d27b2e2023-08-24 14:01:20 +01001887 { ACL_DST, &dst } });
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00001888 gemm.run(gemm_pack);
1889
1890 return dst;
1891 }
1892
1893 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
1894 const ActivationLayerInfo &act_info)
1895 {
1896 if(!validate_result)
1897 return SimpleTensor<T>();
1898
1899 TensorShape dst_shape = lhs_shape;
1900 dst_shape[0] = rhs_shape[0];
1901 dst_shape[1] = lhs_shape[1];
1902
1903 // Create reference
1904 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1905 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
1906 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1907
1908 const int n = rhs_shape[0];
1909 const int m = lhs_shape[1];
1910 const int batch_size = lhs_shape[2];
1911
1912 // Fill reference
1913 fill(lhs, 0);
1914 fill(rhs, 1);
1915 fill(bias, 2);
1916
1917 if(broadcast_bias)
1918 {
1919 // In case of broadcast, we need to simply copy the first into the following "M" ones
1920 for(int i = 1; i < m * batch_size; i++)
1921 {
1922 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1923 }
1924 }
1925
1926 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
1927 }
1928
1929 bool validate_result = true;
1930 TensorType _target{};
1931 SimpleTensor<T> _reference{};
1932};
1933
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +01001934} // namespace validation
1935} // namespace test
1936} // namespace arm_compute
Jakub Sujak0d27b2e2023-08-24 14:01:20 +01001937#endif // ACL_TESTS_VALIDATION_FIXTURES_GEMMFIXTURE_H