blob: 52cd6759a775807a24dffdf941c3dd47d435e0a4 [file] [log] [blame]
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +01001/*
Giorgio Arenab309fc22021-01-05 09:46:16 +00002 * Copyright (c) 2017-2021 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 */
24#ifndef ARM_COMPUTE_TEST_GEMM_FIXTURE
25#define ARM_COMPUTE_TEST_GEMM_FIXTURE
26
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"
SiCongLi1af54162021-10-06 15:25:57 +010030#include "arm_compute/core/experimental/IPostOp.h"
SiCongLi31778612021-11-12 17:33:45 +000031#include "src/core/experimental/PostOpUtils.h"
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010032#include "tests/AssetsLibrary.h"
33#include "tests/Globals.h"
34#include "tests/IAccessor.h"
Moritz Pflanzera09de0c2017-09-01 20:41:12 +010035#include "tests/framework/Asserts.h"
36#include "tests/framework/Fixture.h"
Moritz Pflanzera09de0c2017-09-01 20:41:12 +010037#include "tests/validation/Helpers.h"
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +010038#include "tests/validation/reference/ActivationLayer.h"
SiCongLi1af54162021-10-06 15:25:57 +010039#include "tests/validation/reference/ElementwiseOperations.h"
Georgios Pinitas5a7e7762017-12-01 16:27:29 +000040#include "tests/validation/reference/GEMM.h"
SiCongLi1af54162021-10-06 15:25:57 +010041#include "tests/validation/reference/PostOps.h"
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010042
43#include <random>
44
45namespace arm_compute
46{
47namespace test
48{
49namespace validation
50{
Gian Marco Iodicef3622be2019-07-29 14:27:16 +010051template <typename TensorType, typename AccessorType, typename FunctionType, typename T, bool disable_c = false, bool reinterpret_input_as_3d = false, bool reinterpret_output_as_3d = false>
Gian Marco Iodice68a3f562018-07-26 11:44:03 +010052class GEMMValidationFixture : public framework::Fixture
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010053{
54public:
55 template <typename...>
Pablo Tello0e37b5c2018-10-30 11:18:37 +000056 void setup(TensorShape shape_a, TensorShape shape_b, TensorShape shape_c, TensorShape output_shape, float alpha, float beta, bool pretranspose, DataType data_type)
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010057 {
Michalis Spyrou6bff1952019-10-02 17:22:11 +010058 ARM_COMPUTE_UNUSED(pretranspose);
59 _target = compute_target(shape_a, shape_b, shape_c, output_shape, alpha, beta, data_type);
60 _reference = compute_reference(shape_a, shape_b, output_shape, alpha, beta, data_type);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010061 }
62
63protected:
64 template <typename U>
Pablo Tello0e37b5c2018-10-30 11:18:37 +000065 void fill(U &&tensor, int i, float lo = -1.f, float hi = 1.f)
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010066 {
67 switch(tensor.data_type())
68 {
69 case DataType::F16:
Giorgio Arena6aeb2172020-12-15 15:45:43 +000070 {
Giorgio Arenaa8e2aeb2021-01-06 11:34:57 +000071 arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ float(lo), float(hi) };
Giorgio Arena6aeb2172020-12-15 15:45:43 +000072 library->fill(tensor, distribution, i);
73 break;
74 }
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010075 case DataType::F32:
76 {
Giorgio Arena6aeb2172020-12-15 15:45:43 +000077 std::uniform_real_distribution<float> distribution(lo, hi);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010078 library->fill(tensor, distribution, i);
79 break;
80 }
81 default:
82 library->fill_tensor_uniform(tensor, i);
83 }
84 }
85
86 TensorType compute_target(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &shape_c, const TensorShape &output_shape, float alpha, float beta,
Michalis Spyrou6bff1952019-10-02 17:22:11 +010087 DataType data_type)
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010088 {
89 // Create tensors
Vidhya Sudhan Loganathan014333d2018-07-02 09:13:49 +010090 TensorType a = create_tensor<TensorType>(shape_a, data_type, 1);
91 TensorType b = create_tensor<TensorType>(shape_b, data_type, 1);
92 TensorType c = create_tensor<TensorType>(shape_c, data_type, 1);
93 TensorType dst = create_tensor<TensorType>(output_shape, data_type, 1);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010094
95 // Create and configure function
96 FunctionType gemm;
Isabella Gottardi8e74f442018-03-01 16:42:00 +000097 // The GEMMinfo includes the values of the depth in case of reinterpreted 3d output.
Gian Marco Iodice3139f032018-11-05 14:26:32 +000098 // 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 +000099 // 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 +0100100 gemm.configure(&a,
101 &b,
102 (disable_c) ? nullptr : &c,
103 &dst,
104 alpha, beta,
Georgios Pinitas4ee8b152021-07-16 16:16:43 +0100105 GEMMInfo(false, false, false, (reinterpret_output_as_3d ? output_shape[2] : 0), reinterpret_input_as_3d, false, GEMMLowpOutputStageInfo(), false, false, (reinterpret_input_as_3d
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100106 || reinterpret_output_as_3d)));
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100107 ARM_COMPUTE_ASSERT(a.info()->is_resizable());
108 ARM_COMPUTE_ASSERT(b.info()->is_resizable());
109 ARM_COMPUTE_ASSERT(c.info()->is_resizable());
110 ARM_COMPUTE_ASSERT(dst.info()->is_resizable());
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100111
Giorgio Arena63825e82021-03-25 14:54:50 +0000112 add_padding_x({ &a, &b, &c, &dst });
113
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100114 // Allocate tensors
115 a.allocator()->allocate();
116 b.allocator()->allocate();
117 c.allocator()->allocate();
118 dst.allocator()->allocate();
119
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100120 ARM_COMPUTE_ASSERT(!a.info()->is_resizable());
121 ARM_COMPUTE_ASSERT(!b.info()->is_resizable());
122 ARM_COMPUTE_ASSERT(!c.info()->is_resizable());
123 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100124
125 // Fill tensors
126 fill(AccessorType(a), 0);
127 fill(AccessorType(b), 1);
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000128 if(!disable_c)
129 {
130 fill(AccessorType(c), 2);
131 }
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100132
133 // Compute GEMM function
134 gemm.run();
135
136 return dst;
137 }
138
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100139 SimpleTensor<T> compute_reference(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &output_shape, float alpha, float beta,
Vidhya Sudhan Loganathan014333d2018-07-02 09:13:49 +0100140 DataType data_type)
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100141 {
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100142 TensorShape shape_a_to_use = shape_a;
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100143
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100144 if(reinterpret_input_as_3d)
145 {
146 // Collapse the second and third dimension if the input is 3D
147 shape_a_to_use.collapse(2U, 1U);
148 }
149
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100150 // Create reference
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100151 SimpleTensor<T> a{ shape_a_to_use, data_type, 1 };
Vidhya Sudhan Loganathan014333d2018-07-02 09:13:49 +0100152 SimpleTensor<T> b{ shape_b, data_type, 1 };
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100153 SimpleTensor<T> c{ output_shape, data_type, 1 };
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100154
155 // Fill reference
156 fill(a, 0);
157 fill(b, 1);
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100158 fill(c, 2);
159
160 if(reinterpret_input_as_3d || reinterpret_output_as_3d)
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000161 {
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100162 const int n = shape_b[0];
163 const int m = reinterpret_output_as_3d ? output_shape[1] * output_shape[2] : output_shape[1];
164 const int batch_size = reinterpret_output_as_3d ? output_shape[3] : output_shape[2];
165
166 // In case of broadcast, we need simply copy the first into the following "M" ones
167 for(int i = 1; i < m * batch_size; i++)
168 {
169 memcpy(c.data() + i * n, c.data(), n * sizeof(T));
170 }
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000171 }
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100172
173 // Setting beta to 0 will effectively disable C for the
174 // computation of the reference: alpha * A * B + 0 * C
175 return reference::gemm<T>(a, b, c, alpha, disable_c ? 0.f : beta);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100176 }
177
178 TensorType _target{};
179 SimpleTensor<T> _reference{};
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100180};
181
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100182template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100183class GEMMMatrixMultiplyValidationFixture : public framework::Fixture
184{
185public:
186 template <typename...>
187 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,
188 DataType data_type, GPUTarget gpu_arch)
189 {
190 // Set the tensor shapes for LHS and RHS matrices
191 const TensorShape lhs_shape(k, m, batch_size);
192 const TensorShape rhs_shape(n, k, batch_size);
193 const TensorShape bias_shape(n,
194 broadcast_bias ? 1 : m,
195 broadcast_bias ? 1 : batch_size);
196
197 _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 +0100198 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100199 }
200
201protected:
202 template <typename U>
203 void fill(U &&tensor, int i)
204 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000205 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 +0000206 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 +0000207
208 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100209 library->fill(tensor, distribution, i);
210
211 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000212 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100213 library->fill_borders_with_garbage(tensor, distribution_inf, i);
214 }
215
216 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,
217 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
218 {
219 // Create tensors
220 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
221 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
222 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
223 TensorType dst;
224
225 const unsigned int m = lhs_shape[1];
226 const unsigned int n = rhs_shape[0];
227 const unsigned int k = lhs_shape[0];
228 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, 0, false, broadcast_bias);
229
230 // The output tensor will be auto-initialized within the function
231
232 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100233 GEMMOperatorType gemm;
234 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 +0100235
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100236 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
237 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
238 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100239
Giorgio Arena63825e82021-03-25 14:54:50 +0000240 add_padding_x({ &lhs, &rhs, &bias, &dst });
241
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100242 // Allocate tensors
243 lhs.allocator()->allocate();
244 rhs.allocator()->allocate();
245 bias.allocator()->allocate();
246 dst.allocator()->allocate();
247
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100248 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
249 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
250 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
251 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100252
253 // Fill tensors
254 fill(AccessorType(lhs), 0);
255 fill(AccessorType(rhs), 1);
256 fill(AccessorType(bias), 2);
257
258 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100259 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
260 { ACL_SRC_1, &rhs },
261 { ACL_SRC_2, &bias },
262 { ACL_DST, &dst }
263 });
264 gemm.run(gemm_pack);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100265
266 return dst;
267 }
268
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100269 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 +0100270 const ActivationLayerInfo &act_info)
271 {
272 TensorShape dst_shape = lhs_shape;
273 dst_shape[0] = rhs_shape[0];
274 dst_shape[1] = lhs_shape[1];
275
276 // Create reference
277 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
278 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
279 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
280
281 const int n = rhs_shape[0];
282 const int m = lhs_shape[1];
283 const int batch_size = lhs_shape[2];
284
285 // Fill reference
286 fill(lhs, 0);
287 fill(rhs, 1);
288 fill(bias, 2);
289
290 if(broadcast_bias)
291 {
292 // In case of broadcast, we need simply copy the first into the following "M" ones
293 for(int i = 1; i < m * batch_size; i++)
294 {
295 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
296 }
297 }
298
299 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
300 }
301
302 TensorType _target{};
303 SimpleTensor<T> _reference{};
304};
305
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100306template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100307class GEMMMatrixMultiply3DValidationFixture : public framework::Fixture
308{
309public:
310 template <typename...>
311 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,
312 const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
313 {
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100314 ARM_COMPUTE_UNUSED(broadcast_bias);
315
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100316 // In case of GEMM3D, m is the product between m_w and m_h
317 const unsigned int m = m_w * m_h;
318
319 // Set the tensor shapes for LHS and RHS matrices
320 const TensorShape lhs_shape(k, m, batch_size);
321 const TensorShape rhs_shape(n, k, batch_size);
322 const TensorShape bias_shape(n, 1, 1);
323
324 _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 +0100325 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100326 }
327
328protected:
329 template <typename U>
330 void fill(U &&tensor, int i)
331 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000332 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 +0000333 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 +0000334
335 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100336 library->fill(tensor, distribution, i);
337 }
338
339 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,
340 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
341 {
342 // Create tensors
343 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
344 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
345 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
346 TensorType dst;
347
348 const unsigned int m = lhs_shape[1];
349 const unsigned int n = rhs_shape[0];
350 const unsigned int k = lhs_shape[0];
351 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, m_h, false, true);
352
353 // The output tensor will be auto-initialized within the function
354
355 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100356 GEMMOperatorType gemm;
357 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 +0100358
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100359 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
360 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
361 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100362
Giorgio Arena63825e82021-03-25 14:54:50 +0000363 add_padding_x({ &lhs, &rhs, &bias, &dst });
364
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100365 // Allocate tensors
366 lhs.allocator()->allocate();
367 rhs.allocator()->allocate();
368 bias.allocator()->allocate();
369 dst.allocator()->allocate();
370
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100371 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
372 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
373 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
374 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100375
376 // Fill tensors
377 fill(AccessorType(lhs), 0);
378 fill(AccessorType(rhs), 1);
379 fill(AccessorType(bias), 2);
380
381 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100382 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
383 { ACL_SRC_1, &rhs },
384 { ACL_SRC_2, &bias },
385 { ACL_DST, &dst }
386 });
387 gemm.run(gemm_pack);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100388
389 return dst;
390 }
391
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100392 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 +0100393 const ActivationLayerInfo &act_info)
394 {
395 TensorShape dst_shape = lhs_shape;
396 dst_shape.set(0, rhs_shape[0]);
397 dst_shape.set(1, lhs_shape[1] / m_h);
398 dst_shape.set(2, m_h);
399 dst_shape.set(3, lhs_shape[2]);
400
401 // Create reference
402 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
403 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
404 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
405
406 const int n = rhs_shape[0];
407 const int m = lhs_shape[1];
408 const int batch_size = lhs_shape[2];
409
410 // Fill reference
411 fill(lhs, 0);
412 fill(rhs, 1);
413 fill(bias, 2);
414
415 // In case of broadcast, we need simply copy the first into the following "M" ones
416 for(int i = 1; i < m * batch_size; i++)
417 {
418 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
419 }
420
421 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
422 }
423
424 TensorType _target{};
425 SimpleTensor<T> _reference{};
426};
427
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100428template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSOperatorType, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100429class GEMMMatrixMultiplyInterleavedTransposedValidationFixture : public framework::Fixture
430{
431public:
432 template <typename...>
433 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,
434 const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
435 {
436 GEMMLHSMatrixInfo lhs_info;
437 lhs_info.m0 = 4;
438 lhs_info.k0 = 4;
439 lhs_info.v0 = v0;
440 lhs_info.interleave = true;
441 lhs_info.transpose = true;
442
443 GEMMRHSMatrixInfo rhs_info;
444 rhs_info.n0 = 16 / sizeof(T);
445 rhs_info.k0 = 1;
446 rhs_info.h0 = h0;
447 rhs_info.interleave = false;
448 rhs_info.transpose = false;
449
450 // Set the tensor shapes for LHS and RHS matrices
451 const TensorShape lhs_shape(k, m, batch_size);
452 const TensorShape rhs_shape(n, k, batch_size);
453 const TensorShape bias_shape(n,
454 broadcast_bias ? 1 : m,
455 broadcast_bias ? 1 : batch_size);
456
457 _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 +0100458 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100459 }
460
461protected:
462 template <typename U>
463 void fill(U &&tensor, int i)
464 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000465 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 +0000466 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 +0000467
468 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100469 library->fill(tensor, distribution, i);
470
471 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000472 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100473 library->fill_borders_with_garbage(tensor, distribution_inf, i);
474 }
475
476 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
477 DataType data_type, float alpha, float beta, bool broadcast_bias, bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
478 {
479 // Create tensors
480 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
481 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
482 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
483 TensorType lhs_reshaped;
484 TensorType rhs_reshaped;
485 TensorType dst;
486
487 const unsigned int m = lhs_shape[1];
488 const unsigned int n = rhs_shape[0];
489 const unsigned int k = lhs_shape[0];
490 GEMMReshapeInfo reshape_info(m, n, k, rhs_info.h0, lhs_info.v0, 0, false, broadcast_bias);
491
492 // The output tensor will be auto-initialized within the function
493
494 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100495 ReshapeLHSOperatorType reshape_lhs;
496 ReshapeRHSOperatorType reshape_rhs;
497 GEMMOperatorType gemm;
498 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
499 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
500 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 +0100501
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100502 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
503 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
504 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100505
Georgios Pinitas3dca91b2021-04-13 13:35:58 +0100506 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +0000507 if(!rhs_info.export_to_cl_image)
508 {
509 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
510 }
511
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100512 // Allocate tensors
513 lhs.allocator()->allocate();
514 rhs.allocator()->allocate();
515 lhs_reshaped.allocator()->allocate();
516 rhs_reshaped.allocator()->allocate();
517 bias.allocator()->allocate();
518 dst.allocator()->allocate();
519
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100520 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
521 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
522 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
523 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
524 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
525 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100526
527 // Fill tensors
528 fill(AccessorType(lhs), 0);
529 fill(AccessorType(rhs), 1);
530 fill(AccessorType(bias), 2);
531
532 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100533 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
534 reshape_lhs.run(reshape_lhs_pack);
535 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
536 reshape_rhs.run(reshape_rhs_pack);
537 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
538 { ACL_SRC_1, &rhs_reshaped },
539 { ACL_SRC_2, &bias },
540 { ACL_DST, &dst }
541 });
542 gemm.run(gemm_pack);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100543
544 return dst;
545 }
546
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100547 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 +0100548 const ActivationLayerInfo &act_info)
549 {
550 TensorShape dst_shape = lhs_shape;
551 dst_shape[0] = rhs_shape[0];
552 dst_shape[1] = lhs_shape[1];
553
554 // Create reference
555 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
556 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
557 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
558
559 const int n = rhs_shape[0];
560 const int m = lhs_shape[1];
561 const int batch_size = lhs_shape[2];
562
563 // Fill reference
564 fill(lhs, 0);
565 fill(rhs, 1);
566 fill(bias, 2);
567
568 if(broadcast_bias)
569 {
570 // In case of broadcast, we need simply copy the first into the following "M" ones
571 for(int i = 1; i < m * batch_size; i++)
572 {
573 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
574 }
575 }
576
577 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
578 }
579
580 TensorType _target{};
581 SimpleTensor<T> _reference{};
582};
583
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100584template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSOperatorType, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100585class GEMMMatrixMultiplyInterleavedTransposed3DValidationFixture : public framework::Fixture
586{
587public:
588 template <typename...>
589 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,
590 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
591 {
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100592 ARM_COMPUTE_UNUSED(broadcast_bias);
593
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100594 GEMMLHSMatrixInfo lhs_info;
595 lhs_info.m0 = 4;
596 lhs_info.k0 = 4;
597 lhs_info.v0 = v0;
598 lhs_info.interleave = true;
599 lhs_info.transpose = true;
600
601 GEMMRHSMatrixInfo rhs_info;
602 rhs_info.n0 = 16 / sizeof(T);
603 rhs_info.k0 = 1;
604 rhs_info.h0 = h0;
605 rhs_info.interleave = false;
606 rhs_info.transpose = false;
607
608 // In case of GEMM3D, m is the product between m_w and m_h
609 const unsigned int m = m_w * m_h;
610
611 // Set the tensor shapes for LHS and RHS matrices
612 const TensorShape lhs_shape(k, m, batch_size);
613 const TensorShape rhs_shape(n, k, batch_size);
614 const TensorShape bias_shape(n, 1, 1);
615
616 _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 +0100617 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100618 }
619
620protected:
621 template <typename U>
622 void fill(U &&tensor, int i)
623 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000624 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 +0000625 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 +0000626
627 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100628 library->fill(tensor, distribution, i);
629 }
630
631 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
632 DataType data_type, float alpha, float beta, unsigned int m_h, bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
633 {
634 // Create tensors
635 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
636 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
637 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
638 TensorType lhs_reshaped;
639 TensorType rhs_reshaped;
640 TensorType dst;
641
642 const unsigned int m = lhs_shape[1];
643 const unsigned int n = rhs_shape[0];
644 const unsigned int k = lhs_shape[0];
645 GEMMReshapeInfo reshape_info(m, n, k, rhs_info.h0, lhs_info.v0, m_h, false, true);
646
647 // The output tensor will be auto-initialized within the function
648
649 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100650 ReshapeLHSOperatorType reshape_lhs;
651 ReshapeRHSOperatorType reshape_rhs;
652 GEMMOperatorType gemm;
653 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
654 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
655 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 +0100656
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100657 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
658 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
659 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100660
Georgios Pinitas3dca91b2021-04-13 13:35:58 +0100661 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +0000662 if(!rhs_info.export_to_cl_image)
663 {
664 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
665 }
666
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100667 // Allocate tensors
668 lhs.allocator()->allocate();
669 rhs.allocator()->allocate();
670 lhs_reshaped.allocator()->allocate();
671 rhs_reshaped.allocator()->allocate();
672 bias.allocator()->allocate();
673 dst.allocator()->allocate();
674
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100675 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
676 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
677 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
678 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
679 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
680 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100681
682 // Fill tensors
683 fill(AccessorType(lhs), 0);
684 fill(AccessorType(rhs), 1);
685 fill(AccessorType(bias), 2);
686
687 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100688 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
689 reshape_lhs.run(reshape_lhs_pack);
690 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
691 reshape_rhs.run(reshape_rhs_pack);
692 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
693 { ACL_SRC_1, &rhs_reshaped },
694 { ACL_SRC_2, &bias },
695 { ACL_DST, &dst }
696 });
697 gemm.run(gemm_pack);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100698
699 return dst;
700 }
701
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100702 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 +0100703 const ActivationLayerInfo &act_info)
704 {
705 TensorShape dst_shape = lhs_shape;
706 dst_shape.set(0, rhs_shape[0]);
707 dst_shape.set(1, lhs_shape[1] / m_h);
708 dst_shape.set(2, m_h);
709 dst_shape.set(3, lhs_shape[2]);
710
711 // Create reference
712 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
713 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
714 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
715
716 const int n = rhs_shape[0];
717 const int m = lhs_shape[1];
718 const int batch_size = lhs_shape[2];
719
720 // Fill reference
721 fill(lhs, 0);
722 fill(rhs, 1);
723 fill(bias, 2);
724
725 // In case of broadcast, we need simply copy the first into the following "M" ones
726 for(int i = 1; i < m * batch_size; i++)
727 {
728 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
729 }
730
731 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
732 }
733
734 TensorType _target{};
735 SimpleTensor<T> _reference{};
736};
737
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100738template <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 +0000739class GEMMMatrixMultiplyReshapedValidationFixture : public framework::Fixture
740{
741public:
742 template <typename...>
743 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 +0100744 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 +0000745 {
746 GEMMLHSMatrixInfo lhs_info;
747 lhs_info.m0 = m0;
748 lhs_info.k0 = k0;
749 lhs_info.v0 = v0;
750 lhs_info.interleave = interleave_lhs;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100751 lhs_info.transpose = lhs_transpose;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000752
753 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodicee3a849a2020-06-10 17:59:30 +0100754 rhs_info.n0 = n0;
755 rhs_info.k0 = k0;
756 rhs_info.h0 = h0;
757 rhs_info.interleave = interleave_rhs;
758 rhs_info.transpose = !lhs_transpose;
759 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000760
761 // Set the tensor shapes for LHS and RHS matrices
762 const TensorShape lhs_shape(k, m, batch_size);
763 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100764 const TensorShape bias_shape(n,
765 broadcast_bias ? 1 : m,
766 broadcast_bias ? 1 : batch_size);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000767
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000768 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
769 if(validate_result)
770 {
771 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
772 }
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000773 }
774
775protected:
776 template <typename U>
777 void fill(U &&tensor, int i)
778 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000779 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 +0000780 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 +0000781
782 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000783 library->fill(tensor, distribution, i);
Gian Marco Iodiceb87b95e2019-01-21 17:14:31 +0000784
785 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000786 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiceb87b95e2019-01-21 17:14:31 +0000787 library->fill_borders_with_garbage(tensor, distribution_inf, i);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000788 }
789
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100790 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 +0100791 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000792 {
793 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100794 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
795 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
796 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000797 TensorType lhs_reshaped;
798 TensorType rhs_reshaped;
799 TensorType dst;
800
801 const unsigned int M = lhs_shape[1];
802 const unsigned int N = rhs_shape[0];
803 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100804 GEMMKernelInfo kernel_info;
805 kernel_info.m = M;
806 kernel_info.n = N;
807 kernel_info.k = K;
808 kernel_info.depth_output_gemm3d = 0;
809 kernel_info.reinterpret_input_as_3d = false;
810 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100811 kernel_info.activation_info = act_info;
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100812 kernel_info.fp_mixed_precision = fp_mixed_precision;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000813
814 // The output tensor will be auto-initialized within the function
815
816 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100817 ReshapeLHSOperatorType reshape_lhs;
818 ReshapeRHSOperatorType reshape_rhs;
819 GEMMOperatorType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000820
821 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
822 validate_result = validate_result || !rhs_info.export_to_cl_image;
823 if(!validate_result)
824 {
825 return nullptr;
826 }
827
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100828 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
829 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
830 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 +0000831
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100832 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
833 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
834 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000835
Georgios Pinitas3dca91b2021-04-13 13:35:58 +0100836 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +0000837 if(!rhs_info.export_to_cl_image)
838 {
839 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
840 }
841
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000842 // Allocate tensors
843 lhs.allocator()->allocate();
844 rhs.allocator()->allocate();
845 lhs_reshaped.allocator()->allocate();
846 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100847 bias.allocator()->allocate();
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000848 dst.allocator()->allocate();
849
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100850 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
851 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
852 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
853 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
854 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
855 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000856
857 // Fill tensors
858 fill(AccessorType(lhs), 0);
859 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100860 fill(AccessorType(bias), 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000861
862 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100863 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
864 reshape_lhs.run(reshape_lhs_pack);
865 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
866 reshape_rhs.run(reshape_rhs_pack);
867 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
868 { ACL_SRC_1, &rhs_reshaped },
869 { ACL_SRC_2, &bias },
870 { ACL_DST, &dst }
871 });
872 gemm.run(gemm_pack);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000873
874 return dst;
875 }
876
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100877 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 +0100878 const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000879 {
880 TensorShape dst_shape = lhs_shape;
881 dst_shape[0] = rhs_shape[0];
882 dst_shape[1] = lhs_shape[1];
883
884 // Create reference
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000885 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
886 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100887 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
888
889 const int n = rhs_shape[0];
890 const int m = lhs_shape[1];
891 const int batch_size = lhs_shape[2];
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000892
893 // Fill reference
894 fill(lhs, 0);
895 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100896 fill(bias, 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000897
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100898 if(broadcast_bias)
899 {
900 // In case of broadcast, we need simply copy the first into the following "M" ones
901 for(int i = 1; i < m * batch_size; i++)
902 {
903 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
904 }
905 }
906
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100907 if(fp_mixed_precision)
908 {
909 return reference::activation_layer(reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta), act_info);
910 }
911 else
912 {
913 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
914 }
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000915 }
916
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000917 bool validate_result = true;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000918 TensorType _target{};
919 SimpleTensor<T> _reference{};
920};
921
SiCongLi1af54162021-10-06 15:25:57 +0100922/** (EXPERIMENTAL_POST_OPS)*/
923template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSOperatorType, typename ReshapeRHSOperatorType, typename GEMMOperatorType, bool fp_mixed_precision = false>
924class GEMMMatrixMultiplyReshapedWithPostOpsValidationFixture : public framework::Fixture
925{
926public:
927 using PostOpArgBroadcast = std::tuple<bool, bool, bool>; // Instruct fixture if we need broadcasting in dimension 0, 1, 2 of each PostOp argument
928public:
929 template <typename...>
930 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,
931 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,
932 const experimental::PostOpList<PostOpArgBroadcast> &post_ops)
933 {
934 GEMMLHSMatrixInfo lhs_info;
935 lhs_info.m0 = m0;
936 lhs_info.k0 = k0;
937 lhs_info.v0 = v0;
938 lhs_info.interleave = interleave_lhs;
939 lhs_info.transpose = lhs_transpose;
940
941 GEMMRHSMatrixInfo rhs_info;
942 rhs_info.n0 = n0;
943 rhs_info.k0 = k0;
944 rhs_info.h0 = h0;
945 rhs_info.interleave = interleave_rhs;
946 rhs_info.transpose = !lhs_transpose;
947 rhs_info.export_to_cl_image = export_to_cl_image;
948
949 // Set the tensor shapes for LHS and RHS matrices
950 const TensorShape lhs_shape(k, m, batch_size);
951 const TensorShape rhs_shape(n, k, batch_size);
952 const TensorShape bias_shape(n,
953 broadcast_bias ? 1 : m,
954 broadcast_bias ? 1 : batch_size);
955 auto post_ops_with_shapes = experimental::transform_post_op_list_arguments<PostOpArgBroadcast, TensorShape>(post_ops,
956 [ = ](auto broadcast)
957 {
958 return TensorShape
959 {
960 std::get<0>(broadcast) ? 1 : n,
961 std::get<1>(broadcast) ? 1 : m,
962 std::get<2>(broadcast) ? 1 : batch_size,
963 };
964 });
965
966 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info, post_ops_with_shapes);
967 if(validate_result)
968 {
969 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info, post_ops_with_shapes);
970 }
971 }
972
973protected:
974 template <typename U>
975 void fill(U &&tensor, int i)
976 {
977 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
978 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;
979
980 DistributionType distribution{ T(-1.0f), T(1.0f) };
981 library->fill(tensor, distribution, i);
982
983 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
984 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
985 library->fill_borders_with_garbage(tensor, distribution_inf, i);
986 }
987
988 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
989 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info, const experimental::PostOpList<TensorShape> &post_ops)
990 {
991 // Create tensors
992 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
993 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
994 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
995
996 // Create post op tensors and populate post op with them
997 std::vector<TensorType> post_op_tensors_holder{};
998 auto populated_post_ops = experimental::transform_post_op_list_arguments<TensorShape, ITensorInfo *>(post_ops,
999 [&post_op_tensors_holder, &data_type](auto shape)
1000 {
1001 auto t = create_tensor<TensorType>(shape, data_type, 1);
1002 post_op_tensors_holder.push_back(std::move(t));
1003 return post_op_tensors_holder.back().info();
1004 });
1005 TensorType lhs_reshaped;
1006 TensorType rhs_reshaped;
1007 TensorType dst;
1008
1009 const unsigned int M = lhs_shape[1];
1010 const unsigned int N = rhs_shape[0];
1011 const unsigned int K = lhs_shape[0];
1012 GEMMKernelInfo kernel_info;
1013 kernel_info.m = M;
1014 kernel_info.n = N;
1015 kernel_info.k = K;
1016 kernel_info.depth_output_gemm3d = 0;
1017 kernel_info.reinterpret_input_as_3d = false;
1018 kernel_info.broadcast_bias = broadcast_bias;
1019 kernel_info.activation_info = act_info;
1020 kernel_info.fp_mixed_precision = fp_mixed_precision;
1021 kernel_info.post_ops = populated_post_ops;
1022
1023 // The output tensor will be auto-initialized within the function
1024
1025 // Create and configure function
1026 ReshapeLHSOperatorType reshape_lhs;
1027 ReshapeRHSOperatorType reshape_rhs;
1028 GEMMOperatorType gemm;
1029
1030 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1031 validate_result = validate_result || !rhs_info.export_to_cl_image;
1032 if(!validate_result)
1033 {
1034 return nullptr;
1035 }
1036
1037 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
1038 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1039 gemm.configure(lhs_reshaped.info(), rhs_reshaped.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
1040
1041 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1042 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1043 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
1044 for(const auto &tensor : post_op_tensors_holder)
1045 {
1046 ARM_COMPUTE_ASSERT(tensor.info()->is_resizable());
1047 }
1048
1049 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
1050 if(!rhs_info.export_to_cl_image)
1051 {
1052 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
1053 for(auto &tensor : post_op_tensors_holder)
1054 {
1055 add_padding_x({ &tensor });
1056 }
1057 }
1058
1059 // Allocate tensors
1060 lhs.allocator()->allocate();
1061 rhs.allocator()->allocate();
1062 lhs_reshaped.allocator()->allocate();
1063 rhs_reshaped.allocator()->allocate();
1064 bias.allocator()->allocate();
1065 dst.allocator()->allocate();
1066 for(auto &tensor : post_op_tensors_holder)
1067 {
1068 tensor.allocator()->allocate();
1069 }
1070
1071 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1072 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1073 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1074 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
1075 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1076 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
1077 for(const auto &tensor : post_op_tensors_holder)
1078 {
1079 ARM_COMPUTE_ASSERT(!tensor.info()->is_resizable());
1080 }
1081
1082 // Fill tensors
1083 fill(AccessorType(lhs), 0);
1084 fill(AccessorType(rhs), 1);
1085 fill(AccessorType(bias), 2);
1086 for(size_t i = 0; i < post_op_tensors_holder.size(); ++i)
1087 {
1088 fill(AccessorType(post_op_tensors_holder.at(i)), 3 + i);
1089 }
1090
1091 // Compute GEMM
1092 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
1093 reshape_lhs.run(reshape_lhs_pack);
1094 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1095 reshape_rhs.run(reshape_rhs_pack);
1096 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
1097 { ACL_SRC_1, &rhs_reshaped },
1098 { ACL_SRC_2, &bias },
1099 { ACL_DST, &dst }
1100 });
1101 for(size_t i = 0; i < post_op_tensors_holder.size(); ++i)
1102 {
1103 gemm_pack.add_tensor(experimental::get_post_op_arg_type(i), &post_op_tensors_holder.at(i));
1104 }
1105 gemm.run(gemm_pack);
1106
1107 return dst;
1108 }
1109
1110 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
1111 const ActivationLayerInfo &act_info, const experimental::PostOpList<TensorShape> &post_ops)
1112 {
1113 TensorShape dst_shape = lhs_shape;
1114 dst_shape[0] = rhs_shape[0];
1115 dst_shape[1] = lhs_shape[1];
1116
1117 // Create reference
1118 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1119 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
1120 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1121 // Create post op tensors and populate post op with them
1122 auto populated_post_ops = experimental::transform_post_op_list_arguments<TensorShape, SimpleTensor<T>>(post_ops, [&data_type](auto shape)
1123 {
1124 return SimpleTensor<T> { shape, data_type, 1 };
1125 });
1126
1127 const int n = rhs_shape[0];
1128 const int m = lhs_shape[1];
1129 const int batch_size = lhs_shape[2];
1130
1131 // Fill reference
1132 int tensor_idx = 0;
1133 fill(lhs, tensor_idx++);
1134 fill(rhs, tensor_idx++);
1135 fill(bias, tensor_idx++);
1136 for(auto &op : populated_post_ops.get_list())
1137 {
1138 for(auto tensor : op->arguments())
1139 {
1140 fill(*tensor, tensor_idx++);
1141 }
1142 }
1143
1144 if(broadcast_bias)
1145 {
1146 // In case of broadcast, we need simply copy the first into the following "M" ones
1147 for(int i = 1; i < m * batch_size; i++)
1148 {
1149 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1150 }
1151 }
1152
1153 SimpleTensor<T> out;
1154 if(fp_mixed_precision)
1155 {
1156 out = reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta);
1157 }
1158 else
1159 {
1160 out = reference::gemm<T>(lhs, rhs, bias, alpha, beta);
1161 }
1162 // Ignore activation info if post ops are used instead
1163 if(populated_post_ops.size() > 0)
1164 {
1165 out = reference::post_ops<T>(out, populated_post_ops);
1166 }
1167 else
1168 {
1169 out = reference::activation_layer(out, act_info);
1170 }
1171 return out;
1172 }
1173
1174 bool validate_result = true;
1175 TensorType _target{};
1176 SimpleTensor<T> _reference{};
1177};
1178
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001179template <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 +00001180class GEMMMatrixMultiplyReshaped3DValidationFixture : public framework::Fixture
1181{
1182public:
1183 template <typename...>
1184 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 +01001185 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 +00001186 {
1187 GEMMLHSMatrixInfo lhs_info;
1188 lhs_info.m0 = m0;
1189 lhs_info.k0 = k0;
1190 lhs_info.v0 = v0;
1191 lhs_info.interleave = interleave_lhs;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +01001192 lhs_info.transpose = lhs_transpose;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001193
1194 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodicee3a849a2020-06-10 17:59:30 +01001195 rhs_info.n0 = n0;
1196 rhs_info.k0 = k0;
1197 rhs_info.h0 = h0;
1198 rhs_info.interleave = interleave_rhs;
1199 rhs_info.transpose = !lhs_transpose;
1200 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001201
1202 // In case of GEMM3D, m is the product between m_w and m_h
1203 const unsigned int m = m_w * m_h;
1204
1205 // Set the tensor shapes for LHS and RHS matrices
1206 const TensorShape lhs_shape(k, m, batch_size);
1207 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001208 const TensorShape bias_shape(n, 1, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001209
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001210 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info);
1211 if(validate_result)
1212 {
1213 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
1214 }
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001215 }
1216
1217protected:
1218 template <typename U>
1219 void fill(U &&tensor, int i)
1220 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001221 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 +00001222 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 +00001223
1224 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001225 library->fill(tensor, distribution, i);
1226 }
1227
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001228 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 +01001229 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001230 {
1231 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001232 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1233 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1234 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001235 TensorType lhs_reshaped;
1236 TensorType rhs_reshaped;
1237 TensorType dst;
1238
1239 const unsigned int M = lhs_shape[1];
1240 const unsigned int N = rhs_shape[0];
1241 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001242 GEMMKernelInfo kernel_info;
1243 kernel_info.m = M;
1244 kernel_info.n = N;
1245 kernel_info.k = K;
1246 kernel_info.depth_output_gemm3d = m_h;
1247 kernel_info.reinterpret_input_as_3d = false;
1248 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001249 kernel_info.activation_info = act_info;
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +01001250 kernel_info.fp_mixed_precision = fp_mixed_precision;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001251
1252 // The output tensor will be auto-initialized within the function
1253
1254 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001255 ReshapeLHSOperatorType reshape_lhs;
1256 ReshapeRHSOperatorType reshape_rhs;
1257 GEMMOperatorType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001258
1259 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1260 validate_result = validate_result || !rhs_info.export_to_cl_image;
1261 if(!validate_result)
1262 {
1263 return nullptr;
1264 }
1265
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001266 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
1267 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1268 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 +00001269
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001270 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1271 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1272 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001273
Georgios Pinitas3dca91b2021-04-13 13:35:58 +01001274 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +00001275 if(!rhs_info.export_to_cl_image)
1276 {
1277 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
1278 }
1279
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001280 // Allocate tensors
1281 lhs.allocator()->allocate();
1282 rhs.allocator()->allocate();
1283 lhs_reshaped.allocator()->allocate();
1284 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001285 bias.allocator()->allocate();
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001286 dst.allocator()->allocate();
1287
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001288 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1289 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1290 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
1291 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1292 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1293 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001294
1295 // Fill tensors
1296 fill(AccessorType(lhs), 0);
1297 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001298 fill(AccessorType(bias), 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001299
1300 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001301 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
1302 reshape_lhs.run(reshape_lhs_pack);
1303 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1304 reshape_rhs.run(reshape_rhs_pack);
1305 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
1306 { ACL_SRC_1, &rhs_reshaped },
1307 { ACL_SRC_2, &bias },
1308 { ACL_DST, &dst }
1309 });
1310 gemm.run(gemm_pack);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001311
1312 return dst;
1313 }
1314
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001315 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 +01001316 const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001317 {
1318 TensorShape dst_shape = lhs_shape;
1319 dst_shape.set(0, rhs_shape[0]);
1320 dst_shape.set(1, lhs_shape[1] / m_h);
1321 dst_shape.set(2, m_h);
1322 dst_shape.set(3, lhs_shape[2]);
1323
1324 // Create reference
1325 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1326 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001327 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1328
1329 const int n = rhs_shape[0];
1330 const int m = lhs_shape[1];
1331 const int batch_size = lhs_shape[2];
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001332
1333 // Fill reference
1334 fill(lhs, 0);
1335 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001336 fill(bias, 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001337
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001338 // In case of broadcast, we need simply copy the first into the following "M" ones
1339 for(int i = 1; i < m * batch_size; i++)
1340 {
1341 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1342 }
1343
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +01001344 if(fp_mixed_precision)
1345 {
1346 return reference::activation_layer(reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta), act_info);
1347 }
1348 else
1349 {
1350 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
1351 }
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001352 }
1353
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001354 bool validate_result = true;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001355 TensorType _target{};
1356 SimpleTensor<T> _reference{};
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +00001357};
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001358
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001359template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001360class GEMMMatrixMultiplyReshapedOnlyRHSValidationFixture : public framework::Fixture
1361{
1362public:
1363 template <typename...>
1364 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 +01001365 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 +00001366 {
1367 GEMMLHSMatrixInfo lhs_info;
1368 lhs_info.m0 = m0;
1369 lhs_info.k0 = k0;
1370
1371 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodice781cba72020-06-19 16:56:57 +01001372 rhs_info.n0 = n0;
1373 rhs_info.k0 = k0;
1374 rhs_info.h0 = h0;
1375 rhs_info.interleave = interleave_rhs;
1376 rhs_info.transpose = transpose_rhs;
1377 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001378
1379 // Set the tensor shapes for LHS and RHS matrices
1380 const TensorShape lhs_shape(k, m, batch_size);
1381 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001382 const TensorShape bias_shape(n,
1383 broadcast_bias ? 1 : m,
1384 broadcast_bias ? 1 : batch_size);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001385
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001386 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
1387 if(validate_result)
1388 {
1389 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
1390 }
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001391 }
1392
1393protected:
1394 template <typename U>
1395 void fill(U &&tensor, int i)
1396 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001397 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 +00001398 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 +00001399
1400 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001401 library->fill(tensor, distribution, i);
1402
1403 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001404 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001405 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1406 }
1407
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001408 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 +01001409 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001410 {
1411 // Create tensors
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001412 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1413 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1414 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001415 TensorType rhs_reshaped;
1416 TensorType dst;
1417
1418 const unsigned int M = lhs_shape[1];
1419 const unsigned int N = rhs_shape[0];
1420 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001421 GEMMKernelInfo kernel_info;
1422 kernel_info.m = M;
1423 kernel_info.n = N;
1424 kernel_info.k = K;
1425 kernel_info.depth_output_gemm3d = 0;
1426 kernel_info.reinterpret_input_as_3d = false;
1427 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001428 kernel_info.activation_info = act_info;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001429
1430 // The output tensor will be auto-initialized within the function
1431
1432 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001433 ReshapeRHSOperatorType reshape_rhs;
1434 GEMMOperatorType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001435
1436 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1437 validate_result = validate_result || !rhs_info.export_to_cl_image;
1438 if(!validate_result)
1439 {
1440 return nullptr;
1441 }
1442
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001443 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1444 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 +00001445
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001446 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1447 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1448 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001449
Georgios Pinitas3dca91b2021-04-13 13:35:58 +01001450 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +00001451 if(!rhs_info.export_to_cl_image)
1452 {
1453 add_padding_x({ &lhs, &rhs, &rhs_reshaped, &bias, &dst });
1454 }
1455
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001456 // Allocate tensors
1457 lhs.allocator()->allocate();
1458 rhs.allocator()->allocate();
1459 rhs_reshaped.allocator()->allocate();
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001460 bias.allocator()->allocate();
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001461 dst.allocator()->allocate();
1462
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001463 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1464 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1465 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1466 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1467 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001468
1469 // Fill tensors
1470 fill(AccessorType(lhs), 0);
1471 fill(AccessorType(rhs), 1);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001472 fill(AccessorType(bias), 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001473
1474 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001475 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1476 reshape_rhs.run(reshape_rhs_pack);
1477 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
1478 { ACL_SRC_1, &rhs_reshaped },
1479 { ACL_SRC_2, &bias },
1480 { ACL_DST, &dst }
1481 });
1482 gemm.run(gemm_pack);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001483
1484 return dst;
1485 }
1486
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001487 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 +01001488 const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001489 {
1490 TensorShape dst_shape = lhs_shape;
1491 dst_shape[0] = rhs_shape[0];
1492 dst_shape[1] = lhs_shape[1];
1493
1494 // Create reference
1495 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1496 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001497 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1498
1499 const int n = rhs_shape[0];
1500 const int m = lhs_shape[1];
1501 const int batch_size = lhs_shape[2];
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001502
1503 // Fill reference
1504 fill(lhs, 0);
1505 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001506 fill(bias, 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001507
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001508 if(broadcast_bias)
1509 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001510 // In case of broadcast, we need simply copy the first into the following "M" ones
1511 for(int i = 1; i < m * batch_size; i++)
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001512 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001513 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001514 }
1515 }
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001516
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001517 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001518 }
1519
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001520 bool validate_result = true;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001521 TensorType _target{};
1522 SimpleTensor<T> _reference{};
1523};
1524
SiCongLiafa19722021-10-24 19:12:33 +01001525/** (EXPERIMENTAL_POST_OPS)*/
1526template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
1527class GEMMMatrixMultiplyReshapedOnlyRHSWithPostOpsValidationFixture : public framework::Fixture
1528{
1529public:
1530 using PostOpArgBroadcast = std::tuple<bool, bool, bool>; // Instruct fixture if we need broadcasting in dimension 0, 1, 2 of each PostOp argument
1531 template <typename...>
1532 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,
1533 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,
1534 const experimental::PostOpList<PostOpArgBroadcast> &post_ops)
1535 {
1536 GEMMLHSMatrixInfo lhs_info;
1537 lhs_info.m0 = m0;
1538 lhs_info.k0 = k0;
1539
1540 GEMMRHSMatrixInfo rhs_info;
1541 rhs_info.n0 = n0;
1542 rhs_info.k0 = k0;
1543 rhs_info.h0 = h0;
1544 rhs_info.interleave = interleave_rhs;
1545 rhs_info.transpose = transpose_rhs;
1546 rhs_info.export_to_cl_image = export_to_cl_image;
1547
1548 // Set the tensor shapes for LHS and RHS matrices
1549 const TensorShape lhs_shape(k, m, batch_size);
1550 const TensorShape rhs_shape(n, k, batch_size);
1551 const TensorShape bias_shape(n,
1552 broadcast_bias ? 1 : m,
1553 broadcast_bias ? 1 : batch_size);
1554 auto post_ops_with_shapes = experimental::transform_post_op_list_arguments<PostOpArgBroadcast, TensorShape>(post_ops,
1555 [ = ](auto broadcast)
1556 {
1557 return TensorShape
1558 {
1559 std::get<0>(broadcast) ? 1 : n,
1560 std::get<1>(broadcast) ? 1 : m,
1561 std::get<2>(broadcast) ? 1 : batch_size,
1562 };
1563 });
1564
1565 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info, post_ops_with_shapes);
1566 if(validate_result)
1567 {
1568 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info, post_ops_with_shapes);
1569 }
1570 }
1571
1572protected:
1573 template <typename U>
1574 void fill(U &&tensor, int i)
1575 {
1576 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
1577 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;
1578
1579 DistributionType distribution{ T(-1.0f), T(1.0f) };
1580 library->fill(tensor, distribution, i);
1581
1582 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
1583 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
1584 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1585 }
1586
1587 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
1588 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info, const experimental::PostOpList<TensorShape> &post_ops)
1589 {
1590 // Create tensors
1591 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1592 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1593 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
1594 TensorType rhs_reshaped;
1595 TensorType dst;
1596 // Create post op tensors and populate post op with them
1597 std::vector<TensorType> post_op_tensors_holder{};
1598 auto populated_post_ops = experimental::transform_post_op_list_arguments<TensorShape, ITensorInfo *>(post_ops,
1599 [&post_op_tensors_holder, &data_type](auto shape)
1600 {
1601 auto t = create_tensor<TensorType>(shape, data_type, 1);
1602 post_op_tensors_holder.push_back(std::move(t));
1603 return post_op_tensors_holder.back().info();
1604 });
1605
1606 const unsigned int M = lhs_shape[1];
1607 const unsigned int N = rhs_shape[0];
1608 const unsigned int K = lhs_shape[0];
1609 GEMMKernelInfo kernel_info;
1610 kernel_info.m = M;
1611 kernel_info.n = N;
1612 kernel_info.k = K;
1613 kernel_info.depth_output_gemm3d = 0;
1614 kernel_info.reinterpret_input_as_3d = false;
1615 kernel_info.broadcast_bias = broadcast_bias;
1616 kernel_info.activation_info = act_info;
1617 kernel_info.post_ops = populated_post_ops;
1618
1619 // The output tensor will be auto-initialized within the function
1620
1621 // Create and configure function
1622 ReshapeRHSOperatorType reshape_rhs;
1623 GEMMOperatorType gemm;
1624
1625 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1626 validate_result = validate_result || !rhs_info.export_to_cl_image;
1627 if(!validate_result)
1628 {
1629 return nullptr;
1630 }
1631
1632 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1633 gemm.configure(lhs.info(), rhs_reshaped.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
1634
1635 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1636 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1637 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
1638 for(const auto &tensor : post_op_tensors_holder)
1639 {
1640 ARM_COMPUTE_ASSERT(tensor.info()->is_resizable());
1641 }
1642
1643 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
1644 if(!rhs_info.export_to_cl_image)
1645 {
1646 add_padding_x({ &lhs, &rhs, &rhs_reshaped, &bias, &dst });
1647 for(auto &tensor : post_op_tensors_holder)
1648 {
1649 add_padding_x({ &tensor });
1650 }
1651 }
1652
1653 // Allocate tensors
1654 lhs.allocator()->allocate();
1655 rhs.allocator()->allocate();
1656 rhs_reshaped.allocator()->allocate();
1657 bias.allocator()->allocate();
1658 dst.allocator()->allocate();
1659 for(auto &tensor : post_op_tensors_holder)
1660 {
1661 tensor.allocator()->allocate();
1662 }
1663
1664 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1665 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1666 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1667 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1668 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
1669 for(const auto &tensor : post_op_tensors_holder)
1670 {
1671 ARM_COMPUTE_ASSERT(!tensor.info()->is_resizable());
1672 }
1673
1674 // Fill tensors
1675 fill(AccessorType(lhs), 0);
1676 fill(AccessorType(rhs), 1);
1677 fill(AccessorType(bias), 2);
1678 for(size_t i = 0; i < post_op_tensors_holder.size(); ++i)
1679 {
1680 fill(AccessorType(post_op_tensors_holder.at(i)), 3 + i);
1681 }
1682
1683 // Compute GEMM
1684 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1685 reshape_rhs.run(reshape_rhs_pack);
1686 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
1687 { ACL_SRC_1, &rhs_reshaped },
1688 { ACL_SRC_2, &bias },
1689 { ACL_DST, &dst }
1690 });
1691 for(size_t i = 0; i < post_op_tensors_holder.size(); ++i)
1692 {
1693 gemm_pack.add_tensor(experimental::get_post_op_arg_type(i), &post_op_tensors_holder.at(i));
1694 }
1695 gemm.run(gemm_pack);
1696
1697 return dst;
1698 }
1699
1700 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
1701 const ActivationLayerInfo &act_info, const experimental::PostOpList<TensorShape> &post_ops)
1702 {
1703 TensorShape dst_shape = lhs_shape;
1704 dst_shape[0] = rhs_shape[0];
1705 dst_shape[1] = lhs_shape[1];
1706
1707 // Create reference
1708 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1709 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
1710 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1711 // Create post op tensors and populate post op with them
1712 auto populated_post_ops = experimental::transform_post_op_list_arguments<TensorShape, SimpleTensor<T>>(post_ops, [&data_type](auto shape)
1713 {
1714 return SimpleTensor<T> { shape, data_type, 1 };
1715 });
1716
1717 const int n = rhs_shape[0];
1718 const int m = lhs_shape[1];
1719 const int batch_size = lhs_shape[2];
1720
1721 // Fill reference
1722 int tensor_idx = 0;
1723 fill(lhs, tensor_idx++);
1724 fill(rhs, tensor_idx++);
1725 fill(bias, tensor_idx++);
1726 for(auto &op : populated_post_ops.get_list())
1727 {
1728 for(auto tensor : op->arguments())
1729 {
1730 fill(*tensor, tensor_idx++);
1731 }
1732 }
1733
1734 if(broadcast_bias)
1735 {
1736 // In case of broadcast, we need simply copy the first into the following "M" ones
1737 for(int i = 1; i < m * batch_size; i++)
1738 {
1739 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1740 }
1741 }
1742
1743 SimpleTensor<T> out;
1744 out = reference::gemm<T>(lhs, rhs, bias, alpha, beta);
1745 // Ignore activation info if post ops are used instead
1746 if(populated_post_ops.size() > 0)
1747 {
1748 out = reference::post_ops<T>(out, populated_post_ops);
1749 }
1750 else
1751 {
1752 out = reference::activation_layer(out, act_info);
1753 }
1754 return out;
1755 }
1756
1757 bool validate_result = true;
1758 TensorType _target{};
1759 SimpleTensor<T> _reference{};
1760};
1761
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001762template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001763class GEMMMatrixMultiplyReshapedOnlyRHS3DValidationFixture : public framework::Fixture
1764{
1765public:
1766 template <typename...>
1767 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 +01001768 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 +01001769 {
1770 GEMMLHSMatrixInfo lhs_info;
1771 lhs_info.m0 = m0;
1772 lhs_info.k0 = k0;
1773
1774 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodice781cba72020-06-19 16:56:57 +01001775 rhs_info.n0 = n0;
1776 rhs_info.k0 = k0;
1777 rhs_info.h0 = h0;
1778 rhs_info.interleave = interleave_rhs;
1779 rhs_info.transpose = transpose_rhs;
1780 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001781
1782 // In case of GEMM3D, m is the product between m_w and m_h
1783 const unsigned int m = m_w * m_h;
1784
1785 // Set the tensor shapes for LHS and RHS matrices
1786 const TensorShape lhs_shape(k, m, batch_size);
1787 const TensorShape rhs_shape(n, k, batch_size);
1788 const TensorShape bias_shape(n, 1, 1);
1789
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001790 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info, has_pad_y);
1791 if(validate_result)
1792 {
1793 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
1794 }
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001795 }
1796
1797protected:
1798 template <typename U>
1799 void fill(U &&tensor, int i)
1800 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001801 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 +00001802 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 +00001803
1804 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001805 library->fill(tensor, distribution, i);
1806 }
1807
1808 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
1809 DataType data_type, float alpha, float beta,
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001810 unsigned int m_h, const ActivationLayerInfo &act_info, bool has_pad_y)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001811 {
1812 // Create tensors
1813 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1814 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1815 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
1816 TensorType rhs_reshaped;
1817 TensorType dst;
1818
1819 const unsigned int M = lhs_shape[1];
1820 const unsigned int N = rhs_shape[0];
1821 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001822 GEMMKernelInfo kernel_info;
1823 kernel_info.m = M;
1824 kernel_info.n = N;
1825 kernel_info.k = K;
1826 kernel_info.depth_output_gemm3d = m_h;
1827 kernel_info.reinterpret_input_as_3d = false;
1828 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001829 kernel_info.activation_info = act_info;
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001830 kernel_info.has_pad_y = has_pad_y;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001831
1832 // The output tensor will be auto-initialized within the function
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001833 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001834 ReshapeRHSOperatorType reshape_rhs;
1835 GEMMOperatorType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001836
1837 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1838 validate_result = validate_result || !rhs_info.export_to_cl_image;
1839 if(!validate_result)
1840 {
1841 return nullptr;
1842 }
1843
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001844 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1845 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 +01001846
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001847 if(has_pad_y)
1848 {
1849 // Add dummy padding into lhs to validate has_pad_y path
1850 lhs.info()->extend_padding(PaddingSize(2, 0, 2, 0));
1851 dst.info()->extend_padding(PaddingSize(2, 0, 1, 0));
1852 }
1853
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001854 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1855 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1856 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001857
Georgios Pinitas3dca91b2021-04-13 13:35:58 +01001858 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +00001859 if(!rhs_info.export_to_cl_image)
1860 {
1861 add_padding_x({ &lhs, &rhs, &rhs_reshaped, &bias, &dst });
1862 }
1863
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001864 // Allocate tensors
1865 lhs.allocator()->allocate();
1866 rhs.allocator()->allocate();
1867 rhs_reshaped.allocator()->allocate();
1868 bias.allocator()->allocate();
1869 dst.allocator()->allocate();
1870
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001871 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1872 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1873 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1874 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1875 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001876
1877 // Fill tensors
1878 fill(AccessorType(lhs), 0);
1879 fill(AccessorType(rhs), 1);
1880 fill(AccessorType(bias), 2);
1881
1882 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001883 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1884 reshape_rhs.run(reshape_rhs_pack);
1885 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
1886 { ACL_SRC_1, &rhs_reshaped },
1887 { ACL_SRC_2, &bias },
1888 { ACL_DST, &dst }
1889 });
1890 gemm.run(gemm_pack);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001891
1892 return dst;
1893 }
1894
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001895 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 +01001896 const ActivationLayerInfo &act_info)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001897 {
1898 TensorShape dst_shape = lhs_shape;
1899 dst_shape.set(0, rhs_shape[0]);
1900 dst_shape.set(1, lhs_shape[1] / m_h);
1901 dst_shape.set(2, m_h);
1902 dst_shape.set(3, lhs_shape[2]);
1903
1904 // Create reference
1905 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1906 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
1907 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1908
1909 const int n = rhs_shape[0];
1910 const int m = lhs_shape[1];
1911 const int batch_size = lhs_shape[2];
1912
1913 // Fill reference
1914 fill(lhs, 0);
1915 fill(rhs, 1);
1916 fill(bias, 2);
1917
1918 // In case of broadcast, we need simply copy the first into the following "M" ones
1919 for(int i = 1; i < m * batch_size; i++)
1920 {
1921 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1922 }
1923
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001924 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001925 }
1926
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001927 bool validate_result = true;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001928 TensorType _target{};
1929 SimpleTensor<T> _reference{};
1930};
1931
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001932template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
giuros01b3204e72019-04-01 13:50:22 +01001933class GEMMMatrixMultiplyNativeValidationFixture : public framework::Fixture
1934{
1935public:
1936 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001937 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,
1938 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001939 {
1940 GEMMLHSMatrixInfo lhs_info;
1941 lhs_info.m0 = m0;
1942 lhs_info.k0 = k0;
1943
1944 GEMMRHSMatrixInfo rhs_info;
1945 rhs_info.n0 = n0;
1946 rhs_info.k0 = k0;
1947
1948 // Set the tensor shapes for LHS and RHS matrices
1949 const TensorShape lhs_shape(k, m, batch_size);
1950 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001951 const TensorShape bias_shape(n,
1952 broadcast_bias ? 1 : m,
1953 broadcast_bias ? 1 : batch_size);
giuros01b3204e72019-04-01 13:50:22 +01001954
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001955 _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 +01001956 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
giuros01b3204e72019-04-01 13:50:22 +01001957 }
1958
1959protected:
1960 template <typename U>
1961 void fill(U &&tensor, int i)
1962 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001963 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 +00001964 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 +00001965
1966 DistributionType distribution{ T(-1.0f), T(1.0f) };
giuros01b3204e72019-04-01 13:50:22 +01001967 library->fill(tensor, distribution, i);
1968
1969 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001970 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
giuros01b3204e72019-04-01 13:50:22 +01001971 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1972 }
1973
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001974 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 +01001975 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001976 {
1977 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001978 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1979 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1980 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01001981 TensorType dst;
1982
1983 const unsigned int M = lhs_shape[1];
1984 const unsigned int N = rhs_shape[0];
1985 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001986 GEMMKernelInfo kernel_info;
1987 kernel_info.m = M;
1988 kernel_info.n = N;
1989 kernel_info.k = K;
1990 kernel_info.depth_output_gemm3d = 0;
1991 kernel_info.reinterpret_input_as_3d = false;
1992 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001993 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01001994
1995 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001996 GEMMOperatorType gemm;
1997 gemm.configure(lhs.info(), rhs.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01001998
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001999 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
2000 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
2001 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
giuros01b3204e72019-04-01 13:50:22 +01002002
Giorgio Arena63825e82021-03-25 14:54:50 +00002003 add_padding_x({ &lhs, &rhs, &bias, &dst });
2004
giuros01b3204e72019-04-01 13:50:22 +01002005 // Allocate tensors
2006 lhs.allocator()->allocate();
2007 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002008 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01002009 dst.allocator()->allocate();
2010
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01002011 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
2012 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
2013 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
2014 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
giuros01b3204e72019-04-01 13:50:22 +01002015
2016 // Fill tensors
2017 fill(AccessorType(lhs), 0);
2018 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002019 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01002020
2021 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01002022 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
2023 { ACL_SRC_1, &rhs },
2024 { ACL_SRC_2, &bias },
2025 { ACL_DST, &dst }
2026 });
2027 gemm.run(gemm_pack);
giuros01b3204e72019-04-01 13:50:22 +01002028
2029 return dst;
2030 }
2031
Michalis Spyrou6bff1952019-10-02 17:22:11 +01002032 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 +01002033 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01002034 {
2035 TensorShape dst_shape = lhs_shape;
2036 dst_shape[0] = rhs_shape[0];
2037 dst_shape[1] = lhs_shape[1];
2038
2039 // Create reference
2040 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
2041 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002042 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
2043
2044 const int n = rhs_shape[0];
2045 const int m = lhs_shape[1];
2046 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01002047
2048 // Fill reference
2049 fill(lhs, 0);
2050 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002051 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01002052
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002053 if(broadcast_bias)
2054 {
2055 // In case of broadcast, we need simply copy the first into the following "M" ones
2056 for(int i = 1; i < m * batch_size; i++)
2057 {
2058 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
2059 }
2060 }
2061
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01002062 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01002063 }
2064
2065 TensorType _target{};
2066 SimpleTensor<T> _reference{};
2067};
2068
Georgios Pinitas856f66e2021-04-22 21:13:21 +01002069template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
SiCongLiafa19722021-10-24 19:12:33 +01002070class GEMMMatrixMultiplyNativeWithPostOpsValidationFixture : public framework::Fixture
2071{
2072public:
2073 using PostOpArgBroadcast = std::tuple<bool, bool, bool>; // Instruct fixture if we need broadcasting in dimension 0, 1, 2 of each PostOp argument
2074public:
2075 template <typename...>
2076 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,
2077 const ActivationLayerInfo &act_info, const experimental::PostOpList<PostOpArgBroadcast> &post_ops)
2078 {
2079 GEMMLHSMatrixInfo lhs_info;
2080 lhs_info.m0 = m0;
2081 lhs_info.k0 = k0;
2082
2083 GEMMRHSMatrixInfo rhs_info;
2084 rhs_info.n0 = n0;
2085 rhs_info.k0 = k0;
2086
2087 // Set the tensor shapes for LHS and RHS matrices
2088 const TensorShape lhs_shape(k, m, batch_size);
2089 const TensorShape rhs_shape(n, k, batch_size);
2090 const TensorShape bias_shape(n,
2091 broadcast_bias ? 1 : m,
2092 broadcast_bias ? 1 : batch_size);
2093 const auto post_ops_with_shapes = experimental::transform_post_op_list_arguments<PostOpArgBroadcast, TensorShape>(post_ops,
2094 [ = ](auto broadcast)
2095 {
2096 return TensorShape
2097 {
2098 std::get<0>(broadcast) ? 1 : n,
2099 std::get<1>(broadcast) ? 1 : m,
2100 std::get<2>(broadcast) ? 1 : batch_size,
2101 };
2102 });
2103
2104 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info, post_ops_with_shapes);
2105 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info, post_ops_with_shapes);
2106 }
2107
2108protected:
2109 template <typename U>
2110 void fill(U &&tensor, int i)
2111 {
2112 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
2113 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;
2114
2115 DistributionType distribution{ T(-1.0f), T(1.0f) };
2116 library->fill(tensor, distribution, i);
2117
2118 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
2119 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
2120 library->fill_borders_with_garbage(tensor, distribution_inf, i);
2121 }
2122
2123 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
2124 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info, const experimental::PostOpList<TensorShape> &post_ops)
2125 {
2126 // Create tensors
2127 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
2128 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
2129 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
2130 TensorType dst;
2131 // Create post op tensors and populate post op with them
2132 std::vector<TensorType> post_op_tensors_holder{};
2133 auto populated_post_ops = experimental::transform_post_op_list_arguments<TensorShape, ITensorInfo *>(post_ops,
2134 [&post_op_tensors_holder, &data_type](auto shape)
2135 {
2136 auto t = create_tensor<TensorType>(shape, data_type, 1);
2137 post_op_tensors_holder.push_back(std::move(t));
2138 return post_op_tensors_holder.back().info();
2139 });
2140
2141 const unsigned int M = lhs_shape[1];
2142 const unsigned int N = rhs_shape[0];
2143 const unsigned int K = lhs_shape[0];
2144 GEMMKernelInfo kernel_info;
2145 kernel_info.m = M;
2146 kernel_info.n = N;
2147 kernel_info.k = K;
2148 kernel_info.depth_output_gemm3d = 0;
2149 kernel_info.reinterpret_input_as_3d = false;
2150 kernel_info.broadcast_bias = broadcast_bias;
2151 kernel_info.activation_info = act_info;
2152 kernel_info.post_ops = populated_post_ops;
2153
2154 // Create and configure function
2155 GEMMOperatorType gemm;
2156 gemm.configure(lhs.info(), rhs.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
2157
2158 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
2159 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
2160 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
2161 for(const auto &tensor : post_op_tensors_holder)
2162 {
2163 ARM_COMPUTE_ASSERT(tensor.info()->is_resizable());
2164 }
2165
2166 add_padding_x({ &lhs, &rhs, &bias, &dst });
2167 for(auto &tensor : post_op_tensors_holder)
2168 {
2169 add_padding_x({ &tensor });
2170 }
2171
2172 // Allocate tensors
2173 lhs.allocator()->allocate();
2174 rhs.allocator()->allocate();
2175 bias.allocator()->allocate();
2176 dst.allocator()->allocate();
2177 for(auto &tensor : post_op_tensors_holder)
2178 {
2179 tensor.allocator()->allocate();
2180 }
2181
2182 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
2183 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
2184 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
2185 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
2186 for(const auto &tensor : post_op_tensors_holder)
2187 {
2188 ARM_COMPUTE_ASSERT(!tensor.info()->is_resizable());
2189 }
2190
2191 // Fill tensors
2192 fill(AccessorType(lhs), 0);
2193 fill(AccessorType(rhs), 1);
2194 fill(AccessorType(bias), 2);
2195 for(size_t i = 0; i < post_op_tensors_holder.size(); ++i)
2196 {
2197 fill(AccessorType(post_op_tensors_holder.at(i)), 3 + i);
2198 }
2199
2200 // Compute GEMM
2201 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
2202 { ACL_SRC_1, &rhs },
2203 { ACL_SRC_2, &bias },
2204 { ACL_DST, &dst }
2205 });
2206 for(size_t i = 0; i < post_op_tensors_holder.size(); ++i)
2207 {
2208 gemm_pack.add_tensor(experimental::get_post_op_arg_type(i), &post_op_tensors_holder.at(i));
2209 }
2210 gemm.run(gemm_pack);
2211
2212 return dst;
2213 }
2214
2215 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
2216 const ActivationLayerInfo &act_info, const experimental::PostOpList<TensorShape> &post_ops)
2217 {
2218 TensorShape dst_shape = lhs_shape;
2219 dst_shape[0] = rhs_shape[0];
2220 dst_shape[1] = lhs_shape[1];
2221
2222 // Create reference
2223 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
2224 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
2225 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
2226 // Create post op tensors and populate post op with them
2227 auto populated_post_ops = experimental::transform_post_op_list_arguments<TensorShape, SimpleTensor<T>>(post_ops, [&data_type](auto shape)
2228 {
2229 return SimpleTensor<T> { shape, data_type, 1 };
2230 });
2231
2232 const int n = rhs_shape[0];
2233 const int m = lhs_shape[1];
2234 const int batch_size = lhs_shape[2];
2235
2236 // Fill reference
2237 int tensor_idx = 0;
2238 fill(lhs, tensor_idx++);
2239 fill(rhs, tensor_idx++);
2240 fill(bias, tensor_idx++);
2241 for(auto &op : populated_post_ops.get_list())
2242 {
2243 for(auto tensor : op->arguments())
2244 {
2245 fill(*tensor, tensor_idx++);
2246 }
2247 }
2248
2249 if(broadcast_bias)
2250 {
2251 // In case of broadcast, we need simply copy the first into the following "M" ones
2252 for(int i = 1; i < m * batch_size; i++)
2253 {
2254 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
2255 }
2256 }
2257
2258 SimpleTensor<T> out;
2259 out = reference::gemm<T>(lhs, rhs, bias, alpha, beta);
2260 // Ignore activation info if post ops are used instead
2261 if(populated_post_ops.size() > 0)
2262 {
2263 out = reference::post_ops<T>(out, populated_post_ops);
2264 }
2265 else
2266 {
2267 out = reference::activation_layer(out, act_info);
2268 }
2269 return out;
2270 }
2271
2272 TensorType _target{};
2273 SimpleTensor<T> _reference{};
2274};
2275
2276template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
giuros01b3204e72019-04-01 13:50:22 +01002277class GEMMMatrixMultiplyNative3DValidationFixture : public framework::Fixture
2278{
2279public:
2280 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01002281 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,
2282 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01002283 {
2284 GEMMLHSMatrixInfo lhs_info;
2285 lhs_info.m0 = m0;
2286 lhs_info.k0 = k0;
2287
2288 GEMMRHSMatrixInfo rhs_info;
2289 rhs_info.n0 = n0;
2290 rhs_info.k0 = k0;
2291
2292 // In case of GEMM3D, m is the product between m_w and m_h
2293 const unsigned int m = m_w * m_h;
2294
2295 // Set the tensor shapes for LHS and RHS matrices
2296 const TensorShape lhs_shape(k, m, batch_size);
2297 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002298 const TensorShape bias_shape(n, 1, 1);
giuros01b3204e72019-04-01 13:50:22 +01002299
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01002300 _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 +01002301 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
giuros01b3204e72019-04-01 13:50:22 +01002302 }
2303
2304protected:
2305 template <typename U>
2306 void fill(U &&tensor, int i)
2307 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00002308 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 +00002309 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 +00002310
2311 DistributionType distribution{ T(-1.0f), T(1.0f) };
giuros01b3204e72019-04-01 13:50:22 +01002312 library->fill(tensor, distribution, i);
2313 }
2314
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002315 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 +01002316 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01002317 {
2318 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002319 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
2320 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
2321 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01002322 TensorType dst;
2323
2324 const unsigned int M = lhs_shape[1];
2325 const unsigned int N = rhs_shape[0];
2326 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01002327 GEMMKernelInfo kernel_info;
2328 kernel_info.m = M;
2329 kernel_info.n = N;
2330 kernel_info.k = K;
2331 kernel_info.depth_output_gemm3d = m_h;
2332 kernel_info.reinterpret_input_as_3d = false;
2333 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01002334 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01002335
2336 // The output tensor will be auto-initialized within the function
2337
2338 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01002339 GEMMOperatorType gemm;
2340 gemm.configure(lhs.info(), rhs.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01002341
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01002342 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
2343 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
2344 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
giuros01b3204e72019-04-01 13:50:22 +01002345
Giorgio Arena63825e82021-03-25 14:54:50 +00002346 add_padding_x({ &lhs, &rhs, &bias, &dst });
2347
giuros01b3204e72019-04-01 13:50:22 +01002348 // Allocate tensors
2349 lhs.allocator()->allocate();
2350 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002351 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01002352 dst.allocator()->allocate();
2353
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01002354 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
2355 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
2356 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
2357 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
giuros01b3204e72019-04-01 13:50:22 +01002358
2359 // Fill tensors
2360 fill(AccessorType(lhs), 0);
2361 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002362 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01002363
2364 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01002365 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
2366 { ACL_SRC_1, &rhs },
2367 { ACL_SRC_2, &bias },
2368 { ACL_DST, &dst }
2369 });
2370 gemm.run(gemm_pack);
giuros01b3204e72019-04-01 13:50:22 +01002371
2372 return dst;
2373 }
2374
Michalis Spyrou6bff1952019-10-02 17:22:11 +01002375 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 +01002376 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01002377 {
2378 TensorShape dst_shape = lhs_shape;
2379 dst_shape.set(0, rhs_shape[0]);
2380 dst_shape.set(1, lhs_shape[1] / m_h);
2381 dst_shape.set(2, m_h);
2382 dst_shape.set(3, lhs_shape[2]);
2383
2384 // Create reference
2385 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
2386 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002387 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
2388
2389 const int n = rhs_shape[0];
2390 const int m = lhs_shape[1];
2391 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01002392
2393 // Fill reference
2394 fill(lhs, 0);
2395 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002396 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01002397
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002398 // In case of broadcast, we need simply copy the first into the following "M" ones
2399 for(int i = 1; i < m * batch_size; i++)
2400 {
2401 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
2402 }
2403
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01002404 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01002405 }
2406
2407 TensorType _target{};
2408 SimpleTensor<T> _reference{};
2409};
2410
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +01002411} // namespace validation
2412} // namespace test
2413} // namespace arm_compute
2414#endif /* ARM_COMPUTE_TEST_GEMM_FIXTURE */