blob: 5dc27117532b1590b2facf446d18e7e714bd54bd [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;
155 if(reinterpret_input_as_3d)
156 {
157 // Collapse the second and third dimension if the input is 3D
158 shape_a_to_use.collapse(2U, 1U);
159 }
160
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100161 // Create reference
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100162 SimpleTensor<T> a{ shape_a_to_use, data_type, 1 };
Vidhya Sudhan Loganathan014333d2018-07-02 09:13:49 +0100163 SimpleTensor<T> b{ shape_b, data_type, 1 };
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100164 SimpleTensor<T> c{ output_shape, data_type, 1 };
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100165
166 // Fill reference
167 fill(a, 0);
168 fill(b, 1);
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100169 fill(c, 2);
170
171 if(reinterpret_input_as_3d || reinterpret_output_as_3d)
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000172 {
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100173 const int n = shape_b[0];
174 const int m = reinterpret_output_as_3d ? output_shape[1] * output_shape[2] : output_shape[1];
175 const int batch_size = reinterpret_output_as_3d ? output_shape[3] : output_shape[2];
176
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000177 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100178 for(int i = 1; i < m * batch_size; i++)
179 {
180 memcpy(c.data() + i * n, c.data(), n * sizeof(T));
181 }
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000182 }
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000183
Adnan AlSinan3bb72b62022-05-06 12:10:11 +0100184 /* Note: Assuming the usual batch matmul dimensions A = (B x M x K), B = (B x K x N), if pretranspose_A is set to true, then A is assumed to be (B x K x M),
185 therefore, A must be pre-transposed before passing it to the fixture. And, we transpose A again in the fixture to make it (B x M x K)
186 in order to be able to call reference implementation that works with (B x M x K) input.
187 Similarly, if pretranspose_B is set to true, then B is assumed to be (B x N x K), B must be pre-transposed before passing it to the fixture. */
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000188
Mohammed Suhail Munshibc5c4072022-04-27 13:49:51 +0100189 // Define transposed shapes
190 TensorShape a_transposed_shape(a.shape().y(), a.shape().x());
191 TensorShape b_transposed_shape(b.shape().y(), b.shape().x());
192
193 // Define transposed tensors
194 SimpleTensor<T> a_transposed{ a_transposed_shape, data_type };
195 SimpleTensor<T> b_transposed{ b_transposed_shape, data_type };
196
197 // pretranspose a if necessary
198 if(pretranspose_a)
199 {
200 transpose_matrix<T>(a, a_transposed);
201 }
202
203 // pretranspose b if necessary
204 if(pretranspose_b)
205 {
206 transpose_matrix<T>(b, b_transposed);
207 }
208
Mohammed Suhail Munshi13a2d002022-09-05 11:57:34 +0100209 // Run with variable inputs.
210 if(run_twice)
211 {
212 reference::gemm<T>((pretranspose_a) ? a_transposed : a, (pretranspose_b) ? b_transposed : b, c, alpha, disable_c ? 0.f : beta);
213 fill((pretranspose_a) ? a_transposed : a, 3);
214 fill((pretranspose_b) ? b_transposed : b, 4);
Adnan AlSinan26c9d1a2022-09-07 13:54:53 +0100215 fill(c, 5);
Mohammed Suhail Munshi13a2d002022-09-05 11:57:34 +0100216 }
217
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100218 // Setting beta to 0 will effectively disable C for the
219 // computation of the reference: alpha * A * B + 0 * C
Mohammed Suhail Munshibc5c4072022-04-27 13:49:51 +0100220 // Use transposed tensors if boolean enabled else use original tensors
Adnan AlSinan26c9d1a2022-09-07 13:54:53 +0100221 auto r = reference::gemm<T>((pretranspose_a) ? a_transposed : a, (pretranspose_b) ? b_transposed : b, c, alpha, disable_c ? 0.f : beta);
Mohammed Suhail Munshi13a2d002022-09-05 11:57:34 +0100222 return r;
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100223 }
224
225 TensorType _target{};
226 SimpleTensor<T> _reference{};
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100227};
228
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100229template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100230class GEMMMatrixMultiplyValidationFixture : public framework::Fixture
231{
232public:
233 template <typename...>
234 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,
235 DataType data_type, GPUTarget gpu_arch)
236 {
237 // Set the tensor shapes for LHS and RHS matrices
238 const TensorShape lhs_shape(k, m, batch_size);
239 const TensorShape rhs_shape(n, k, batch_size);
240 const TensorShape bias_shape(n,
241 broadcast_bias ? 1 : m,
242 broadcast_bias ? 1 : batch_size);
243
244 _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 +0100245 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100246 }
247
248protected:
249 template <typename U>
250 void fill(U &&tensor, int i)
251 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000252 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 +0000253 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 +0000254
255 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100256 library->fill(tensor, distribution, i);
257
258 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000259 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100260 library->fill_borders_with_garbage(tensor, distribution_inf, i);
261 }
262
263 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,
264 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
265 {
266 // Create tensors
267 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
268 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
269 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
270 TensorType dst;
271
272 const unsigned int m = lhs_shape[1];
273 const unsigned int n = rhs_shape[0];
274 const unsigned int k = lhs_shape[0];
275 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, 0, false, broadcast_bias);
276
277 // The output tensor will be auto-initialized within the function
278
279 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100280 GEMMOperatorType gemm;
281 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 +0100282
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100283 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
284 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
285 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100286
Giorgio Arena63825e82021-03-25 14:54:50 +0000287 add_padding_x({ &lhs, &rhs, &bias, &dst });
288
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100289 // Allocate tensors
290 lhs.allocator()->allocate();
291 rhs.allocator()->allocate();
292 bias.allocator()->allocate();
293 dst.allocator()->allocate();
294
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100295 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
296 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
297 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
298 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100299
300 // Fill tensors
301 fill(AccessorType(lhs), 0);
302 fill(AccessorType(rhs), 1);
303 fill(AccessorType(bias), 2);
304
305 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100306 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
307 { ACL_SRC_1, &rhs },
308 { ACL_SRC_2, &bias },
309 { ACL_DST, &dst }
310 });
311 gemm.run(gemm_pack);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100312
313 return dst;
314 }
315
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100316 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 +0100317 const ActivationLayerInfo &act_info)
318 {
319 TensorShape dst_shape = lhs_shape;
320 dst_shape[0] = rhs_shape[0];
321 dst_shape[1] = lhs_shape[1];
322
323 // Create reference
324 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
325 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
326 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
327
328 const int n = rhs_shape[0];
329 const int m = lhs_shape[1];
330 const int batch_size = lhs_shape[2];
331
332 // Fill reference
333 fill(lhs, 0);
334 fill(rhs, 1);
335 fill(bias, 2);
336
337 if(broadcast_bias)
338 {
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000339 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100340 for(int i = 1; i < m * batch_size; i++)
341 {
342 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
343 }
344 }
345
346 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
347 }
348
349 TensorType _target{};
350 SimpleTensor<T> _reference{};
351};
352
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100353template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100354class GEMMMatrixMultiply3DValidationFixture : public framework::Fixture
355{
356public:
357 template <typename...>
358 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,
359 const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
360 {
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100361 ARM_COMPUTE_UNUSED(broadcast_bias);
362
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100363 // In case of GEMM3D, m is the product between m_w and m_h
364 const unsigned int m = m_w * m_h;
365
366 // Set the tensor shapes for LHS and RHS matrices
367 const TensorShape lhs_shape(k, m, batch_size);
368 const TensorShape rhs_shape(n, k, batch_size);
369 const TensorShape bias_shape(n, 1, 1);
370
371 _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 +0100372 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100373 }
374
375protected:
376 template <typename U>
377 void fill(U &&tensor, int i)
378 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000379 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 +0000380 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 +0000381
382 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100383 library->fill(tensor, distribution, i);
384 }
385
386 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,
387 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
388 {
389 // Create tensors
390 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
391 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
392 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
393 TensorType dst;
394
395 const unsigned int m = lhs_shape[1];
396 const unsigned int n = rhs_shape[0];
397 const unsigned int k = lhs_shape[0];
398 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, m_h, false, true);
399
400 // The output tensor will be auto-initialized within the function
401
402 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100403 GEMMOperatorType gemm;
404 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 +0100405
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100406 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
407 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
408 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100409
Giorgio Arena63825e82021-03-25 14:54:50 +0000410 add_padding_x({ &lhs, &rhs, &bias, &dst });
411
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100412 // Allocate tensors
413 lhs.allocator()->allocate();
414 rhs.allocator()->allocate();
415 bias.allocator()->allocate();
416 dst.allocator()->allocate();
417
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100418 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
419 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
420 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
421 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100422
423 // Fill tensors
424 fill(AccessorType(lhs), 0);
425 fill(AccessorType(rhs), 1);
426 fill(AccessorType(bias), 2);
427
428 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100429 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
430 { ACL_SRC_1, &rhs },
431 { ACL_SRC_2, &bias },
432 { ACL_DST, &dst }
433 });
434 gemm.run(gemm_pack);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100435
436 return dst;
437 }
438
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100439 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 +0100440 const ActivationLayerInfo &act_info)
441 {
442 TensorShape dst_shape = lhs_shape;
443 dst_shape.set(0, rhs_shape[0]);
444 dst_shape.set(1, lhs_shape[1] / m_h);
445 dst_shape.set(2, m_h);
446 dst_shape.set(3, lhs_shape[2]);
447
448 // Create reference
449 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
450 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
451 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
452
453 const int n = rhs_shape[0];
454 const int m = lhs_shape[1];
455 const int batch_size = lhs_shape[2];
456
457 // Fill reference
458 fill(lhs, 0);
459 fill(rhs, 1);
460 fill(bias, 2);
461
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000462 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100463 for(int i = 1; i < m * batch_size; i++)
464 {
465 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
466 }
467
468 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
469 }
470
471 TensorType _target{};
472 SimpleTensor<T> _reference{};
473};
474
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100475template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSOperatorType, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100476class GEMMMatrixMultiplyInterleavedTransposedValidationFixture : public framework::Fixture
477{
478public:
479 template <typename...>
480 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,
481 const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
482 {
483 GEMMLHSMatrixInfo lhs_info;
484 lhs_info.m0 = 4;
485 lhs_info.k0 = 4;
486 lhs_info.v0 = v0;
487 lhs_info.interleave = true;
488 lhs_info.transpose = true;
489
490 GEMMRHSMatrixInfo rhs_info;
491 rhs_info.n0 = 16 / sizeof(T);
492 rhs_info.k0 = 1;
493 rhs_info.h0 = h0;
494 rhs_info.interleave = false;
495 rhs_info.transpose = false;
496
497 // Set the tensor shapes for LHS and RHS matrices
498 const TensorShape lhs_shape(k, m, batch_size);
499 const TensorShape rhs_shape(n, k, batch_size);
500 const TensorShape bias_shape(n,
501 broadcast_bias ? 1 : m,
502 broadcast_bias ? 1 : batch_size);
503
504 _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 +0100505 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100506 }
507
508protected:
509 template <typename U>
510 void fill(U &&tensor, int i)
511 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000512 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 +0000513 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 +0000514
515 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100516 library->fill(tensor, distribution, i);
517
518 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000519 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100520 library->fill_borders_with_garbage(tensor, distribution_inf, i);
521 }
522
523 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
524 DataType data_type, float alpha, float beta, bool broadcast_bias, bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
525 {
526 // Create tensors
527 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
528 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
529 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
530 TensorType lhs_reshaped;
531 TensorType rhs_reshaped;
532 TensorType dst;
533
534 const unsigned int m = lhs_shape[1];
535 const unsigned int n = rhs_shape[0];
536 const unsigned int k = lhs_shape[0];
537 GEMMReshapeInfo reshape_info(m, n, k, rhs_info.h0, lhs_info.v0, 0, false, broadcast_bias);
538
539 // The output tensor will be auto-initialized within the function
540
541 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100542 ReshapeLHSOperatorType reshape_lhs;
543 ReshapeRHSOperatorType reshape_rhs;
544 GEMMOperatorType gemm;
545 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
546 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
547 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 +0100548
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100549 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
550 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
551 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100552
Georgios Pinitas3dca91b2021-04-13 13:35:58 +0100553 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +0000554 if(!rhs_info.export_to_cl_image)
555 {
556 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
557 }
558
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100559 // Allocate tensors
560 lhs.allocator()->allocate();
561 rhs.allocator()->allocate();
562 lhs_reshaped.allocator()->allocate();
563 rhs_reshaped.allocator()->allocate();
564 bias.allocator()->allocate();
565 dst.allocator()->allocate();
566
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100567 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
568 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
569 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
570 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
571 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
572 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100573
574 // Fill tensors
575 fill(AccessorType(lhs), 0);
576 fill(AccessorType(rhs), 1);
577 fill(AccessorType(bias), 2);
578
579 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100580 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
581 reshape_lhs.run(reshape_lhs_pack);
582 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
583 reshape_rhs.run(reshape_rhs_pack);
584 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
585 { ACL_SRC_1, &rhs_reshaped },
586 { ACL_SRC_2, &bias },
587 { ACL_DST, &dst }
588 });
589 gemm.run(gemm_pack);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100590
591 return dst;
592 }
593
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100594 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 +0100595 const ActivationLayerInfo &act_info)
596 {
597 TensorShape dst_shape = lhs_shape;
598 dst_shape[0] = rhs_shape[0];
599 dst_shape[1] = lhs_shape[1];
600
601 // Create reference
602 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
603 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
604 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
605
606 const int n = rhs_shape[0];
607 const int m = lhs_shape[1];
608 const int batch_size = lhs_shape[2];
609
610 // Fill reference
611 fill(lhs, 0);
612 fill(rhs, 1);
613 fill(bias, 2);
614
615 if(broadcast_bias)
616 {
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000617 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100618 for(int i = 1; i < m * batch_size; i++)
619 {
620 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
621 }
622 }
623
624 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
625 }
626
627 TensorType _target{};
628 SimpleTensor<T> _reference{};
629};
630
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100631template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSOperatorType, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100632class GEMMMatrixMultiplyInterleavedTransposed3DValidationFixture : public framework::Fixture
633{
634public:
635 template <typename...>
636 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,
637 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
638 {
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100639 ARM_COMPUTE_UNUSED(broadcast_bias);
640
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100641 GEMMLHSMatrixInfo lhs_info;
642 lhs_info.m0 = 4;
643 lhs_info.k0 = 4;
644 lhs_info.v0 = v0;
645 lhs_info.interleave = true;
646 lhs_info.transpose = true;
647
648 GEMMRHSMatrixInfo rhs_info;
649 rhs_info.n0 = 16 / sizeof(T);
650 rhs_info.k0 = 1;
651 rhs_info.h0 = h0;
652 rhs_info.interleave = false;
653 rhs_info.transpose = false;
654
655 // In case of GEMM3D, m is the product between m_w and m_h
656 const unsigned int m = m_w * m_h;
657
658 // Set the tensor shapes for LHS and RHS matrices
659 const TensorShape lhs_shape(k, m, batch_size);
660 const TensorShape rhs_shape(n, k, batch_size);
661 const TensorShape bias_shape(n, 1, 1);
662
663 _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 +0100664 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100665 }
666
667protected:
668 template <typename U>
669 void fill(U &&tensor, int i)
670 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000671 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 +0000672 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 +0000673
674 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100675 library->fill(tensor, distribution, i);
676 }
677
678 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
679 DataType data_type, float alpha, float beta, unsigned int m_h, bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
680 {
681 // Create tensors
682 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
683 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
684 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
685 TensorType lhs_reshaped;
686 TensorType rhs_reshaped;
687 TensorType dst;
688
689 const unsigned int m = lhs_shape[1];
690 const unsigned int n = rhs_shape[0];
691 const unsigned int k = lhs_shape[0];
692 GEMMReshapeInfo reshape_info(m, n, k, rhs_info.h0, lhs_info.v0, m_h, false, true);
693
694 // The output tensor will be auto-initialized within the function
695
696 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100697 ReshapeLHSOperatorType reshape_lhs;
698 ReshapeRHSOperatorType reshape_rhs;
699 GEMMOperatorType gemm;
700 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
701 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
702 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 +0100703
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100704 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
705 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
706 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100707
Georgios Pinitas3dca91b2021-04-13 13:35:58 +0100708 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +0000709 if(!rhs_info.export_to_cl_image)
710 {
711 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
712 }
713
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100714 // Allocate tensors
715 lhs.allocator()->allocate();
716 rhs.allocator()->allocate();
717 lhs_reshaped.allocator()->allocate();
718 rhs_reshaped.allocator()->allocate();
719 bias.allocator()->allocate();
720 dst.allocator()->allocate();
721
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100722 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
723 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
724 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
725 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
726 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
727 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100728
729 // Fill tensors
730 fill(AccessorType(lhs), 0);
731 fill(AccessorType(rhs), 1);
732 fill(AccessorType(bias), 2);
733
734 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100735 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
736 reshape_lhs.run(reshape_lhs_pack);
737 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
738 reshape_rhs.run(reshape_rhs_pack);
739 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
740 { ACL_SRC_1, &rhs_reshaped },
741 { ACL_SRC_2, &bias },
742 { ACL_DST, &dst }
743 });
744 gemm.run(gemm_pack);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100745
746 return dst;
747 }
748
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100749 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 +0100750 const ActivationLayerInfo &act_info)
751 {
752 TensorShape dst_shape = lhs_shape;
753 dst_shape.set(0, rhs_shape[0]);
754 dst_shape.set(1, lhs_shape[1] / m_h);
755 dst_shape.set(2, m_h);
756 dst_shape.set(3, lhs_shape[2]);
757
758 // Create reference
759 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
760 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
761 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
762
763 const int n = rhs_shape[0];
764 const int m = lhs_shape[1];
765 const int batch_size = lhs_shape[2];
766
767 // Fill reference
768 fill(lhs, 0);
769 fill(rhs, 1);
770 fill(bias, 2);
771
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000772 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100773 for(int i = 1; i < m * batch_size; i++)
774 {
775 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
776 }
777
778 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
779 }
780
781 TensorType _target{};
782 SimpleTensor<T> _reference{};
783};
784
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100785template <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 +0000786class GEMMMatrixMultiplyReshapedValidationFixture : public framework::Fixture
787{
788public:
789 template <typename...>
790 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 +0100791 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 +0000792 {
793 GEMMLHSMatrixInfo lhs_info;
794 lhs_info.m0 = m0;
795 lhs_info.k0 = k0;
796 lhs_info.v0 = v0;
797 lhs_info.interleave = interleave_lhs;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100798 lhs_info.transpose = lhs_transpose;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000799
800 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodicee3a849a2020-06-10 17:59:30 +0100801 rhs_info.n0 = n0;
802 rhs_info.k0 = k0;
803 rhs_info.h0 = h0;
804 rhs_info.interleave = interleave_rhs;
805 rhs_info.transpose = !lhs_transpose;
806 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000807
808 // Set the tensor shapes for LHS and RHS matrices
809 const TensorShape lhs_shape(k, m, batch_size);
810 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100811 const TensorShape bias_shape(n,
812 broadcast_bias ? 1 : m,
813 broadcast_bias ? 1 : batch_size);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000814
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000815 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
816 if(validate_result)
817 {
818 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
819 }
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000820 }
821
822protected:
823 template <typename U>
824 void fill(U &&tensor, int i)
825 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000826 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 +0000827 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 +0000828
829 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000830 library->fill(tensor, distribution, i);
Gian Marco Iodiceb87b95e2019-01-21 17:14:31 +0000831
832 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000833 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiceb87b95e2019-01-21 17:14:31 +0000834 library->fill_borders_with_garbage(tensor, distribution_inf, i);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000835 }
836
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100837 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 +0100838 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000839 {
840 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100841 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
842 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
843 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000844 TensorType lhs_reshaped;
845 TensorType rhs_reshaped;
846 TensorType dst;
847
848 const unsigned int M = lhs_shape[1];
849 const unsigned int N = rhs_shape[0];
850 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100851 GEMMKernelInfo kernel_info;
852 kernel_info.m = M;
853 kernel_info.n = N;
854 kernel_info.k = K;
855 kernel_info.depth_output_gemm3d = 0;
856 kernel_info.reinterpret_input_as_3d = false;
857 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100858 kernel_info.activation_info = act_info;
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100859 kernel_info.fp_mixed_precision = fp_mixed_precision;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000860
861 // The output tensor will be auto-initialized within the function
862
863 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100864 ReshapeLHSOperatorType reshape_lhs;
865 ReshapeRHSOperatorType reshape_rhs;
866 GEMMOperatorType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000867
868 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
869 validate_result = validate_result || !rhs_info.export_to_cl_image;
870 if(!validate_result)
871 {
872 return nullptr;
873 }
874
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100875 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
876 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
877 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 +0000878
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100879 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
880 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
881 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000882
Georgios Pinitas3dca91b2021-04-13 13:35:58 +0100883 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +0000884 if(!rhs_info.export_to_cl_image)
885 {
886 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
887 }
888
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000889 // Allocate tensors
890 lhs.allocator()->allocate();
891 rhs.allocator()->allocate();
892 lhs_reshaped.allocator()->allocate();
893 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100894 bias.allocator()->allocate();
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000895 dst.allocator()->allocate();
896
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +0100897 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
898 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
899 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
900 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
901 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
902 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000903
904 // Fill tensors
905 fill(AccessorType(lhs), 0);
906 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100907 fill(AccessorType(bias), 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000908
909 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +0100910 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
911 reshape_lhs.run(reshape_lhs_pack);
912 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
913 reshape_rhs.run(reshape_rhs_pack);
914 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
915 { ACL_SRC_1, &rhs_reshaped },
916 { ACL_SRC_2, &bias },
917 { ACL_DST, &dst }
918 });
919 gemm.run(gemm_pack);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000920
921 return dst;
922 }
923
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100924 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 +0100925 const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000926 {
927 TensorShape dst_shape = lhs_shape;
928 dst_shape[0] = rhs_shape[0];
929 dst_shape[1] = lhs_shape[1];
930
931 // Create reference
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000932 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
933 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100934 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
935
936 const int n = rhs_shape[0];
937 const int m = lhs_shape[1];
938 const int batch_size = lhs_shape[2];
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000939
940 // Fill reference
941 fill(lhs, 0);
942 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100943 fill(bias, 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000944
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100945 if(broadcast_bias)
946 {
Gunes Bayir4bfc70e2021-12-10 16:17:56 +0000947 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100948 for(int i = 1; i < m * batch_size; i++)
949 {
950 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
951 }
952 }
953
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100954 if(fp_mixed_precision)
955 {
956 return reference::activation_layer(reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta), act_info);
957 }
958 else
959 {
960 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
961 }
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000962 }
963
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000964 bool validate_result = true;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000965 TensorType _target{};
966 SimpleTensor<T> _reference{};
967};
968
SiCongLi1af54162021-10-06 15:25:57 +0100969/** (EXPERIMENTAL_POST_OPS)*/
970template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSOperatorType, typename ReshapeRHSOperatorType, typename GEMMOperatorType, bool fp_mixed_precision = false>
971class GEMMMatrixMultiplyReshapedWithPostOpsValidationFixture : public framework::Fixture
972{
973public:
974 using PostOpArgBroadcast = std::tuple<bool, bool, bool>; // Instruct fixture if we need broadcasting in dimension 0, 1, 2 of each PostOp argument
975public:
976 template <typename...>
977 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,
978 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,
979 const experimental::PostOpList<PostOpArgBroadcast> &post_ops)
980 {
981 GEMMLHSMatrixInfo lhs_info;
982 lhs_info.m0 = m0;
983 lhs_info.k0 = k0;
984 lhs_info.v0 = v0;
985 lhs_info.interleave = interleave_lhs;
986 lhs_info.transpose = lhs_transpose;
987
988 GEMMRHSMatrixInfo rhs_info;
989 rhs_info.n0 = n0;
990 rhs_info.k0 = k0;
991 rhs_info.h0 = h0;
992 rhs_info.interleave = interleave_rhs;
993 rhs_info.transpose = !lhs_transpose;
994 rhs_info.export_to_cl_image = export_to_cl_image;
995
996 // Set the tensor shapes for LHS and RHS matrices
997 const TensorShape lhs_shape(k, m, batch_size);
998 const TensorShape rhs_shape(n, k, batch_size);
999 const TensorShape bias_shape(n,
1000 broadcast_bias ? 1 : m,
1001 broadcast_bias ? 1 : batch_size);
1002 auto post_ops_with_shapes = experimental::transform_post_op_list_arguments<PostOpArgBroadcast, TensorShape>(post_ops,
1003 [ = ](auto broadcast)
1004 {
1005 return TensorShape
1006 {
1007 std::get<0>(broadcast) ? 1 : n,
1008 std::get<1>(broadcast) ? 1 : m,
1009 std::get<2>(broadcast) ? 1 : batch_size,
1010 };
1011 });
1012
1013 _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);
1014 if(validate_result)
1015 {
1016 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info, post_ops_with_shapes);
1017 }
1018 }
1019
1020protected:
1021 template <typename U>
1022 void fill(U &&tensor, int i)
1023 {
1024 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
1025 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;
1026
1027 DistributionType distribution{ T(-1.0f), T(1.0f) };
1028 library->fill(tensor, distribution, i);
1029
1030 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
1031 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
1032 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1033 }
1034
1035 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
1036 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info, const experimental::PostOpList<TensorShape> &post_ops)
1037 {
1038 // Create tensors
1039 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1040 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1041 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
1042
1043 // Create post op tensors and populate post op with them
1044 std::vector<TensorType> post_op_tensors_holder{};
1045 auto populated_post_ops = experimental::transform_post_op_list_arguments<TensorShape, ITensorInfo *>(post_ops,
1046 [&post_op_tensors_holder, &data_type](auto shape)
1047 {
1048 auto t = create_tensor<TensorType>(shape, data_type, 1);
1049 post_op_tensors_holder.push_back(std::move(t));
1050 return post_op_tensors_holder.back().info();
1051 });
1052 TensorType lhs_reshaped;
1053 TensorType rhs_reshaped;
1054 TensorType dst;
1055
1056 const unsigned int M = lhs_shape[1];
1057 const unsigned int N = rhs_shape[0];
1058 const unsigned int K = lhs_shape[0];
1059 GEMMKernelInfo kernel_info;
1060 kernel_info.m = M;
1061 kernel_info.n = N;
1062 kernel_info.k = K;
1063 kernel_info.depth_output_gemm3d = 0;
1064 kernel_info.reinterpret_input_as_3d = false;
1065 kernel_info.broadcast_bias = broadcast_bias;
1066 kernel_info.activation_info = act_info;
1067 kernel_info.fp_mixed_precision = fp_mixed_precision;
1068 kernel_info.post_ops = populated_post_ops;
1069
1070 // The output tensor will be auto-initialized within the function
1071
1072 // Create and configure function
1073 ReshapeLHSOperatorType reshape_lhs;
1074 ReshapeRHSOperatorType reshape_rhs;
1075 GEMMOperatorType gemm;
1076
1077 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1078 validate_result = validate_result || !rhs_info.export_to_cl_image;
1079 if(!validate_result)
1080 {
1081 return nullptr;
1082 }
1083
1084 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
1085 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1086 gemm.configure(lhs_reshaped.info(), rhs_reshaped.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
1087
1088 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1089 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1090 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
1091 for(const auto &tensor : post_op_tensors_holder)
1092 {
1093 ARM_COMPUTE_ASSERT(tensor.info()->is_resizable());
1094 }
1095
1096 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
1097 if(!rhs_info.export_to_cl_image)
1098 {
1099 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
1100 for(auto &tensor : post_op_tensors_holder)
1101 {
1102 add_padding_x({ &tensor });
1103 }
1104 }
1105
1106 // Allocate tensors
1107 lhs.allocator()->allocate();
1108 rhs.allocator()->allocate();
1109 lhs_reshaped.allocator()->allocate();
1110 rhs_reshaped.allocator()->allocate();
1111 bias.allocator()->allocate();
1112 dst.allocator()->allocate();
1113 for(auto &tensor : post_op_tensors_holder)
1114 {
1115 tensor.allocator()->allocate();
1116 }
1117
1118 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1119 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1120 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1121 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
1122 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1123 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
1124 for(const auto &tensor : post_op_tensors_holder)
1125 {
1126 ARM_COMPUTE_ASSERT(!tensor.info()->is_resizable());
1127 }
1128
1129 // Fill tensors
1130 fill(AccessorType(lhs), 0);
1131 fill(AccessorType(rhs), 1);
1132 fill(AccessorType(bias), 2);
1133 for(size_t i = 0; i < post_op_tensors_holder.size(); ++i)
1134 {
1135 fill(AccessorType(post_op_tensors_holder.at(i)), 3 + i);
1136 }
1137
1138 // Compute GEMM
1139 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
1140 reshape_lhs.run(reshape_lhs_pack);
1141 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1142 reshape_rhs.run(reshape_rhs_pack);
1143 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
1144 { ACL_SRC_1, &rhs_reshaped },
1145 { ACL_SRC_2, &bias },
1146 { ACL_DST, &dst }
1147 });
1148 for(size_t i = 0; i < post_op_tensors_holder.size(); ++i)
1149 {
1150 gemm_pack.add_tensor(experimental::get_post_op_arg_type(i), &post_op_tensors_holder.at(i));
1151 }
1152 gemm.run(gemm_pack);
1153
1154 return dst;
1155 }
1156
1157 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
1158 const ActivationLayerInfo &act_info, const experimental::PostOpList<TensorShape> &post_ops)
1159 {
1160 TensorShape dst_shape = lhs_shape;
1161 dst_shape[0] = rhs_shape[0];
1162 dst_shape[1] = lhs_shape[1];
1163
1164 // Create reference
1165 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1166 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
1167 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1168 // Create post op tensors and populate post op with them
1169 auto populated_post_ops = experimental::transform_post_op_list_arguments<TensorShape, SimpleTensor<T>>(post_ops, [&data_type](auto shape)
1170 {
1171 return SimpleTensor<T> { shape, data_type, 1 };
1172 });
1173
1174 const int n = rhs_shape[0];
1175 const int m = lhs_shape[1];
1176 const int batch_size = lhs_shape[2];
1177
1178 // Fill reference
1179 int tensor_idx = 0;
1180 fill(lhs, tensor_idx++);
1181 fill(rhs, tensor_idx++);
1182 fill(bias, tensor_idx++);
1183 for(auto &op : populated_post_ops.get_list())
1184 {
1185 for(auto tensor : op->arguments())
1186 {
1187 fill(*tensor, tensor_idx++);
1188 }
1189 }
1190
1191 if(broadcast_bias)
1192 {
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00001193 // In case of broadcast, we need to simply copy the first into the following "M" ones
SiCongLi1af54162021-10-06 15:25:57 +01001194 for(int i = 1; i < m * batch_size; i++)
1195 {
1196 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1197 }
1198 }
1199
1200 SimpleTensor<T> out;
1201 if(fp_mixed_precision)
1202 {
1203 out = reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta);
1204 }
1205 else
1206 {
1207 out = reference::gemm<T>(lhs, rhs, bias, alpha, beta);
1208 }
1209 // Ignore activation info if post ops are used instead
1210 if(populated_post_ops.size() > 0)
1211 {
1212 out = reference::post_ops<T>(out, populated_post_ops);
1213 }
1214 else
1215 {
1216 out = reference::activation_layer(out, act_info);
1217 }
1218 return out;
1219 }
1220
1221 bool validate_result = true;
1222 TensorType _target{};
1223 SimpleTensor<T> _reference{};
1224};
1225
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001226template <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 +00001227class GEMMMatrixMultiplyReshaped3DValidationFixture : public framework::Fixture
1228{
1229public:
1230 template <typename...>
1231 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 +01001232 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 +00001233 {
1234 GEMMLHSMatrixInfo lhs_info;
1235 lhs_info.m0 = m0;
1236 lhs_info.k0 = k0;
1237 lhs_info.v0 = v0;
1238 lhs_info.interleave = interleave_lhs;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +01001239 lhs_info.transpose = lhs_transpose;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001240
1241 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodicee3a849a2020-06-10 17:59:30 +01001242 rhs_info.n0 = n0;
1243 rhs_info.k0 = k0;
1244 rhs_info.h0 = h0;
1245 rhs_info.interleave = interleave_rhs;
1246 rhs_info.transpose = !lhs_transpose;
1247 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001248
1249 // In case of GEMM3D, m is the product between m_w and m_h
1250 const unsigned int m = m_w * m_h;
1251
1252 // Set the tensor shapes for LHS and RHS matrices
1253 const TensorShape lhs_shape(k, m, batch_size);
1254 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001255 const TensorShape bias_shape(n, 1, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001256
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001257 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info);
1258 if(validate_result)
1259 {
1260 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
1261 }
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001262 }
1263
1264protected:
1265 template <typename U>
1266 void fill(U &&tensor, int i)
1267 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001268 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 +00001269 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 +00001270
1271 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001272 library->fill(tensor, distribution, i);
1273 }
1274
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001275 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 +01001276 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001277 {
1278 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001279 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1280 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1281 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001282 TensorType lhs_reshaped;
1283 TensorType rhs_reshaped;
1284 TensorType dst;
1285
1286 const unsigned int M = lhs_shape[1];
1287 const unsigned int N = rhs_shape[0];
1288 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001289 GEMMKernelInfo kernel_info;
1290 kernel_info.m = M;
1291 kernel_info.n = N;
1292 kernel_info.k = K;
1293 kernel_info.depth_output_gemm3d = m_h;
1294 kernel_info.reinterpret_input_as_3d = false;
1295 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001296 kernel_info.activation_info = act_info;
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +01001297 kernel_info.fp_mixed_precision = fp_mixed_precision;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001298
1299 // The output tensor will be auto-initialized within the function
1300
1301 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001302 ReshapeLHSOperatorType reshape_lhs;
1303 ReshapeRHSOperatorType reshape_rhs;
1304 GEMMOperatorType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001305
1306 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1307 validate_result = validate_result || !rhs_info.export_to_cl_image;
1308 if(!validate_result)
1309 {
1310 return nullptr;
1311 }
1312
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001313 reshape_lhs.configure(lhs.info(), lhs_reshaped.info(), lhs_info);
1314 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1315 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 +00001316
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001317 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1318 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1319 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001320
Georgios Pinitas3dca91b2021-04-13 13:35:58 +01001321 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +00001322 if(!rhs_info.export_to_cl_image)
1323 {
1324 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
1325 }
1326
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001327 // Allocate tensors
1328 lhs.allocator()->allocate();
1329 rhs.allocator()->allocate();
1330 lhs_reshaped.allocator()->allocate();
1331 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001332 bias.allocator()->allocate();
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001333 dst.allocator()->allocate();
1334
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001335 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1336 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1337 ARM_COMPUTE_ASSERT(!lhs_reshaped.info()->is_resizable());
1338 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1339 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1340 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001341
1342 // Fill tensors
1343 fill(AccessorType(lhs), 0);
1344 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001345 fill(AccessorType(bias), 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001346
1347 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001348 ITensorPack reshape_lhs_pack = { { ACL_SRC, &lhs }, { ACL_DST, &lhs_reshaped } };
1349 reshape_lhs.run(reshape_lhs_pack);
1350 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1351 reshape_rhs.run(reshape_rhs_pack);
1352 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs_reshaped },
1353 { ACL_SRC_1, &rhs_reshaped },
1354 { ACL_SRC_2, &bias },
1355 { ACL_DST, &dst }
1356 });
1357 gemm.run(gemm_pack);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001358
1359 return dst;
1360 }
1361
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001362 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 +01001363 const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001364 {
1365 TensorShape dst_shape = lhs_shape;
1366 dst_shape.set(0, rhs_shape[0]);
1367 dst_shape.set(1, lhs_shape[1] / m_h);
1368 dst_shape.set(2, m_h);
1369 dst_shape.set(3, lhs_shape[2]);
1370
1371 // Create reference
1372 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1373 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001374 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1375
1376 const int n = rhs_shape[0];
1377 const int m = lhs_shape[1];
1378 const int batch_size = lhs_shape[2];
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001379
1380 // Fill reference
1381 fill(lhs, 0);
1382 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001383 fill(bias, 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001384
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00001385 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001386 for(int i = 1; i < m * batch_size; i++)
1387 {
1388 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1389 }
1390
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +01001391 if(fp_mixed_precision)
1392 {
1393 return reference::activation_layer(reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta), act_info);
1394 }
1395 else
1396 {
1397 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
1398 }
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001399 }
1400
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001401 bool validate_result = true;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001402 TensorType _target{};
1403 SimpleTensor<T> _reference{};
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +00001404};
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001405
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001406template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001407class GEMMMatrixMultiplyReshapedOnlyRHSValidationFixture : public framework::Fixture
1408{
1409public:
1410 template <typename...>
1411 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 +01001412 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 +00001413 {
1414 GEMMLHSMatrixInfo lhs_info;
1415 lhs_info.m0 = m0;
1416 lhs_info.k0 = k0;
1417
1418 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodice781cba72020-06-19 16:56:57 +01001419 rhs_info.n0 = n0;
1420 rhs_info.k0 = k0;
1421 rhs_info.h0 = h0;
1422 rhs_info.interleave = interleave_rhs;
1423 rhs_info.transpose = transpose_rhs;
1424 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001425
1426 // Set the tensor shapes for LHS and RHS matrices
1427 const TensorShape lhs_shape(k, m, batch_size);
1428 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001429 const TensorShape bias_shape(n,
1430 broadcast_bias ? 1 : m,
1431 broadcast_bias ? 1 : batch_size);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001432
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001433 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
1434 if(validate_result)
1435 {
1436 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
1437 }
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001438 }
1439
1440protected:
1441 template <typename U>
1442 void fill(U &&tensor, int i)
1443 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001444 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 +00001445 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 +00001446
1447 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001448 library->fill(tensor, distribution, i);
1449
1450 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001451 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001452 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1453 }
1454
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001455 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 +01001456 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001457 {
1458 // Create tensors
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001459 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1460 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1461 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001462 TensorType rhs_reshaped;
1463 TensorType dst;
1464
1465 const unsigned int M = lhs_shape[1];
1466 const unsigned int N = rhs_shape[0];
1467 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001468 GEMMKernelInfo kernel_info;
1469 kernel_info.m = M;
1470 kernel_info.n = N;
1471 kernel_info.k = K;
1472 kernel_info.depth_output_gemm3d = 0;
1473 kernel_info.reinterpret_input_as_3d = false;
1474 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001475 kernel_info.activation_info = act_info;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001476
1477 // The output tensor will be auto-initialized within the function
1478
1479 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001480 ReshapeRHSOperatorType reshape_rhs;
1481 GEMMOperatorType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001482
1483 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1484 validate_result = validate_result || !rhs_info.export_to_cl_image;
1485 if(!validate_result)
1486 {
1487 return nullptr;
1488 }
1489
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001490 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1491 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 +00001492
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001493 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1494 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1495 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001496
Georgios Pinitas3dca91b2021-04-13 13:35:58 +01001497 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +00001498 if(!rhs_info.export_to_cl_image)
1499 {
1500 add_padding_x({ &lhs, &rhs, &rhs_reshaped, &bias, &dst });
1501 }
1502
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001503 // Allocate tensors
1504 lhs.allocator()->allocate();
1505 rhs.allocator()->allocate();
1506 rhs_reshaped.allocator()->allocate();
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001507 bias.allocator()->allocate();
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001508 dst.allocator()->allocate();
1509
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001510 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1511 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1512 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1513 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1514 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001515
1516 // Fill tensors
1517 fill(AccessorType(lhs), 0);
1518 fill(AccessorType(rhs), 1);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001519 fill(AccessorType(bias), 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001520
1521 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001522 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1523 reshape_rhs.run(reshape_rhs_pack);
1524 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
1525 { ACL_SRC_1, &rhs_reshaped },
1526 { ACL_SRC_2, &bias },
1527 { ACL_DST, &dst }
1528 });
1529 gemm.run(gemm_pack);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001530
1531 return dst;
1532 }
1533
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001534 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001535 const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001536 {
1537 TensorShape dst_shape = lhs_shape;
1538 dst_shape[0] = rhs_shape[0];
1539 dst_shape[1] = lhs_shape[1];
1540
1541 // Create reference
1542 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1543 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001544 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1545
1546 const int n = rhs_shape[0];
1547 const int m = lhs_shape[1];
1548 const int batch_size = lhs_shape[2];
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001549
1550 // Fill reference
1551 fill(lhs, 0);
1552 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001553 fill(bias, 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001554
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001555 if(broadcast_bias)
1556 {
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00001557 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001558 for(int i = 1; i < m * batch_size; i++)
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001559 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001560 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001561 }
1562 }
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001563
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001564 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001565 }
1566
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001567 bool validate_result = true;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001568 TensorType _target{};
1569 SimpleTensor<T> _reference{};
1570};
1571
SiCongLiafa19722021-10-24 19:12:33 +01001572/** (EXPERIMENTAL_POST_OPS)*/
1573template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
1574class GEMMMatrixMultiplyReshapedOnlyRHSWithPostOpsValidationFixture : public framework::Fixture
1575{
1576public:
1577 using PostOpArgBroadcast = std::tuple<bool, bool, bool>; // Instruct fixture if we need broadcasting in dimension 0, 1, 2 of each PostOp argument
1578 template <typename...>
1579 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,
1580 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,
1581 const experimental::PostOpList<PostOpArgBroadcast> &post_ops)
1582 {
1583 GEMMLHSMatrixInfo lhs_info;
1584 lhs_info.m0 = m0;
1585 lhs_info.k0 = k0;
1586
1587 GEMMRHSMatrixInfo rhs_info;
1588 rhs_info.n0 = n0;
1589 rhs_info.k0 = k0;
1590 rhs_info.h0 = h0;
1591 rhs_info.interleave = interleave_rhs;
1592 rhs_info.transpose = transpose_rhs;
1593 rhs_info.export_to_cl_image = export_to_cl_image;
1594
1595 // Set the tensor shapes for LHS and RHS matrices
1596 const TensorShape lhs_shape(k, m, batch_size);
1597 const TensorShape rhs_shape(n, k, batch_size);
1598 const TensorShape bias_shape(n,
1599 broadcast_bias ? 1 : m,
1600 broadcast_bias ? 1 : batch_size);
1601 auto post_ops_with_shapes = experimental::transform_post_op_list_arguments<PostOpArgBroadcast, TensorShape>(post_ops,
1602 [ = ](auto broadcast)
1603 {
1604 return TensorShape
1605 {
1606 std::get<0>(broadcast) ? 1 : n,
1607 std::get<1>(broadcast) ? 1 : m,
1608 std::get<2>(broadcast) ? 1 : batch_size,
1609 };
1610 });
1611
1612 _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);
1613 if(validate_result)
1614 {
1615 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info, post_ops_with_shapes);
1616 }
1617 }
1618
1619protected:
1620 template <typename U>
1621 void fill(U &&tensor, int i)
1622 {
1623 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
1624 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;
1625
1626 DistributionType distribution{ T(-1.0f), T(1.0f) };
1627 library->fill(tensor, distribution, i);
1628
1629 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
1630 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
1631 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1632 }
1633
1634 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
1635 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info, const experimental::PostOpList<TensorShape> &post_ops)
1636 {
1637 // Create tensors
1638 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1639 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1640 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
1641 TensorType rhs_reshaped;
1642 TensorType dst;
1643 // Create post op tensors and populate post op with them
1644 std::vector<TensorType> post_op_tensors_holder{};
1645 auto populated_post_ops = experimental::transform_post_op_list_arguments<TensorShape, ITensorInfo *>(post_ops,
1646 [&post_op_tensors_holder, &data_type](auto shape)
1647 {
1648 auto t = create_tensor<TensorType>(shape, data_type, 1);
1649 post_op_tensors_holder.push_back(std::move(t));
1650 return post_op_tensors_holder.back().info();
1651 });
1652
1653 const unsigned int M = lhs_shape[1];
1654 const unsigned int N = rhs_shape[0];
1655 const unsigned int K = lhs_shape[0];
1656 GEMMKernelInfo kernel_info;
1657 kernel_info.m = M;
1658 kernel_info.n = N;
1659 kernel_info.k = K;
1660 kernel_info.depth_output_gemm3d = 0;
1661 kernel_info.reinterpret_input_as_3d = false;
1662 kernel_info.broadcast_bias = broadcast_bias;
1663 kernel_info.activation_info = act_info;
1664 kernel_info.post_ops = populated_post_ops;
1665
1666 // The output tensor will be auto-initialized within the function
1667
1668 // Create and configure function
1669 ReshapeRHSOperatorType reshape_rhs;
1670 GEMMOperatorType gemm;
1671
1672 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1673 validate_result = validate_result || !rhs_info.export_to_cl_image;
1674 if(!validate_result)
1675 {
1676 return nullptr;
1677 }
1678
1679 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1680 gemm.configure(lhs.info(), rhs_reshaped.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
1681
1682 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1683 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1684 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
1685 for(const auto &tensor : post_op_tensors_holder)
1686 {
1687 ARM_COMPUTE_ASSERT(tensor.info()->is_resizable());
1688 }
1689
1690 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
1691 if(!rhs_info.export_to_cl_image)
1692 {
1693 add_padding_x({ &lhs, &rhs, &rhs_reshaped, &bias, &dst });
1694 for(auto &tensor : post_op_tensors_holder)
1695 {
1696 add_padding_x({ &tensor });
1697 }
1698 }
1699
1700 // Allocate tensors
1701 lhs.allocator()->allocate();
1702 rhs.allocator()->allocate();
1703 rhs_reshaped.allocator()->allocate();
1704 bias.allocator()->allocate();
1705 dst.allocator()->allocate();
1706 for(auto &tensor : post_op_tensors_holder)
1707 {
1708 tensor.allocator()->allocate();
1709 }
1710
1711 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1712 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1713 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1714 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1715 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
1716 for(const auto &tensor : post_op_tensors_holder)
1717 {
1718 ARM_COMPUTE_ASSERT(!tensor.info()->is_resizable());
1719 }
1720
1721 // Fill tensors
1722 fill(AccessorType(lhs), 0);
1723 fill(AccessorType(rhs), 1);
1724 fill(AccessorType(bias), 2);
1725 for(size_t i = 0; i < post_op_tensors_holder.size(); ++i)
1726 {
1727 fill(AccessorType(post_op_tensors_holder.at(i)), 3 + i);
1728 }
1729
1730 // Compute GEMM
1731 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1732 reshape_rhs.run(reshape_rhs_pack);
1733 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
1734 { ACL_SRC_1, &rhs_reshaped },
1735 { ACL_SRC_2, &bias },
1736 { ACL_DST, &dst }
1737 });
1738 for(size_t i = 0; i < post_op_tensors_holder.size(); ++i)
1739 {
1740 gemm_pack.add_tensor(experimental::get_post_op_arg_type(i), &post_op_tensors_holder.at(i));
1741 }
1742 gemm.run(gemm_pack);
1743
1744 return dst;
1745 }
1746
1747 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
1748 const ActivationLayerInfo &act_info, const experimental::PostOpList<TensorShape> &post_ops)
1749 {
1750 TensorShape dst_shape = lhs_shape;
1751 dst_shape[0] = rhs_shape[0];
1752 dst_shape[1] = lhs_shape[1];
1753
1754 // Create reference
1755 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1756 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
1757 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1758 // Create post op tensors and populate post op with them
1759 auto populated_post_ops = experimental::transform_post_op_list_arguments<TensorShape, SimpleTensor<T>>(post_ops, [&data_type](auto shape)
1760 {
1761 return SimpleTensor<T> { shape, data_type, 1 };
1762 });
1763
1764 const int n = rhs_shape[0];
1765 const int m = lhs_shape[1];
1766 const int batch_size = lhs_shape[2];
1767
1768 // Fill reference
1769 int tensor_idx = 0;
1770 fill(lhs, tensor_idx++);
1771 fill(rhs, tensor_idx++);
1772 fill(bias, tensor_idx++);
1773 for(auto &op : populated_post_ops.get_list())
1774 {
1775 for(auto tensor : op->arguments())
1776 {
1777 fill(*tensor, tensor_idx++);
1778 }
1779 }
1780
1781 if(broadcast_bias)
1782 {
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00001783 // In case of broadcast, we need to simply copy the first into the following "M" ones
SiCongLiafa19722021-10-24 19:12:33 +01001784 for(int i = 1; i < m * batch_size; i++)
1785 {
1786 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1787 }
1788 }
1789
1790 SimpleTensor<T> out;
1791 out = reference::gemm<T>(lhs, rhs, bias, alpha, beta);
1792 // Ignore activation info if post ops are used instead
1793 if(populated_post_ops.size() > 0)
1794 {
1795 out = reference::post_ops<T>(out, populated_post_ops);
1796 }
1797 else
1798 {
1799 out = reference::activation_layer(out, act_info);
1800 }
1801 return out;
1802 }
1803
1804 bool validate_result = true;
1805 TensorType _target{};
1806 SimpleTensor<T> _reference{};
1807};
1808
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001809template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001810class GEMMMatrixMultiplyReshapedOnlyRHS3DValidationFixture : public framework::Fixture
1811{
1812public:
1813 template <typename...>
1814 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 +01001815 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 +01001816 {
1817 GEMMLHSMatrixInfo lhs_info;
1818 lhs_info.m0 = m0;
1819 lhs_info.k0 = k0;
1820
1821 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodice781cba72020-06-19 16:56:57 +01001822 rhs_info.n0 = n0;
1823 rhs_info.k0 = k0;
1824 rhs_info.h0 = h0;
1825 rhs_info.interleave = interleave_rhs;
1826 rhs_info.transpose = transpose_rhs;
1827 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001828
1829 // In case of GEMM3D, m is the product between m_w and m_h
1830 const unsigned int m = m_w * m_h;
1831
1832 // Set the tensor shapes for LHS and RHS matrices
1833 const TensorShape lhs_shape(k, m, batch_size);
1834 const TensorShape rhs_shape(n, k, batch_size);
1835 const TensorShape bias_shape(n, 1, 1);
1836
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001837 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info, has_pad_y);
1838 if(validate_result)
1839 {
1840 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
1841 }
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001842 }
1843
1844protected:
1845 template <typename U>
1846 void fill(U &&tensor, int i)
1847 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001848 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 +00001849 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 +00001850
1851 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001852 library->fill(tensor, distribution, i);
1853 }
1854
1855 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
1856 DataType data_type, float alpha, float beta,
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001857 unsigned int m_h, const ActivationLayerInfo &act_info, bool has_pad_y)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001858 {
1859 // Create tensors
1860 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1861 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1862 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
1863 TensorType rhs_reshaped;
1864 TensorType dst;
1865
1866 const unsigned int M = lhs_shape[1];
1867 const unsigned int N = rhs_shape[0];
1868 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001869 GEMMKernelInfo kernel_info;
1870 kernel_info.m = M;
1871 kernel_info.n = N;
1872 kernel_info.k = K;
1873 kernel_info.depth_output_gemm3d = m_h;
1874 kernel_info.reinterpret_input_as_3d = false;
1875 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001876 kernel_info.activation_info = act_info;
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001877 kernel_info.has_pad_y = has_pad_y;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001878
1879 // The output tensor will be auto-initialized within the function
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001880 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001881 ReshapeRHSOperatorType reshape_rhs;
1882 GEMMOperatorType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001883
1884 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1885 validate_result = validate_result || !rhs_info.export_to_cl_image;
1886 if(!validate_result)
1887 {
1888 return nullptr;
1889 }
1890
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001891 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
1892 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 +01001893
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001894 if(has_pad_y)
1895 {
1896 // Add dummy padding into lhs to validate has_pad_y path
1897 lhs.info()->extend_padding(PaddingSize(2, 0, 2, 0));
1898 dst.info()->extend_padding(PaddingSize(2, 0, 1, 0));
1899 }
1900
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001901 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
1902 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
1903 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001904
Georgios Pinitas3dca91b2021-04-13 13:35:58 +01001905 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +00001906 if(!rhs_info.export_to_cl_image)
1907 {
1908 add_padding_x({ &lhs, &rhs, &rhs_reshaped, &bias, &dst });
1909 }
1910
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001911 // Allocate tensors
1912 lhs.allocator()->allocate();
1913 rhs.allocator()->allocate();
1914 rhs_reshaped.allocator()->allocate();
1915 bias.allocator()->allocate();
1916 dst.allocator()->allocate();
1917
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01001918 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
1919 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
1920 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
1921 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
1922 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001923
1924 // Fill tensors
1925 fill(AccessorType(lhs), 0);
1926 fill(AccessorType(rhs), 1);
1927 fill(AccessorType(bias), 2);
1928
1929 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001930 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
1931 reshape_rhs.run(reshape_rhs_pack);
1932 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
1933 { ACL_SRC_1, &rhs_reshaped },
1934 { ACL_SRC_2, &bias },
1935 { ACL_DST, &dst }
1936 });
1937 gemm.run(gemm_pack);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001938
1939 return dst;
1940 }
1941
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001942 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 +01001943 const ActivationLayerInfo &act_info)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001944 {
1945 TensorShape dst_shape = lhs_shape;
1946 dst_shape.set(0, rhs_shape[0]);
1947 dst_shape.set(1, lhs_shape[1] / m_h);
1948 dst_shape.set(2, m_h);
1949 dst_shape.set(3, lhs_shape[2]);
1950
1951 // Create reference
1952 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1953 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
1954 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1955
1956 const int n = rhs_shape[0];
1957 const int m = lhs_shape[1];
1958 const int batch_size = lhs_shape[2];
1959
1960 // Fill reference
1961 fill(lhs, 0);
1962 fill(rhs, 1);
1963 fill(bias, 2);
1964
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00001965 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001966 for(int i = 1; i < m * batch_size; i++)
1967 {
1968 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1969 }
1970
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001971 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001972 }
1973
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001974 bool validate_result = true;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001975 TensorType _target{};
1976 SimpleTensor<T> _reference{};
1977};
1978
Georgios Pinitas856f66e2021-04-22 21:13:21 +01001979template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
giuros01b3204e72019-04-01 13:50:22 +01001980class GEMMMatrixMultiplyNativeValidationFixture : public framework::Fixture
1981{
1982public:
1983 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001984 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,
1985 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001986 {
1987 GEMMLHSMatrixInfo lhs_info;
1988 lhs_info.m0 = m0;
1989 lhs_info.k0 = k0;
1990
1991 GEMMRHSMatrixInfo rhs_info;
1992 rhs_info.n0 = n0;
1993 rhs_info.k0 = k0;
1994
1995 // Set the tensor shapes for LHS and RHS matrices
1996 const TensorShape lhs_shape(k, m, batch_size);
1997 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001998 const TensorShape bias_shape(n,
1999 broadcast_bias ? 1 : m,
2000 broadcast_bias ? 1 : batch_size);
giuros01b3204e72019-04-01 13:50:22 +01002001
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01002002 _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 +01002003 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
giuros01b3204e72019-04-01 13:50:22 +01002004 }
2005
2006protected:
2007 template <typename U>
2008 void fill(U &&tensor, int i)
2009 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00002010 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 +00002011 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 +00002012
2013 DistributionType distribution{ T(-1.0f), T(1.0f) };
giuros01b3204e72019-04-01 13:50:22 +01002014 library->fill(tensor, distribution, i);
2015
2016 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +00002017 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
giuros01b3204e72019-04-01 13:50:22 +01002018 library->fill_borders_with_garbage(tensor, distribution_inf, i);
2019 }
2020
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002021 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 +01002022 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01002023 {
2024 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002025 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
2026 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
2027 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01002028 TensorType dst;
2029
2030 const unsigned int M = lhs_shape[1];
2031 const unsigned int N = rhs_shape[0];
2032 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01002033 GEMMKernelInfo kernel_info;
2034 kernel_info.m = M;
2035 kernel_info.n = N;
2036 kernel_info.k = K;
2037 kernel_info.depth_output_gemm3d = 0;
2038 kernel_info.reinterpret_input_as_3d = false;
2039 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01002040 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01002041
2042 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01002043 GEMMOperatorType gemm;
2044 gemm.configure(lhs.info(), rhs.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01002045
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01002046 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
2047 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
2048 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
giuros01b3204e72019-04-01 13:50:22 +01002049
Giorgio Arena63825e82021-03-25 14:54:50 +00002050 add_padding_x({ &lhs, &rhs, &bias, &dst });
2051
giuros01b3204e72019-04-01 13:50:22 +01002052 // Allocate tensors
2053 lhs.allocator()->allocate();
2054 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002055 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01002056 dst.allocator()->allocate();
2057
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01002058 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
2059 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
2060 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
2061 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
giuros01b3204e72019-04-01 13:50:22 +01002062
2063 // Fill tensors
2064 fill(AccessorType(lhs), 0);
2065 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002066 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01002067
2068 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01002069 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
2070 { ACL_SRC_1, &rhs },
2071 { ACL_SRC_2, &bias },
2072 { ACL_DST, &dst }
2073 });
2074 gemm.run(gemm_pack);
giuros01b3204e72019-04-01 13:50:22 +01002075
2076 return dst;
2077 }
2078
Michalis Spyrou6bff1952019-10-02 17:22:11 +01002079 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 +01002080 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01002081 {
2082 TensorShape dst_shape = lhs_shape;
2083 dst_shape[0] = rhs_shape[0];
2084 dst_shape[1] = lhs_shape[1];
2085
2086 // Create reference
2087 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
2088 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002089 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
2090
2091 const int n = rhs_shape[0];
2092 const int m = lhs_shape[1];
2093 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01002094
2095 // Fill reference
2096 fill(lhs, 0);
2097 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002098 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01002099
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002100 if(broadcast_bias)
2101 {
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00002102 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002103 for(int i = 1; i < m * batch_size; i++)
2104 {
2105 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
2106 }
2107 }
2108
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01002109 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01002110 }
2111
2112 TensorType _target{};
2113 SimpleTensor<T> _reference{};
2114};
2115
Georgios Pinitas856f66e2021-04-22 21:13:21 +01002116template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
SiCongLiafa19722021-10-24 19:12:33 +01002117class GEMMMatrixMultiplyNativeWithPostOpsValidationFixture : public framework::Fixture
2118{
2119public:
2120 using PostOpArgBroadcast = std::tuple<bool, bool, bool>; // Instruct fixture if we need broadcasting in dimension 0, 1, 2 of each PostOp argument
2121public:
2122 template <typename...>
2123 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,
2124 const ActivationLayerInfo &act_info, const experimental::PostOpList<PostOpArgBroadcast> &post_ops)
2125 {
2126 GEMMLHSMatrixInfo lhs_info;
2127 lhs_info.m0 = m0;
2128 lhs_info.k0 = k0;
2129
2130 GEMMRHSMatrixInfo rhs_info;
2131 rhs_info.n0 = n0;
2132 rhs_info.k0 = k0;
2133
2134 // Set the tensor shapes for LHS and RHS matrices
2135 const TensorShape lhs_shape(k, m, batch_size);
2136 const TensorShape rhs_shape(n, k, batch_size);
2137 const TensorShape bias_shape(n,
2138 broadcast_bias ? 1 : m,
2139 broadcast_bias ? 1 : batch_size);
2140 const auto post_ops_with_shapes = experimental::transform_post_op_list_arguments<PostOpArgBroadcast, TensorShape>(post_ops,
2141 [ = ](auto broadcast)
2142 {
2143 return TensorShape
2144 {
2145 std::get<0>(broadcast) ? 1 : n,
2146 std::get<1>(broadcast) ? 1 : m,
2147 std::get<2>(broadcast) ? 1 : batch_size,
2148 };
2149 });
2150
2151 _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);
2152 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info, post_ops_with_shapes);
2153 }
2154
2155protected:
2156 template <typename U>
2157 void fill(U &&tensor, int i)
2158 {
2159 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
2160 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;
2161
2162 DistributionType distribution{ T(-1.0f), T(1.0f) };
2163 library->fill(tensor, distribution, i);
2164
2165 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
2166 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
2167 library->fill_borders_with_garbage(tensor, distribution_inf, i);
2168 }
2169
2170 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
2171 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info, const experimental::PostOpList<TensorShape> &post_ops)
2172 {
2173 // Create tensors
2174 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
2175 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
2176 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
2177 TensorType dst;
2178 // Create post op tensors and populate post op with them
2179 std::vector<TensorType> post_op_tensors_holder{};
2180 auto populated_post_ops = experimental::transform_post_op_list_arguments<TensorShape, ITensorInfo *>(post_ops,
2181 [&post_op_tensors_holder, &data_type](auto shape)
2182 {
2183 auto t = create_tensor<TensorType>(shape, data_type, 1);
2184 post_op_tensors_holder.push_back(std::move(t));
2185 return post_op_tensors_holder.back().info();
2186 });
2187
2188 const unsigned int M = lhs_shape[1];
2189 const unsigned int N = rhs_shape[0];
2190 const unsigned int K = lhs_shape[0];
2191 GEMMKernelInfo kernel_info;
2192 kernel_info.m = M;
2193 kernel_info.n = N;
2194 kernel_info.k = K;
2195 kernel_info.depth_output_gemm3d = 0;
2196 kernel_info.reinterpret_input_as_3d = false;
2197 kernel_info.broadcast_bias = broadcast_bias;
2198 kernel_info.activation_info = act_info;
2199 kernel_info.post_ops = populated_post_ops;
2200
2201 // Create and configure function
2202 GEMMOperatorType gemm;
2203 gemm.configure(lhs.info(), rhs.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
2204
2205 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
2206 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
2207 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
2208 for(const auto &tensor : post_op_tensors_holder)
2209 {
2210 ARM_COMPUTE_ASSERT(tensor.info()->is_resizable());
2211 }
2212
2213 add_padding_x({ &lhs, &rhs, &bias, &dst });
2214 for(auto &tensor : post_op_tensors_holder)
2215 {
2216 add_padding_x({ &tensor });
2217 }
2218
2219 // Allocate tensors
2220 lhs.allocator()->allocate();
2221 rhs.allocator()->allocate();
2222 bias.allocator()->allocate();
2223 dst.allocator()->allocate();
2224 for(auto &tensor : post_op_tensors_holder)
2225 {
2226 tensor.allocator()->allocate();
2227 }
2228
2229 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
2230 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
2231 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
2232 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
2233 for(const auto &tensor : post_op_tensors_holder)
2234 {
2235 ARM_COMPUTE_ASSERT(!tensor.info()->is_resizable());
2236 }
2237
2238 // Fill tensors
2239 fill(AccessorType(lhs), 0);
2240 fill(AccessorType(rhs), 1);
2241 fill(AccessorType(bias), 2);
2242 for(size_t i = 0; i < post_op_tensors_holder.size(); ++i)
2243 {
2244 fill(AccessorType(post_op_tensors_holder.at(i)), 3 + i);
2245 }
2246
2247 // Compute GEMM
2248 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
2249 { ACL_SRC_1, &rhs },
2250 { ACL_SRC_2, &bias },
2251 { ACL_DST, &dst }
2252 });
2253 for(size_t i = 0; i < post_op_tensors_holder.size(); ++i)
2254 {
2255 gemm_pack.add_tensor(experimental::get_post_op_arg_type(i), &post_op_tensors_holder.at(i));
2256 }
2257 gemm.run(gemm_pack);
2258
2259 return dst;
2260 }
2261
2262 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
2263 const ActivationLayerInfo &act_info, const experimental::PostOpList<TensorShape> &post_ops)
2264 {
2265 TensorShape dst_shape = lhs_shape;
2266 dst_shape[0] = rhs_shape[0];
2267 dst_shape[1] = lhs_shape[1];
2268
2269 // Create reference
2270 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
2271 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
2272 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
2273 // Create post op tensors and populate post op with them
2274 auto populated_post_ops = experimental::transform_post_op_list_arguments<TensorShape, SimpleTensor<T>>(post_ops, [&data_type](auto shape)
2275 {
2276 return SimpleTensor<T> { shape, data_type, 1 };
2277 });
2278
2279 const int n = rhs_shape[0];
2280 const int m = lhs_shape[1];
2281 const int batch_size = lhs_shape[2];
2282
2283 // Fill reference
2284 int tensor_idx = 0;
2285 fill(lhs, tensor_idx++);
2286 fill(rhs, tensor_idx++);
2287 fill(bias, tensor_idx++);
2288 for(auto &op : populated_post_ops.get_list())
2289 {
2290 for(auto tensor : op->arguments())
2291 {
2292 fill(*tensor, tensor_idx++);
2293 }
2294 }
2295
2296 if(broadcast_bias)
2297 {
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00002298 // In case of broadcast, we need to simply copy the first into the following "M" ones
SiCongLiafa19722021-10-24 19:12:33 +01002299 for(int i = 1; i < m * batch_size; i++)
2300 {
2301 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
2302 }
2303 }
2304
2305 SimpleTensor<T> out;
2306 out = reference::gemm<T>(lhs, rhs, bias, alpha, beta);
2307 // Ignore activation info if post ops are used instead
2308 if(populated_post_ops.size() > 0)
2309 {
2310 out = reference::post_ops<T>(out, populated_post_ops);
2311 }
2312 else
2313 {
2314 out = reference::activation_layer(out, act_info);
2315 }
2316 return out;
2317 }
2318
2319 TensorType _target{};
2320 SimpleTensor<T> _reference{};
2321};
2322
2323template <typename TensorType, typename AccessorType, typename T, typename GEMMOperatorType>
giuros01b3204e72019-04-01 13:50:22 +01002324class GEMMMatrixMultiplyNative3DValidationFixture : public framework::Fixture
2325{
2326public:
2327 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01002328 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,
2329 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01002330 {
2331 GEMMLHSMatrixInfo lhs_info;
2332 lhs_info.m0 = m0;
2333 lhs_info.k0 = k0;
2334
2335 GEMMRHSMatrixInfo rhs_info;
2336 rhs_info.n0 = n0;
2337 rhs_info.k0 = k0;
2338
2339 // In case of GEMM3D, m is the product between m_w and m_h
2340 const unsigned int m = m_w * m_h;
2341
2342 // Set the tensor shapes for LHS and RHS matrices
2343 const TensorShape lhs_shape(k, m, batch_size);
2344 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002345 const TensorShape bias_shape(n, 1, 1);
giuros01b3204e72019-04-01 13:50:22 +01002346
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01002347 _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 +01002348 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
giuros01b3204e72019-04-01 13:50:22 +01002349 }
2350
2351protected:
2352 template <typename U>
2353 void fill(U &&tensor, int i)
2354 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00002355 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 +00002356 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 +00002357
2358 DistributionType distribution{ T(-1.0f), T(1.0f) };
giuros01b3204e72019-04-01 13:50:22 +01002359 library->fill(tensor, distribution, i);
2360 }
2361
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002362 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 +01002363 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01002364 {
2365 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002366 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
2367 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
2368 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01002369 TensorType dst;
2370
2371 const unsigned int M = lhs_shape[1];
2372 const unsigned int N = rhs_shape[0];
2373 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01002374 GEMMKernelInfo kernel_info;
2375 kernel_info.m = M;
2376 kernel_info.n = N;
2377 kernel_info.k = K;
2378 kernel_info.depth_output_gemm3d = m_h;
2379 kernel_info.reinterpret_input_as_3d = false;
2380 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01002381 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01002382
2383 // The output tensor will be auto-initialized within the function
2384
2385 // Create and configure function
Georgios Pinitas856f66e2021-04-22 21:13:21 +01002386 GEMMOperatorType gemm;
2387 gemm.configure(lhs.info(), rhs.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01002388
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01002389 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
2390 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
2391 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
giuros01b3204e72019-04-01 13:50:22 +01002392
Giorgio Arena63825e82021-03-25 14:54:50 +00002393 add_padding_x({ &lhs, &rhs, &bias, &dst });
2394
giuros01b3204e72019-04-01 13:50:22 +01002395 // Allocate tensors
2396 lhs.allocator()->allocate();
2397 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002398 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01002399 dst.allocator()->allocate();
2400
Michele Di Giorgio4fc10b32021-04-30 18:30:41 +01002401 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
2402 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
2403 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
2404 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
giuros01b3204e72019-04-01 13:50:22 +01002405
2406 // Fill tensors
2407 fill(AccessorType(lhs), 0);
2408 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002409 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01002410
2411 // Compute GEMM
Georgios Pinitas856f66e2021-04-22 21:13:21 +01002412 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
2413 { ACL_SRC_1, &rhs },
2414 { ACL_SRC_2, &bias },
2415 { ACL_DST, &dst }
2416 });
2417 gemm.run(gemm_pack);
giuros01b3204e72019-04-01 13:50:22 +01002418
2419 return dst;
2420 }
2421
Michalis Spyrou6bff1952019-10-02 17:22:11 +01002422 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 +01002423 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01002424 {
2425 TensorShape dst_shape = lhs_shape;
2426 dst_shape.set(0, rhs_shape[0]);
2427 dst_shape.set(1, lhs_shape[1] / m_h);
2428 dst_shape.set(2, m_h);
2429 dst_shape.set(3, lhs_shape[2]);
2430
2431 // Create reference
2432 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
2433 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002434 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
2435
2436 const int n = rhs_shape[0];
2437 const int m = lhs_shape[1];
2438 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01002439
2440 // Fill reference
2441 fill(lhs, 0);
2442 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002443 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01002444
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00002445 // In case of broadcast, we need to simply copy the first into the following "M" ones
Gian Marco Iodice944170e2019-06-24 14:40:30 +01002446 for(int i = 1; i < m * batch_size; i++)
2447 {
2448 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
2449 }
2450
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01002451 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01002452 }
2453
2454 TensorType _target{};
2455 SimpleTensor<T> _reference{};
2456};
2457
Gunes Bayir4bfc70e2021-12-10 16:17:56 +00002458template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSOperatorType, typename GEMMOperatorType>
2459class GEMMMatrixMultiplyReshapedOnlyRhsMMULValidationFixture : public framework::Fixture
2460{
2461public:
2462 template <typename...>
2463 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,
2464 float beta, bool broadcast_bias,
2465 const ActivationLayerInfo &act_info)
2466 {
2467 GEMMLHSMatrixInfo lhs_info;
2468 lhs_info.m0 = m0;
2469 lhs_info.k0 = k0;
2470
2471 GEMMRHSMatrixInfo rhs_info;
2472 rhs_info.n0 = n0;
2473 rhs_info.k0 = k0;
2474 rhs_info.interleave = true;
2475 rhs_info.transpose = false;
2476 rhs_info.h0 = 4;
2477 rhs_info.export_to_cl_image = export_to_cl_image;
2478
2479 // Set the tensor shapes for LHS and RHS matrices
2480 const TensorShape lhs_shape(k, m, batch_size);
2481 const TensorShape rhs_shape(n, k, batch_size);
2482 const TensorShape bias_shape(n,
2483 broadcast_bias ? 1 : m,
2484 broadcast_bias ? 1 : batch_size);
2485
2486 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
2487 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
2488 }
2489
2490protected:
2491 template <typename U>
2492 void fill(U &&tensor, int i)
2493 {
2494 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
2495 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;
2496
2497 DistributionType distribution{ T(-1.0f), T(1.0f) };
2498 library->fill(tensor, distribution, i);
2499
2500 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
2501 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
2502 library->fill_borders_with_garbage(tensor, distribution_inf, i);
2503 }
2504
2505 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
2506 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
2507 {
2508 // Create tensors
2509 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
2510 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
2511 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
2512 TensorType rhs_reshaped;
2513 TensorType dst;
2514
2515 const unsigned int M = lhs_shape[1];
2516 const unsigned int N = rhs_shape[0];
2517 const unsigned int K = lhs_shape[0];
2518 GEMMKernelInfo kernel_info;
2519 kernel_info.m = M;
2520 kernel_info.n = N;
2521 kernel_info.k = K;
2522 kernel_info.depth_output_gemm3d = 0;
2523 kernel_info.reinterpret_input_as_3d = false;
2524 kernel_info.broadcast_bias = broadcast_bias;
2525 kernel_info.activation_info = act_info;
2526
2527 // Create and configure function
2528 ReshapeRHSOperatorType reshape_rhs;
2529 GEMMOperatorType gemm;
2530
2531 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
2532 if(!validate_result)
2533 {
2534 return nullptr;
2535 }
2536
2537 reshape_rhs.configure(rhs.info(), rhs_reshaped.info(), rhs_info);
2538
2539 validate_result = bool(gemm.validate(lhs.info(), rhs_reshaped.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info));
2540 if(!validate_result)
2541 {
2542 return nullptr;
2543 }
2544
2545 gemm.configure(lhs.info(), rhs_reshaped.info(), bias.info(), dst.info(), alpha, beta, lhs_info, rhs_info, kernel_info);
2546
2547 ARM_COMPUTE_ASSERT(lhs.info()->is_resizable());
2548 ARM_COMPUTE_ASSERT(rhs.info()->is_resizable());
2549 ARM_COMPUTE_ASSERT(bias.info()->is_resizable());
2550
2551 // Allocate tensors
2552 lhs.allocator()->allocate();
2553 rhs.allocator()->allocate();
2554 rhs_reshaped.allocator()->allocate();
2555 bias.allocator()->allocate();
2556 dst.allocator()->allocate();
2557
2558 ARM_COMPUTE_ASSERT(!lhs.info()->is_resizable());
2559 ARM_COMPUTE_ASSERT(!rhs.info()->is_resizable());
2560 ARM_COMPUTE_ASSERT(!rhs_reshaped.info()->is_resizable());
2561 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable());
2562 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable());
2563
2564 // Fill tensors
2565 fill(AccessorType(lhs), 0);
2566 fill(AccessorType(rhs), 1);
2567 fill(AccessorType(bias), 2);
2568
2569 // Compute GEMM
2570 ITensorPack reshape_rhs_pack = { { ACL_SRC, &rhs }, { ACL_DST, &rhs_reshaped } };
2571 reshape_rhs.run(reshape_rhs_pack);
2572 ITensorPack gemm_pack({ { ACL_SRC_0, &lhs },
2573 { ACL_SRC_1, &rhs_reshaped },
2574 { ACL_SRC_2, &bias },
2575 { ACL_DST, &dst }
2576 });
2577 gemm.run(gemm_pack);
2578
2579 return dst;
2580 }
2581
2582 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
2583 const ActivationLayerInfo &act_info)
2584 {
2585 if(!validate_result)
2586 return SimpleTensor<T>();
2587
2588 TensorShape dst_shape = lhs_shape;
2589 dst_shape[0] = rhs_shape[0];
2590 dst_shape[1] = lhs_shape[1];
2591
2592 // Create reference
2593 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
2594 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
2595 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
2596
2597 const int n = rhs_shape[0];
2598 const int m = lhs_shape[1];
2599 const int batch_size = lhs_shape[2];
2600
2601 // Fill reference
2602 fill(lhs, 0);
2603 fill(rhs, 1);
2604 fill(bias, 2);
2605
2606 if(broadcast_bias)
2607 {
2608 // In case of broadcast, we need to simply copy the first into the following "M" ones
2609 for(int i = 1; i < m * batch_size; i++)
2610 {
2611 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
2612 }
2613 }
2614
2615 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
2616 }
2617
2618 bool validate_result = true;
2619 TensorType _target{};
2620 SimpleTensor<T> _reference{};
2621};
2622
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +01002623} // namespace validation
2624} // namespace test
2625} // namespace arm_compute
2626#endif /* ARM_COMPUTE_TEST_GEMM_FIXTURE */