blob: 5f5fa3b6533bd8f94c675a884cbba691dd02dc64 [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"
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010030#include "tests/AssetsLibrary.h"
31#include "tests/Globals.h"
32#include "tests/IAccessor.h"
Moritz Pflanzera09de0c2017-09-01 20:41:12 +010033#include "tests/framework/Asserts.h"
34#include "tests/framework/Fixture.h"
Moritz Pflanzera09de0c2017-09-01 20:41:12 +010035#include "tests/validation/Helpers.h"
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +010036#include "tests/validation/reference/ActivationLayer.h"
Georgios Pinitas5a7e7762017-12-01 16:27:29 +000037#include "tests/validation/reference/GEMM.h"
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010038
39#include <random>
40
41namespace arm_compute
42{
43namespace test
44{
45namespace validation
46{
Gian Marco Iodicef3622be2019-07-29 14:27:16 +010047template <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 +010048class GEMMValidationFixture : public framework::Fixture
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010049{
50public:
51 template <typename...>
Pablo Tello0e37b5c2018-10-30 11:18:37 +000052 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 +010053 {
Michalis Spyrou6bff1952019-10-02 17:22:11 +010054 ARM_COMPUTE_UNUSED(pretranspose);
55 _target = compute_target(shape_a, shape_b, shape_c, output_shape, alpha, beta, data_type);
56 _reference = compute_reference(shape_a, shape_b, output_shape, alpha, beta, data_type);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010057 }
58
59protected:
60 template <typename U>
Pablo Tello0e37b5c2018-10-30 11:18:37 +000061 void fill(U &&tensor, int i, float lo = -1.f, float hi = 1.f)
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010062 {
63 switch(tensor.data_type())
64 {
65 case DataType::F16:
Giorgio Arena6aeb2172020-12-15 15:45:43 +000066 {
Giorgio Arenaa8e2aeb2021-01-06 11:34:57 +000067 arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ float(lo), float(hi) };
Giorgio Arena6aeb2172020-12-15 15:45:43 +000068 library->fill(tensor, distribution, i);
69 break;
70 }
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010071 case DataType::F32:
72 {
Giorgio Arena6aeb2172020-12-15 15:45:43 +000073 std::uniform_real_distribution<float> distribution(lo, hi);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010074 library->fill(tensor, distribution, i);
75 break;
76 }
77 default:
78 library->fill_tensor_uniform(tensor, i);
79 }
80 }
81
82 TensorType compute_target(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &shape_c, const TensorShape &output_shape, float alpha, float beta,
Michalis Spyrou6bff1952019-10-02 17:22:11 +010083 DataType data_type)
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010084 {
85 // Create tensors
Vidhya Sudhan Loganathan014333d2018-07-02 09:13:49 +010086 TensorType a = create_tensor<TensorType>(shape_a, data_type, 1);
87 TensorType b = create_tensor<TensorType>(shape_b, data_type, 1);
88 TensorType c = create_tensor<TensorType>(shape_c, data_type, 1);
89 TensorType dst = create_tensor<TensorType>(output_shape, data_type, 1);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010090
91 // Create and configure function
92 FunctionType gemm;
Isabella Gottardi8e74f442018-03-01 16:42:00 +000093 // The GEMMinfo includes the values of the depth in case of reinterpreted 3d output.
Gian Marco Iodice3139f032018-11-05 14:26:32 +000094 // If the output shape has the same number of dimensions of the input the method called is a 2D matrix multiplication (depth_output_reinterpreted_as_3D = 0),
Isabella Gottardi8e74f442018-03-01 16:42:00 +000095 // in the other case we have to use the reinterpreted version of GEMM (depth_output_reinterpreted_as_3D = depth of the 3D output).
Gian Marco Iodicef3622be2019-07-29 14:27:16 +010096 gemm.configure(&a,
97 &b,
98 (disable_c) ? nullptr : &c,
99 &dst,
100 alpha, beta,
Georgios Pinitas4ee8b152021-07-16 16:16:43 +0100101 GEMMInfo(false, false, false, (reinterpret_output_as_3d ? output_shape[2] : 0), reinterpret_input_as_3d, false, GEMMLowpOutputStageInfo(), false, false, (reinterpret_input_as_3d
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100102 || reinterpret_output_as_3d)));
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100103 ARM_COMPUTE_ASSERT(a.info()->is_resizable());
104 ARM_COMPUTE_ASSERT(b.info()->is_resizable());
105 ARM_COMPUTE_ASSERT(c.info()->is_resizable());
106 ARM_COMPUTE_ASSERT(dst.info()->is_resizable());
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100107
Giorgio Arena63825e82021-03-25 14:54:50 +0000108 add_padding_x({ &a, &b, &c, &dst });
109
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100110 // Allocate tensors
111 a.allocator()->allocate();
112 b.allocator()->allocate();
113 c.allocator()->allocate();
114 dst.allocator()->allocate();
115
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100116 ARM_COMPUTE_ASSERT(!a.info()->is_resizable());
117 ARM_COMPUTE_ASSERT(!b.info()->is_resizable());
118 ARM_COMPUTE_ASSERT(!c.info()->is_resizable());
119 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100120
121 // Fill tensors
122 fill(AccessorType(a), 0);
123 fill(AccessorType(b), 1);
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000124 if(!disable_c)
125 {
126 fill(AccessorType(c), 2);
127 }
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100128
129 // Compute GEMM function
130 gemm.run();
131
132 return dst;
133 }
134
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100135 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 +0100136 DataType data_type)
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100137 {
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100138 TensorShape shape_a_to_use = shape_a;
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100139
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100140 if(reinterpret_input_as_3d)
141 {
142 // Collapse the second and third dimension if the input is 3D
143 shape_a_to_use.collapse(2U, 1U);
144 }
145
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100146 // Create reference
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100147 SimpleTensor<T> a{ shape_a_to_use, data_type, 1 };
Vidhya Sudhan Loganathan014333d2018-07-02 09:13:49 +0100148 SimpleTensor<T> b{ shape_b, data_type, 1 };
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100149 SimpleTensor<T> c{ output_shape, data_type, 1 };
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100150
151 // Fill reference
152 fill(a, 0);
153 fill(b, 1);
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100154 fill(c, 2);
155
156 if(reinterpret_input_as_3d || reinterpret_output_as_3d)
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000157 {
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100158 const int n = shape_b[0];
159 const int m = reinterpret_output_as_3d ? output_shape[1] * output_shape[2] : output_shape[1];
160 const int batch_size = reinterpret_output_as_3d ? output_shape[3] : output_shape[2];
161
162 // In case of broadcast, we need simply copy the first into the following "M" ones
163 for(int i = 1; i < m * batch_size; i++)
164 {
165 memcpy(c.data() + i * n, c.data(), n * sizeof(T));
166 }
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000167 }
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100168
169 // Setting beta to 0 will effectively disable C for the
170 // computation of the reference: alpha * A * B + 0 * C
171 return reference::gemm<T>(a, b, c, alpha, disable_c ? 0.f : beta);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100172 }
173
174 TensorType _target{};
175 SimpleTensor<T> _reference{};
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100176};
177
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100178template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100179class GEMMMatrixMultiplyValidationFixture : public framework::Fixture
180{
181public:
182 template <typename...>
183 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,
184 DataType data_type, GPUTarget gpu_arch)
185 {
186 // Set the tensor shapes for LHS and RHS matrices
187 const TensorShape lhs_shape(k, m, batch_size);
188 const TensorShape rhs_shape(n, k, batch_size);
189 const TensorShape bias_shape(n,
190 broadcast_bias ? 1 : m,
191 broadcast_bias ? 1 : batch_size);
192
193 _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 +0100194 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100195 }
196
197protected:
198 template <typename U>
199 void fill(U &&tensor, int i)
200 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000201 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 +0000202 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 +0000203
204 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100205 library->fill(tensor, distribution, i);
206
207 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000208 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100209 library->fill_borders_with_garbage(tensor, distribution_inf, i);
210 }
211
212 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,
213 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
214 {
215 // Create tensors
216 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
217 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
218 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
219 TensorType dst;
220
221 const unsigned int m = lhs_shape[1];
222 const unsigned int n = rhs_shape[0];
223 const unsigned int k = lhs_shape[0];
224 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, 0, false, broadcast_bias);
225
226 // The output tensor will be auto-initialized within the function
227
228 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100229 GEMMOperatorType gemm;
230 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 +0100231
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100232 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
233 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
234 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100235
Giorgio Arena63825e82021-03-25 14:54:50 +0000236 add_padding_x({ &lhs, &rhs, &bias, &dst });
237
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100238 // Allocate tensors
239 lhs.allocator()->allocate();
240 rhs.allocator()->allocate();
241 bias.allocator()->allocate();
242 dst.allocator()->allocate();
243
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100244 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
245 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
246 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
247 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100248
249 // Fill tensors
250 fill(AccessorType(lhs), 0);
251 fill(AccessorType(rhs), 1);
252 fill(AccessorType(bias), 2);
253
254 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100255 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
256 { ACL_SRC_1, &rhs },
257 { ACL_SRC_2, &bias },
258 { ACL_DST, &dst }
259 });
260 gemm.run(gemm_pack);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100261
262 return dst;
263 }
264
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100265 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 +0100266 const ActivationLayerInfo &act_info)
267 {
268 TensorShape dst_shape = lhs_shape;
269 dst_shape[0] = rhs_shape[0];
270 dst_shape[1] = lhs_shape[1];
271
272 // Create reference
273 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
274 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
275 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
276
277 const int n = rhs_shape[0];
278 const int m = lhs_shape[1];
279 const int batch_size = lhs_shape[2];
280
281 // Fill reference
282 fill(lhs, 0);
283 fill(rhs, 1);
284 fill(bias, 2);
285
286 if(broadcast_bias)
287 {
288 // In case of broadcast, we need simply copy the first into the following "M" ones
289 for(int i = 1; i < m * batch_size; i++)
290 {
291 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
292 }
293 }
294
295 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
296 }
297
298 TensorType _target{};
299 SimpleTensor<T> _reference{};
300};
301
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100302template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100303class GEMMMatrixMultiply3DValidationFixture : public framework::Fixture
304{
305public:
306 template <typename...>
307 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,
308 const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
309 {
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100310 ARM_COMPUTE_UNUSED(broadcast_bias);
311
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100312 // In case of GEMM3D, m is the product between m_w and m_h
313 const unsigned int m = m_w * m_h;
314
315 // Set the tensor shapes for LHS and RHS matrices
316 const TensorShape lhs_shape(k, m, batch_size);
317 const TensorShape rhs_shape(n, k, batch_size);
318 const TensorShape bias_shape(n, 1, 1);
319
320 _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 +0100321 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100322 }
323
324protected:
325 template <typename U>
326 void fill(U &&tensor, int i)
327 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000328 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 +0000329 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 +0000330
331 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100332 library->fill(tensor, distribution, i);
333 }
334
335 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,
336 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
337 {
338 // Create tensors
339 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
340 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
341 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
342 TensorType dst;
343
344 const unsigned int m = lhs_shape[1];
345 const unsigned int n = rhs_shape[0];
346 const unsigned int k = lhs_shape[0];
347 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, m_h, false, true);
348
349 // The output tensor will be auto-initialized within the function
350
351 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100352 GEMMOperatorType gemm;
353 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 +0100354
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100355 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
356 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
357 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100358
Giorgio Arena63825e82021-03-25 14:54:50 +0000359 add_padding_x({ &lhs, &rhs, &bias, &dst });
360
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100361 // Allocate tensors
362 lhs.allocator()->allocate();
363 rhs.allocator()->allocate();
364 bias.allocator()->allocate();
365 dst.allocator()->allocate();
366
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100367 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
368 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
369 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
370 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100371
372 // Fill tensors
373 fill(AccessorType(lhs), 0);
374 fill(AccessorType(rhs), 1);
375 fill(AccessorType(bias), 2);
376
377 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100378 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
379 { ACL_SRC_1, &rhs },
380 { ACL_SRC_2, &bias },
381 { ACL_DST, &dst }
382 });
383 gemm.run(gemm_pack);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100384
385 return dst;
386 }
387
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100388 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 +0100389 const ActivationLayerInfo &act_info)
390 {
391 TensorShape dst_shape = lhs_shape;
392 dst_shape.set(0, rhs_shape[0]);
393 dst_shape.set(1, lhs_shape[1] / m_h);
394 dst_shape.set(2, m_h);
395 dst_shape.set(3, lhs_shape[2]);
396
397 // Create reference
398 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
399 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
400 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
401
402 const int n = rhs_shape[0];
403 const int m = lhs_shape[1];
404 const int batch_size = lhs_shape[2];
405
406 // Fill reference
407 fill(lhs, 0);
408 fill(rhs, 1);
409 fill(bias, 2);
410
411 // In case of broadcast, we need simply copy the first into the following "M" ones
412 for(int i = 1; i < m * batch_size; i++)
413 {
414 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
415 }
416
417 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
418 }
419
420 TensorType _target{};
421 SimpleTensor<T> _reference{};
422};
423
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100424template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSOperatorType, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100425class GEMMMatrixMultiplyInterleavedTransposedValidationFixture : public framework::Fixture
426{
427public:
428 template <typename...>
429 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,
430 const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
431 {
432 GEMMLHSMatrixInfo lhs_info;
433 lhs_info.m0 = 4;
434 lhs_info.k0 = 4;
435 lhs_info.v0 = v0;
436 lhs_info.interleave = true;
437 lhs_info.transpose = true;
438
439 GEMMRHSMatrixInfo rhs_info;
440 rhs_info.n0 = 16 / sizeof(T);
441 rhs_info.k0 = 1;
442 rhs_info.h0 = h0;
443 rhs_info.interleave = false;
444 rhs_info.transpose = false;
445
446 // Set the tensor shapes for LHS and RHS matrices
447 const TensorShape lhs_shape(k, m, batch_size);
448 const TensorShape rhs_shape(n, k, batch_size);
449 const TensorShape bias_shape(n,
450 broadcast_bias ? 1 : m,
451 broadcast_bias ? 1 : batch_size);
452
453 _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 +0100454 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100455 }
456
457protected:
458 template <typename U>
459 void fill(U &&tensor, int i)
460 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000461 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 +0000462 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 +0000463
464 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100465 library->fill(tensor, distribution, i);
466
467 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000468 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100469 library->fill_borders_with_garbage(tensor, distribution_inf, i);
470 }
471
472 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
473 DataType data_type, float alpha, float beta, bool broadcast_bias, bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
474 {
475 // Create tensors
476 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
477 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
478 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
479 TensorType lhs_reshaped;
480 TensorType rhs_reshaped;
481 TensorType dst;
482
483 const unsigned int m = lhs_shape[1];
484 const unsigned int n = rhs_shape[0];
485 const unsigned int k = lhs_shape[0];
486 GEMMReshapeInfo reshape_info(m, n, k, rhs_info.h0, lhs_info.v0, 0, false, broadcast_bias);
487
488 // The output tensor will be auto-initialized within the function
489
490 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100491 ReshapeLHSOperatorType reshape_lhs;
492 ReshapeRHSOperatorType reshape_rhs;
493 GEMMOperatorType gemm;
494 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
495 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
496 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 +0100497
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100498 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
499 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
500 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100501
Georgios Pinitas3dca91b2021-04-13 13:35:58 +0100502 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +0000503 if(!rhs_info.export_to_cl_image)
504 {
505 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
506 }
507
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100508 // Allocate tensors
509 lhs.allocator()->allocate();
510 rhs.allocator()->allocate();
511 lhs_reshaped.allocator()->allocate();
512 rhs_reshaped.allocator()->allocate();
513 bias.allocator()->allocate();
514 dst.allocator()->allocate();
515
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100516 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
517 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
518 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
519 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
520 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
521 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100522
523 // Fill tensors
524 fill(AccessorType(lhs), 0);
525 fill(AccessorType(rhs), 1);
526 fill(AccessorType(bias), 2);
527
528 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100529 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
530 reshape_lhs.run(reshape_lhs_pack);
531 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
532 reshape_rhs.run(reshape_rhs_pack);
533 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
534 { ACL_SRC_1, &rhs_reshaped },
535 { ACL_SRC_2, &bias },
536 { ACL_DST, &dst }
537 });
538 gemm.run(gemm_pack);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100539
540 return dst;
541 }
542
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100543 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 +0100544 const ActivationLayerInfo &act_info)
545 {
546 TensorShape dst_shape = lhs_shape;
547 dst_shape[0] = rhs_shape[0];
548 dst_shape[1] = lhs_shape[1];
549
550 // Create reference
551 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
552 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
553 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
554
555 const int n = rhs_shape[0];
556 const int m = lhs_shape[1];
557 const int batch_size = lhs_shape[2];
558
559 // Fill reference
560 fill(lhs, 0);
561 fill(rhs, 1);
562 fill(bias, 2);
563
564 if(broadcast_bias)
565 {
566 // In case of broadcast, we need simply copy the first into the following "M" ones
567 for(int i = 1; i < m * batch_size; i++)
568 {
569 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
570 }
571 }
572
573 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
574 }
575
576 TensorType _target{};
577 SimpleTensor<T> _reference{};
578};
579
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100580template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSOperatorType, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100581class GEMMMatrixMultiplyInterleavedTransposed3DValidationFixture : public framework::Fixture
582{
583public:
584 template <typename...>
585 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,
586 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
587 {
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100588 ARM_COMPUTE_UNUSED(broadcast_bias);
589
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100590 GEMMLHSMatrixInfo lhs_info;
591 lhs_info.m0 = 4;
592 lhs_info.k0 = 4;
593 lhs_info.v0 = v0;
594 lhs_info.interleave = true;
595 lhs_info.transpose = true;
596
597 GEMMRHSMatrixInfo rhs_info;
598 rhs_info.n0 = 16 / sizeof(T);
599 rhs_info.k0 = 1;
600 rhs_info.h0 = h0;
601 rhs_info.interleave = false;
602 rhs_info.transpose = false;
603
604 // In case of GEMM3D, m is the product between m_w and m_h
605 const unsigned int m = m_w * m_h;
606
607 // Set the tensor shapes for LHS and RHS matrices
608 const TensorShape lhs_shape(k, m, batch_size);
609 const TensorShape rhs_shape(n, k, batch_size);
610 const TensorShape bias_shape(n, 1, 1);
611
612 _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 +0100613 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100614 }
615
616protected:
617 template <typename U>
618 void fill(U &&tensor, int i)
619 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000620 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 +0000621 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 +0000622
623 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100624 library->fill(tensor, distribution, i);
625 }
626
627 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
628 DataType data_type, float alpha, float beta, unsigned int m_h, bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
629 {
630 // Create tensors
631 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
632 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
633 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
634 TensorType lhs_reshaped;
635 TensorType rhs_reshaped;
636 TensorType dst;
637
638 const unsigned int m = lhs_shape[1];
639 const unsigned int n = rhs_shape[0];
640 const unsigned int k = lhs_shape[0];
641 GEMMReshapeInfo reshape_info(m, n, k, rhs_info.h0, lhs_info.v0, m_h, false, true);
642
643 // The output tensor will be auto-initialized within the function
644
645 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100646 ReshapeLHSOperatorType reshape_lhs;
647 ReshapeRHSOperatorType reshape_rhs;
648 GEMMOperatorType gemm;
649 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
650 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
651 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 +0100652
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100653 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
654 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
655 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100656
Georgios Pinitas3dca91b2021-04-13 13:35:58 +0100657 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +0000658 if(!rhs_info.export_to_cl_image)
659 {
660 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
661 }
662
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100663 // Allocate tensors
664 lhs.allocator()->allocate();
665 rhs.allocator()->allocate();
666 lhs_reshaped.allocator()->allocate();
667 rhs_reshaped.allocator()->allocate();
668 bias.allocator()->allocate();
669 dst.allocator()->allocate();
670
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100671 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
672 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
673 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
674 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
675 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
676 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100677
678 // Fill tensors
679 fill(AccessorType(lhs), 0);
680 fill(AccessorType(rhs), 1);
681 fill(AccessorType(bias), 2);
682
683 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100684 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
685 reshape_lhs.run(reshape_lhs_pack);
686 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
687 reshape_rhs.run(reshape_rhs_pack);
688 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
689 { ACL_SRC_1, &rhs_reshaped },
690 { ACL_SRC_2, &bias },
691 { ACL_DST, &dst }
692 });
693 gemm.run(gemm_pack);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100694
695 return dst;
696 }
697
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100698 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 +0100699 const ActivationLayerInfo &act_info)
700 {
701 TensorShape dst_shape = lhs_shape;
702 dst_shape.set(0, rhs_shape[0]);
703 dst_shape.set(1, lhs_shape[1] / m_h);
704 dst_shape.set(2, m_h);
705 dst_shape.set(3, lhs_shape[2]);
706
707 // Create reference
708 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
709 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
710 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
711
712 const int n = rhs_shape[0];
713 const int m = lhs_shape[1];
714 const int batch_size = lhs_shape[2];
715
716 // Fill reference
717 fill(lhs, 0);
718 fill(rhs, 1);
719 fill(bias, 2);
720
721 // In case of broadcast, we need simply copy the first into the following "M" ones
722 for(int i = 1; i < m * batch_size; i++)
723 {
724 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
725 }
726
727 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
728 }
729
730 TensorType _target{};
731 SimpleTensor<T> _reference{};
732};
733
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100734template <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 +0000735class GEMMMatrixMultiplyReshapedValidationFixture : public framework::Fixture
736{
737public:
738 template <typename...>
739 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 +0100740 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 +0000741 {
742 GEMMLHSMatrixInfo lhs_info;
743 lhs_info.m0 = m0;
744 lhs_info.k0 = k0;
745 lhs_info.v0 = v0;
746 lhs_info.interleave = interleave_lhs;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100747 lhs_info.transpose = lhs_transpose;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000748
749 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodicee3a849a2020-06-10 17:59:30 +0100750 rhs_info.n0 = n0;
751 rhs_info.k0 = k0;
752 rhs_info.h0 = h0;
753 rhs_info.interleave = interleave_rhs;
754 rhs_info.transpose = !lhs_transpose;
755 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000756
757 // Set the tensor shapes for LHS and RHS matrices
758 const TensorShape lhs_shape(k, m, batch_size);
759 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100760 const TensorShape bias_shape(n,
761 broadcast_bias ? 1 : m,
762 broadcast_bias ? 1 : batch_size);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000763
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000764 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
765 if(validate_result)
766 {
767 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
768 }
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000769 }
770
771protected:
772 template <typename U>
773 void fill(U &&tensor, int i)
774 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000775 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 +0000776 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 +0000777
778 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000779 library->fill(tensor, distribution, i);
Gian Marco Iodiceb87b95e2019-01-21 17:14:31 +0000780
781 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000782 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiceb87b95e2019-01-21 17:14:31 +0000783 library->fill_borders_with_garbage(tensor, distribution_inf, i);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000784 }
785
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100786 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 +0100787 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000788 {
789 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100790 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
791 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
792 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000793 TensorType lhs_reshaped;
794 TensorType rhs_reshaped;
795 TensorType dst;
796
797 const unsigned int M = lhs_shape[1];
798 const unsigned int N = rhs_shape[0];
799 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100800 GEMMKernelInfo kernel_info;
801 kernel_info.m = M;
802 kernel_info.n = N;
803 kernel_info.k = K;
804 kernel_info.depth_output_gemm3d = 0;
805 kernel_info.reinterpret_input_as_3d = false;
806 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100807 kernel_info.activation_info = act_info;
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100808 kernel_info.fp_mixed_precision = fp_mixed_precision;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000809
810 // The output tensor will be auto-initialized within the function
811
812 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100813 ReshapeLHSOperatorType reshape_lhs;
814 ReshapeRHSOperatorType reshape_rhs;
815 GEMMOperatorType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000816
817 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
818 validate_result = validate_result || !rhs_info.export_to_cl_image;
819 if(!validate_result)
820 {
821 return nullptr;
822 }
823
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100824 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
825 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
826 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 +0000827
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100828 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
829 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
830 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000831
Georgios Pinitas3dca91b2021-04-13 13:35:58 +0100832 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +0000833 if(!rhs_info.export_to_cl_image)
834 {
835 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
836 }
837
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000838 // Allocate tensors
839 lhs.allocator()->allocate();
840 rhs.allocator()->allocate();
841 lhs_reshaped.allocator()->allocate();
842 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100843 bias.allocator()->allocate();
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000844 dst.allocator()->allocate();
845
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100846 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
847 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
848 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
849 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
850 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
851 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000852
853 // Fill tensors
854 fill(AccessorType(lhs), 0);
855 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100856 fill(AccessorType(bias), 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000857
858 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100859 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
860 reshape_lhs.run(reshape_lhs_pack);
861 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
862 reshape_rhs.run(reshape_rhs_pack);
863 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
864 { ACL_SRC_1, &rhs_reshaped },
865 { ACL_SRC_2, &bias },
866 { ACL_DST, &dst }
867 });
868 gemm.run(gemm_pack);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000869
870 return dst;
871 }
872
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100873 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 +0100874 const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000875 {
876 TensorShape dst_shape = lhs_shape;
877 dst_shape[0] = rhs_shape[0];
878 dst_shape[1] = lhs_shape[1];
879
880 // Create reference
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000881 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
882 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100883 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
884
885 const int n = rhs_shape[0];
886 const int m = lhs_shape[1];
887 const int batch_size = lhs_shape[2];
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000888
889 // Fill reference
890 fill(lhs, 0);
891 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100892 fill(bias, 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000893
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100894 if(broadcast_bias)
895 {
896 // In case of broadcast, we need simply copy the first into the following "M" ones
897 for(int i = 1; i < m * batch_size; i++)
898 {
899 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
900 }
901 }
902
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100903 if(fp_mixed_precision)
904 {
905 return reference::activation_layer(reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta), act_info);
906 }
907 else
908 {
909 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
910 }
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000911 }
912
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000913 bool validate_result = true;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000914 TensorType _target{};
915 SimpleTensor<T> _reference{};
916};
917
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100918template <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 +0000919class GEMMMatrixMultiplyReshaped3DValidationFixture : public framework::Fixture
920{
921public:
922 template <typename...>
923 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 +0100924 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 +0000925 {
926 GEMMLHSMatrixInfo lhs_info;
927 lhs_info.m0 = m0;
928 lhs_info.k0 = k0;
929 lhs_info.v0 = v0;
930 lhs_info.interleave = interleave_lhs;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100931 lhs_info.transpose = lhs_transpose;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000932
933 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodicee3a849a2020-06-10 17:59:30 +0100934 rhs_info.n0 = n0;
935 rhs_info.k0 = k0;
936 rhs_info.h0 = h0;
937 rhs_info.interleave = interleave_rhs;
938 rhs_info.transpose = !lhs_transpose;
939 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000940
941 // In case of GEMM3D, m is the product between m_w and m_h
942 const unsigned int m = m_w * m_h;
943
944 // Set the tensor shapes for LHS and RHS matrices
945 const TensorShape lhs_shape(k, m, batch_size);
946 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100947 const TensorShape bias_shape(n, 1, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000948
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000949 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info);
950 if(validate_result)
951 {
952 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
953 }
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000954 }
955
956protected:
957 template <typename U>
958 void fill(U &&tensor, int i)
959 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000960 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 +0000961 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 +0000962
963 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000964 library->fill(tensor, distribution, i);
965 }
966
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100967 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 +0100968 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000969 {
970 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100971 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
972 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
973 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000974 TensorType lhs_reshaped;
975 TensorType rhs_reshaped;
976 TensorType dst;
977
978 const unsigned int M = lhs_shape[1];
979 const unsigned int N = rhs_shape[0];
980 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100981 GEMMKernelInfo kernel_info;
982 kernel_info.m = M;
983 kernel_info.n = N;
984 kernel_info.k = K;
985 kernel_info.depth_output_gemm3d = m_h;
986 kernel_info.reinterpret_input_as_3d = false;
987 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100988 kernel_info.activation_info = act_info;
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100989 kernel_info.fp_mixed_precision = fp_mixed_precision;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000990
991 // The output tensor will be auto-initialized within the function
992
993 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100994 ReshapeLHSOperatorType reshape_lhs;
995 ReshapeRHSOperatorType reshape_rhs;
996 GEMMOperatorType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000997
998 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
999 validate_result = validate_result || !rhs_info.export_to_cl_image;
1000 if(!validate_result)
1001 {
1002 return nullptr;
1003 }
1004
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001005 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
1006 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1007 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 +00001008
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001009 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1010 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1011 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001012
Georgios Pinitas3dca91b2021-04-13 13:35:58 +01001013 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +00001014 if(!rhs_info.export_to_cl_image)
1015 {
1016 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
1017 }
1018
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001019 // Allocate tensors
1020 lhs.allocator()->allocate();
1021 rhs.allocator()->allocate();
1022 lhs_reshaped.allocator()->allocate();
1023 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001024 bias.allocator()->allocate();
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001025 dst.allocator()->allocate();
1026
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001027 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1028 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1029 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
1030 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1031 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1032 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001033
1034 // Fill tensors
1035 fill(AccessorType(lhs), 0);
1036 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001037 fill(AccessorType(bias), 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001038
1039 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001040 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
1041 reshape_lhs.run(reshape_lhs_pack);
1042 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1043 reshape_rhs.run(reshape_rhs_pack);
1044 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
1045 { ACL_SRC_1, &rhs_reshaped },
1046 { ACL_SRC_2, &bias },
1047 { ACL_DST, &dst }
1048 });
1049 gemm.run(gemm_pack);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001050
1051 return dst;
1052 }
1053
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001054 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 +01001055 const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001056 {
1057 TensorShape dst_shape = lhs_shape;
1058 dst_shape.set(0, rhs_shape[0]);
1059 dst_shape.set(1, lhs_shape[1] / m_h);
1060 dst_shape.set(2, m_h);
1061 dst_shape.set(3, lhs_shape[2]);
1062
1063 // Create reference
1064 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1065 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001066 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1067
1068 const int n = rhs_shape[0];
1069 const int m = lhs_shape[1];
1070 const int batch_size = lhs_shape[2];
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001071
1072 // Fill reference
1073 fill(lhs, 0);
1074 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001075 fill(bias, 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001076
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001077 // In case of broadcast, we need simply copy the first into the following "M" ones
1078 for(int i = 1; i < m * batch_size; i++)
1079 {
1080 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1081 }
1082
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +01001083 if(fp_mixed_precision)
1084 {
1085 return reference::activation_layer(reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta), act_info);
1086 }
1087 else
1088 {
1089 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
1090 }
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001091 }
1092
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001093 bool validate_result = true;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001094 TensorType _target{};
1095 SimpleTensor<T> _reference{};
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +00001096};
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001097
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001098template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001099class GEMMMatrixMultiplyReshapedOnlyRHSValidationFixture : public framework::Fixture
1100{
1101public:
1102 template <typename...>
1103 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 +01001104 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 +00001105 {
1106 GEMMLHSMatrixInfo lhs_info;
1107 lhs_info.m0 = m0;
1108 lhs_info.k0 = k0;
1109
1110 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodice781cba72020-06-19 16:56:57 +01001111 rhs_info.n0 = n0;
1112 rhs_info.k0 = k0;
1113 rhs_info.h0 = h0;
1114 rhs_info.interleave = interleave_rhs;
1115 rhs_info.transpose = transpose_rhs;
1116 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001117
1118 // Set the tensor shapes for LHS and RHS matrices
1119 const TensorShape lhs_shape(k, m, batch_size);
1120 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001121 const TensorShape bias_shape(n,
1122 broadcast_bias ? 1 : m,
1123 broadcast_bias ? 1 : batch_size);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001124
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001125 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
1126 if(validate_result)
1127 {
1128 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
1129 }
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001130 }
1131
1132protected:
1133 template <typename U>
1134 void fill(U &&tensor, int i)
1135 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001136 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 +00001137 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 +00001138
1139 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001140 library->fill(tensor, distribution, i);
1141
1142 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001143 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001144 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1145 }
1146
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001147 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 +01001148 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001149 {
1150 // Create tensors
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001151 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1152 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1153 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001154 TensorType rhs_reshaped;
1155 TensorType dst;
1156
1157 const unsigned int M = lhs_shape[1];
1158 const unsigned int N = rhs_shape[0];
1159 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001160 GEMMKernelInfo kernel_info;
1161 kernel_info.m = M;
1162 kernel_info.n = N;
1163 kernel_info.k = K;
1164 kernel_info.depth_output_gemm3d = 0;
1165 kernel_info.reinterpret_input_as_3d = false;
1166 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001167 kernel_info.activation_info = act_info;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001168
1169 // The output tensor will be auto-initialized within the function
1170
1171 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001172 ReshapeRHSOperatorType reshape_rhs;
1173 GEMMOperatorType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001174
1175 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1176 validate_result = validate_result || !rhs_info.export_to_cl_image;
1177 if(!validate_result)
1178 {
1179 return nullptr;
1180 }
1181
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001182 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1183 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 +00001184
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001185 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1186 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1187 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001188
Georgios Pinitas3dca91b2021-04-13 13:35:58 +01001189 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +00001190 if(!rhs_info.export_to_cl_image)
1191 {
1192 add_padding_x({ &lhs, &rhs, &rhs_reshaped, &bias, &dst });
1193 }
1194
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001195 // Allocate tensors
1196 lhs.allocator()->allocate();
1197 rhs.allocator()->allocate();
1198 rhs_reshaped.allocator()->allocate();
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001199 bias.allocator()->allocate();
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001200 dst.allocator()->allocate();
1201
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001202 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1203 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1204 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1205 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1206 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001207
1208 // Fill tensors
1209 fill(AccessorType(lhs), 0);
1210 fill(AccessorType(rhs), 1);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001211 fill(AccessorType(bias), 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001212
1213 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001214 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1215 reshape_rhs.run(reshape_rhs_pack);
1216 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
1217 { ACL_SRC_1, &rhs_reshaped },
1218 { ACL_SRC_2, &bias },
1219 { ACL_DST, &dst }
1220 });
1221 gemm.run(gemm_pack);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001222
1223 return dst;
1224 }
1225
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001226 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 +01001227 const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001228 {
1229 TensorShape dst_shape = lhs_shape;
1230 dst_shape[0] = rhs_shape[0];
1231 dst_shape[1] = lhs_shape[1];
1232
1233 // Create reference
1234 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1235 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001236 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1237
1238 const int n = rhs_shape[0];
1239 const int m = lhs_shape[1];
1240 const int batch_size = lhs_shape[2];
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001241
1242 // Fill reference
1243 fill(lhs, 0);
1244 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001245 fill(bias, 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001246
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001247 if(broadcast_bias)
1248 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001249 // In case of broadcast, we need simply copy the first into the following "M" ones
1250 for(int i = 1; i < m * batch_size; i++)
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001251 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001252 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001253 }
1254 }
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001255
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001256 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001257 }
1258
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001259 bool validate_result = true;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001260 TensorType _target{};
1261 SimpleTensor<T> _reference{};
1262};
1263
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001264template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001265class GEMMMatrixMultiplyReshapedOnlyRHS3DValidationFixture : public framework::Fixture
1266{
1267public:
1268 template <typename...>
1269 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 +01001270 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 +01001271 {
1272 GEMMLHSMatrixInfo lhs_info;
1273 lhs_info.m0 = m0;
1274 lhs_info.k0 = k0;
1275
1276 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodice781cba72020-06-19 16:56:57 +01001277 rhs_info.n0 = n0;
1278 rhs_info.k0 = k0;
1279 rhs_info.h0 = h0;
1280 rhs_info.interleave = interleave_rhs;
1281 rhs_info.transpose = transpose_rhs;
1282 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001283
1284 // In case of GEMM3D, m is the product between m_w and m_h
1285 const unsigned int m = m_w * m_h;
1286
1287 // Set the tensor shapes for LHS and RHS matrices
1288 const TensorShape lhs_shape(k, m, batch_size);
1289 const TensorShape rhs_shape(n, k, batch_size);
1290 const TensorShape bias_shape(n, 1, 1);
1291
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001292 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info, has_pad_y);
1293 if(validate_result)
1294 {
1295 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
1296 }
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001297 }
1298
1299protected:
1300 template <typename U>
1301 void fill(U &&tensor, int i)
1302 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001303 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 +00001304 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 +00001305
1306 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001307 library->fill(tensor, distribution, i);
1308 }
1309
1310 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
1311 DataType data_type, float alpha, float beta,
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001312 unsigned int m_h, const ActivationLayerInfo &act_info, bool has_pad_y)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001313 {
1314 // Create tensors
1315 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1316 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1317 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
1318 TensorType rhs_reshaped;
1319 TensorType dst;
1320
1321 const unsigned int M = lhs_shape[1];
1322 const unsigned int N = rhs_shape[0];
1323 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001324 GEMMKernelInfo kernel_info;
1325 kernel_info.m = M;
1326 kernel_info.n = N;
1327 kernel_info.k = K;
1328 kernel_info.depth_output_gemm3d = m_h;
1329 kernel_info.reinterpret_input_as_3d = false;
1330 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001331 kernel_info.activation_info = act_info;
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001332 kernel_info.has_pad_y = has_pad_y;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001333
1334 // The output tensor will be auto-initialized within the function
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001335 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001336 ReshapeRHSOperatorType reshape_rhs;
1337 GEMMOperatorType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001338
1339 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1340 validate_result = validate_result || !rhs_info.export_to_cl_image;
1341 if(!validate_result)
1342 {
1343 return nullptr;
1344 }
1345
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001346 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1347 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 +01001348
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001349 if(has_pad_y)
1350 {
1351 // Add dummy padding into lhs to validate has_pad_y path
1352 lhs.info()->extend_padding(PaddingSize(2, 0, 2, 0));
1353 dst.info()->extend_padding(PaddingSize(2, 0, 1, 0));
1354 }
1355
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001356 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1357 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1358 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001359
Georgios Pinitas3dca91b2021-04-13 13:35:58 +01001360 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +00001361 if(!rhs_info.export_to_cl_image)
1362 {
1363 add_padding_x({ &lhs, &rhs, &rhs_reshaped, &bias, &dst });
1364 }
1365
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001366 // Allocate tensors
1367 lhs.allocator()->allocate();
1368 rhs.allocator()->allocate();
1369 rhs_reshaped.allocator()->allocate();
1370 bias.allocator()->allocate();
1371 dst.allocator()->allocate();
1372
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001373 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1374 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1375 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1376 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1377 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001378
1379 // Fill tensors
1380 fill(AccessorType(lhs), 0);
1381 fill(AccessorType(rhs), 1);
1382 fill(AccessorType(bias), 2);
1383
1384 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001385 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1386 reshape_rhs.run(reshape_rhs_pack);
1387 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
1388 { ACL_SRC_1, &rhs_reshaped },
1389 { ACL_SRC_2, &bias },
1390 { ACL_DST, &dst }
1391 });
1392 gemm.run(gemm_pack);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001393
1394 return dst;
1395 }
1396
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001397 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 +01001398 const ActivationLayerInfo &act_info)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001399 {
1400 TensorShape dst_shape = lhs_shape;
1401 dst_shape.set(0, rhs_shape[0]);
1402 dst_shape.set(1, lhs_shape[1] / m_h);
1403 dst_shape.set(2, m_h);
1404 dst_shape.set(3, lhs_shape[2]);
1405
1406 // Create reference
1407 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1408 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
1409 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1410
1411 const int n = rhs_shape[0];
1412 const int m = lhs_shape[1];
1413 const int batch_size = lhs_shape[2];
1414
1415 // Fill reference
1416 fill(lhs, 0);
1417 fill(rhs, 1);
1418 fill(bias, 2);
1419
1420 // In case of broadcast, we need simply copy the first into the following "M" ones
1421 for(int i = 1; i < m * batch_size; i++)
1422 {
1423 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1424 }
1425
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001426 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001427 }
1428
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001429 bool validate_result = true;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001430 TensorType _target{};
1431 SimpleTensor<T> _reference{};
1432};
1433
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001434template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
giuros01b3204e72019-04-01 13:50:22 +01001435class GEMMMatrixMultiplyNativeValidationFixture : public framework::Fixture
1436{
1437public:
1438 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001439 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,
1440 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001441 {
1442 GEMMLHSMatrixInfo lhs_info;
1443 lhs_info.m0 = m0;
1444 lhs_info.k0 = k0;
1445
1446 GEMMRHSMatrixInfo rhs_info;
1447 rhs_info.n0 = n0;
1448 rhs_info.k0 = k0;
1449
1450 // Set the tensor shapes for LHS and RHS matrices
1451 const TensorShape lhs_shape(k, m, batch_size);
1452 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001453 const TensorShape bias_shape(n,
1454 broadcast_bias ? 1 : m,
1455 broadcast_bias ? 1 : batch_size);
giuros01b3204e72019-04-01 13:50:22 +01001456
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001457 _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 +01001458 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
giuros01b3204e72019-04-01 13:50:22 +01001459 }
1460
1461protected:
1462 template <typename U>
1463 void fill(U &&tensor, int i)
1464 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001465 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 +00001466 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 +00001467
1468 DistributionType distribution{ T(-1.0f), T(1.0f) };
giuros01b3204e72019-04-01 13:50:22 +01001469 library->fill(tensor, distribution, i);
1470
1471 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001472 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
giuros01b3204e72019-04-01 13:50:22 +01001473 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1474 }
1475
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001476 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 +01001477 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001478 {
1479 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001480 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1481 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1482 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01001483 TensorType dst;
1484
1485 const unsigned int M = lhs_shape[1];
1486 const unsigned int N = rhs_shape[0];
1487 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001488 GEMMKernelInfo kernel_info;
1489 kernel_info.m = M;
1490 kernel_info.n = N;
1491 kernel_info.k = K;
1492 kernel_info.depth_output_gemm3d = 0;
1493 kernel_info.reinterpret_input_as_3d = false;
1494 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001495 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01001496
1497 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001498 GEMMOperatorType gemm;
1499 gemm.configure(lhs.info(), rhs.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01001500
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001501 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1502 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1503 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
giuros01b3204e72019-04-01 13:50:22 +01001504
Giorgio Arena63825e82021-03-25 14:54:50 +00001505 add_padding_x({ &lhs, &rhs, &bias, &dst });
1506
giuros01b3204e72019-04-01 13:50:22 +01001507 // Allocate tensors
1508 lhs.allocator()->allocate();
1509 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001510 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01001511 dst.allocator()->allocate();
1512
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001513 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1514 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1515 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1516 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
giuros01b3204e72019-04-01 13:50:22 +01001517
1518 // Fill tensors
1519 fill(AccessorType(lhs), 0);
1520 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001521 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01001522
1523 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001524 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
1525 { ACL_SRC_1, &rhs },
1526 { ACL_SRC_2, &bias },
1527 { ACL_DST, &dst }
1528 });
1529 gemm.run(gemm_pack);
giuros01b3204e72019-04-01 13:50:22 +01001530
1531 return dst;
1532 }
1533
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001534 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 +01001535 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001536 {
1537 TensorShape dst_shape = lhs_shape;
1538 dst_shape[0] = rhs_shape[0];
1539 dst_shape[1] = lhs_shape[1];
1540
1541 // Create reference
1542 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1543 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001544 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1545
1546 const int n = rhs_shape[0];
1547 const int m = lhs_shape[1];
1548 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01001549
1550 // Fill reference
1551 fill(lhs, 0);
1552 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001553 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01001554
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001555 if(broadcast_bias)
1556 {
1557 // In case of broadcast, we need simply copy the first into the following "M" ones
1558 for(int i = 1; i < m * batch_size; i++)
1559 {
1560 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1561 }
1562 }
1563
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001564 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01001565 }
1566
1567 TensorType _target{};
1568 SimpleTensor<T> _reference{};
1569};
1570
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001571template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
giuros01b3204e72019-04-01 13:50:22 +01001572class GEMMMatrixMultiplyNative3DValidationFixture : public framework::Fixture
1573{
1574public:
1575 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001576 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,
1577 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001578 {
1579 GEMMLHSMatrixInfo lhs_info;
1580 lhs_info.m0 = m0;
1581 lhs_info.k0 = k0;
1582
1583 GEMMRHSMatrixInfo rhs_info;
1584 rhs_info.n0 = n0;
1585 rhs_info.k0 = k0;
1586
1587 // In case of GEMM3D, m is the product between m_w and m_h
1588 const unsigned int m = m_w * m_h;
1589
1590 // Set the tensor shapes for LHS and RHS matrices
1591 const TensorShape lhs_shape(k, m, batch_size);
1592 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001593 const TensorShape bias_shape(n, 1, 1);
giuros01b3204e72019-04-01 13:50:22 +01001594
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001595 _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 +01001596 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
giuros01b3204e72019-04-01 13:50:22 +01001597 }
1598
1599protected:
1600 template <typename U>
1601 void fill(U &&tensor, int i)
1602 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001603 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 +00001604 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 +00001605
1606 DistributionType distribution{ T(-1.0f), T(1.0f) };
giuros01b3204e72019-04-01 13:50:22 +01001607 library->fill(tensor, distribution, i);
1608 }
1609
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001610 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 +01001611 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001612 {
1613 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001614 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1615 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1616 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01001617 TensorType dst;
1618
1619 const unsigned int M = lhs_shape[1];
1620 const unsigned int N = rhs_shape[0];
1621 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001622 GEMMKernelInfo kernel_info;
1623 kernel_info.m = M;
1624 kernel_info.n = N;
1625 kernel_info.k = K;
1626 kernel_info.depth_output_gemm3d = m_h;
1627 kernel_info.reinterpret_input_as_3d = false;
1628 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001629 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01001630
1631 // The output tensor will be auto-initialized within the function
1632
1633 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001634 GEMMOperatorType gemm;
1635 gemm.configure(lhs.info(), rhs.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01001636
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001637 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1638 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1639 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
giuros01b3204e72019-04-01 13:50:22 +01001640
Giorgio Arena63825e82021-03-25 14:54:50 +00001641 add_padding_x({ &lhs, &rhs, &bias, &dst });
1642
giuros01b3204e72019-04-01 13:50:22 +01001643 // Allocate tensors
1644 lhs.allocator()->allocate();
1645 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001646 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01001647 dst.allocator()->allocate();
1648
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001649 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1650 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1651 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1652 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
giuros01b3204e72019-04-01 13:50:22 +01001653
1654 // Fill tensors
1655 fill(AccessorType(lhs), 0);
1656 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001657 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01001658
1659 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001660 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
1661 { ACL_SRC_1, &rhs },
1662 { ACL_SRC_2, &bias },
1663 { ACL_DST, &dst }
1664 });
1665 gemm.run(gemm_pack);
giuros01b3204e72019-04-01 13:50:22 +01001666
1667 return dst;
1668 }
1669
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001670 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 +01001671 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001672 {
1673 TensorShape dst_shape = lhs_shape;
1674 dst_shape.set(0, rhs_shape[0]);
1675 dst_shape.set(1, lhs_shape[1] / m_h);
1676 dst_shape.set(2, m_h);
1677 dst_shape.set(3, lhs_shape[2]);
1678
1679 // Create reference
1680 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1681 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001682 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1683
1684 const int n = rhs_shape[0];
1685 const int m = lhs_shape[1];
1686 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01001687
1688 // Fill reference
1689 fill(lhs, 0);
1690 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001691 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01001692
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001693 // In case of broadcast, we need simply copy the first into the following "M" ones
1694 for(int i = 1; i < m * batch_size; i++)
1695 {
1696 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1697 }
1698
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001699 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01001700 }
1701
1702 TensorType _target{};
1703 SimpleTensor<T> _reference{};
1704};
1705
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +01001706} // namespace validation
1707} // namespace test
1708} // namespace arm_compute
1709#endif /* ARM_COMPUTE_TEST_GEMM_FIXTURE */