blob: 868eed48147af230269dd56d72186ae58047d30d [file] [log] [blame]
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +01001/*
Giorgio Arenab309fc22021-01-05 09:46:16 +00002 * Copyright (c) 2017-2021 Arm Limited.
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +01003 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24#ifndef ARM_COMPUTE_TEST_GEMM_FIXTURE
25#define ARM_COMPUTE_TEST_GEMM_FIXTURE
26
Gian Marco Iodice7026b302019-06-26 17:18:11 +010027#include "arm_compute/core/KernelDescriptors.h"
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010028#include "arm_compute/core/TensorShape.h"
29#include "arm_compute/core/Types.h"
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010030#include "tests/AssetsLibrary.h"
31#include "tests/Globals.h"
32#include "tests/IAccessor.h"
Moritz Pflanzera09de0c2017-09-01 20:41:12 +010033#include "tests/framework/Asserts.h"
34#include "tests/framework/Fixture.h"
Moritz Pflanzera09de0c2017-09-01 20:41:12 +010035#include "tests/validation/Helpers.h"
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +010036#include "tests/validation/reference/ActivationLayer.h"
Georgios Pinitas5a7e7762017-12-01 16:27:29 +000037#include "tests/validation/reference/GEMM.h"
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010038
39#include <random>
40
41namespace arm_compute
42{
43namespace test
44{
45namespace validation
46{
Gian Marco Iodicef3622be2019-07-29 14:27:16 +010047template <typename TensorType, typename AccessorType, typename FunctionType, typename T, bool disable_c = false, bool reinterpret_input_as_3d = false, bool reinterpret_output_as_3d = false>
Gian Marco Iodice68a3f562018-07-26 11:44:03 +010048class GEMMValidationFixture : public framework::Fixture
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010049{
50public:
51 template <typename...>
Pablo Tello0e37b5c2018-10-30 11:18:37 +000052 void setup(TensorShape shape_a, TensorShape shape_b, TensorShape shape_c, TensorShape output_shape, float alpha, float beta, bool pretranspose, DataType data_type)
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010053 {
Michalis Spyrou6bff1952019-10-02 17:22:11 +010054 ARM_COMPUTE_UNUSED(pretranspose);
55 _target = compute_target(shape_a, shape_b, shape_c, output_shape, alpha, beta, data_type);
56 _reference = compute_reference(shape_a, shape_b, output_shape, alpha, beta, data_type);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010057 }
58
59protected:
60 template <typename U>
Pablo Tello0e37b5c2018-10-30 11:18:37 +000061 void fill(U &&tensor, int i, float lo = -1.f, float hi = 1.f)
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010062 {
63 switch(tensor.data_type())
64 {
65 case DataType::F16:
Giorgio Arena6aeb2172020-12-15 15:45:43 +000066 {
Giorgio Arenaa8e2aeb2021-01-06 11:34:57 +000067 arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ float(lo), float(hi) };
Giorgio Arena6aeb2172020-12-15 15:45:43 +000068 library->fill(tensor, distribution, i);
69 break;
70 }
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010071 case DataType::F32:
72 {
Giorgio Arena6aeb2172020-12-15 15:45:43 +000073 std::uniform_real_distribution<float> distribution(lo, hi);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010074 library->fill(tensor, distribution, i);
75 break;
76 }
77 default:
78 library->fill_tensor_uniform(tensor, i);
79 }
80 }
81
82 TensorType compute_target(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &shape_c, const TensorShape &output_shape, float alpha, float beta,
Michalis Spyrou6bff1952019-10-02 17:22:11 +010083 DataType data_type)
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010084 {
85 // Create tensors
Vidhya Sudhan Loganathan014333d2018-07-02 09:13:49 +010086 TensorType a = create_tensor<TensorType>(shape_a, data_type, 1);
87 TensorType b = create_tensor<TensorType>(shape_b, data_type, 1);
88 TensorType c = create_tensor<TensorType>(shape_c, data_type, 1);
89 TensorType dst = create_tensor<TensorType>(output_shape, data_type, 1);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010090
91 // Create and configure function
92 FunctionType gemm;
Isabella Gottardi8e74f442018-03-01 16:42:00 +000093 // The GEMMinfo includes the values of the depth in case of reinterpreted 3d output.
Gian Marco Iodice3139f032018-11-05 14:26:32 +000094 // If the output shape has the same number of dimensions of the input the method called is a 2D matrix multiplication (depth_output_reinterpreted_as_3D = 0),
Isabella Gottardi8e74f442018-03-01 16:42:00 +000095 // in the other case we have to use the reinterpreted version of GEMM (depth_output_reinterpreted_as_3D = depth of the 3D output).
Gian Marco Iodicef3622be2019-07-29 14:27:16 +010096 gemm.configure(&a,
97 &b,
98 (disable_c) ? nullptr : &c,
99 &dst,
100 alpha, beta,
101 GEMMInfo(false, false, false, (reinterpret_output_as_3d ? output_shape[2] : 0), reinterpret_input_as_3d, false, GEMMLowpOutputStageInfo(), false, (reinterpret_input_as_3d
102 || reinterpret_output_as_3d)));
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100103 ARM_COMPUTE_EXPECT(a.info()->is_resizable(), framework::LogLevel::ERRORS);
104 ARM_COMPUTE_EXPECT(b.info()->is_resizable(), framework::LogLevel::ERRORS);
105 ARM_COMPUTE_EXPECT(c.info()->is_resizable(), framework::LogLevel::ERRORS);
106 ARM_COMPUTE_EXPECT(dst.info()->is_resizable(), framework::LogLevel::ERRORS);
107
Giorgio Arena63825e82021-03-25 14:54:50 +0000108 add_padding_x({ &a, &b, &c, &dst });
109
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100110 // Allocate tensors
111 a.allocator()->allocate();
112 b.allocator()->allocate();
113 c.allocator()->allocate();
114 dst.allocator()->allocate();
115
116 ARM_COMPUTE_EXPECT(!a.info()->is_resizable(), framework::LogLevel::ERRORS);
117 ARM_COMPUTE_EXPECT(!b.info()->is_resizable(), framework::LogLevel::ERRORS);
118 ARM_COMPUTE_EXPECT(!c.info()->is_resizable(), framework::LogLevel::ERRORS);
119 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
120
121 // Fill tensors
122 fill(AccessorType(a), 0);
123 fill(AccessorType(b), 1);
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000124 if(!disable_c)
125 {
126 fill(AccessorType(c), 2);
127 }
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100128
129 // Compute GEMM function
130 gemm.run();
131
132 return dst;
133 }
134
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100135 SimpleTensor<T> compute_reference(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &output_shape, float alpha, float beta,
Vidhya Sudhan Loganathan014333d2018-07-02 09:13:49 +0100136 DataType data_type)
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100137 {
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100138 TensorShape shape_a_to_use = shape_a;
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100139
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100140 if(reinterpret_input_as_3d)
141 {
142 // Collapse the second and third dimension if the input is 3D
143 shape_a_to_use.collapse(2U, 1U);
144 }
145
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100146 // Create reference
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100147 SimpleTensor<T> a{ shape_a_to_use, data_type, 1 };
Vidhya Sudhan Loganathan014333d2018-07-02 09:13:49 +0100148 SimpleTensor<T> b{ shape_b, data_type, 1 };
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100149 SimpleTensor<T> c{ output_shape, data_type, 1 };
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100150
151 // Fill reference
152 fill(a, 0);
153 fill(b, 1);
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100154 fill(c, 2);
155
156 if(reinterpret_input_as_3d || reinterpret_output_as_3d)
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000157 {
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100158 const int n = shape_b[0];
159 const int m = reinterpret_output_as_3d ? output_shape[1] * output_shape[2] : output_shape[1];
160 const int batch_size = reinterpret_output_as_3d ? output_shape[3] : output_shape[2];
161
162 // In case of broadcast, we need simply copy the first into the following "M" ones
163 for(int i = 1; i < m * batch_size; i++)
164 {
165 memcpy(c.data() + i * n, c.data(), n * sizeof(T));
166 }
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000167 }
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100168
169 // Setting beta to 0 will effectively disable C for the
170 // computation of the reference: alpha * A * B + 0 * C
171 return reference::gemm<T>(a, b, c, alpha, disable_c ? 0.f : beta);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100172 }
173
174 TensorType _target{};
175 SimpleTensor<T> _reference{};
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100176};
177
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100178template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
179class GEMMMatrixMultiplyValidationFixture : public framework::Fixture
180{
181public:
182 template <typename...>
183 void setup(unsigned int m, unsigned int n, unsigned int k, unsigned int batch_size, float alpha, float beta, bool broadcast_bias, bool fp16_mixed_precision, const ActivationLayerInfo &act_info,
184 DataType data_type, GPUTarget gpu_arch)
185 {
186 // Set the tensor shapes for LHS and RHS matrices
187 const TensorShape lhs_shape(k, m, batch_size);
188 const TensorShape rhs_shape(n, k, batch_size);
189 const TensorShape bias_shape(n,
190 broadcast_bias ? 1 : m,
191 broadcast_bias ? 1 : batch_size);
192
193 _target = compute_target(lhs_shape, rhs_shape, bias_shape, data_type, alpha, beta, broadcast_bias, fp16_mixed_precision, act_info, gpu_arch);
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100194 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100195 }
196
197protected:
198 template <typename U>
199 void fill(U &&tensor, int i)
200 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000201 static_assert(std::is_floating_point<T>::value || std::is_same<T, half>::value, "Only floating point data types supported.");
Giorgio Arena33b103b2021-01-08 10:37:15 +0000202 using DistributionType = typename std::conditional<std::is_same<T, half>::value, arm_compute::utils::uniform_real_distribution_16bit<T>, std::uniform_real_distribution<T>>::type;
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000203
204 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100205 library->fill(tensor, distribution, i);
206
207 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000208 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100209 library->fill_borders_with_garbage(tensor, distribution_inf, i);
210 }
211
212 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
213 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
214 {
215 // Create tensors
216 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
217 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
218 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
219 TensorType dst;
220
221 const unsigned int m = lhs_shape[1];
222 const unsigned int n = rhs_shape[0];
223 const unsigned int k = lhs_shape[0];
224 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, 0, false, broadcast_bias);
225
226 // The output tensor will be auto-initialized within the function
227
228 // Create and configure function
229 GEMMFunctionType gemm;
230 gemm.configure(gpu_arch, &lhs, &rhs, &bias, &dst, alpha, beta, false, reshape_info, fp16_mixed_precision, act_info);
231
232 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
233 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
234 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
235
Giorgio Arena63825e82021-03-25 14:54:50 +0000236 add_padding_x({ &lhs, &rhs, &bias, &dst });
237
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100238 // Allocate tensors
239 lhs.allocator()->allocate();
240 rhs.allocator()->allocate();
241 bias.allocator()->allocate();
242 dst.allocator()->allocate();
243
244 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
245 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
246 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
247 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
248
249 // Fill tensors
250 fill(AccessorType(lhs), 0);
251 fill(AccessorType(rhs), 1);
252 fill(AccessorType(bias), 2);
253
254 // Compute GEMM
255 gemm.run();
256
257 return dst;
258 }
259
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100260 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 +0100261 const ActivationLayerInfo &act_info)
262 {
263 TensorShape dst_shape = lhs_shape;
264 dst_shape[0] = rhs_shape[0];
265 dst_shape[1] = lhs_shape[1];
266
267 // Create reference
268 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
269 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
270 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
271
272 const int n = rhs_shape[0];
273 const int m = lhs_shape[1];
274 const int batch_size = lhs_shape[2];
275
276 // Fill reference
277 fill(lhs, 0);
278 fill(rhs, 1);
279 fill(bias, 2);
280
281 if(broadcast_bias)
282 {
283 // In case of broadcast, we need simply copy the first into the following "M" ones
284 for(int i = 1; i < m * batch_size; i++)
285 {
286 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
287 }
288 }
289
290 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
291 }
292
293 TensorType _target{};
294 SimpleTensor<T> _reference{};
295};
296
297template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
298class GEMMMatrixMultiply3DValidationFixture : public framework::Fixture
299{
300public:
301 template <typename...>
302 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,
303 const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
304 {
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100305 ARM_COMPUTE_UNUSED(broadcast_bias);
306
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100307 // In case of GEMM3D, m is the product between m_w and m_h
308 const unsigned int m = m_w * m_h;
309
310 // Set the tensor shapes for LHS and RHS matrices
311 const TensorShape lhs_shape(k, m, batch_size);
312 const TensorShape rhs_shape(n, k, batch_size);
313 const TensorShape bias_shape(n, 1, 1);
314
315 _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 +0100316 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100317 }
318
319protected:
320 template <typename U>
321 void fill(U &&tensor, int i)
322 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000323 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 +0000324 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 +0000325
326 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100327 library->fill(tensor, distribution, i);
328 }
329
330 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,
331 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
332 {
333 // Create tensors
334 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
335 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
336 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
337 TensorType dst;
338
339 const unsigned int m = lhs_shape[1];
340 const unsigned int n = rhs_shape[0];
341 const unsigned int k = lhs_shape[0];
342 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, m_h, false, true);
343
344 // The output tensor will be auto-initialized within the function
345
346 // Create and configure function
347 GEMMFunctionType gemm;
348 gemm.configure(gpu_arch, &lhs, &rhs, &bias, &dst, alpha, beta, false, reshape_info, fp16_mixed_precision, act_info);
349
350 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
351 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
352 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
353
Giorgio Arena63825e82021-03-25 14:54:50 +0000354 add_padding_x({ &lhs, &rhs, &bias, &dst });
355
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100356 // Allocate tensors
357 lhs.allocator()->allocate();
358 rhs.allocator()->allocate();
359 bias.allocator()->allocate();
360 dst.allocator()->allocate();
361
362 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
363 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
364 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
365 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
366
367 // Fill tensors
368 fill(AccessorType(lhs), 0);
369 fill(AccessorType(rhs), 1);
370 fill(AccessorType(bias), 2);
371
372 // Compute GEMM
373 gemm.run();
374
375 return dst;
376 }
377
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100378 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 +0100379 const ActivationLayerInfo &act_info)
380 {
381 TensorShape dst_shape = lhs_shape;
382 dst_shape.set(0, rhs_shape[0]);
383 dst_shape.set(1, lhs_shape[1] / m_h);
384 dst_shape.set(2, m_h);
385 dst_shape.set(3, lhs_shape[2]);
386
387 // Create reference
388 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
389 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
390 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
391
392 const int n = rhs_shape[0];
393 const int m = lhs_shape[1];
394 const int batch_size = lhs_shape[2];
395
396 // Fill reference
397 fill(lhs, 0);
398 fill(rhs, 1);
399 fill(bias, 2);
400
401 // In case of broadcast, we need simply copy the first into the following "M" ones
402 for(int i = 1; i < m * batch_size; i++)
403 {
404 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
405 }
406
407 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
408 }
409
410 TensorType _target{};
411 SimpleTensor<T> _reference{};
412};
413
414template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSFunctionType, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
415class GEMMMatrixMultiplyInterleavedTransposedValidationFixture : public framework::Fixture
416{
417public:
418 template <typename...>
419 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,
420 const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
421 {
422 GEMMLHSMatrixInfo lhs_info;
423 lhs_info.m0 = 4;
424 lhs_info.k0 = 4;
425 lhs_info.v0 = v0;
426 lhs_info.interleave = true;
427 lhs_info.transpose = true;
428
429 GEMMRHSMatrixInfo rhs_info;
430 rhs_info.n0 = 16 / sizeof(T);
431 rhs_info.k0 = 1;
432 rhs_info.h0 = h0;
433 rhs_info.interleave = false;
434 rhs_info.transpose = false;
435
436 // Set the tensor shapes for LHS and RHS matrices
437 const TensorShape lhs_shape(k, m, batch_size);
438 const TensorShape rhs_shape(n, k, batch_size);
439 const TensorShape bias_shape(n,
440 broadcast_bias ? 1 : m,
441 broadcast_bias ? 1 : batch_size);
442
443 _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 +0100444 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100445 }
446
447protected:
448 template <typename U>
449 void fill(U &&tensor, int i)
450 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000451 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 +0000452 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 +0000453
454 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100455 library->fill(tensor, distribution, i);
456
457 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000458 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100459 library->fill_borders_with_garbage(tensor, distribution_inf, i);
460 }
461
462 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
463 DataType data_type, float alpha, float beta, bool broadcast_bias, bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
464 {
465 // Create tensors
466 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
467 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
468 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
469 TensorType lhs_reshaped;
470 TensorType rhs_reshaped;
471 TensorType dst;
472
473 const unsigned int m = lhs_shape[1];
474 const unsigned int n = rhs_shape[0];
475 const unsigned int k = lhs_shape[0];
476 GEMMReshapeInfo reshape_info(m, n, k, rhs_info.h0, lhs_info.v0, 0, false, broadcast_bias);
477
478 // The output tensor will be auto-initialized within the function
479
480 // Create and configure function
481 ReshapeLHSFunctionType reshape_lhs;
482 ReshapeRHSFunctionType reshape_rhs;
483 GEMMFunctionType gemm;
484 reshape_lhs.configure(&lhs, &lhs_reshaped, lhs_info);
485 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
486 gemm.configure(gpu_arch, &lhs_reshaped, &rhs_reshaped, &bias, &dst, alpha, beta, true, reshape_info, fp16_mixed_precision, act_info);
487
488 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
489 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
490 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
491
Georgios Pinitas3dca91b2021-04-13 13:35:58 +0100492 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +0000493 if(!rhs_info.export_to_cl_image)
494 {
495 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
496 }
497
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100498 // Allocate tensors
499 lhs.allocator()->allocate();
500 rhs.allocator()->allocate();
501 lhs_reshaped.allocator()->allocate();
502 rhs_reshaped.allocator()->allocate();
503 bias.allocator()->allocate();
504 dst.allocator()->allocate();
505
506 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
507 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
508 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
509 ARM_COMPUTE_EXPECT(!lhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
510 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
511 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
512
513 // Fill tensors
514 fill(AccessorType(lhs), 0);
515 fill(AccessorType(rhs), 1);
516 fill(AccessorType(bias), 2);
517
518 // Compute GEMM
519 reshape_lhs.run();
520 reshape_rhs.run();
521 gemm.run();
522
523 return dst;
524 }
525
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100526 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 +0100527 const ActivationLayerInfo &act_info)
528 {
529 TensorShape dst_shape = lhs_shape;
530 dst_shape[0] = rhs_shape[0];
531 dst_shape[1] = lhs_shape[1];
532
533 // Create reference
534 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
535 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
536 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
537
538 const int n = rhs_shape[0];
539 const int m = lhs_shape[1];
540 const int batch_size = lhs_shape[2];
541
542 // Fill reference
543 fill(lhs, 0);
544 fill(rhs, 1);
545 fill(bias, 2);
546
547 if(broadcast_bias)
548 {
549 // In case of broadcast, we need simply copy the first into the following "M" ones
550 for(int i = 1; i < m * batch_size; i++)
551 {
552 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
553 }
554 }
555
556 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
557 }
558
559 TensorType _target{};
560 SimpleTensor<T> _reference{};
561};
562
563template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSFunctionType, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
564class GEMMMatrixMultiplyInterleavedTransposed3DValidationFixture : public framework::Fixture
565{
566public:
567 template <typename...>
568 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,
569 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
570 {
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100571 ARM_COMPUTE_UNUSED(broadcast_bias);
572
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100573 GEMMLHSMatrixInfo lhs_info;
574 lhs_info.m0 = 4;
575 lhs_info.k0 = 4;
576 lhs_info.v0 = v0;
577 lhs_info.interleave = true;
578 lhs_info.transpose = true;
579
580 GEMMRHSMatrixInfo rhs_info;
581 rhs_info.n0 = 16 / sizeof(T);
582 rhs_info.k0 = 1;
583 rhs_info.h0 = h0;
584 rhs_info.interleave = false;
585 rhs_info.transpose = false;
586
587 // In case of GEMM3D, m is the product between m_w and m_h
588 const unsigned int m = m_w * m_h;
589
590 // Set the tensor shapes for LHS and RHS matrices
591 const TensorShape lhs_shape(k, m, batch_size);
592 const TensorShape rhs_shape(n, k, batch_size);
593 const TensorShape bias_shape(n, 1, 1);
594
595 _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 +0100596 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100597 }
598
599protected:
600 template <typename U>
601 void fill(U &&tensor, int i)
602 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000603 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 +0000604 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 +0000605
606 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100607 library->fill(tensor, distribution, i);
608 }
609
610 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
611 DataType data_type, float alpha, float beta, unsigned int m_h, bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
612 {
613 // Create tensors
614 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
615 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
616 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
617 TensorType lhs_reshaped;
618 TensorType rhs_reshaped;
619 TensorType dst;
620
621 const unsigned int m = lhs_shape[1];
622 const unsigned int n = rhs_shape[0];
623 const unsigned int k = lhs_shape[0];
624 GEMMReshapeInfo reshape_info(m, n, k, rhs_info.h0, lhs_info.v0, m_h, false, true);
625
626 // The output tensor will be auto-initialized within the function
627
628 // Create and configure function
629 ReshapeLHSFunctionType reshape_lhs;
630 ReshapeRHSFunctionType reshape_rhs;
631 GEMMFunctionType gemm;
632 reshape_lhs.configure(&lhs, &lhs_reshaped, lhs_info);
633 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
634 gemm.configure(gpu_arch, &lhs_reshaped, &rhs_reshaped, &bias, &dst, alpha, beta, true, reshape_info, fp16_mixed_precision, act_info);
635
636 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
637 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
638 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
639
Georgios Pinitas3dca91b2021-04-13 13:35:58 +0100640 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +0000641 if(!rhs_info.export_to_cl_image)
642 {
643 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
644 }
645
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100646 // Allocate tensors
647 lhs.allocator()->allocate();
648 rhs.allocator()->allocate();
649 lhs_reshaped.allocator()->allocate();
650 rhs_reshaped.allocator()->allocate();
651 bias.allocator()->allocate();
652 dst.allocator()->allocate();
653
654 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
655 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
656 ARM_COMPUTE_EXPECT(!lhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
657 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
658 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
659 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
660
661 // Fill tensors
662 fill(AccessorType(lhs), 0);
663 fill(AccessorType(rhs), 1);
664 fill(AccessorType(bias), 2);
665
666 // Compute GEMM
667 reshape_lhs.run();
668 reshape_rhs.run();
669 gemm.run();
670
671 return dst;
672 }
673
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100674 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 +0100675 const ActivationLayerInfo &act_info)
676 {
677 TensorShape dst_shape = lhs_shape;
678 dst_shape.set(0, rhs_shape[0]);
679 dst_shape.set(1, lhs_shape[1] / m_h);
680 dst_shape.set(2, m_h);
681 dst_shape.set(3, lhs_shape[2]);
682
683 // Create reference
684 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
685 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
686 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
687
688 const int n = rhs_shape[0];
689 const int m = lhs_shape[1];
690 const int batch_size = lhs_shape[2];
691
692 // Fill reference
693 fill(lhs, 0);
694 fill(rhs, 1);
695 fill(bias, 2);
696
697 // In case of broadcast, we need simply copy the first into the following "M" ones
698 for(int i = 1; i < m * batch_size; i++)
699 {
700 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
701 }
702
703 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
704 }
705
706 TensorType _target{};
707 SimpleTensor<T> _reference{};
708};
709
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100710template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSFunctionType, typename ReshapeRHSFunctionType, typename GEMMFunctionType, bool fp_mixed_precision = false>
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000711class GEMMMatrixMultiplyReshapedValidationFixture : public framework::Fixture
712{
713public:
714 template <typename...>
715 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 +0100716 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 +0000717 {
718 GEMMLHSMatrixInfo lhs_info;
719 lhs_info.m0 = m0;
720 lhs_info.k0 = k0;
721 lhs_info.v0 = v0;
722 lhs_info.interleave = interleave_lhs;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100723 lhs_info.transpose = lhs_transpose;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000724
725 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodicee3a849a2020-06-10 17:59:30 +0100726 rhs_info.n0 = n0;
727 rhs_info.k0 = k0;
728 rhs_info.h0 = h0;
729 rhs_info.interleave = interleave_rhs;
730 rhs_info.transpose = !lhs_transpose;
731 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000732
733 // Set the tensor shapes for LHS and RHS matrices
734 const TensorShape lhs_shape(k, m, batch_size);
735 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100736 const TensorShape bias_shape(n,
737 broadcast_bias ? 1 : m,
738 broadcast_bias ? 1 : batch_size);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000739
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000740 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
741 if(validate_result)
742 {
743 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
744 }
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000745 }
746
747protected:
748 template <typename U>
749 void fill(U &&tensor, int i)
750 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000751 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 +0000752 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 +0000753
754 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000755 library->fill(tensor, distribution, i);
Gian Marco Iodiceb87b95e2019-01-21 17:14:31 +0000756
757 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000758 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiceb87b95e2019-01-21 17:14:31 +0000759 library->fill_borders_with_garbage(tensor, distribution_inf, i);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000760 }
761
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100762 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 +0100763 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000764 {
765 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100766 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
767 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
768 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000769 TensorType lhs_reshaped;
770 TensorType rhs_reshaped;
771 TensorType dst;
772
773 const unsigned int M = lhs_shape[1];
774 const unsigned int N = rhs_shape[0];
775 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100776 GEMMKernelInfo kernel_info;
777 kernel_info.m = M;
778 kernel_info.n = N;
779 kernel_info.k = K;
780 kernel_info.depth_output_gemm3d = 0;
781 kernel_info.reinterpret_input_as_3d = false;
782 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100783 kernel_info.activation_info = act_info;
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100784 kernel_info.fp_mixed_precision = fp_mixed_precision;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000785
786 // The output tensor will be auto-initialized within the function
787
788 // Create and configure function
789 ReshapeLHSFunctionType reshape_lhs;
790 ReshapeRHSFunctionType reshape_rhs;
791 GEMMFunctionType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000792
793 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
794 validate_result = validate_result || !rhs_info.export_to_cl_image;
795 if(!validate_result)
796 {
797 return nullptr;
798 }
799
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000800 reshape_lhs.configure(&lhs, &lhs_reshaped, lhs_info);
801 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100802 gemm.configure(&lhs_reshaped, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000803
804 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
805 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100806 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000807
Georgios Pinitas3dca91b2021-04-13 13:35:58 +0100808 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +0000809 if(!rhs_info.export_to_cl_image)
810 {
811 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
812 }
813
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000814 // Allocate tensors
815 lhs.allocator()->allocate();
816 rhs.allocator()->allocate();
817 lhs_reshaped.allocator()->allocate();
818 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100819 bias.allocator()->allocate();
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000820 dst.allocator()->allocate();
821
822 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
823 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100824 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000825 ARM_COMPUTE_EXPECT(!lhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
826 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
827 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
828
829 // Fill tensors
830 fill(AccessorType(lhs), 0);
831 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100832 fill(AccessorType(bias), 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000833
834 // Compute GEMM
835 reshape_lhs.run();
836 reshape_rhs.run();
837 gemm.run();
838
839 return dst;
840 }
841
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100842 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 +0100843 const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000844 {
845 TensorShape dst_shape = lhs_shape;
846 dst_shape[0] = rhs_shape[0];
847 dst_shape[1] = lhs_shape[1];
848
849 // Create reference
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000850 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
851 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100852 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
853
854 const int n = rhs_shape[0];
855 const int m = lhs_shape[1];
856 const int batch_size = lhs_shape[2];
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000857
858 // Fill reference
859 fill(lhs, 0);
860 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100861 fill(bias, 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000862
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100863 if(broadcast_bias)
864 {
865 // In case of broadcast, we need simply copy the first into the following "M" ones
866 for(int i = 1; i < m * batch_size; i++)
867 {
868 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
869 }
870 }
871
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100872 if(fp_mixed_precision)
873 {
874 return reference::activation_layer(reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta), act_info);
875 }
876 else
877 {
878 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
879 }
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000880 }
881
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000882 bool validate_result = true;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000883 TensorType _target{};
884 SimpleTensor<T> _reference{};
885};
886
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100887template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSFunctionType, typename ReshapeRHSFunctionType, typename GEMMFunctionType, bool fp_mixed_precision = false>
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000888class GEMMMatrixMultiplyReshaped3DValidationFixture : public framework::Fixture
889{
890public:
891 template <typename...>
892 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 +0100893 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 +0000894 {
895 GEMMLHSMatrixInfo lhs_info;
896 lhs_info.m0 = m0;
897 lhs_info.k0 = k0;
898 lhs_info.v0 = v0;
899 lhs_info.interleave = interleave_lhs;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100900 lhs_info.transpose = lhs_transpose;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000901
902 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodicee3a849a2020-06-10 17:59:30 +0100903 rhs_info.n0 = n0;
904 rhs_info.k0 = k0;
905 rhs_info.h0 = h0;
906 rhs_info.interleave = interleave_rhs;
907 rhs_info.transpose = !lhs_transpose;
908 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000909
910 // In case of GEMM3D, m is the product between m_w and m_h
911 const unsigned int m = m_w * m_h;
912
913 // Set the tensor shapes for LHS and RHS matrices
914 const TensorShape lhs_shape(k, m, batch_size);
915 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100916 const TensorShape bias_shape(n, 1, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000917
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000918 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info);
919 if(validate_result)
920 {
921 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
922 }
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000923 }
924
925protected:
926 template <typename U>
927 void fill(U &&tensor, int i)
928 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +0000929 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 +0000930 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 +0000931
932 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000933 library->fill(tensor, distribution, i);
934 }
935
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100936 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 +0100937 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000938 {
939 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100940 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
941 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
942 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000943 TensorType lhs_reshaped;
944 TensorType rhs_reshaped;
945 TensorType dst;
946
947 const unsigned int M = lhs_shape[1];
948 const unsigned int N = rhs_shape[0];
949 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100950 GEMMKernelInfo kernel_info;
951 kernel_info.m = M;
952 kernel_info.n = N;
953 kernel_info.k = K;
954 kernel_info.depth_output_gemm3d = m_h;
955 kernel_info.reinterpret_input_as_3d = false;
956 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100957 kernel_info.activation_info = act_info;
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100958 kernel_info.fp_mixed_precision = fp_mixed_precision;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000959
960 // The output tensor will be auto-initialized within the function
961
962 // Create and configure function
963 ReshapeLHSFunctionType reshape_lhs;
964 ReshapeRHSFunctionType reshape_rhs;
965 GEMMFunctionType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000966
967 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
968 validate_result = validate_result || !rhs_info.export_to_cl_image;
969 if(!validate_result)
970 {
971 return nullptr;
972 }
973
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000974 reshape_lhs.configure(&lhs, &lhs_reshaped, lhs_info);
975 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100976 gemm.configure(&lhs_reshaped, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000977
978 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
979 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100980 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000981
Georgios Pinitas3dca91b2021-04-13 13:35:58 +0100982 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +0000983 if(!rhs_info.export_to_cl_image)
984 {
985 add_padding_x({ &lhs, &rhs, &lhs_reshaped, &rhs_reshaped, &bias, &dst });
986 }
987
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000988 // Allocate tensors
989 lhs.allocator()->allocate();
990 rhs.allocator()->allocate();
991 lhs_reshaped.allocator()->allocate();
992 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100993 bias.allocator()->allocate();
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000994 dst.allocator()->allocate();
995
996 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
997 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
998 ARM_COMPUTE_EXPECT(!lhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
999 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001000 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001001 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1002
1003 // Fill tensors
1004 fill(AccessorType(lhs), 0);
1005 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001006 fill(AccessorType(bias), 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001007
1008 // Compute GEMM
1009 reshape_lhs.run();
1010 reshape_rhs.run();
1011 gemm.run();
1012
1013 return dst;
1014 }
1015
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001016 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 +01001017 const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001018 {
1019 TensorShape dst_shape = lhs_shape;
1020 dst_shape.set(0, rhs_shape[0]);
1021 dst_shape.set(1, lhs_shape[1] / m_h);
1022 dst_shape.set(2, m_h);
1023 dst_shape.set(3, lhs_shape[2]);
1024
1025 // Create reference
1026 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1027 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001028 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1029
1030 const int n = rhs_shape[0];
1031 const int m = lhs_shape[1];
1032 const int batch_size = lhs_shape[2];
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001033
1034 // Fill reference
1035 fill(lhs, 0);
1036 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001037 fill(bias, 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001038
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001039 // In case of broadcast, we need simply copy the first into the following "M" ones
1040 for(int i = 1; i < m * batch_size; i++)
1041 {
1042 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1043 }
1044
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +01001045 if(fp_mixed_precision)
1046 {
1047 return reference::activation_layer(reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta), act_info);
1048 }
1049 else
1050 {
1051 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
1052 }
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001053 }
1054
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001055 bool validate_result = true;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001056 TensorType _target{};
1057 SimpleTensor<T> _reference{};
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +00001058};
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001059
1060template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
1061class GEMMMatrixMultiplyReshapedOnlyRHSValidationFixture : public framework::Fixture
1062{
1063public:
1064 template <typename...>
1065 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 +01001066 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 +00001067 {
1068 GEMMLHSMatrixInfo lhs_info;
1069 lhs_info.m0 = m0;
1070 lhs_info.k0 = k0;
1071
1072 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodice781cba72020-06-19 16:56:57 +01001073 rhs_info.n0 = n0;
1074 rhs_info.k0 = k0;
1075 rhs_info.h0 = h0;
1076 rhs_info.interleave = interleave_rhs;
1077 rhs_info.transpose = transpose_rhs;
1078 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001079
1080 // Set the tensor shapes for LHS and RHS matrices
1081 const TensorShape lhs_shape(k, m, batch_size);
1082 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001083 const TensorShape bias_shape(n,
1084 broadcast_bias ? 1 : m,
1085 broadcast_bias ? 1 : batch_size);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001086
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001087 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
1088 if(validate_result)
1089 {
1090 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
1091 }
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001092 }
1093
1094protected:
1095 template <typename U>
1096 void fill(U &&tensor, int i)
1097 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001098 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 +00001099 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 +00001100
1101 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001102 library->fill(tensor, distribution, i);
1103
1104 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001105 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001106 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1107 }
1108
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001109 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 +01001110 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001111 {
1112 // Create tensors
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001113 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1114 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1115 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001116 TensorType rhs_reshaped;
1117 TensorType dst;
1118
1119 const unsigned int M = lhs_shape[1];
1120 const unsigned int N = rhs_shape[0];
1121 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001122 GEMMKernelInfo kernel_info;
1123 kernel_info.m = M;
1124 kernel_info.n = N;
1125 kernel_info.k = K;
1126 kernel_info.depth_output_gemm3d = 0;
1127 kernel_info.reinterpret_input_as_3d = false;
1128 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001129 kernel_info.activation_info = act_info;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001130
1131 // The output tensor will be auto-initialized within the function
1132
1133 // Create and configure function
1134 ReshapeRHSFunctionType reshape_rhs;
1135 GEMMFunctionType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001136
1137 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1138 validate_result = validate_result || !rhs_info.export_to_cl_image;
1139 if(!validate_result)
1140 {
1141 return nullptr;
1142 }
1143
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001144 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001145 gemm.configure(&lhs, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001146
1147 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1148 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001149 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001150
Georgios Pinitas3dca91b2021-04-13 13:35:58 +01001151 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +00001152 if(!rhs_info.export_to_cl_image)
1153 {
1154 add_padding_x({ &lhs, &rhs, &rhs_reshaped, &bias, &dst });
1155 }
1156
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001157 // Allocate tensors
1158 lhs.allocator()->allocate();
1159 rhs.allocator()->allocate();
1160 rhs_reshaped.allocator()->allocate();
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001161 bias.allocator()->allocate();
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001162 dst.allocator()->allocate();
1163
1164 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1165 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1166 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001167 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001168 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1169
1170 // Fill tensors
1171 fill(AccessorType(lhs), 0);
1172 fill(AccessorType(rhs), 1);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001173 fill(AccessorType(bias), 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001174
1175 // Compute GEMM
1176 reshape_rhs.run();
1177 gemm.run();
1178
1179 return dst;
1180 }
1181
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001182 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 +01001183 const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001184 {
1185 TensorShape dst_shape = lhs_shape;
1186 dst_shape[0] = rhs_shape[0];
1187 dst_shape[1] = lhs_shape[1];
1188
1189 // Create reference
1190 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1191 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001192 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1193
1194 const int n = rhs_shape[0];
1195 const int m = lhs_shape[1];
1196 const int batch_size = lhs_shape[2];
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001197
1198 // Fill reference
1199 fill(lhs, 0);
1200 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001201 fill(bias, 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001202
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001203 if(broadcast_bias)
1204 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001205 // In case of broadcast, we need simply copy the first into the following "M" ones
1206 for(int i = 1; i < m * batch_size; i++)
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001207 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001208 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001209 }
1210 }
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001211
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001212 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001213 }
1214
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001215 bool validate_result = true;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001216 TensorType _target{};
1217 SimpleTensor<T> _reference{};
1218};
1219
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001220template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
1221class GEMMMatrixMultiplyReshapedOnlyRHS3DValidationFixture : public framework::Fixture
1222{
1223public:
1224 template <typename...>
1225 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 +01001226 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 +01001227 {
1228 GEMMLHSMatrixInfo lhs_info;
1229 lhs_info.m0 = m0;
1230 lhs_info.k0 = k0;
1231
1232 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodice781cba72020-06-19 16:56:57 +01001233 rhs_info.n0 = n0;
1234 rhs_info.k0 = k0;
1235 rhs_info.h0 = h0;
1236 rhs_info.interleave = interleave_rhs;
1237 rhs_info.transpose = transpose_rhs;
1238 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001239
1240 // In case of GEMM3D, m is the product between m_w and m_h
1241 const unsigned int m = m_w * m_h;
1242
1243 // Set the tensor shapes for LHS and RHS matrices
1244 const TensorShape lhs_shape(k, m, batch_size);
1245 const TensorShape rhs_shape(n, k, batch_size);
1246 const TensorShape bias_shape(n, 1, 1);
1247
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001248 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info, has_pad_y);
1249 if(validate_result)
1250 {
1251 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
1252 }
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001253 }
1254
1255protected:
1256 template <typename U>
1257 void fill(U &&tensor, int i)
1258 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001259 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 +00001260 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 +00001261
1262 DistributionType distribution{ T(-1.0f), T(1.0f) };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001263 library->fill(tensor, distribution, i);
1264 }
1265
1266 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
1267 DataType data_type, float alpha, float beta,
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001268 unsigned int m_h, const ActivationLayerInfo &act_info, bool has_pad_y)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001269 {
1270 // Create tensors
1271 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1272 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1273 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
1274 TensorType rhs_reshaped;
1275 TensorType dst;
1276
1277 const unsigned int M = lhs_shape[1];
1278 const unsigned int N = rhs_shape[0];
1279 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001280 GEMMKernelInfo kernel_info;
1281 kernel_info.m = M;
1282 kernel_info.n = N;
1283 kernel_info.k = K;
1284 kernel_info.depth_output_gemm3d = m_h;
1285 kernel_info.reinterpret_input_as_3d = false;
1286 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001287 kernel_info.activation_info = act_info;
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001288 kernel_info.has_pad_y = has_pad_y;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001289
1290 // The output tensor will be auto-initialized within the function
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001291 // Create and configure function
1292 ReshapeRHSFunctionType reshape_rhs;
1293 GEMMFunctionType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001294
1295 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1296 validate_result = validate_result || !rhs_info.export_to_cl_image;
1297 if(!validate_result)
1298 {
1299 return nullptr;
1300 }
1301
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001302 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001303 gemm.configure(&lhs, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001304
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001305 if(has_pad_y)
1306 {
1307 // Add dummy padding into lhs to validate has_pad_y path
1308 lhs.info()->extend_padding(PaddingSize(2, 0, 2, 0));
1309 dst.info()->extend_padding(PaddingSize(2, 0, 1, 0));
1310 }
1311
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001312 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1313 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1314 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
1315
Georgios Pinitas3dca91b2021-04-13 13:35:58 +01001316 // We do not pad when using image as it needs to comply to strict pitch alignment restrictions
Giorgio Arena63825e82021-03-25 14:54:50 +00001317 if(!rhs_info.export_to_cl_image)
1318 {
1319 add_padding_x({ &lhs, &rhs, &rhs_reshaped, &bias, &dst });
1320 }
1321
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001322 // Allocate tensors
1323 lhs.allocator()->allocate();
1324 rhs.allocator()->allocate();
1325 rhs_reshaped.allocator()->allocate();
1326 bias.allocator()->allocate();
1327 dst.allocator()->allocate();
1328
1329 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1330 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1331 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
1332 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
1333 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1334
1335 // Fill tensors
1336 fill(AccessorType(lhs), 0);
1337 fill(AccessorType(rhs), 1);
1338 fill(AccessorType(bias), 2);
1339
1340 // Compute GEMM
1341 reshape_rhs.run();
1342 gemm.run();
1343
1344 return dst;
1345 }
1346
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001347 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 +01001348 const ActivationLayerInfo &act_info)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001349 {
1350 TensorShape dst_shape = lhs_shape;
1351 dst_shape.set(0, rhs_shape[0]);
1352 dst_shape.set(1, lhs_shape[1] / m_h);
1353 dst_shape.set(2, m_h);
1354 dst_shape.set(3, lhs_shape[2]);
1355
1356 // Create reference
1357 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1358 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
1359 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1360
1361 const int n = rhs_shape[0];
1362 const int m = lhs_shape[1];
1363 const int batch_size = lhs_shape[2];
1364
1365 // Fill reference
1366 fill(lhs, 0);
1367 fill(rhs, 1);
1368 fill(bias, 2);
1369
1370 // In case of broadcast, we need simply copy the first into the following "M" ones
1371 for(int i = 1; i < m * batch_size; i++)
1372 {
1373 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1374 }
1375
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001376 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001377 }
1378
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001379 bool validate_result = true;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001380 TensorType _target{};
1381 SimpleTensor<T> _reference{};
1382};
1383
giuros01b3204e72019-04-01 13:50:22 +01001384template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
1385class GEMMMatrixMultiplyNativeValidationFixture : public framework::Fixture
1386{
1387public:
1388 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001389 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,
1390 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001391 {
1392 GEMMLHSMatrixInfo lhs_info;
1393 lhs_info.m0 = m0;
1394 lhs_info.k0 = k0;
1395
1396 GEMMRHSMatrixInfo rhs_info;
1397 rhs_info.n0 = n0;
1398 rhs_info.k0 = k0;
1399
1400 // Set the tensor shapes for LHS and RHS matrices
1401 const TensorShape lhs_shape(k, m, batch_size);
1402 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001403 const TensorShape bias_shape(n,
1404 broadcast_bias ? 1 : m,
1405 broadcast_bias ? 1 : batch_size);
giuros01b3204e72019-04-01 13:50:22 +01001406
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001407 _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 +01001408 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
giuros01b3204e72019-04-01 13:50:22 +01001409 }
1410
1411protected:
1412 template <typename U>
1413 void fill(U &&tensor, int i)
1414 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001415 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 +00001416 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 +00001417
1418 DistributionType distribution{ T(-1.0f), T(1.0f) };
giuros01b3204e72019-04-01 13:50:22 +01001419 library->fill(tensor, distribution, i);
1420
1421 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001422 DistributionType distribution_inf{ T(std::numeric_limits<float>::infinity()), T(std::numeric_limits<float>::infinity()) };
giuros01b3204e72019-04-01 13:50:22 +01001423 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1424 }
1425
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001426 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 +01001427 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001428 {
1429 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001430 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1431 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1432 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01001433 TensorType dst;
1434
1435 const unsigned int M = lhs_shape[1];
1436 const unsigned int N = rhs_shape[0];
1437 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001438 GEMMKernelInfo kernel_info;
1439 kernel_info.m = M;
1440 kernel_info.n = N;
1441 kernel_info.k = K;
1442 kernel_info.depth_output_gemm3d = 0;
1443 kernel_info.reinterpret_input_as_3d = false;
1444 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001445 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01001446
1447 // Create and configure function
1448 GEMMFunctionType gemm;
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001449 gemm.configure(&lhs, &rhs, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01001450
1451 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1452 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001453 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001454
Giorgio Arena63825e82021-03-25 14:54:50 +00001455 add_padding_x({ &lhs, &rhs, &bias, &dst });
1456
giuros01b3204e72019-04-01 13:50:22 +01001457 // Allocate tensors
1458 lhs.allocator()->allocate();
1459 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001460 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01001461 dst.allocator()->allocate();
1462
1463 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1464 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001465 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001466 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1467
1468 // Fill tensors
1469 fill(AccessorType(lhs), 0);
1470 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001471 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01001472
1473 // Compute GEMM
1474 gemm.run();
1475
1476 return dst;
1477 }
1478
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001479 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 +01001480 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001481 {
1482 TensorShape dst_shape = lhs_shape;
1483 dst_shape[0] = rhs_shape[0];
1484 dst_shape[1] = lhs_shape[1];
1485
1486 // Create reference
1487 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1488 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001489 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1490
1491 const int n = rhs_shape[0];
1492 const int m = lhs_shape[1];
1493 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01001494
1495 // Fill reference
1496 fill(lhs, 0);
1497 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001498 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01001499
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001500 if(broadcast_bias)
1501 {
1502 // In case of broadcast, we need simply copy the first into the following "M" ones
1503 for(int i = 1; i < m * batch_size; i++)
1504 {
1505 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1506 }
1507 }
1508
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001509 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01001510 }
1511
1512 TensorType _target{};
1513 SimpleTensor<T> _reference{};
1514};
1515
giuros01b3204e72019-04-01 13:50:22 +01001516template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
1517class GEMMMatrixMultiplyNative3DValidationFixture : public framework::Fixture
1518{
1519public:
1520 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001521 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,
1522 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001523 {
1524 GEMMLHSMatrixInfo lhs_info;
1525 lhs_info.m0 = m0;
1526 lhs_info.k0 = k0;
1527
1528 GEMMRHSMatrixInfo rhs_info;
1529 rhs_info.n0 = n0;
1530 rhs_info.k0 = k0;
1531
1532 // In case of GEMM3D, m is the product between m_w and m_h
1533 const unsigned int m = m_w * m_h;
1534
1535 // Set the tensor shapes for LHS and RHS matrices
1536 const TensorShape lhs_shape(k, m, batch_size);
1537 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001538 const TensorShape bias_shape(n, 1, 1);
giuros01b3204e72019-04-01 13:50:22 +01001539
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001540 _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 +01001541 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
giuros01b3204e72019-04-01 13:50:22 +01001542 }
1543
1544protected:
1545 template <typename U>
1546 void fill(U &&tensor, int i)
1547 {
Giorgio Arena4bdd1772020-12-17 16:47:07 +00001548 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 +00001549 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 +00001550
1551 DistributionType distribution{ T(-1.0f), T(1.0f) };
giuros01b3204e72019-04-01 13:50:22 +01001552 library->fill(tensor, distribution, i);
1553 }
1554
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001555 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 +01001556 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001557 {
1558 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001559 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1560 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1561 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01001562 TensorType dst;
1563
1564 const unsigned int M = lhs_shape[1];
1565 const unsigned int N = rhs_shape[0];
1566 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001567 GEMMKernelInfo kernel_info;
1568 kernel_info.m = M;
1569 kernel_info.n = N;
1570 kernel_info.k = K;
1571 kernel_info.depth_output_gemm3d = m_h;
1572 kernel_info.reinterpret_input_as_3d = false;
1573 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001574 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01001575
1576 // The output tensor will be auto-initialized within the function
1577
1578 // Create and configure function
1579 GEMMFunctionType gemm;
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001580 gemm.configure(&lhs, &rhs, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01001581
1582 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1583 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001584 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001585
Giorgio Arena63825e82021-03-25 14:54:50 +00001586 add_padding_x({ &lhs, &rhs, &bias, &dst });
1587
giuros01b3204e72019-04-01 13:50:22 +01001588 // Allocate tensors
1589 lhs.allocator()->allocate();
1590 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001591 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01001592 dst.allocator()->allocate();
1593
1594 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1595 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001596 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001597 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1598
1599 // Fill tensors
1600 fill(AccessorType(lhs), 0);
1601 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001602 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01001603
1604 // Compute GEMM
1605 gemm.run();
1606
1607 return dst;
1608 }
1609
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001610 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 +01001611 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001612 {
1613 TensorShape dst_shape = lhs_shape;
1614 dst_shape.set(0, rhs_shape[0]);
1615 dst_shape.set(1, lhs_shape[1] / m_h);
1616 dst_shape.set(2, m_h);
1617 dst_shape.set(3, lhs_shape[2]);
1618
1619 // Create reference
1620 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1621 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001622 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1623
1624 const int n = rhs_shape[0];
1625 const int m = lhs_shape[1];
1626 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01001627
1628 // Fill reference
1629 fill(lhs, 0);
1630 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001631 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01001632
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001633 // In case of broadcast, we need simply copy the first into the following "M" ones
1634 for(int i = 1; i < m * batch_size; i++)
1635 {
1636 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1637 }
1638
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001639 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01001640 }
1641
1642 TensorType _target{};
1643 SimpleTensor<T> _reference{};
1644};
1645
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +01001646} // namespace validation
1647} // namespace test
1648} // namespace arm_compute
1649#endif /* ARM_COMPUTE_TEST_GEMM_FIXTURE */