blob: 0682337c82b83e1605e82f9b525e9c271d387e8e [file] [log] [blame]
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +01001/*
Gian Marco Iodice10e88a72021-11-29 12:49:19 +00002 * Copyright (c) 2017-2022 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{
Mohammed Suhail Munshi13a2d002022-09-05 11:57:34 +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, bool pretranspose_a = false, bool pretranspose_b = false, bool run_twice = 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
Mohammed Suhail Munshi13a2d002022-09-05 11:57:34 +0100133 // Run with variable inputs.
134 if(run_twice)
135 {
136 gemm.run();
137 fill(AccessorType(a), 3); // Fill tensors with new seed after run
138 fill(AccessorType(b), 4);
139 if(!disable_c)
140 {
141 fill(AccessorType(c), 5);
142 }
143 }
144
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100145 // Compute GEMM function
146 gemm.run();
147
148 return dst;
149 }
150
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100151 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 +0100152 DataType data_type)
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100153 {
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100154 TensorShape shape_a_to_use = shape_a;
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100155
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100156 if(reinterpret_input_as_3d)
157 {
158 // Collapse the second and third dimension if the input is 3D
159 shape_a_to_use.collapse(2U, 1U);
160 }
161
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100162 // Create reference
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100163 SimpleTensor<T> a{ shape_a_to_use, data_type, 1 };
Vidhya Sudhan Loganathan014333d2018-07-02 09:13:49 +0100164 SimpleTensor<T> b{ shape_b, data_type, 1 };
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100165 SimpleTensor<T> c{ output_shape, data_type, 1 };
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100166
167 // Fill reference
168 fill(a, 0);
169 fill(b, 1);
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100170 fill(c, 2);
171
172 if(reinterpret_input_as_3d || reinterpret_output_as_3d)
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000173 {
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100174 const int n = shape_b[0];
175 const int m = reinterpret_output_as_3d ? output_shape[1] * output_shape[2] : output_shape[1];
176 const int batch_size = reinterpret_output_as_3d ? output_shape[3] : output_shape[2];
177
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000178 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100179 for(int i = 1; i < m * batch_size; i++)
180 {
181 memcpy(c.data() + i * n, c.data(), n * sizeof(T));
182 }
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000183 }
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000184
Adnan AlSinan3bb72b62022-05-06 12:10:11 +0100185 /* Note: Assuming the usual batch matmul dimensions A = (B x M x K), B = (B x K x N), if pretranspose_A is set to true, then A is assumed to be (B x K x M),
186 therefore, A must be pre-transposed before passing it to the fixture. And, we transpose A again in the fixture to make it (B x M x K)
187 in order to be able to call reference implementation that works with (B x M x K) input.
188 Similarly, if pretranspose_B is set to true, then B is assumed to be (B x N x K), B must be pre-transposed before passing it to the fixture. */
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000189
Mohammed Suhail Munshibc5c4072022-04-27 13:49:51 +0100190 // Define transposed shapes
191 TensorShape a_transposed_shape(a.shape().y(), a.shape().x());
192 TensorShape b_transposed_shape(b.shape().y(), b.shape().x());
193
194 // Define transposed tensors
195 SimpleTensor<T> a_transposed{ a_transposed_shape, data_type };
196 SimpleTensor<T> b_transposed{ b_transposed_shape, data_type };
197
198 // pretranspose a if necessary
199 if(pretranspose_a)
200 {
201 transpose_matrix<T>(a, a_transposed);
202 }
203
204 // pretranspose b if necessary
205 if(pretranspose_b)
206 {
207 transpose_matrix<T>(b, b_transposed);
208 }
209
Mohammed Suhail Munshi13a2d002022-09-05 11:57:34 +0100210 // Run with variable inputs.
211 if(run_twice)
212 {
213 reference::gemm<T>((pretranspose_a) ? a_transposed : a, (pretranspose_b) ? b_transposed : b, c, alpha, disable_c ? 0.f : beta);
214 fill((pretranspose_a) ? a_transposed : a, 3);
215 fill((pretranspose_b) ? b_transposed : b, 4);
216 fill(c , 5);
217 }
218
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100219 // Setting beta to 0 will effectively disable C for the
220 // computation of the reference: alpha * A * B + 0 * C
Mohammed Suhail Munshibc5c4072022-04-27 13:49:51 +0100221 // Use transposed tensors if boolean enabled else use original tensors
Mohammed Suhail Munshi13a2d002022-09-05 11:57:34 +0100222 auto r = reference::gemm<T>((pretranspose_a) ? a_transposed : a, (pretranspose_b) ? b_transposed : b, c, alpha, disable_c ? 0.f : beta);
223 return r;
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100224 }
225
226 TensorType _target{};
227 SimpleTensor<T> _reference{};
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100228};
229
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100230template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100231class GEMMMatrixMultiplyValidationFixture : public framework::Fixture
232{
233public:
234 template <typename...>
235 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,
236 DataType data_type, GPUTarget gpu_arch)
237 {
238 // Set the tensor shapes for LHS and RHS matrices
239 const TensorShape lhs_shape(k, m, batch_size);
240 const TensorShape rhs_shape(n, k, batch_size);
241 const TensorShape bias_shape(n,
242 broadcast_bias ? 1 : m,
243 broadcast_bias ? 1 : batch_size);
244
245 _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 +0100246 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100247 }
248
249protected:
250 template <typename U>
251 void fill(U &&tensor, int i)
252 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000253 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 +0000254 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 +0000255
256 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100257 library->fill(tensor, distribution, i);
258
259 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000260 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100261 library->fill_borders_with_garbage(tensor, distribution_inf, i);
262 }
263
264 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,
265 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
266 {
267 // Create tensors
268 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
269 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
270 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
271 TensorType dst;
272
273 const unsigned int m = lhs_shape[1];
274 const unsigned int n = rhs_shape[0];
275 const unsigned int k = lhs_shape[0];
276 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, 0, false, broadcast_bias);
277
278 // The output tensor will be auto-initialized within the function
279
280 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100281 GEMMOperatorType gemm;
282 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 +0100283
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100284 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
285 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
286 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100287
Giorgio Arena63825e82021-03-25 14:54:50 +0000288 add_padding_x({ &lhs, &rhs, &bias, &dst });
289
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100290 // Allocate tensors
291 lhs.allocator()->allocate();
292 rhs.allocator()->allocate();
293 bias.allocator()->allocate();
294 dst.allocator()->allocate();
295
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100296 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
297 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
298 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
299 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100300
301 // Fill tensors
302 fill(AccessorType(lhs), 0);
303 fill(AccessorType(rhs), 1);
304 fill(AccessorType(bias), 2);
305
306 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100307 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
308 { ACL_SRC_1, &rhs },
309 { ACL_SRC_2, &bias },
310 { ACL_DST, &dst }
311 });
312 gemm.run(gemm_pack);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100313
314 return dst;
315 }
316
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100317 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 +0100318 const ActivationLayerInfo &act_info)
319 {
320 TensorShape dst_shape = lhs_shape;
321 dst_shape[0] = rhs_shape[0];
322 dst_shape[1] = lhs_shape[1];
323
324 // Create reference
325 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
326 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
327 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
328
329 const int n = rhs_shape[0];
330 const int m = lhs_shape[1];
331 const int batch_size = lhs_shape[2];
332
333 // Fill reference
334 fill(lhs, 0);
335 fill(rhs, 1);
336 fill(bias, 2);
337
338 if(broadcast_bias)
339 {
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000340 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100341 for(int i = 1; i < m * batch_size; i++)
342 {
343 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
344 }
345 }
346
347 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
348 }
349
350 TensorType _target{};
351 SimpleTensor<T> _reference{};
352};
353
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100354template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100355class GEMMMatrixMultiply3DValidationFixture : public framework::Fixture
356{
357public:
358 template <typename...>
359 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,
360 const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
361 {
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100362 ARM_COMPUTE_UNUSED(broadcast_bias);
363
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100364 // In case of GEMM3D, m is the product between m_w and m_h
365 const unsigned int m = m_w * m_h;
366
367 // Set the tensor shapes for LHS and RHS matrices
368 const TensorShape lhs_shape(k, m, batch_size);
369 const TensorShape rhs_shape(n, k, batch_size);
370 const TensorShape bias_shape(n, 1, 1);
371
372 _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 +0100373 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100374 }
375
376protected:
377 template <typename U>
378 void fill(U &&tensor, int i)
379 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000380 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 +0000381 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 +0000382
383 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100384 library->fill(tensor, distribution, i);
385 }
386
387 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,
388 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
389 {
390 // Create tensors
391 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
392 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
393 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
394 TensorType dst;
395
396 const unsigned int m = lhs_shape[1];
397 const unsigned int n = rhs_shape[0];
398 const unsigned int k = lhs_shape[0];
399 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, m_h, false, true);
400
401 // The output tensor will be auto-initialized within the function
402
403 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100404 GEMMOperatorType gemm;
405 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 +0100406
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100407 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
408 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
409 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100410
Giorgio Arena63825e82021-03-25 14:54:50 +0000411 add_padding_x({ &lhs, &rhs, &bias, &dst });
412
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100413 // Allocate tensors
414 lhs.allocator()->allocate();
415 rhs.allocator()->allocate();
416 bias.allocator()->allocate();
417 dst.allocator()->allocate();
418
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100419 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
420 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
421 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
422 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100423
424 // Fill tensors
425 fill(AccessorType(lhs), 0);
426 fill(AccessorType(rhs), 1);
427 fill(AccessorType(bias), 2);
428
429 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100430 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
431 { ACL_SRC_1, &rhs },
432 { ACL_SRC_2, &bias },
433 { ACL_DST, &dst }
434 });
435 gemm.run(gemm_pack);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100436
437 return dst;
438 }
439
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100440 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 +0100441 const ActivationLayerInfo &act_info)
442 {
443 TensorShape dst_shape = lhs_shape;
444 dst_shape.set(0, rhs_shape[0]);
445 dst_shape.set(1, lhs_shape[1] / m_h);
446 dst_shape.set(2, m_h);
447 dst_shape.set(3, lhs_shape[2]);
448
449 // Create reference
450 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
451 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
452 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
453
454 const int n = rhs_shape[0];
455 const int m = lhs_shape[1];
456 const int batch_size = lhs_shape[2];
457
458 // Fill reference
459 fill(lhs, 0);
460 fill(rhs, 1);
461 fill(bias, 2);
462
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000463 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100464 for(int i = 1; i < m * batch_size; i++)
465 {
466 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
467 }
468
469 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
470 }
471
472 TensorType _target{};
473 SimpleTensor<T> _reference{};
474};
475
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100476template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSOperatorType, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100477class GEMMMatrixMultiplyInterleavedTransposedValidationFixture : public framework::Fixture
478{
479public:
480 template <typename...>
481 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,
482 const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
483 {
484 GEMMLHSMatrixInfo lhs_info;
485 lhs_info.m0 = 4;
486 lhs_info.k0 = 4;
487 lhs_info.v0 = v0;
488 lhs_info.interleave = true;
489 lhs_info.transpose = true;
490
491 GEMMRHSMatrixInfo rhs_info;
492 rhs_info.n0 = 16 / sizeof(T);
493 rhs_info.k0 = 1;
494 rhs_info.h0 = h0;
495 rhs_info.interleave = false;
496 rhs_info.transpose = false;
497
498 // Set the tensor shapes for LHS and RHS matrices
499 const TensorShape lhs_shape(k, m, batch_size);
500 const TensorShape rhs_shape(n, k, batch_size);
501 const TensorShape bias_shape(n,
502 broadcast_bias ? 1 : m,
503 broadcast_bias ? 1 : batch_size);
504
505 _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 +0100506 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100507 }
508
509protected:
510 template <typename U>
511 void fill(U &&tensor, int i)
512 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000513 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 +0000514 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 +0000515
516 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100517 library->fill(tensor, distribution, i);
518
519 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000520 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100521 library->fill_borders_with_garbage(tensor, distribution_inf, i);
522 }
523
524 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
525 DataType data_type, float alpha, float beta, bool broadcast_bias, bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
526 {
527 // Create tensors
528 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
529 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
530 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
531 TensorType lhs_reshaped;
532 TensorType rhs_reshaped;
533 TensorType dst;
534
535 const unsigned int m = lhs_shape[1];
536 const unsigned int n = rhs_shape[0];
537 const unsigned int k = lhs_shape[0];
538 GEMMReshapeInfo reshape_info(m, n, k, rhs_info.h0, lhs_info.v0, 0, false, broadcast_bias);
539
540 // The output tensor will be auto-initialized within the function
541
542 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100543 ReshapeLHSOperatorType reshape_lhs;
544 ReshapeRHSOperatorType reshape_rhs;
545 GEMMOperatorType gemm;
546 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
547 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
548 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 +0100549
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100550 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
551 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
552 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100553
Georgios Pinitas3dca91b2021-04-13 13:35:58 +0100554 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +0000555 if(!rhs_info.export_to_cl_image)
556 {
557 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
558 }
559
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100560 // Allocate tensors
561 lhs.allocator()->allocate();
562 rhs.allocator()->allocate();
563 lhs_reshaped.allocator()->allocate();
564 rhs_reshaped.allocator()->allocate();
565 bias.allocator()->allocate();
566 dst.allocator()->allocate();
567
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100568 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
569 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
570 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
571 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
572 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
573 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100574
575 // Fill tensors
576 fill(AccessorType(lhs), 0);
577 fill(AccessorType(rhs), 1);
578 fill(AccessorType(bias), 2);
579
580 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100581 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
582 reshape_lhs.run(reshape_lhs_pack);
583 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
584 reshape_rhs.run(reshape_rhs_pack);
585 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
586 { ACL_SRC_1, &rhs_reshaped },
587 { ACL_SRC_2, &bias },
588 { ACL_DST, &dst }
589 });
590 gemm.run(gemm_pack);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100591
592 return dst;
593 }
594
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100595 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 +0100596 const ActivationLayerInfo &act_info)
597 {
598 TensorShape dst_shape = lhs_shape;
599 dst_shape[0] = rhs_shape[0];
600 dst_shape[1] = lhs_shape[1];
601
602 // Create reference
603 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
604 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
605 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
606
607 const int n = rhs_shape[0];
608 const int m = lhs_shape[1];
609 const int batch_size = lhs_shape[2];
610
611 // Fill reference
612 fill(lhs, 0);
613 fill(rhs, 1);
614 fill(bias, 2);
615
616 if(broadcast_bias)
617 {
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000618 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100619 for(int i = 1; i < m * batch_size; i++)
620 {
621 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
622 }
623 }
624
625 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
626 }
627
628 TensorType _target{};
629 SimpleTensor<T> _reference{};
630};
631
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100632template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSOperatorType, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100633class GEMMMatrixMultiplyInterleavedTransposed3DValidationFixture : public framework::Fixture
634{
635public:
636 template <typename...>
637 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,
638 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
639 {
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100640 ARM_COMPUTE_UNUSED(broadcast_bias);
641
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100642 GEMMLHSMatrixInfo lhs_info;
643 lhs_info.m0 = 4;
644 lhs_info.k0 = 4;
645 lhs_info.v0 = v0;
646 lhs_info.interleave = true;
647 lhs_info.transpose = true;
648
649 GEMMRHSMatrixInfo rhs_info;
650 rhs_info.n0 = 16 / sizeof(T);
651 rhs_info.k0 = 1;
652 rhs_info.h0 = h0;
653 rhs_info.interleave = false;
654 rhs_info.transpose = false;
655
656 // In case of GEMM3D, m is the product between m_w and m_h
657 const unsigned int m = m_w * m_h;
658
659 // Set the tensor shapes for LHS and RHS matrices
660 const TensorShape lhs_shape(k, m, batch_size);
661 const TensorShape rhs_shape(n, k, batch_size);
662 const TensorShape bias_shape(n, 1, 1);
663
664 _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 +0100665 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100666 }
667
668protected:
669 template <typename U>
670 void fill(U &&tensor, int i)
671 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000672 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 +0000673 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 +0000674
675 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100676 library->fill(tensor, distribution, i);
677 }
678
679 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
680 DataType data_type, float alpha, float beta, unsigned int m_h, bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
681 {
682 // Create tensors
683 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
684 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
685 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
686 TensorType lhs_reshaped;
687 TensorType rhs_reshaped;
688 TensorType dst;
689
690 const unsigned int m = lhs_shape[1];
691 const unsigned int n = rhs_shape[0];
692 const unsigned int k = lhs_shape[0];
693 GEMMReshapeInfo reshape_info(m, n, k, rhs_info.h0, lhs_info.v0, m_h, false, true);
694
695 // The output tensor will be auto-initialized within the function
696
697 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100698 ReshapeLHSOperatorType reshape_lhs;
699 ReshapeRHSOperatorType reshape_rhs;
700 GEMMOperatorType gemm;
701 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
702 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
703 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 +0100704
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100705 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
706 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
707 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100708
Georgios Pinitas3dca91b2021-04-13 13:35:58 +0100709 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +0000710 if(!rhs_info.export_to_cl_image)
711 {
712 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
713 }
714
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100715 // Allocate tensors
716 lhs.allocator()->allocate();
717 rhs.allocator()->allocate();
718 lhs_reshaped.allocator()->allocate();
719 rhs_reshaped.allocator()->allocate();
720 bias.allocator()->allocate();
721 dst.allocator()->allocate();
722
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100723 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
724 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
725 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
726 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
727 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
728 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100729
730 // Fill tensors
731 fill(AccessorType(lhs), 0);
732 fill(AccessorType(rhs), 1);
733 fill(AccessorType(bias), 2);
734
735 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100736 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
737 reshape_lhs.run(reshape_lhs_pack);
738 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
739 reshape_rhs.run(reshape_rhs_pack);
740 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
741 { ACL_SRC_1, &rhs_reshaped },
742 { ACL_SRC_2, &bias },
743 { ACL_DST, &dst }
744 });
745 gemm.run(gemm_pack);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100746
747 return dst;
748 }
749
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100750 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 +0100751 const ActivationLayerInfo &act_info)
752 {
753 TensorShape dst_shape = lhs_shape;
754 dst_shape.set(0, rhs_shape[0]);
755 dst_shape.set(1, lhs_shape[1] / m_h);
756 dst_shape.set(2, m_h);
757 dst_shape.set(3, lhs_shape[2]);
758
759 // Create reference
760 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
761 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
762 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
763
764 const int n = rhs_shape[0];
765 const int m = lhs_shape[1];
766 const int batch_size = lhs_shape[2];
767
768 // Fill reference
769 fill(lhs, 0);
770 fill(rhs, 1);
771 fill(bias, 2);
772
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000773 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100774 for(int i = 1; i < m * batch_size; i++)
775 {
776 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
777 }
778
779 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
780 }
781
782 TensorType _target{};
783 SimpleTensor<T> _reference{};
784};
785
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100786template <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 +0000787class GEMMMatrixMultiplyReshapedValidationFixture : public framework::Fixture
788{
789public:
790 template <typename...>
791 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 +0100792 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 +0000793 {
794 GEMMLHSMatrixInfo lhs_info;
795 lhs_info.m0 = m0;
796 lhs_info.k0 = k0;
797 lhs_info.v0 = v0;
798 lhs_info.interleave = interleave_lhs;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100799 lhs_info.transpose = lhs_transpose;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000800
801 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodicee3a849a2020-06-10 17:59:30 +0100802 rhs_info.n0 = n0;
803 rhs_info.k0 = k0;
804 rhs_info.h0 = h0;
805 rhs_info.interleave = interleave_rhs;
806 rhs_info.transpose = !lhs_transpose;
807 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000808
809 // Set the tensor shapes for LHS and RHS matrices
810 const TensorShape lhs_shape(k, m, batch_size);
811 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100812 const TensorShape bias_shape(n,
813 broadcast_bias ? 1 : m,
814 broadcast_bias ? 1 : batch_size);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000815
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000816 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
817 if(validate_result)
818 {
819 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
820 }
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000821 }
822
823protected:
824 template <typename U>
825 void fill(U &&tensor, int i)
826 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000827 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 +0000828 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 +0000829
830 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000831 library->fill(tensor, distribution, i);
Gian Marco Iodiceb87b95e2019-01-21 17:14:31 +0000832
833 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000834 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiceb87b95e2019-01-21 17:14:31 +0000835 library->fill_borders_with_garbage(tensor, distribution_inf, i);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000836 }
837
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100838 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 +0100839 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000840 {
841 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100842 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
843 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
844 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000845 TensorType lhs_reshaped;
846 TensorType rhs_reshaped;
847 TensorType dst;
848
849 const unsigned int M = lhs_shape[1];
850 const unsigned int N = rhs_shape[0];
851 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100852 GEMMKernelInfo kernel_info;
853 kernel_info.m = M;
854 kernel_info.n = N;
855 kernel_info.k = K;
856 kernel_info.depth_output_gemm3d = 0;
857 kernel_info.reinterpret_input_as_3d = false;
858 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100859 kernel_info.activation_info = act_info;
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100860 kernel_info.fp_mixed_precision = fp_mixed_precision;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000861
862 // The output tensor will be auto-initialized within the function
863
864 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100865 ReshapeLHSOperatorType reshape_lhs;
866 ReshapeRHSOperatorType reshape_rhs;
867 GEMMOperatorType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000868
869 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
870 validate_result = validate_result || !rhs_info.export_to_cl_image;
871 if(!validate_result)
872 {
873 return nullptr;
874 }
875
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100876 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
877 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
878 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 +0000879
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100880 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
881 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
882 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000883
Georgios Pinitas3dca91b2021-04-13 13:35:58 +0100884 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +0000885 if(!rhs_info.export_to_cl_image)
886 {
887 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
888 }
889
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000890 // Allocate tensors
891 lhs.allocator()->allocate();
892 rhs.allocator()->allocate();
893 lhs_reshaped.allocator()->allocate();
894 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100895 bias.allocator()->allocate();
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000896 dst.allocator()->allocate();
897
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100898 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
899 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
900 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
901 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
902 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
903 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000904
905 // Fill tensors
906 fill(AccessorType(lhs), 0);
907 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100908 fill(AccessorType(bias), 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000909
910 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100911 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
912 reshape_lhs.run(reshape_lhs_pack);
913 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
914 reshape_rhs.run(reshape_rhs_pack);
915 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
916 { ACL_SRC_1, &rhs_reshaped },
917 { ACL_SRC_2, &bias },
918 { ACL_DST, &dst }
919 });
920 gemm.run(gemm_pack);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000921
922 return dst;
923 }
924
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100925 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 +0100926 const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000927 {
928 TensorShape dst_shape = lhs_shape;
929 dst_shape[0] = rhs_shape[0];
930 dst_shape[1] = lhs_shape[1];
931
932 // Create reference
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000933 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
934 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100935 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
936
937 const int n = rhs_shape[0];
938 const int m = lhs_shape[1];
939 const int batch_size = lhs_shape[2];
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000940
941 // Fill reference
942 fill(lhs, 0);
943 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100944 fill(bias, 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000945
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100946 if(broadcast_bias)
947 {
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000948 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100949 for(int i = 1; i < m * batch_size; i++)
950 {
951 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
952 }
953 }
954
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100955 if(fp_mixed_precision)
956 {
957 return reference::activation_layer(reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta), act_info);
958 }
959 else
960 {
961 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
962 }
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000963 }
964
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000965 bool validate_result = true;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000966 TensorType _target{};
967 SimpleTensor<T> _reference{};
968};
969
SiCongLi1af54162021-10-06 15:25:57 +0100970/** (EXPERIMENTAL_POST_OPS)*/
971template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSOperatorType, typename ReshapeRHSOperatorType, typename GEMMOperatorType, bool fp_mixed_precision = false>
972class GEMMMatrixMultiplyReshapedWithPostOpsValidationFixture : public framework::Fixture
973{
974public:
975 using PostOpArgBroadcast = std::tuple<bool, bool, bool>; // Instruct fixture if we need broadcasting in dimension 0, 1, 2 of each PostOp argument
976public:
977 template <typename...>
978 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,
979 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,
980 const experimental::PostOpList<PostOpArgBroadcast> &post_ops)
981 {
982 GEMMLHSMatrixInfo lhs_info;
983 lhs_info.m0 = m0;
984 lhs_info.k0 = k0;
985 lhs_info.v0 = v0;
986 lhs_info.interleave = interleave_lhs;
987 lhs_info.transpose = lhs_transpose;
988
989 GEMMRHSMatrixInfo rhs_info;
990 rhs_info.n0 = n0;
991 rhs_info.k0 = k0;
992 rhs_info.h0 = h0;
993 rhs_info.interleave = interleave_rhs;
994 rhs_info.transpose = !lhs_transpose;
995 rhs_info.export_to_cl_image = export_to_cl_image;
996
997 // Set the tensor shapes for LHS and RHS matrices
998 const TensorShape lhs_shape(k, m, batch_size);
999 const TensorShape rhs_shape(n, k, batch_size);
1000 const TensorShape bias_shape(n,
1001 broadcast_bias ? 1 : m,
1002 broadcast_bias ? 1 : batch_size);
1003 auto post_ops_with_shapes = experimental::transform_post_op_list_arguments<PostOpArgBroadcast, TensorShape>(post_ops,
1004 [ = ](auto broadcast)
1005 {
1006 return TensorShape
1007 {
1008 std::get<0>(broadcast) ? 1 : n,
1009 std::get<1>(broadcast) ? 1 : m,
1010 std::get<2>(broadcast) ? 1 : batch_size,
1011 };
1012 });
1013
1014 _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);
1015 if(validate_result)
1016 {
1017 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info, post_ops_with_shapes);
1018 }
1019 }
1020
1021protected:
1022 template <typename U>
1023 void fill(U &&tensor, int i)
1024 {
1025 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
1026 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;
1027
1028 DistributionType distribution{ T(-1.0f), T(1.0f) };
1029 library->fill(tensor, distribution, i);
1030
1031 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
1032 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
1033 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1034 }
1035
1036 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
1037 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info, const experimental::PostOpList<TensorShape> &post_ops)
1038 {
1039 // Create tensors
1040 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1041 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1042 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
1043
1044 // Create post op tensors and populate post op with them
1045 std::vector<TensorType> post_op_tensors_holder{};
1046 auto populated_post_ops = experimental::transform_post_op_list_arguments<TensorShape, ITensorInfo *>(post_ops,
1047 [&post_op_tensors_holder, &data_type](auto shape)
1048 {
1049 auto t = create_tensor<TensorType>(shape, data_type, 1);
1050 post_op_tensors_holder.push_back(std::move(t));
1051 return post_op_tensors_holder.back().info();
1052 });
1053 TensorType lhs_reshaped;
1054 TensorType rhs_reshaped;
1055 TensorType dst;
1056
1057 const unsigned int M = lhs_shape[1];
1058 const unsigned int N = rhs_shape[0];
1059 const unsigned int K = lhs_shape[0];
1060 GEMMKernelInfo kernel_info;
1061 kernel_info.m = M;
1062 kernel_info.n = N;
1063 kernel_info.k = K;
1064 kernel_info.depth_output_gemm3d = 0;
1065 kernel_info.reinterpret_input_as_3d = false;
1066 kernel_info.broadcast_bias = broadcast_bias;
1067 kernel_info.activation_info = act_info;
1068 kernel_info.fp_mixed_precision = fp_mixed_precision;
1069 kernel_info.post_ops = populated_post_ops;
1070
1071 // The output tensor will be auto-initialized within the function
1072
1073 // Create and configure function
1074 ReshapeLHSOperatorType reshape_lhs;
1075 ReshapeRHSOperatorType reshape_rhs;
1076 GEMMOperatorType gemm;
1077
1078 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1079 validate_result = validate_result || !rhs_info.export_to_cl_image;
1080 if(!validate_result)
1081 {
1082 return nullptr;
1083 }
1084
1085 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
1086 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1087 gemm.configure(lhs_reshaped.info(), rhs_reshaped.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
1088
1089 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1090 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1091 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
1092 for(const auto &tensor : post_op_tensors_holder)
1093 {
1094 ARM_COMPUTE_ASSERT(tensor.info()->is_resizable());
1095 }
1096
1097 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
1098 if(!rhs_info.export_to_cl_image)
1099 {
1100 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
1101 for(auto &tensor : post_op_tensors_holder)
1102 {
1103 add_padding_x({ &tensor });
1104 }
1105 }
1106
1107 // Allocate tensors
1108 lhs.allocator()->allocate();
1109 rhs.allocator()->allocate();
1110 lhs_reshaped.allocator()->allocate();
1111 rhs_reshaped.allocator()->allocate();
1112 bias.allocator()->allocate();
1113 dst.allocator()->allocate();
1114 for(auto &tensor : post_op_tensors_holder)
1115 {
1116 tensor.allocator()->allocate();
1117 }
1118
1119 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1120 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1121 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1122 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
1123 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1124 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
1125 for(const auto &tensor : post_op_tensors_holder)
1126 {
1127 ARM_COMPUTE_ASSERT(!tensor.info()->is_resizable());
1128 }
1129
1130 // Fill tensors
1131 fill(AccessorType(lhs), 0);
1132 fill(AccessorType(rhs), 1);
1133 fill(AccessorType(bias), 2);
1134 for(size_t i = 0; i < post_op_tensors_holder.size(); ++i)
1135 {
1136 fill(AccessorType(post_op_tensors_holder.at(i)), 3 + i);
1137 }
1138
1139 // Compute GEMM
1140 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
1141 reshape_lhs.run(reshape_lhs_pack);
1142 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1143 reshape_rhs.run(reshape_rhs_pack);
1144 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
1145 { ACL_SRC_1, &rhs_reshaped },
1146 { ACL_SRC_2, &bias },
1147 { ACL_DST, &dst }
1148 });
1149 for(size_t i = 0; i < post_op_tensors_holder.size(); ++i)
1150 {
1151 gemm_pack.add_tensor(experimental::get_post_op_arg_type(i), &post_op_tensors_holder.at(i));
1152 }
1153 gemm.run(gemm_pack);
1154
1155 return dst;
1156 }
1157
1158 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
1159 const ActivationLayerInfo &act_info, const experimental::PostOpList<TensorShape> &post_ops)
1160 {
1161 TensorShape dst_shape = lhs_shape;
1162 dst_shape[0] = rhs_shape[0];
1163 dst_shape[1] = lhs_shape[1];
1164
1165 // Create reference
1166 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1167 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
1168 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1169 // Create post op tensors and populate post op with them
1170 auto populated_post_ops = experimental::transform_post_op_list_arguments<TensorShape, SimpleTensor<T>>(post_ops, [&data_type](auto shape)
1171 {
1172 return SimpleTensor<T> { shape, data_type, 1 };
1173 });
1174
1175 const int n = rhs_shape[0];
1176 const int m = lhs_shape[1];
1177 const int batch_size = lhs_shape[2];
1178
1179 // Fill reference
1180 int tensor_idx = 0;
1181 fill(lhs, tensor_idx++);
1182 fill(rhs, tensor_idx++);
1183 fill(bias, tensor_idx++);
1184 for(auto &op : populated_post_ops.get_list())
1185 {
1186 for(auto tensor : op->arguments())
1187 {
1188 fill(*tensor, tensor_idx++);
1189 }
1190 }
1191
1192 if(broadcast_bias)
1193 {
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00001194 // In case of broadcast, we need to simply copy the first into the following "M" ones
SiCongLi1af54162021-10-06 15:25:57 +01001195 for(int i = 1; i < m * batch_size; i++)
1196 {
1197 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1198 }
1199 }
1200
1201 SimpleTensor<T> out;
1202 if(fp_mixed_precision)
1203 {
1204 out = reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta);
1205 }
1206 else
1207 {
1208 out = reference::gemm<T>(lhs, rhs, bias, alpha, beta);
1209 }
1210 // Ignore activation info if post ops are used instead
1211 if(populated_post_ops.size() > 0)
1212 {
1213 out = reference::post_ops<T>(out, populated_post_ops);
1214 }
1215 else
1216 {
1217 out = reference::activation_layer(out, act_info);
1218 }
1219 return out;
1220 }
1221
1222 bool validate_result = true;
1223 TensorType _target{};
1224 SimpleTensor<T> _reference{};
1225};
1226
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001227template <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 +00001228class GEMMMatrixMultiplyReshaped3DValidationFixture : public framework::Fixture
1229{
1230public:
1231 template <typename...>
1232 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 +01001233 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 +00001234 {
1235 GEMMLHSMatrixInfo lhs_info;
1236 lhs_info.m0 = m0;
1237 lhs_info.k0 = k0;
1238 lhs_info.v0 = v0;
1239 lhs_info.interleave = interleave_lhs;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +01001240 lhs_info.transpose = lhs_transpose;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001241
1242 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodicee3a849a2020-06-10 17:59:30 +01001243 rhs_info.n0 = n0;
1244 rhs_info.k0 = k0;
1245 rhs_info.h0 = h0;
1246 rhs_info.interleave = interleave_rhs;
1247 rhs_info.transpose = !lhs_transpose;
1248 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001249
1250 // In case of GEMM3D, m is the product between m_w and m_h
1251 const unsigned int m = m_w * m_h;
1252
1253 // Set the tensor shapes for LHS and RHS matrices
1254 const TensorShape lhs_shape(k, m, batch_size);
1255 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001256 const TensorShape bias_shape(n, 1, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001257
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001258 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info);
1259 if(validate_result)
1260 {
1261 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
1262 }
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001263 }
1264
1265protected:
1266 template <typename U>
1267 void fill(U &&tensor, int i)
1268 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001269 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 +00001270 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 +00001271
1272 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001273 library->fill(tensor, distribution, i);
1274 }
1275
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001276 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 +01001277 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001278 {
1279 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001280 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1281 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1282 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001283 TensorType lhs_reshaped;
1284 TensorType rhs_reshaped;
1285 TensorType dst;
1286
1287 const unsigned int M = lhs_shape[1];
1288 const unsigned int N = rhs_shape[0];
1289 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001290 GEMMKernelInfo kernel_info;
1291 kernel_info.m = M;
1292 kernel_info.n = N;
1293 kernel_info.k = K;
1294 kernel_info.depth_output_gemm3d = m_h;
1295 kernel_info.reinterpret_input_as_3d = false;
1296 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001297 kernel_info.activation_info = act_info;
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +01001298 kernel_info.fp_mixed_precision = fp_mixed_precision;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001299
1300 // The output tensor will be auto-initialized within the function
1301
1302 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001303 ReshapeLHSOperatorType reshape_lhs;
1304 ReshapeRHSOperatorType reshape_rhs;
1305 GEMMOperatorType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001306
1307 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1308 validate_result = validate_result || !rhs_info.export_to_cl_image;
1309 if(!validate_result)
1310 {
1311 return nullptr;
1312 }
1313
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001314 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
1315 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1316 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 +00001317
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001318 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1319 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1320 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001321
Georgios Pinitas3dca91b2021-04-13 13:35:58 +01001322 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +00001323 if(!rhs_info.export_to_cl_image)
1324 {
1325 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
1326 }
1327
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001328 // Allocate tensors
1329 lhs.allocator()->allocate();
1330 rhs.allocator()->allocate();
1331 lhs_reshaped.allocator()->allocate();
1332 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001333 bias.allocator()->allocate();
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001334 dst.allocator()->allocate();
1335
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001336 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1337 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1338 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
1339 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1340 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1341 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001342
1343 // Fill tensors
1344 fill(AccessorType(lhs), 0);
1345 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001346 fill(AccessorType(bias), 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001347
1348 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001349 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
1350 reshape_lhs.run(reshape_lhs_pack);
1351 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1352 reshape_rhs.run(reshape_rhs_pack);
1353 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
1354 { ACL_SRC_1, &rhs_reshaped },
1355 { ACL_SRC_2, &bias },
1356 { ACL_DST, &dst }
1357 });
1358 gemm.run(gemm_pack);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001359
1360 return dst;
1361 }
1362
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001363 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 +01001364 const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001365 {
1366 TensorShape dst_shape = lhs_shape;
1367 dst_shape.set(0, rhs_shape[0]);
1368 dst_shape.set(1, lhs_shape[1] / m_h);
1369 dst_shape.set(2, m_h);
1370 dst_shape.set(3, lhs_shape[2]);
1371
1372 // Create reference
1373 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1374 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001375 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1376
1377 const int n = rhs_shape[0];
1378 const int m = lhs_shape[1];
1379 const int batch_size = lhs_shape[2];
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001380
1381 // Fill reference
1382 fill(lhs, 0);
1383 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001384 fill(bias, 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001385
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00001386 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001387 for(int i = 1; i < m * batch_size; i++)
1388 {
1389 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1390 }
1391
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +01001392 if(fp_mixed_precision)
1393 {
1394 return reference::activation_layer(reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta), act_info);
1395 }
1396 else
1397 {
1398 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
1399 }
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001400 }
1401
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001402 bool validate_result = true;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001403 TensorType _target{};
1404 SimpleTensor<T> _reference{};
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +00001405};
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001406
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001407template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001408class GEMMMatrixMultiplyReshapedOnlyRHSValidationFixture : public framework::Fixture
1409{
1410public:
1411 template <typename...>
1412 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 +01001413 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 +00001414 {
1415 GEMMLHSMatrixInfo lhs_info;
1416 lhs_info.m0 = m0;
1417 lhs_info.k0 = k0;
1418
1419 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodice781cba72020-06-19 16:56:57 +01001420 rhs_info.n0 = n0;
1421 rhs_info.k0 = k0;
1422 rhs_info.h0 = h0;
1423 rhs_info.interleave = interleave_rhs;
1424 rhs_info.transpose = transpose_rhs;
1425 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001426
1427 // Set the tensor shapes for LHS and RHS matrices
1428 const TensorShape lhs_shape(k, m, batch_size);
1429 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001430 const TensorShape bias_shape(n,
1431 broadcast_bias ? 1 : m,
1432 broadcast_bias ? 1 : batch_size);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001433
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001434 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
1435 if(validate_result)
1436 {
1437 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
1438 }
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001439 }
1440
1441protected:
1442 template <typename U>
1443 void fill(U &&tensor, int i)
1444 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001445 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 +00001446 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 +00001447
1448 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001449 library->fill(tensor, distribution, i);
1450
1451 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001452 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001453 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1454 }
1455
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001456 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 +01001457 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001458 {
1459 // Create tensors
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001460 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1461 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1462 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001463 TensorType rhs_reshaped;
1464 TensorType dst;
1465
1466 const unsigned int M = lhs_shape[1];
1467 const unsigned int N = rhs_shape[0];
1468 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001469 GEMMKernelInfo kernel_info;
1470 kernel_info.m = M;
1471 kernel_info.n = N;
1472 kernel_info.k = K;
1473 kernel_info.depth_output_gemm3d = 0;
1474 kernel_info.reinterpret_input_as_3d = false;
1475 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001476 kernel_info.activation_info = act_info;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001477
1478 // The output tensor will be auto-initialized within the function
1479
1480 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001481 ReshapeRHSOperatorType reshape_rhs;
1482 GEMMOperatorType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001483
1484 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1485 validate_result = validate_result || !rhs_info.export_to_cl_image;
1486 if(!validate_result)
1487 {
1488 return nullptr;
1489 }
1490
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001491 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1492 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 +00001493
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001494 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1495 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1496 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001497
Georgios Pinitas3dca91b2021-04-13 13:35:58 +01001498 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +00001499 if(!rhs_info.export_to_cl_image)
1500 {
1501 add_padding_x({ &lhs, &rhs, &rhs_reshaped, &bias, &dst });
1502 }
1503
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001504 // Allocate tensors
1505 lhs.allocator()->allocate();
1506 rhs.allocator()->allocate();
1507 rhs_reshaped.allocator()->allocate();
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001508 bias.allocator()->allocate();
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001509 dst.allocator()->allocate();
1510
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001511 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1512 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1513 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1514 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1515 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001516
1517 // Fill tensors
1518 fill(AccessorType(lhs), 0);
1519 fill(AccessorType(rhs), 1);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001520 fill(AccessorType(bias), 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001521
1522 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001523 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1524 reshape_rhs.run(reshape_rhs_pack);
1525 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
1526 { ACL_SRC_1, &rhs_reshaped },
1527 { ACL_SRC_2, &bias },
1528 { ACL_DST, &dst }
1529 });
1530 gemm.run(gemm_pack);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001531
1532 return dst;
1533 }
1534
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001535 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 +01001536 const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001537 {
1538 TensorShape dst_shape = lhs_shape;
1539 dst_shape[0] = rhs_shape[0];
1540 dst_shape[1] = lhs_shape[1];
1541
1542 // Create reference
1543 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1544 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001545 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1546
1547 const int n = rhs_shape[0];
1548 const int m = lhs_shape[1];
1549 const int batch_size = lhs_shape[2];
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001550
1551 // Fill reference
1552 fill(lhs, 0);
1553 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001554 fill(bias, 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001555
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001556 if(broadcast_bias)
1557 {
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00001558 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001559 for(int i = 1; i < m * batch_size; i++)
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001560 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001561 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001562 }
1563 }
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001564
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001565 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001566 }
1567
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001568 bool validate_result = true;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001569 TensorType _target{};
1570 SimpleTensor<T> _reference{};
1571};
1572
SiCongLiafa19722021-10-24 19:12:33 +01001573/** (EXPERIMENTAL_POST_OPS)*/
1574template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
1575class GEMMMatrixMultiplyReshapedOnlyRHSWithPostOpsValidationFixture : public framework::Fixture
1576{
1577public:
1578 using PostOpArgBroadcast = std::tuple<bool, bool, bool>; // Instruct fixture if we need broadcasting in dimension 0, 1, 2 of each PostOp argument
1579 template <typename...>
1580 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,
1581 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,
1582 const experimental::PostOpList<PostOpArgBroadcast> &post_ops)
1583 {
1584 GEMMLHSMatrixInfo lhs_info;
1585 lhs_info.m0 = m0;
1586 lhs_info.k0 = k0;
1587
1588 GEMMRHSMatrixInfo rhs_info;
1589 rhs_info.n0 = n0;
1590 rhs_info.k0 = k0;
1591 rhs_info.h0 = h0;
1592 rhs_info.interleave = interleave_rhs;
1593 rhs_info.transpose = transpose_rhs;
1594 rhs_info.export_to_cl_image = export_to_cl_image;
1595
1596 // Set the tensor shapes for LHS and RHS matrices
1597 const TensorShape lhs_shape(k, m, batch_size);
1598 const TensorShape rhs_shape(n, k, batch_size);
1599 const TensorShape bias_shape(n,
1600 broadcast_bias ? 1 : m,
1601 broadcast_bias ? 1 : batch_size);
1602 auto post_ops_with_shapes = experimental::transform_post_op_list_arguments<PostOpArgBroadcast, TensorShape>(post_ops,
1603 [ = ](auto broadcast)
1604 {
1605 return TensorShape
1606 {
1607 std::get<0>(broadcast) ? 1 : n,
1608 std::get<1>(broadcast) ? 1 : m,
1609 std::get<2>(broadcast) ? 1 : batch_size,
1610 };
1611 });
1612
1613 _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);
1614 if(validate_result)
1615 {
1616 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info, post_ops_with_shapes);
1617 }
1618 }
1619
1620protected:
1621 template <typename U>
1622 void fill(U &&tensor, int i)
1623 {
1624 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
1625 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;
1626
1627 DistributionType distribution{ T(-1.0f), T(1.0f) };
1628 library->fill(tensor, distribution, i);
1629
1630 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
1631 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
1632 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1633 }
1634
1635 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
1636 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info, const experimental::PostOpList<TensorShape> &post_ops)
1637 {
1638 // Create tensors
1639 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1640 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1641 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
1642 TensorType rhs_reshaped;
1643 TensorType dst;
1644 // Create post op tensors and populate post op with them
1645 std::vector<TensorType> post_op_tensors_holder{};
1646 auto populated_post_ops = experimental::transform_post_op_list_arguments<TensorShape, ITensorInfo *>(post_ops,
1647 [&post_op_tensors_holder, &data_type](auto shape)
1648 {
1649 auto t = create_tensor<TensorType>(shape, data_type, 1);
1650 post_op_tensors_holder.push_back(std::move(t));
1651 return post_op_tensors_holder.back().info();
1652 });
1653
1654 const unsigned int M = lhs_shape[1];
1655 const unsigned int N = rhs_shape[0];
1656 const unsigned int K = lhs_shape[0];
1657 GEMMKernelInfo kernel_info;
1658 kernel_info.m = M;
1659 kernel_info.n = N;
1660 kernel_info.k = K;
1661 kernel_info.depth_output_gemm3d = 0;
1662 kernel_info.reinterpret_input_as_3d = false;
1663 kernel_info.broadcast_bias = broadcast_bias;
1664 kernel_info.activation_info = act_info;
1665 kernel_info.post_ops = populated_post_ops;
1666
1667 // The output tensor will be auto-initialized within the function
1668
1669 // Create and configure function
1670 ReshapeRHSOperatorType reshape_rhs;
1671 GEMMOperatorType gemm;
1672
1673 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1674 validate_result = validate_result || !rhs_info.export_to_cl_image;
1675 if(!validate_result)
1676 {
1677 return nullptr;
1678 }
1679
1680 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1681 gemm.configure(lhs.info(), rhs_reshaped.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
1682
1683 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1684 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1685 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
1686 for(const auto &tensor : post_op_tensors_holder)
1687 {
1688 ARM_COMPUTE_ASSERT(tensor.info()->is_resizable());
1689 }
1690
1691 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
1692 if(!rhs_info.export_to_cl_image)
1693 {
1694 add_padding_x({ &lhs, &rhs, &rhs_reshaped, &bias, &dst });
1695 for(auto &tensor : post_op_tensors_holder)
1696 {
1697 add_padding_x({ &tensor });
1698 }
1699 }
1700
1701 // Allocate tensors
1702 lhs.allocator()->allocate();
1703 rhs.allocator()->allocate();
1704 rhs_reshaped.allocator()->allocate();
1705 bias.allocator()->allocate();
1706 dst.allocator()->allocate();
1707 for(auto &tensor : post_op_tensors_holder)
1708 {
1709 tensor.allocator()->allocate();
1710 }
1711
1712 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1713 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1714 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1715 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1716 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
1717 for(const auto &tensor : post_op_tensors_holder)
1718 {
1719 ARM_COMPUTE_ASSERT(!tensor.info()->is_resizable());
1720 }
1721
1722 // Fill tensors
1723 fill(AccessorType(lhs), 0);
1724 fill(AccessorType(rhs), 1);
1725 fill(AccessorType(bias), 2);
1726 for(size_t i = 0; i < post_op_tensors_holder.size(); ++i)
1727 {
1728 fill(AccessorType(post_op_tensors_holder.at(i)), 3 + i);
1729 }
1730
1731 // Compute GEMM
1732 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1733 reshape_rhs.run(reshape_rhs_pack);
1734 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
1735 { ACL_SRC_1, &rhs_reshaped },
1736 { ACL_SRC_2, &bias },
1737 { ACL_DST, &dst }
1738 });
1739 for(size_t i = 0; i < post_op_tensors_holder.size(); ++i)
1740 {
1741 gemm_pack.add_tensor(experimental::get_post_op_arg_type(i), &post_op_tensors_holder.at(i));
1742 }
1743 gemm.run(gemm_pack);
1744
1745 return dst;
1746 }
1747
1748 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
1749 const ActivationLayerInfo &act_info, const experimental::PostOpList<TensorShape> &post_ops)
1750 {
1751 TensorShape dst_shape = lhs_shape;
1752 dst_shape[0] = rhs_shape[0];
1753 dst_shape[1] = lhs_shape[1];
1754
1755 // Create reference
1756 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1757 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
1758 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1759 // Create post op tensors and populate post op with them
1760 auto populated_post_ops = experimental::transform_post_op_list_arguments<TensorShape, SimpleTensor<T>>(post_ops, [&data_type](auto shape)
1761 {
1762 return SimpleTensor<T> { shape, data_type, 1 };
1763 });
1764
1765 const int n = rhs_shape[0];
1766 const int m = lhs_shape[1];
1767 const int batch_size = lhs_shape[2];
1768
1769 // Fill reference
1770 int tensor_idx = 0;
1771 fill(lhs, tensor_idx++);
1772 fill(rhs, tensor_idx++);
1773 fill(bias, tensor_idx++);
1774 for(auto &op : populated_post_ops.get_list())
1775 {
1776 for(auto tensor : op->arguments())
1777 {
1778 fill(*tensor, tensor_idx++);
1779 }
1780 }
1781
1782 if(broadcast_bias)
1783 {
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00001784 // In case of broadcast, we need to simply copy the first into the following "M" ones
SiCongLiafa19722021-10-24 19:12:33 +01001785 for(int i = 1; i < m * batch_size; i++)
1786 {
1787 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1788 }
1789 }
1790
1791 SimpleTensor<T> out;
1792 out = reference::gemm<T>(lhs, rhs, bias, alpha, beta);
1793 // Ignore activation info if post ops are used instead
1794 if(populated_post_ops.size() > 0)
1795 {
1796 out = reference::post_ops<T>(out, populated_post_ops);
1797 }
1798 else
1799 {
1800 out = reference::activation_layer(out, act_info);
1801 }
1802 return out;
1803 }
1804
1805 bool validate_result = true;
1806 TensorType _target{};
1807 SimpleTensor<T> _reference{};
1808};
1809
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001810template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001811class GEMMMatrixMultiplyReshapedOnlyRHS3DValidationFixture : public framework::Fixture
1812{
1813public:
1814 template <typename...>
1815 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 +01001816 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 +01001817 {
1818 GEMMLHSMatrixInfo lhs_info;
1819 lhs_info.m0 = m0;
1820 lhs_info.k0 = k0;
1821
1822 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodice781cba72020-06-19 16:56:57 +01001823 rhs_info.n0 = n0;
1824 rhs_info.k0 = k0;
1825 rhs_info.h0 = h0;
1826 rhs_info.interleave = interleave_rhs;
1827 rhs_info.transpose = transpose_rhs;
1828 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001829
1830 // In case of GEMM3D, m is the product between m_w and m_h
1831 const unsigned int m = m_w * m_h;
1832
1833 // Set the tensor shapes for LHS and RHS matrices
1834 const TensorShape lhs_shape(k, m, batch_size);
1835 const TensorShape rhs_shape(n, k, batch_size);
1836 const TensorShape bias_shape(n, 1, 1);
1837
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001838 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info, has_pad_y);
1839 if(validate_result)
1840 {
1841 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
1842 }
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001843 }
1844
1845protected:
1846 template <typename U>
1847 void fill(U &&tensor, int i)
1848 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001849 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 +00001850 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 +00001851
1852 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001853 library->fill(tensor, distribution, i);
1854 }
1855
1856 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
1857 DataType data_type, float alpha, float beta,
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001858 unsigned int m_h, const ActivationLayerInfo &act_info, bool has_pad_y)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001859 {
1860 // Create tensors
1861 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1862 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1863 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
1864 TensorType rhs_reshaped;
1865 TensorType dst;
1866
1867 const unsigned int M = lhs_shape[1];
1868 const unsigned int N = rhs_shape[0];
1869 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001870 GEMMKernelInfo kernel_info;
1871 kernel_info.m = M;
1872 kernel_info.n = N;
1873 kernel_info.k = K;
1874 kernel_info.depth_output_gemm3d = m_h;
1875 kernel_info.reinterpret_input_as_3d = false;
1876 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001877 kernel_info.activation_info = act_info;
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001878 kernel_info.has_pad_y = has_pad_y;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001879
1880 // The output tensor will be auto-initialized within the function
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001881 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001882 ReshapeRHSOperatorType reshape_rhs;
1883 GEMMOperatorType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001884
1885 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1886 validate_result = validate_result || !rhs_info.export_to_cl_image;
1887 if(!validate_result)
1888 {
1889 return nullptr;
1890 }
1891
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001892 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1893 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 +01001894
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001895 if(has_pad_y)
1896 {
1897 // Add dummy padding into lhs to validate has_pad_y path
1898 lhs.info()->extend_padding(PaddingSize(2, 0, 2, 0));
1899 dst.info()->extend_padding(PaddingSize(2, 0, 1, 0));
1900 }
1901
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001902 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1903 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1904 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001905
Georgios Pinitas3dca91b2021-04-13 13:35:58 +01001906 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +00001907 if(!rhs_info.export_to_cl_image)
1908 {
1909 add_padding_x({ &lhs, &rhs, &rhs_reshaped, &bias, &dst });
1910 }
1911
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001912 // Allocate tensors
1913 lhs.allocator()->allocate();
1914 rhs.allocator()->allocate();
1915 rhs_reshaped.allocator()->allocate();
1916 bias.allocator()->allocate();
1917 dst.allocator()->allocate();
1918
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001919 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1920 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1921 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1922 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1923 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001924
1925 // Fill tensors
1926 fill(AccessorType(lhs), 0);
1927 fill(AccessorType(rhs), 1);
1928 fill(AccessorType(bias), 2);
1929
1930 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001931 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1932 reshape_rhs.run(reshape_rhs_pack);
1933 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
1934 { ACL_SRC_1, &rhs_reshaped },
1935 { ACL_SRC_2, &bias },
1936 { ACL_DST, &dst }
1937 });
1938 gemm.run(gemm_pack);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001939
1940 return dst;
1941 }
1942
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001943 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 +01001944 const ActivationLayerInfo &act_info)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001945 {
1946 TensorShape dst_shape = lhs_shape;
1947 dst_shape.set(0, rhs_shape[0]);
1948 dst_shape.set(1, lhs_shape[1] / m_h);
1949 dst_shape.set(2, m_h);
1950 dst_shape.set(3, lhs_shape[2]);
1951
1952 // Create reference
1953 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1954 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
1955 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1956
1957 const int n = rhs_shape[0];
1958 const int m = lhs_shape[1];
1959 const int batch_size = lhs_shape[2];
1960
1961 // Fill reference
1962 fill(lhs, 0);
1963 fill(rhs, 1);
1964 fill(bias, 2);
1965
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00001966 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001967 for(int i = 1; i < m * batch_size; i++)
1968 {
1969 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1970 }
1971
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001972 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001973 }
1974
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001975 bool validate_result = true;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001976 TensorType _target{};
1977 SimpleTensor<T> _reference{};
1978};
1979
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001980template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
giuros01b3204e72019-04-01 13:50:22 +01001981class GEMMMatrixMultiplyNativeValidationFixture : public framework::Fixture
1982{
1983public:
1984 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001985 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,
1986 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001987 {
1988 GEMMLHSMatrixInfo lhs_info;
1989 lhs_info.m0 = m0;
1990 lhs_info.k0 = k0;
1991
1992 GEMMRHSMatrixInfo rhs_info;
1993 rhs_info.n0 = n0;
1994 rhs_info.k0 = k0;
1995
1996 // Set the tensor shapes for LHS and RHS matrices
1997 const TensorShape lhs_shape(k, m, batch_size);
1998 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001999 const TensorShape bias_shape(n,
2000 broadcast_bias ? 1 : m,
2001 broadcast_bias ? 1 : batch_size);
giuros01b3204e72019-04-01 13:50:22 +01002002
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01002003 _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 +01002004 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
giuros01b3204e72019-04-01 13:50:22 +01002005 }
2006
2007protected:
2008 template <typename U>
2009 void fill(U &&tensor, int i)
2010 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00002011 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 +00002012 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 +00002013
2014 DistributionType distribution{ T(-1.0f), T(1.0f) };
giuros01b3204e72019-04-01 13:50:22 +01002015 library->fill(tensor, distribution, i);
2016
2017 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +00002018 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
giuros01b3204e72019-04-01 13:50:22 +01002019 library->fill_borders_with_garbage(tensor, distribution_inf, i);
2020 }
2021
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002022 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 +01002023 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01002024 {
2025 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002026 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
2027 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
2028 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01002029 TensorType dst;
2030
2031 const unsigned int M = lhs_shape[1];
2032 const unsigned int N = rhs_shape[0];
2033 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01002034 GEMMKernelInfo kernel_info;
2035 kernel_info.m = M;
2036 kernel_info.n = N;
2037 kernel_info.k = K;
2038 kernel_info.depth_output_gemm3d = 0;
2039 kernel_info.reinterpret_input_as_3d = false;
2040 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01002041 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01002042
2043 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01002044 GEMMOperatorType gemm;
2045 gemm.configure(lhs.info(), rhs.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01002046
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01002047 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
2048 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
2049 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
giuros01b3204e72019-04-01 13:50:22 +01002050
Giorgio Arena63825e82021-03-25 14:54:50 +00002051 add_padding_x({ &lhs, &rhs, &bias, &dst });
2052
giuros01b3204e72019-04-01 13:50:22 +01002053 // Allocate tensors
2054 lhs.allocator()->allocate();
2055 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002056 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01002057 dst.allocator()->allocate();
2058
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01002059 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
2060 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
2061 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
2062 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
giuros01b3204e72019-04-01 13:50:22 +01002063
2064 // Fill tensors
2065 fill(AccessorType(lhs), 0);
2066 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002067 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01002068
2069 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01002070 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
2071 { ACL_SRC_1, &rhs },
2072 { ACL_SRC_2, &bias },
2073 { ACL_DST, &dst }
2074 });
2075 gemm.run(gemm_pack);
giuros01b3204e72019-04-01 13:50:22 +01002076
2077 return dst;
2078 }
2079
Michalis Spyrou6bff1952019-10-02 17:22:11 +01002080 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 +01002081 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01002082 {
2083 TensorShape dst_shape = lhs_shape;
2084 dst_shape[0] = rhs_shape[0];
2085 dst_shape[1] = lhs_shape[1];
2086
2087 // Create reference
2088 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
2089 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002090 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
2091
2092 const int n = rhs_shape[0];
2093 const int m = lhs_shape[1];
2094 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01002095
2096 // Fill reference
2097 fill(lhs, 0);
2098 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002099 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01002100
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002101 if(broadcast_bias)
2102 {
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00002103 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002104 for(int i = 1; i < m * batch_size; i++)
2105 {
2106 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
2107 }
2108 }
2109
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01002110 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01002111 }
2112
2113 TensorType _target{};
2114 SimpleTensor<T> _reference{};
2115};
2116
Georgios Pinitas856f66e2021-04-22 21:13:21 +01002117template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
SiCongLiafa19722021-10-24 19:12:33 +01002118class GEMMMatrixMultiplyNativeWithPostOpsValidationFixture : public framework::Fixture
2119{
2120public:
2121 using PostOpArgBroadcast = std::tuple<bool, bool, bool>; // Instruct fixture if we need broadcasting in dimension 0, 1, 2 of each PostOp argument
2122public:
2123 template <typename...>
2124 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,
2125 const ActivationLayerInfo &act_info, const experimental::PostOpList<PostOpArgBroadcast> &post_ops)
2126 {
2127 GEMMLHSMatrixInfo lhs_info;
2128 lhs_info.m0 = m0;
2129 lhs_info.k0 = k0;
2130
2131 GEMMRHSMatrixInfo rhs_info;
2132 rhs_info.n0 = n0;
2133 rhs_info.k0 = k0;
2134
2135 // Set the tensor shapes for LHS and RHS matrices
2136 const TensorShape lhs_shape(k, m, batch_size);
2137 const TensorShape rhs_shape(n, k, batch_size);
2138 const TensorShape bias_shape(n,
2139 broadcast_bias ? 1 : m,
2140 broadcast_bias ? 1 : batch_size);
2141 const auto post_ops_with_shapes = experimental::transform_post_op_list_arguments<PostOpArgBroadcast, TensorShape>(post_ops,
2142 [ = ](auto broadcast)
2143 {
2144 return TensorShape
2145 {
2146 std::get<0>(broadcast) ? 1 : n,
2147 std::get<1>(broadcast) ? 1 : m,
2148 std::get<2>(broadcast) ? 1 : batch_size,
2149 };
2150 });
2151
2152 _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);
2153 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info, post_ops_with_shapes);
2154 }
2155
2156protected:
2157 template <typename U>
2158 void fill(U &&tensor, int i)
2159 {
2160 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
2161 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;
2162
2163 DistributionType distribution{ T(-1.0f), T(1.0f) };
2164 library->fill(tensor, distribution, i);
2165
2166 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
2167 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
2168 library->fill_borders_with_garbage(tensor, distribution_inf, i);
2169 }
2170
2171 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
2172 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info, const experimental::PostOpList<TensorShape> &post_ops)
2173 {
2174 // Create tensors
2175 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
2176 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
2177 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
2178 TensorType dst;
2179 // Create post op tensors and populate post op with them
2180 std::vector<TensorType> post_op_tensors_holder{};
2181 auto populated_post_ops = experimental::transform_post_op_list_arguments<TensorShape, ITensorInfo *>(post_ops,
2182 [&post_op_tensors_holder, &data_type](auto shape)
2183 {
2184 auto t = create_tensor<TensorType>(shape, data_type, 1);
2185 post_op_tensors_holder.push_back(std::move(t));
2186 return post_op_tensors_holder.back().info();
2187 });
2188
2189 const unsigned int M = lhs_shape[1];
2190 const unsigned int N = rhs_shape[0];
2191 const unsigned int K = lhs_shape[0];
2192 GEMMKernelInfo kernel_info;
2193 kernel_info.m = M;
2194 kernel_info.n = N;
2195 kernel_info.k = K;
2196 kernel_info.depth_output_gemm3d = 0;
2197 kernel_info.reinterpret_input_as_3d = false;
2198 kernel_info.broadcast_bias = broadcast_bias;
2199 kernel_info.activation_info = act_info;
2200 kernel_info.post_ops = populated_post_ops;
2201
2202 // Create and configure function
2203 GEMMOperatorType gemm;
2204 gemm.configure(lhs.info(), rhs.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
2205
2206 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
2207 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
2208 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
2209 for(const auto &tensor : post_op_tensors_holder)
2210 {
2211 ARM_COMPUTE_ASSERT(tensor.info()->is_resizable());
2212 }
2213
2214 add_padding_x({ &lhs, &rhs, &bias, &dst });
2215 for(auto &tensor : post_op_tensors_holder)
2216 {
2217 add_padding_x({ &tensor });
2218 }
2219
2220 // Allocate tensors
2221 lhs.allocator()->allocate();
2222 rhs.allocator()->allocate();
2223 bias.allocator()->allocate();
2224 dst.allocator()->allocate();
2225 for(auto &tensor : post_op_tensors_holder)
2226 {
2227 tensor.allocator()->allocate();
2228 }
2229
2230 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
2231 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
2232 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
2233 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
2234 for(const auto &tensor : post_op_tensors_holder)
2235 {
2236 ARM_COMPUTE_ASSERT(!tensor.info()->is_resizable());
2237 }
2238
2239 // Fill tensors
2240 fill(AccessorType(lhs), 0);
2241 fill(AccessorType(rhs), 1);
2242 fill(AccessorType(bias), 2);
2243 for(size_t i = 0; i < post_op_tensors_holder.size(); ++i)
2244 {
2245 fill(AccessorType(post_op_tensors_holder.at(i)), 3 + i);
2246 }
2247
2248 // Compute GEMM
2249 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
2250 { ACL_SRC_1, &rhs },
2251 { ACL_SRC_2, &bias },
2252 { ACL_DST, &dst }
2253 });
2254 for(size_t i = 0; i < post_op_tensors_holder.size(); ++i)
2255 {
2256 gemm_pack.add_tensor(experimental::get_post_op_arg_type(i), &post_op_tensors_holder.at(i));
2257 }
2258 gemm.run(gemm_pack);
2259
2260 return dst;
2261 }
2262
2263 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
2264 const ActivationLayerInfo &act_info, const experimental::PostOpList<TensorShape> &post_ops)
2265 {
2266 TensorShape dst_shape = lhs_shape;
2267 dst_shape[0] = rhs_shape[0];
2268 dst_shape[1] = lhs_shape[1];
2269
2270 // Create reference
2271 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
2272 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
2273 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
2274 // Create post op tensors and populate post op with them
2275 auto populated_post_ops = experimental::transform_post_op_list_arguments<TensorShape, SimpleTensor<T>>(post_ops, [&data_type](auto shape)
2276 {
2277 return SimpleTensor<T> { shape, data_type, 1 };
2278 });
2279
2280 const int n = rhs_shape[0];
2281 const int m = lhs_shape[1];
2282 const int batch_size = lhs_shape[2];
2283
2284 // Fill reference
2285 int tensor_idx = 0;
2286 fill(lhs, tensor_idx++);
2287 fill(rhs, tensor_idx++);
2288 fill(bias, tensor_idx++);
2289 for(auto &op : populated_post_ops.get_list())
2290 {
2291 for(auto tensor : op->arguments())
2292 {
2293 fill(*tensor, tensor_idx++);
2294 }
2295 }
2296
2297 if(broadcast_bias)
2298 {
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00002299 // In case of broadcast, we need to simply copy the first into the following "M" ones
SiCongLiafa19722021-10-24 19:12:33 +01002300 for(int i = 1; i < m * batch_size; i++)
2301 {
2302 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
2303 }
2304 }
2305
2306 SimpleTensor<T> out;
2307 out = reference::gemm<T>(lhs, rhs, bias, alpha, beta);
2308 // Ignore activation info if post ops are used instead
2309 if(populated_post_ops.size() > 0)
2310 {
2311 out = reference::post_ops<T>(out, populated_post_ops);
2312 }
2313 else
2314 {
2315 out = reference::activation_layer(out, act_info);
2316 }
2317 return out;
2318 }
2319
2320 TensorType _target{};
2321 SimpleTensor<T> _reference{};
2322};
2323
2324template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
giuros01b3204e72019-04-01 13:50:22 +01002325class GEMMMatrixMultiplyNative3DValidationFixture : public framework::Fixture
2326{
2327public:
2328 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01002329 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,
2330 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01002331 {
2332 GEMMLHSMatrixInfo lhs_info;
2333 lhs_info.m0 = m0;
2334 lhs_info.k0 = k0;
2335
2336 GEMMRHSMatrixInfo rhs_info;
2337 rhs_info.n0 = n0;
2338 rhs_info.k0 = k0;
2339
2340 // In case of GEMM3D, m is the product between m_w and m_h
2341 const unsigned int m = m_w * m_h;
2342
2343 // Set the tensor shapes for LHS and RHS matrices
2344 const TensorShape lhs_shape(k, m, batch_size);
2345 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002346 const TensorShape bias_shape(n, 1, 1);
giuros01b3204e72019-04-01 13:50:22 +01002347
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01002348 _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 +01002349 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
giuros01b3204e72019-04-01 13:50:22 +01002350 }
2351
2352protected:
2353 template <typename U>
2354 void fill(U &&tensor, int i)
2355 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00002356 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 +00002357 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 +00002358
2359 DistributionType distribution{ T(-1.0f), T(1.0f) };
giuros01b3204e72019-04-01 13:50:22 +01002360 library->fill(tensor, distribution, i);
2361 }
2362
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002363 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 +01002364 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01002365 {
2366 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002367 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
2368 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
2369 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01002370 TensorType dst;
2371
2372 const unsigned int M = lhs_shape[1];
2373 const unsigned int N = rhs_shape[0];
2374 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01002375 GEMMKernelInfo kernel_info;
2376 kernel_info.m = M;
2377 kernel_info.n = N;
2378 kernel_info.k = K;
2379 kernel_info.depth_output_gemm3d = m_h;
2380 kernel_info.reinterpret_input_as_3d = false;
2381 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01002382 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01002383
2384 // The output tensor will be auto-initialized within the function
2385
2386 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01002387 GEMMOperatorType gemm;
2388 gemm.configure(lhs.info(), rhs.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01002389
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01002390 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
2391 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
2392 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
giuros01b3204e72019-04-01 13:50:22 +01002393
Giorgio Arena63825e82021-03-25 14:54:50 +00002394 add_padding_x({ &lhs, &rhs, &bias, &dst });
2395
giuros01b3204e72019-04-01 13:50:22 +01002396 // Allocate tensors
2397 lhs.allocator()->allocate();
2398 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002399 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01002400 dst.allocator()->allocate();
2401
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01002402 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
2403 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
2404 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
2405 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
giuros01b3204e72019-04-01 13:50:22 +01002406
2407 // Fill tensors
2408 fill(AccessorType(lhs), 0);
2409 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002410 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01002411
2412 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01002413 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
2414 { ACL_SRC_1, &rhs },
2415 { ACL_SRC_2, &bias },
2416 { ACL_DST, &dst }
2417 });
2418 gemm.run(gemm_pack);
giuros01b3204e72019-04-01 13:50:22 +01002419
2420 return dst;
2421 }
2422
Michalis Spyrou6bff1952019-10-02 17:22:11 +01002423 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 +01002424 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01002425 {
2426 TensorShape dst_shape = lhs_shape;
2427 dst_shape.set(0, rhs_shape[0]);
2428 dst_shape.set(1, lhs_shape[1] / m_h);
2429 dst_shape.set(2, m_h);
2430 dst_shape.set(3, lhs_shape[2]);
2431
2432 // Create reference
2433 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
2434 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002435 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
2436
2437 const int n = rhs_shape[0];
2438 const int m = lhs_shape[1];
2439 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01002440
2441 // Fill reference
2442 fill(lhs, 0);
2443 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002444 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01002445
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00002446 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002447 for(int i = 1; i < m * batch_size; i++)
2448 {
2449 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
2450 }
2451
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01002452 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01002453 }
2454
2455 TensorType _target{};
2456 SimpleTensor<T> _reference{};
2457};
2458
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00002459template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
2460class GEMMMatrixMultiplyReshapedOnlyRhsMMULValidationFixture : public framework::Fixture
2461{
2462public:
2463 template <typename...>
2464 void setup(unsigned int m, unsigned int n, unsigned int k, unsigned int batch_size, unsigned int m0, unsigned int n0, unsigned int k0, bool export_to_cl_image, DataType data_type, float alpha,
2465 float beta, bool broadcast_bias,
2466 const ActivationLayerInfo &act_info)
2467 {
2468 GEMMLHSMatrixInfo lhs_info;
2469 lhs_info.m0 = m0;
2470 lhs_info.k0 = k0;
2471
2472 GEMMRHSMatrixInfo rhs_info;
2473 rhs_info.n0 = n0;
2474 rhs_info.k0 = k0;
2475 rhs_info.interleave = true;
2476 rhs_info.transpose = false;
2477 rhs_info.h0 = 4;
2478 rhs_info.export_to_cl_image = export_to_cl_image;
2479
2480 // Set the tensor shapes for LHS and RHS matrices
2481 const TensorShape lhs_shape(k, m, batch_size);
2482 const TensorShape rhs_shape(n, k, batch_size);
2483 const TensorShape bias_shape(n,
2484 broadcast_bias ? 1 : m,
2485 broadcast_bias ? 1 : batch_size);
2486
2487 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
2488 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
2489 }
2490
2491protected:
2492 template <typename U>
2493 void fill(U &&tensor, int i)
2494 {
2495 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
2496 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;
2497
2498 DistributionType distribution{ T(-1.0f), T(1.0f) };
2499 library->fill(tensor, distribution, i);
2500
2501 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
2502 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
2503 library->fill_borders_with_garbage(tensor, distribution_inf, i);
2504 }
2505
2506 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
2507 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
2508 {
2509 // Create tensors
2510 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
2511 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
2512 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
2513 TensorType rhs_reshaped;
2514 TensorType dst;
2515
2516 const unsigned int M = lhs_shape[1];
2517 const unsigned int N = rhs_shape[0];
2518 const unsigned int K = lhs_shape[0];
2519 GEMMKernelInfo kernel_info;
2520 kernel_info.m = M;
2521 kernel_info.n = N;
2522 kernel_info.k = K;
2523 kernel_info.depth_output_gemm3d = 0;
2524 kernel_info.reinterpret_input_as_3d = false;
2525 kernel_info.broadcast_bias = broadcast_bias;
2526 kernel_info.activation_info = act_info;
2527
2528 // Create and configure function
2529 ReshapeRHSOperatorType reshape_rhs;
2530 GEMMOperatorType gemm;
2531
2532 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
2533 if(!validate_result)
2534 {
2535 return nullptr;
2536 }
2537
2538 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
2539
2540 validate_result = bool(gemm.validate(lhs.info(), rhs_reshaped.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info));
2541 if(!validate_result)
2542 {
2543 return nullptr;
2544 }
2545
2546 gemm.configure(lhs.info(), rhs_reshaped.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
2547
2548 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
2549 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
2550 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
2551
2552 // Allocate tensors
2553 lhs.allocator()->allocate();
2554 rhs.allocator()->allocate();
2555 rhs_reshaped.allocator()->allocate();
2556 bias.allocator()->allocate();
2557 dst.allocator()->allocate();
2558
2559 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
2560 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
2561 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
2562 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
2563 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
2564
2565 // Fill tensors
2566 fill(AccessorType(lhs), 0);
2567 fill(AccessorType(rhs), 1);
2568 fill(AccessorType(bias), 2);
2569
2570 // Compute GEMM
2571 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
2572 reshape_rhs.run(reshape_rhs_pack);
2573 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
2574 { ACL_SRC_1, &rhs_reshaped },
2575 { ACL_SRC_2, &bias },
2576 { ACL_DST, &dst }
2577 });
2578 gemm.run(gemm_pack);
2579
2580 return dst;
2581 }
2582
2583 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
2584 const ActivationLayerInfo &act_info)
2585 {
2586 if(!validate_result)
2587 return SimpleTensor<T>();
2588
2589 TensorShape dst_shape = lhs_shape;
2590 dst_shape[0] = rhs_shape[0];
2591 dst_shape[1] = lhs_shape[1];
2592
2593 // Create reference
2594 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
2595 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
2596 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
2597
2598 const int n = rhs_shape[0];
2599 const int m = lhs_shape[1];
2600 const int batch_size = lhs_shape[2];
2601
2602 // Fill reference
2603 fill(lhs, 0);
2604 fill(rhs, 1);
2605 fill(bias, 2);
2606
2607 if(broadcast_bias)
2608 {
2609 // In case of broadcast, we need to simply copy the first into the following "M" ones
2610 for(int i = 1; i < m * batch_size; i++)
2611 {
2612 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
2613 }
2614 }
2615
2616 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
2617 }
2618
2619 bool validate_result = true;
2620 TensorType _target{};
2621 SimpleTensor<T> _reference{};
2622};
2623
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +01002624} // namespace validation
2625} // namespace test
2626} // namespace arm_compute
2627#endif /* ARM_COMPUTE_TEST_GEMM_FIXTURE */