blob: 0c2f0a410e12babb0c378b8c807ed9d0c0337494 [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 Arenab309fc22021-01-05 09:46:16 +000067 arm_compute::utils::uniform_real_distribution_fp16 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
108 // Allocate tensors
109 a.allocator()->allocate();
110 b.allocator()->allocate();
111 c.allocator()->allocate();
112 dst.allocator()->allocate();
113
114 ARM_COMPUTE_EXPECT(!a.info()->is_resizable(), framework::LogLevel::ERRORS);
115 ARM_COMPUTE_EXPECT(!b.info()->is_resizable(), framework::LogLevel::ERRORS);
116 ARM_COMPUTE_EXPECT(!c.info()->is_resizable(), framework::LogLevel::ERRORS);
117 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
118
119 // Fill tensors
120 fill(AccessorType(a), 0);
121 fill(AccessorType(b), 1);
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000122 if(!disable_c)
123 {
124 fill(AccessorType(c), 2);
125 }
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100126
127 // Compute GEMM function
128 gemm.run();
129
130 return dst;
131 }
132
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100133 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 +0100134 DataType data_type)
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100135 {
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100136 TensorShape shape_a_to_use = shape_a;
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100137
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100138 if(reinterpret_input_as_3d)
139 {
140 // Collapse the second and third dimension if the input is 3D
141 shape_a_to_use.collapse(2U, 1U);
142 }
143
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100144 // Create reference
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100145 SimpleTensor<T> a{ shape_a_to_use, data_type, 1 };
Vidhya Sudhan Loganathan014333d2018-07-02 09:13:49 +0100146 SimpleTensor<T> b{ shape_b, data_type, 1 };
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100147 SimpleTensor<T> c{ output_shape, data_type, 1 };
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100148
149 // Fill reference
150 fill(a, 0);
151 fill(b, 1);
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100152 fill(c, 2);
153
154 if(reinterpret_input_as_3d || reinterpret_output_as_3d)
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000155 {
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100156 const int n = shape_b[0];
157 const int m = reinterpret_output_as_3d ? output_shape[1] * output_shape[2] : output_shape[1];
158 const int batch_size = reinterpret_output_as_3d ? output_shape[3] : output_shape[2];
159
160 // In case of broadcast, we need simply copy the first into the following "M" ones
161 for(int i = 1; i < m * batch_size; i++)
162 {
163 memcpy(c.data() + i * n, c.data(), n * sizeof(T));
164 }
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000165 }
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100166
167 // Setting beta to 0 will effectively disable C for the
168 // computation of the reference: alpha * A * B + 0 * C
169 return reference::gemm<T>(a, b, c, alpha, disable_c ? 0.f : beta);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100170 }
171
172 TensorType _target{};
173 SimpleTensor<T> _reference{};
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100174};
175
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100176template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
177class GEMMMatrixMultiplyValidationFixture : public framework::Fixture
178{
179public:
180 template <typename...>
181 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,
182 DataType data_type, GPUTarget gpu_arch)
183 {
184 // Set the tensor shapes for LHS and RHS matrices
185 const TensorShape lhs_shape(k, m, batch_size);
186 const TensorShape rhs_shape(n, k, batch_size);
187 const TensorShape bias_shape(n,
188 broadcast_bias ? 1 : m,
189 broadcast_bias ? 1 : batch_size);
190
191 _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 +0100192 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100193 }
194
195protected:
196 template <typename U>
197 void fill(U &&tensor, int i)
198 {
199 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
200 library->fill(tensor, distribution, i);
201
202 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
203 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
204 library->fill_borders_with_garbage(tensor, distribution_inf, i);
205 }
206
207 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,
208 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
209 {
210 // Create tensors
211 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
212 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
213 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
214 TensorType dst;
215
216 const unsigned int m = lhs_shape[1];
217 const unsigned int n = rhs_shape[0];
218 const unsigned int k = lhs_shape[0];
219 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, 0, false, broadcast_bias);
220
221 // The output tensor will be auto-initialized within the function
222
223 // Create and configure function
224 GEMMFunctionType gemm;
225 gemm.configure(gpu_arch, &lhs, &rhs, &bias, &dst, alpha, beta, false, reshape_info, fp16_mixed_precision, act_info);
226
227 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
228 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
229 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
230
231 // Allocate tensors
232 lhs.allocator()->allocate();
233 rhs.allocator()->allocate();
234 bias.allocator()->allocate();
235 dst.allocator()->allocate();
236
237 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
238 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
239 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
240 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
241
242 // Fill tensors
243 fill(AccessorType(lhs), 0);
244 fill(AccessorType(rhs), 1);
245 fill(AccessorType(bias), 2);
246
247 // Compute GEMM
248 gemm.run();
249
250 return dst;
251 }
252
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100253 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 +0100254 const ActivationLayerInfo &act_info)
255 {
256 TensorShape dst_shape = lhs_shape;
257 dst_shape[0] = rhs_shape[0];
258 dst_shape[1] = lhs_shape[1];
259
260 // Create reference
261 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
262 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
263 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
264
265 const int n = rhs_shape[0];
266 const int m = lhs_shape[1];
267 const int batch_size = lhs_shape[2];
268
269 // Fill reference
270 fill(lhs, 0);
271 fill(rhs, 1);
272 fill(bias, 2);
273
274 if(broadcast_bias)
275 {
276 // In case of broadcast, we need simply copy the first into the following "M" ones
277 for(int i = 1; i < m * batch_size; i++)
278 {
279 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
280 }
281 }
282
283 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
284 }
285
286 TensorType _target{};
287 SimpleTensor<T> _reference{};
288};
289
290template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
291class GEMMMatrixMultiply3DValidationFixture : public framework::Fixture
292{
293public:
294 template <typename...>
295 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,
296 const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
297 {
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100298 ARM_COMPUTE_UNUSED(broadcast_bias);
299
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100300 // In case of GEMM3D, m is the product between m_w and m_h
301 const unsigned int m = m_w * m_h;
302
303 // Set the tensor shapes for LHS and RHS matrices
304 const TensorShape lhs_shape(k, m, batch_size);
305 const TensorShape rhs_shape(n, k, batch_size);
306 const TensorShape bias_shape(n, 1, 1);
307
308 _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 +0100309 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100310 }
311
312protected:
313 template <typename U>
314 void fill(U &&tensor, int i)
315 {
316 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
317 library->fill(tensor, distribution, i);
318 }
319
320 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,
321 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
322 {
323 // Create tensors
324 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
325 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
326 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
327 TensorType dst;
328
329 const unsigned int m = lhs_shape[1];
330 const unsigned int n = rhs_shape[0];
331 const unsigned int k = lhs_shape[0];
332 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, m_h, false, true);
333
334 // The output tensor will be auto-initialized within the function
335
336 // Create and configure function
337 GEMMFunctionType gemm;
338 gemm.configure(gpu_arch, &lhs, &rhs, &bias, &dst, alpha, beta, false, reshape_info, fp16_mixed_precision, act_info);
339
340 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
341 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
342 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
343
344 // Allocate tensors
345 lhs.allocator()->allocate();
346 rhs.allocator()->allocate();
347 bias.allocator()->allocate();
348 dst.allocator()->allocate();
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 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
354
355 // Fill tensors
356 fill(AccessorType(lhs), 0);
357 fill(AccessorType(rhs), 1);
358 fill(AccessorType(bias), 2);
359
360 // Compute GEMM
361 gemm.run();
362
363 return dst;
364 }
365
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100366 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 +0100367 const ActivationLayerInfo &act_info)
368 {
369 TensorShape dst_shape = lhs_shape;
370 dst_shape.set(0, rhs_shape[0]);
371 dst_shape.set(1, lhs_shape[1] / m_h);
372 dst_shape.set(2, m_h);
373 dst_shape.set(3, lhs_shape[2]);
374
375 // Create reference
376 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
377 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
378 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
379
380 const int n = rhs_shape[0];
381 const int m = lhs_shape[1];
382 const int batch_size = lhs_shape[2];
383
384 // Fill reference
385 fill(lhs, 0);
386 fill(rhs, 1);
387 fill(bias, 2);
388
389 // In case of broadcast, we need simply copy the first into the following "M" ones
390 for(int i = 1; i < m * batch_size; i++)
391 {
392 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
393 }
394
395 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
396 }
397
398 TensorType _target{};
399 SimpleTensor<T> _reference{};
400};
401
402template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSFunctionType, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
403class GEMMMatrixMultiplyInterleavedTransposedValidationFixture : public framework::Fixture
404{
405public:
406 template <typename...>
407 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,
408 const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
409 {
410 GEMMLHSMatrixInfo lhs_info;
411 lhs_info.m0 = 4;
412 lhs_info.k0 = 4;
413 lhs_info.v0 = v0;
414 lhs_info.interleave = true;
415 lhs_info.transpose = true;
416
417 GEMMRHSMatrixInfo rhs_info;
418 rhs_info.n0 = 16 / sizeof(T);
419 rhs_info.k0 = 1;
420 rhs_info.h0 = h0;
421 rhs_info.interleave = false;
422 rhs_info.transpose = false;
423
424 // Set the tensor shapes for LHS and RHS matrices
425 const TensorShape lhs_shape(k, m, batch_size);
426 const TensorShape rhs_shape(n, k, batch_size);
427 const TensorShape bias_shape(n,
428 broadcast_bias ? 1 : m,
429 broadcast_bias ? 1 : batch_size);
430
431 _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 +0100432 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100433 }
434
435protected:
436 template <typename U>
437 void fill(U &&tensor, int i)
438 {
439 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
440 library->fill(tensor, distribution, i);
441
442 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
443 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
444 library->fill_borders_with_garbage(tensor, distribution_inf, i);
445 }
446
447 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
448 DataType data_type, float alpha, float beta, bool broadcast_bias, bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
449 {
450 // Create tensors
451 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
452 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
453 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
454 TensorType lhs_reshaped;
455 TensorType rhs_reshaped;
456 TensorType dst;
457
458 const unsigned int m = lhs_shape[1];
459 const unsigned int n = rhs_shape[0];
460 const unsigned int k = lhs_shape[0];
461 GEMMReshapeInfo reshape_info(m, n, k, rhs_info.h0, lhs_info.v0, 0, false, broadcast_bias);
462
463 // The output tensor will be auto-initialized within the function
464
465 // Create and configure function
466 ReshapeLHSFunctionType reshape_lhs;
467 ReshapeRHSFunctionType reshape_rhs;
468 GEMMFunctionType gemm;
469 reshape_lhs.configure(&lhs, &lhs_reshaped, lhs_info);
470 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
471 gemm.configure(gpu_arch, &lhs_reshaped, &rhs_reshaped, &bias, &dst, alpha, beta, true, reshape_info, fp16_mixed_precision, act_info);
472
473 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
474 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
475 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
476
477 // Allocate tensors
478 lhs.allocator()->allocate();
479 rhs.allocator()->allocate();
480 lhs_reshaped.allocator()->allocate();
481 rhs_reshaped.allocator()->allocate();
482 bias.allocator()->allocate();
483 dst.allocator()->allocate();
484
485 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
486 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
487 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
488 ARM_COMPUTE_EXPECT(!lhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
489 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
490 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
491
492 // Fill tensors
493 fill(AccessorType(lhs), 0);
494 fill(AccessorType(rhs), 1);
495 fill(AccessorType(bias), 2);
496
497 // Compute GEMM
498 reshape_lhs.run();
499 reshape_rhs.run();
500 gemm.run();
501
502 return dst;
503 }
504
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100505 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 +0100506 const ActivationLayerInfo &act_info)
507 {
508 TensorShape dst_shape = lhs_shape;
509 dst_shape[0] = rhs_shape[0];
510 dst_shape[1] = lhs_shape[1];
511
512 // Create reference
513 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
514 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
515 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
516
517 const int n = rhs_shape[0];
518 const int m = lhs_shape[1];
519 const int batch_size = lhs_shape[2];
520
521 // Fill reference
522 fill(lhs, 0);
523 fill(rhs, 1);
524 fill(bias, 2);
525
526 if(broadcast_bias)
527 {
528 // In case of broadcast, we need simply copy the first into the following "M" ones
529 for(int i = 1; i < m * batch_size; i++)
530 {
531 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
532 }
533 }
534
535 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
536 }
537
538 TensorType _target{};
539 SimpleTensor<T> _reference{};
540};
541
542template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSFunctionType, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
543class GEMMMatrixMultiplyInterleavedTransposed3DValidationFixture : public framework::Fixture
544{
545public:
546 template <typename...>
547 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,
548 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
549 {
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100550 ARM_COMPUTE_UNUSED(broadcast_bias);
551
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100552 GEMMLHSMatrixInfo lhs_info;
553 lhs_info.m0 = 4;
554 lhs_info.k0 = 4;
555 lhs_info.v0 = v0;
556 lhs_info.interleave = true;
557 lhs_info.transpose = true;
558
559 GEMMRHSMatrixInfo rhs_info;
560 rhs_info.n0 = 16 / sizeof(T);
561 rhs_info.k0 = 1;
562 rhs_info.h0 = h0;
563 rhs_info.interleave = false;
564 rhs_info.transpose = false;
565
566 // In case of GEMM3D, m is the product between m_w and m_h
567 const unsigned int m = m_w * m_h;
568
569 // Set the tensor shapes for LHS and RHS matrices
570 const TensorShape lhs_shape(k, m, batch_size);
571 const TensorShape rhs_shape(n, k, batch_size);
572 const TensorShape bias_shape(n, 1, 1);
573
574 _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 +0100575 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100576 }
577
578protected:
579 template <typename U>
580 void fill(U &&tensor, int i)
581 {
582 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
583 library->fill(tensor, distribution, i);
584 }
585
586 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
587 DataType data_type, float alpha, float beta, unsigned int m_h, bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
588 {
589 // Create tensors
590 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
591 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
592 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
593 TensorType lhs_reshaped;
594 TensorType rhs_reshaped;
595 TensorType dst;
596
597 const unsigned int m = lhs_shape[1];
598 const unsigned int n = rhs_shape[0];
599 const unsigned int k = lhs_shape[0];
600 GEMMReshapeInfo reshape_info(m, n, k, rhs_info.h0, lhs_info.v0, m_h, false, true);
601
602 // The output tensor will be auto-initialized within the function
603
604 // Create and configure function
605 ReshapeLHSFunctionType reshape_lhs;
606 ReshapeRHSFunctionType reshape_rhs;
607 GEMMFunctionType gemm;
608 reshape_lhs.configure(&lhs, &lhs_reshaped, lhs_info);
609 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
610 gemm.configure(gpu_arch, &lhs_reshaped, &rhs_reshaped, &bias, &dst, alpha, beta, true, reshape_info, fp16_mixed_precision, act_info);
611
612 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
613 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
614 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
615
616 // Allocate tensors
617 lhs.allocator()->allocate();
618 rhs.allocator()->allocate();
619 lhs_reshaped.allocator()->allocate();
620 rhs_reshaped.allocator()->allocate();
621 bias.allocator()->allocate();
622 dst.allocator()->allocate();
623
624 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
625 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
626 ARM_COMPUTE_EXPECT(!lhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
627 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
628 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
629 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
630
631 // Fill tensors
632 fill(AccessorType(lhs), 0);
633 fill(AccessorType(rhs), 1);
634 fill(AccessorType(bias), 2);
635
636 // Compute GEMM
637 reshape_lhs.run();
638 reshape_rhs.run();
639 gemm.run();
640
641 return dst;
642 }
643
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100644 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 +0100645 const ActivationLayerInfo &act_info)
646 {
647 TensorShape dst_shape = lhs_shape;
648 dst_shape.set(0, rhs_shape[0]);
649 dst_shape.set(1, lhs_shape[1] / m_h);
650 dst_shape.set(2, m_h);
651 dst_shape.set(3, lhs_shape[2]);
652
653 // Create reference
654 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
655 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
656 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
657
658 const int n = rhs_shape[0];
659 const int m = lhs_shape[1];
660 const int batch_size = lhs_shape[2];
661
662 // Fill reference
663 fill(lhs, 0);
664 fill(rhs, 1);
665 fill(bias, 2);
666
667 // In case of broadcast, we need simply copy the first into the following "M" ones
668 for(int i = 1; i < m * batch_size; i++)
669 {
670 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
671 }
672
673 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
674 }
675
676 TensorType _target{};
677 SimpleTensor<T> _reference{};
678};
679
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100680template <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 +0000681class GEMMMatrixMultiplyReshapedValidationFixture : public framework::Fixture
682{
683public:
684 template <typename...>
685 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 +0100686 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 +0000687 {
688 GEMMLHSMatrixInfo lhs_info;
689 lhs_info.m0 = m0;
690 lhs_info.k0 = k0;
691 lhs_info.v0 = v0;
692 lhs_info.interleave = interleave_lhs;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100693 lhs_info.transpose = lhs_transpose;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000694
695 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodicee3a849a2020-06-10 17:59:30 +0100696 rhs_info.n0 = n0;
697 rhs_info.k0 = k0;
698 rhs_info.h0 = h0;
699 rhs_info.interleave = interleave_rhs;
700 rhs_info.transpose = !lhs_transpose;
701 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000702
703 // Set the tensor shapes for LHS and RHS matrices
704 const TensorShape lhs_shape(k, m, batch_size);
705 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100706 const TensorShape bias_shape(n,
707 broadcast_bias ? 1 : m,
708 broadcast_bias ? 1 : batch_size);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000709
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000710 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
711 if(validate_result)
712 {
713 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
714 }
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000715 }
716
717protected:
718 template <typename U>
719 void fill(U &&tensor, int i)
720 {
721 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
722 library->fill(tensor, distribution, i);
Gian Marco Iodiceb87b95e2019-01-21 17:14:31 +0000723
724 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
725 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
726 library->fill_borders_with_garbage(tensor, distribution_inf, i);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000727 }
728
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100729 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 +0100730 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000731 {
732 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100733 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
734 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
735 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000736 TensorType lhs_reshaped;
737 TensorType rhs_reshaped;
738 TensorType dst;
739
740 const unsigned int M = lhs_shape[1];
741 const unsigned int N = rhs_shape[0];
742 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100743 GEMMKernelInfo kernel_info;
744 kernel_info.m = M;
745 kernel_info.n = N;
746 kernel_info.k = K;
747 kernel_info.depth_output_gemm3d = 0;
748 kernel_info.reinterpret_input_as_3d = false;
749 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100750 kernel_info.activation_info = act_info;
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100751 kernel_info.fp_mixed_precision = fp_mixed_precision;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000752
753 // The output tensor will be auto-initialized within the function
754
755 // Create and configure function
756 ReshapeLHSFunctionType reshape_lhs;
757 ReshapeRHSFunctionType reshape_rhs;
758 GEMMFunctionType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000759
760 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
761 validate_result = validate_result || !rhs_info.export_to_cl_image;
762 if(!validate_result)
763 {
764 return nullptr;
765 }
766
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000767 reshape_lhs.configure(&lhs, &lhs_reshaped, lhs_info);
768 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100769 gemm.configure(&lhs_reshaped, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000770
771 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
772 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100773 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000774
775 // Allocate tensors
776 lhs.allocator()->allocate();
777 rhs.allocator()->allocate();
778 lhs_reshaped.allocator()->allocate();
779 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100780 bias.allocator()->allocate();
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000781 dst.allocator()->allocate();
782
783 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
784 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100785 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000786 ARM_COMPUTE_EXPECT(!lhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
787 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
788 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
789
790 // Fill tensors
791 fill(AccessorType(lhs), 0);
792 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100793 fill(AccessorType(bias), 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000794
795 // Compute GEMM
796 reshape_lhs.run();
797 reshape_rhs.run();
798 gemm.run();
799
800 return dst;
801 }
802
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100803 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 +0100804 const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000805 {
806 TensorShape dst_shape = lhs_shape;
807 dst_shape[0] = rhs_shape[0];
808 dst_shape[1] = lhs_shape[1];
809
810 // Create reference
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000811 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
812 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100813 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
814
815 const int n = rhs_shape[0];
816 const int m = lhs_shape[1];
817 const int batch_size = lhs_shape[2];
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000818
819 // Fill reference
820 fill(lhs, 0);
821 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100822 fill(bias, 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000823
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100824 if(broadcast_bias)
825 {
826 // In case of broadcast, we need simply copy the first into the following "M" ones
827 for(int i = 1; i < m * batch_size; i++)
828 {
829 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
830 }
831 }
832
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100833 if(fp_mixed_precision)
834 {
835 return reference::activation_layer(reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta), act_info);
836 }
837 else
838 {
839 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
840 }
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000841 }
842
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000843 bool validate_result = true;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000844 TensorType _target{};
845 SimpleTensor<T> _reference{};
846};
847
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100848template <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 +0000849class GEMMMatrixMultiplyReshaped3DValidationFixture : public framework::Fixture
850{
851public:
852 template <typename...>
853 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 +0100854 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 +0000855 {
856 GEMMLHSMatrixInfo lhs_info;
857 lhs_info.m0 = m0;
858 lhs_info.k0 = k0;
859 lhs_info.v0 = v0;
860 lhs_info.interleave = interleave_lhs;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100861 lhs_info.transpose = lhs_transpose;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000862
863 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodicee3a849a2020-06-10 17:59:30 +0100864 rhs_info.n0 = n0;
865 rhs_info.k0 = k0;
866 rhs_info.h0 = h0;
867 rhs_info.interleave = interleave_rhs;
868 rhs_info.transpose = !lhs_transpose;
869 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000870
871 // In case of GEMM3D, m is the product between m_w and m_h
872 const unsigned int m = m_w * m_h;
873
874 // Set the tensor shapes for LHS and RHS matrices
875 const TensorShape lhs_shape(k, m, batch_size);
876 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100877 const TensorShape bias_shape(n, 1, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000878
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000879 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info);
880 if(validate_result)
881 {
882 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
883 }
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000884 }
885
886protected:
887 template <typename U>
888 void fill(U &&tensor, int i)
889 {
890 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
891 library->fill(tensor, distribution, i);
892 }
893
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100894 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 +0100895 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000896 {
897 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100898 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
899 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
900 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000901 TensorType lhs_reshaped;
902 TensorType rhs_reshaped;
903 TensorType dst;
904
905 const unsigned int M = lhs_shape[1];
906 const unsigned int N = rhs_shape[0];
907 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100908 GEMMKernelInfo kernel_info;
909 kernel_info.m = M;
910 kernel_info.n = N;
911 kernel_info.k = K;
912 kernel_info.depth_output_gemm3d = m_h;
913 kernel_info.reinterpret_input_as_3d = false;
914 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100915 kernel_info.activation_info = act_info;
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100916 kernel_info.fp_mixed_precision = fp_mixed_precision;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000917
918 // The output tensor will be auto-initialized within the function
919
920 // Create and configure function
921 ReshapeLHSFunctionType reshape_lhs;
922 ReshapeRHSFunctionType reshape_rhs;
923 GEMMFunctionType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000924
925 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
926 validate_result = validate_result || !rhs_info.export_to_cl_image;
927 if(!validate_result)
928 {
929 return nullptr;
930 }
931
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000932 reshape_lhs.configure(&lhs, &lhs_reshaped, lhs_info);
933 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100934 gemm.configure(&lhs_reshaped, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000935
936 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
937 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100938 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000939
940 // Allocate tensors
941 lhs.allocator()->allocate();
942 rhs.allocator()->allocate();
943 lhs_reshaped.allocator()->allocate();
944 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100945 bias.allocator()->allocate();
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000946 dst.allocator()->allocate();
947
948 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
949 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
950 ARM_COMPUTE_EXPECT(!lhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
951 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100952 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000953 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
954
955 // Fill tensors
956 fill(AccessorType(lhs), 0);
957 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100958 fill(AccessorType(bias), 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000959
960 // Compute GEMM
961 reshape_lhs.run();
962 reshape_rhs.run();
963 gemm.run();
964
965 return dst;
966 }
967
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100968 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 +0100969 const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000970 {
971 TensorShape dst_shape = lhs_shape;
972 dst_shape.set(0, rhs_shape[0]);
973 dst_shape.set(1, lhs_shape[1] / m_h);
974 dst_shape.set(2, m_h);
975 dst_shape.set(3, lhs_shape[2]);
976
977 // Create reference
978 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
979 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100980 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
981
982 const int n = rhs_shape[0];
983 const int m = lhs_shape[1];
984 const int batch_size = lhs_shape[2];
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000985
986 // Fill reference
987 fill(lhs, 0);
988 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100989 fill(bias, 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000990
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100991 // In case of broadcast, we need simply copy the first into the following "M" ones
992 for(int i = 1; i < m * batch_size; i++)
993 {
994 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
995 }
996
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100997 if(fp_mixed_precision)
998 {
999 return reference::activation_layer(reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta), act_info);
1000 }
1001 else
1002 {
1003 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
1004 }
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001005 }
1006
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001007 bool validate_result = true;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001008 TensorType _target{};
1009 SimpleTensor<T> _reference{};
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +00001010};
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001011
1012template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
1013class GEMMMatrixMultiplyReshapedOnlyRHSValidationFixture : public framework::Fixture
1014{
1015public:
1016 template <typename...>
1017 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 +01001018 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 +00001019 {
1020 GEMMLHSMatrixInfo lhs_info;
1021 lhs_info.m0 = m0;
1022 lhs_info.k0 = k0;
1023
1024 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodice781cba72020-06-19 16:56:57 +01001025 rhs_info.n0 = n0;
1026 rhs_info.k0 = k0;
1027 rhs_info.h0 = h0;
1028 rhs_info.interleave = interleave_rhs;
1029 rhs_info.transpose = transpose_rhs;
1030 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001031
1032 // Set the tensor shapes for LHS and RHS matrices
1033 const TensorShape lhs_shape(k, m, batch_size);
1034 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001035 const TensorShape bias_shape(n,
1036 broadcast_bias ? 1 : m,
1037 broadcast_bias ? 1 : batch_size);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001038
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001039 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
1040 if(validate_result)
1041 {
1042 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
1043 }
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001044 }
1045
1046protected:
1047 template <typename U>
1048 void fill(U &&tensor, int i)
1049 {
1050 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1051 library->fill(tensor, distribution, i);
1052
1053 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
1054 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
1055 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1056 }
1057
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001058 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 +01001059 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001060 {
1061 // Create tensors
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001062 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1063 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1064 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001065 TensorType rhs_reshaped;
1066 TensorType dst;
1067
1068 const unsigned int M = lhs_shape[1];
1069 const unsigned int N = rhs_shape[0];
1070 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001071 GEMMKernelInfo kernel_info;
1072 kernel_info.m = M;
1073 kernel_info.n = N;
1074 kernel_info.k = K;
1075 kernel_info.depth_output_gemm3d = 0;
1076 kernel_info.reinterpret_input_as_3d = false;
1077 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001078 kernel_info.activation_info = act_info;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001079
1080 // The output tensor will be auto-initialized within the function
1081
1082 // Create and configure function
1083 ReshapeRHSFunctionType reshape_rhs;
1084 GEMMFunctionType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001085
1086 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1087 validate_result = validate_result || !rhs_info.export_to_cl_image;
1088 if(!validate_result)
1089 {
1090 return nullptr;
1091 }
1092
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001093 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001094 gemm.configure(&lhs, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001095
1096 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1097 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001098 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001099
1100 // Allocate tensors
1101 lhs.allocator()->allocate();
1102 rhs.allocator()->allocate();
1103 rhs_reshaped.allocator()->allocate();
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001104 bias.allocator()->allocate();
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001105 dst.allocator()->allocate();
1106
1107 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1108 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1109 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001110 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001111 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1112
1113 // Fill tensors
1114 fill(AccessorType(lhs), 0);
1115 fill(AccessorType(rhs), 1);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001116 fill(AccessorType(bias), 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001117
1118 // Compute GEMM
1119 reshape_rhs.run();
1120 gemm.run();
1121
1122 return dst;
1123 }
1124
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001125 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 +01001126 const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001127 {
1128 TensorShape dst_shape = lhs_shape;
1129 dst_shape[0] = rhs_shape[0];
1130 dst_shape[1] = lhs_shape[1];
1131
1132 // Create reference
1133 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1134 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001135 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1136
1137 const int n = rhs_shape[0];
1138 const int m = lhs_shape[1];
1139 const int batch_size = lhs_shape[2];
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001140
1141 // Fill reference
1142 fill(lhs, 0);
1143 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001144 fill(bias, 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001145
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001146 if(broadcast_bias)
1147 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001148 // In case of broadcast, we need simply copy the first into the following "M" ones
1149 for(int i = 1; i < m * batch_size; i++)
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001150 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001151 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001152 }
1153 }
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001154
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001155 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001156 }
1157
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001158 bool validate_result = true;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001159 TensorType _target{};
1160 SimpleTensor<T> _reference{};
1161};
1162
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001163template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
1164class GEMMMatrixMultiplyReshapedOnlyRHS3DValidationFixture : public framework::Fixture
1165{
1166public:
1167 template <typename...>
1168 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 +01001169 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 +01001170 {
1171 GEMMLHSMatrixInfo lhs_info;
1172 lhs_info.m0 = m0;
1173 lhs_info.k0 = k0;
1174
1175 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodice781cba72020-06-19 16:56:57 +01001176 rhs_info.n0 = n0;
1177 rhs_info.k0 = k0;
1178 rhs_info.h0 = h0;
1179 rhs_info.interleave = interleave_rhs;
1180 rhs_info.transpose = transpose_rhs;
1181 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001182
1183 // In case of GEMM3D, m is the product between m_w and m_h
1184 const unsigned int m = m_w * m_h;
1185
1186 // Set the tensor shapes for LHS and RHS matrices
1187 const TensorShape lhs_shape(k, m, batch_size);
1188 const TensorShape rhs_shape(n, k, batch_size);
1189 const TensorShape bias_shape(n, 1, 1);
1190
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001191 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info, has_pad_y);
1192 if(validate_result)
1193 {
1194 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
1195 }
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001196 }
1197
1198protected:
1199 template <typename U>
1200 void fill(U &&tensor, int i)
1201 {
1202 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1203 library->fill(tensor, distribution, i);
1204 }
1205
1206 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
1207 DataType data_type, float alpha, float beta,
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001208 unsigned int m_h, const ActivationLayerInfo &act_info, bool has_pad_y)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001209 {
1210 // Create tensors
1211 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1212 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1213 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
1214 TensorType rhs_reshaped;
1215 TensorType dst;
1216
1217 const unsigned int M = lhs_shape[1];
1218 const unsigned int N = rhs_shape[0];
1219 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001220 GEMMKernelInfo kernel_info;
1221 kernel_info.m = M;
1222 kernel_info.n = N;
1223 kernel_info.k = K;
1224 kernel_info.depth_output_gemm3d = m_h;
1225 kernel_info.reinterpret_input_as_3d = false;
1226 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001227 kernel_info.activation_info = act_info;
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001228 kernel_info.has_pad_y = has_pad_y;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001229
1230 // The output tensor will be auto-initialized within the function
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001231 // Create and configure function
1232 ReshapeRHSFunctionType reshape_rhs;
1233 GEMMFunctionType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001234
1235 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1236 validate_result = validate_result || !rhs_info.export_to_cl_image;
1237 if(!validate_result)
1238 {
1239 return nullptr;
1240 }
1241
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001242 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001243 gemm.configure(&lhs, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001244
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001245 if(has_pad_y)
1246 {
1247 // Add dummy padding into lhs to validate has_pad_y path
1248 lhs.info()->extend_padding(PaddingSize(2, 0, 2, 0));
1249 dst.info()->extend_padding(PaddingSize(2, 0, 1, 0));
1250 }
1251
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001252 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1253 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1254 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
1255
1256 // Allocate tensors
1257 lhs.allocator()->allocate();
1258 rhs.allocator()->allocate();
1259 rhs_reshaped.allocator()->allocate();
1260 bias.allocator()->allocate();
1261 dst.allocator()->allocate();
1262
1263 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1264 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1265 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
1266 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
1267 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1268
1269 // Fill tensors
1270 fill(AccessorType(lhs), 0);
1271 fill(AccessorType(rhs), 1);
1272 fill(AccessorType(bias), 2);
1273
1274 // Compute GEMM
1275 reshape_rhs.run();
1276 gemm.run();
1277
1278 return dst;
1279 }
1280
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001281 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 +01001282 const ActivationLayerInfo &act_info)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001283 {
1284 TensorShape dst_shape = lhs_shape;
1285 dst_shape.set(0, rhs_shape[0]);
1286 dst_shape.set(1, lhs_shape[1] / m_h);
1287 dst_shape.set(2, m_h);
1288 dst_shape.set(3, lhs_shape[2]);
1289
1290 // Create reference
1291 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1292 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
1293 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1294
1295 const int n = rhs_shape[0];
1296 const int m = lhs_shape[1];
1297 const int batch_size = lhs_shape[2];
1298
1299 // Fill reference
1300 fill(lhs, 0);
1301 fill(rhs, 1);
1302 fill(bias, 2);
1303
1304 // In case of broadcast, we need simply copy the first into the following "M" ones
1305 for(int i = 1; i < m * batch_size; i++)
1306 {
1307 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1308 }
1309
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001310 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001311 }
1312
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001313 bool validate_result = true;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001314 TensorType _target{};
1315 SimpleTensor<T> _reference{};
1316};
1317
giuros01b3204e72019-04-01 13:50:22 +01001318template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
1319class GEMMMatrixMultiplyNativeValidationFixture : public framework::Fixture
1320{
1321public:
1322 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001323 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,
1324 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001325 {
1326 GEMMLHSMatrixInfo lhs_info;
1327 lhs_info.m0 = m0;
1328 lhs_info.k0 = k0;
1329
1330 GEMMRHSMatrixInfo rhs_info;
1331 rhs_info.n0 = n0;
1332 rhs_info.k0 = k0;
1333
1334 // Set the tensor shapes for LHS and RHS matrices
1335 const TensorShape lhs_shape(k, m, batch_size);
1336 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001337 const TensorShape bias_shape(n,
1338 broadcast_bias ? 1 : m,
1339 broadcast_bias ? 1 : batch_size);
giuros01b3204e72019-04-01 13:50:22 +01001340
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001341 _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 +01001342 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
giuros01b3204e72019-04-01 13:50:22 +01001343 }
1344
1345protected:
1346 template <typename U>
1347 void fill(U &&tensor, int i)
1348 {
1349 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1350 library->fill(tensor, distribution, i);
1351
1352 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
1353 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
1354 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1355 }
1356
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001357 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 +01001358 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001359 {
1360 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001361 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1362 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1363 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01001364 TensorType dst;
1365
1366 const unsigned int M = lhs_shape[1];
1367 const unsigned int N = rhs_shape[0];
1368 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001369 GEMMKernelInfo kernel_info;
1370 kernel_info.m = M;
1371 kernel_info.n = N;
1372 kernel_info.k = K;
1373 kernel_info.depth_output_gemm3d = 0;
1374 kernel_info.reinterpret_input_as_3d = false;
1375 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001376 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01001377
1378 // Create and configure function
1379 GEMMFunctionType gemm;
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001380 gemm.configure(&lhs, &rhs, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01001381
1382 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1383 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001384 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001385
1386 // Allocate tensors
1387 lhs.allocator()->allocate();
1388 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001389 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01001390 dst.allocator()->allocate();
1391
1392 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1393 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001394 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001395 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1396
1397 // Fill tensors
1398 fill(AccessorType(lhs), 0);
1399 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001400 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01001401
1402 // Compute GEMM
1403 gemm.run();
1404
1405 return dst;
1406 }
1407
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001408 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 +01001409 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001410 {
1411 TensorShape dst_shape = lhs_shape;
1412 dst_shape[0] = rhs_shape[0];
1413 dst_shape[1] = lhs_shape[1];
1414
1415 // Create reference
1416 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1417 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001418 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1419
1420 const int n = rhs_shape[0];
1421 const int m = lhs_shape[1];
1422 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01001423
1424 // Fill reference
1425 fill(lhs, 0);
1426 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001427 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01001428
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001429 if(broadcast_bias)
1430 {
1431 // In case of broadcast, we need simply copy the first into the following "M" ones
1432 for(int i = 1; i < m * batch_size; i++)
1433 {
1434 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1435 }
1436 }
1437
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001438 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01001439 }
1440
1441 TensorType _target{};
1442 SimpleTensor<T> _reference{};
1443};
1444
giuros01b3204e72019-04-01 13:50:22 +01001445template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
1446class GEMMMatrixMultiplyNative3DValidationFixture : public framework::Fixture
1447{
1448public:
1449 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001450 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,
1451 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001452 {
1453 GEMMLHSMatrixInfo lhs_info;
1454 lhs_info.m0 = m0;
1455 lhs_info.k0 = k0;
1456
1457 GEMMRHSMatrixInfo rhs_info;
1458 rhs_info.n0 = n0;
1459 rhs_info.k0 = k0;
1460
1461 // In case of GEMM3D, m is the product between m_w and m_h
1462 const unsigned int m = m_w * m_h;
1463
1464 // Set the tensor shapes for LHS and RHS matrices
1465 const TensorShape lhs_shape(k, m, batch_size);
1466 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001467 const TensorShape bias_shape(n, 1, 1);
giuros01b3204e72019-04-01 13:50:22 +01001468
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001469 _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 +01001470 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
giuros01b3204e72019-04-01 13:50:22 +01001471 }
1472
1473protected:
1474 template <typename U>
1475 void fill(U &&tensor, int i)
1476 {
1477 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1478 library->fill(tensor, distribution, i);
1479 }
1480
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001481 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 +01001482 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001483 {
1484 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001485 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1486 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1487 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01001488 TensorType dst;
1489
1490 const unsigned int M = lhs_shape[1];
1491 const unsigned int N = rhs_shape[0];
1492 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001493 GEMMKernelInfo kernel_info;
1494 kernel_info.m = M;
1495 kernel_info.n = N;
1496 kernel_info.k = K;
1497 kernel_info.depth_output_gemm3d = m_h;
1498 kernel_info.reinterpret_input_as_3d = false;
1499 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001500 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01001501
1502 // The output tensor will be auto-initialized within the function
1503
1504 // Create and configure function
1505 GEMMFunctionType gemm;
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001506 gemm.configure(&lhs, &rhs, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01001507
1508 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1509 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001510 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001511
1512 // Allocate tensors
1513 lhs.allocator()->allocate();
1514 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001515 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01001516 dst.allocator()->allocate();
1517
1518 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1519 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001520 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001521 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1522
1523 // Fill tensors
1524 fill(AccessorType(lhs), 0);
1525 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001526 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01001527
1528 // Compute GEMM
1529 gemm.run();
1530
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, unsigned int m_h,
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001535 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001536 {
1537 TensorShape dst_shape = lhs_shape;
1538 dst_shape.set(0, rhs_shape[0]);
1539 dst_shape.set(1, lhs_shape[1] / m_h);
1540 dst_shape.set(2, m_h);
1541 dst_shape.set(3, lhs_shape[2]);
1542
1543 // Create reference
1544 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1545 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001546 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1547
1548 const int n = rhs_shape[0];
1549 const int m = lhs_shape[1];
1550 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01001551
1552 // Fill reference
1553 fill(lhs, 0);
1554 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001555 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01001556
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001557 // In case of broadcast, we need simply copy the first into the following "M" ones
1558 for(int i = 1; i < m * batch_size; i++)
1559 {
1560 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1561 }
1562
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001563 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01001564 }
1565
1566 TensorType _target{};
1567 SimpleTensor<T> _reference{};
1568};
1569
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +01001570} // namespace validation
1571} // namespace test
1572} // namespace arm_compute
1573#endif /* ARM_COMPUTE_TEST_GEMM_FIXTURE */