blob: 358056ad65044f35d4b80c17aea8391d0164c048 [file] [log] [blame]
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +01001/*
Michele Di Giorgiod9eaf612020-07-08 11:12:57 +01002 * Copyright (c) 2017-2020 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:
66 case DataType::F32:
67 {
Pablo Tello0e37b5c2018-10-30 11:18:37 +000068 std::uniform_real_distribution<> distribution(lo, hi);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010069 library->fill(tensor, distribution, i);
70 break;
71 }
72 default:
73 library->fill_tensor_uniform(tensor, i);
74 }
75 }
76
77 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 +010078 DataType data_type)
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010079 {
80 // Create tensors
Vidhya Sudhan Loganathan014333d2018-07-02 09:13:49 +010081 TensorType a = create_tensor<TensorType>(shape_a, data_type, 1);
82 TensorType b = create_tensor<TensorType>(shape_b, data_type, 1);
83 TensorType c = create_tensor<TensorType>(shape_c, data_type, 1);
84 TensorType dst = create_tensor<TensorType>(output_shape, data_type, 1);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010085
86 // Create and configure function
87 FunctionType gemm;
Isabella Gottardi8e74f442018-03-01 16:42:00 +000088 // The GEMMinfo includes the values of the depth in case of reinterpreted 3d output.
Gian Marco Iodice3139f032018-11-05 14:26:32 +000089 // 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 +000090 // 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 +010091 gemm.configure(&a,
92 &b,
93 (disable_c) ? nullptr : &c,
94 &dst,
95 alpha, beta,
96 GEMMInfo(false, false, false, (reinterpret_output_as_3d ? output_shape[2] : 0), reinterpret_input_as_3d, false, GEMMLowpOutputStageInfo(), false, (reinterpret_input_as_3d
97 || reinterpret_output_as_3d)));
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010098 ARM_COMPUTE_EXPECT(a.info()->is_resizable(), framework::LogLevel::ERRORS);
99 ARM_COMPUTE_EXPECT(b.info()->is_resizable(), framework::LogLevel::ERRORS);
100 ARM_COMPUTE_EXPECT(c.info()->is_resizable(), framework::LogLevel::ERRORS);
101 ARM_COMPUTE_EXPECT(dst.info()->is_resizable(), framework::LogLevel::ERRORS);
102
103 // Allocate tensors
104 a.allocator()->allocate();
105 b.allocator()->allocate();
106 c.allocator()->allocate();
107 dst.allocator()->allocate();
108
109 ARM_COMPUTE_EXPECT(!a.info()->is_resizable(), framework::LogLevel::ERRORS);
110 ARM_COMPUTE_EXPECT(!b.info()->is_resizable(), framework::LogLevel::ERRORS);
111 ARM_COMPUTE_EXPECT(!c.info()->is_resizable(), framework::LogLevel::ERRORS);
112 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
113
114 // Fill tensors
115 fill(AccessorType(a), 0);
116 fill(AccessorType(b), 1);
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000117 if(!disable_c)
118 {
119 fill(AccessorType(c), 2);
120 }
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100121
122 // Compute GEMM function
123 gemm.run();
124
125 return dst;
126 }
127
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100128 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 +0100129 DataType data_type)
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100130 {
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100131 TensorShape shape_a_to_use = shape_a;
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100132
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100133 if(reinterpret_input_as_3d)
134 {
135 // Collapse the second and third dimension if the input is 3D
136 shape_a_to_use.collapse(2U, 1U);
137 }
138
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100139 // Create reference
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100140 SimpleTensor<T> a{ shape_a_to_use, data_type, 1 };
Vidhya Sudhan Loganathan014333d2018-07-02 09:13:49 +0100141 SimpleTensor<T> b{ shape_b, data_type, 1 };
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100142 SimpleTensor<T> c{ output_shape, data_type, 1 };
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100143
144 // Fill reference
145 fill(a, 0);
146 fill(b, 1);
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100147 fill(c, 2);
148
149 if(reinterpret_input_as_3d || reinterpret_output_as_3d)
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000150 {
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100151 const int n = shape_b[0];
152 const int m = reinterpret_output_as_3d ? output_shape[1] * output_shape[2] : output_shape[1];
153 const int batch_size = reinterpret_output_as_3d ? output_shape[3] : output_shape[2];
154
155 // In case of broadcast, we need simply copy the first into the following "M" ones
156 for(int i = 1; i < m * batch_size; i++)
157 {
158 memcpy(c.data() + i * n, c.data(), n * sizeof(T));
159 }
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000160 }
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100161
162 // Setting beta to 0 will effectively disable C for the
163 // computation of the reference: alpha * A * B + 0 * C
164 return reference::gemm<T>(a, b, c, alpha, disable_c ? 0.f : beta);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100165 }
166
167 TensorType _target{};
168 SimpleTensor<T> _reference{};
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100169};
170
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100171template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
172class GEMMMatrixMultiplyValidationFixture : public framework::Fixture
173{
174public:
175 template <typename...>
176 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,
177 DataType data_type, GPUTarget gpu_arch)
178 {
179 // Set the tensor shapes for LHS and RHS matrices
180 const TensorShape lhs_shape(k, m, batch_size);
181 const TensorShape rhs_shape(n, k, batch_size);
182 const TensorShape bias_shape(n,
183 broadcast_bias ? 1 : m,
184 broadcast_bias ? 1 : batch_size);
185
186 _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 +0100187 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100188 }
189
190protected:
191 template <typename U>
192 void fill(U &&tensor, int i)
193 {
194 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
195 library->fill(tensor, distribution, i);
196
197 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
198 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
199 library->fill_borders_with_garbage(tensor, distribution_inf, i);
200 }
201
202 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,
203 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
204 {
205 // Create tensors
206 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
207 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
208 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
209 TensorType dst;
210
211 const unsigned int m = lhs_shape[1];
212 const unsigned int n = rhs_shape[0];
213 const unsigned int k = lhs_shape[0];
214 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, 0, false, broadcast_bias);
215
216 // The output tensor will be auto-initialized within the function
217
218 // Create and configure function
219 GEMMFunctionType gemm;
220 gemm.configure(gpu_arch, &lhs, &rhs, &bias, &dst, alpha, beta, false, reshape_info, fp16_mixed_precision, act_info);
221
222 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
223 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
224 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
225
226 // Allocate tensors
227 lhs.allocator()->allocate();
228 rhs.allocator()->allocate();
229 bias.allocator()->allocate();
230 dst.allocator()->allocate();
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 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
236
237 // Fill tensors
238 fill(AccessorType(lhs), 0);
239 fill(AccessorType(rhs), 1);
240 fill(AccessorType(bias), 2);
241
242 // Compute GEMM
243 gemm.run();
244
245 return dst;
246 }
247
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100248 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 +0100249 const ActivationLayerInfo &act_info)
250 {
251 TensorShape dst_shape = lhs_shape;
252 dst_shape[0] = rhs_shape[0];
253 dst_shape[1] = lhs_shape[1];
254
255 // Create reference
256 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
257 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
258 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
259
260 const int n = rhs_shape[0];
261 const int m = lhs_shape[1];
262 const int batch_size = lhs_shape[2];
263
264 // Fill reference
265 fill(lhs, 0);
266 fill(rhs, 1);
267 fill(bias, 2);
268
269 if(broadcast_bias)
270 {
271 // In case of broadcast, we need simply copy the first into the following "M" ones
272 for(int i = 1; i < m * batch_size; i++)
273 {
274 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
275 }
276 }
277
278 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
279 }
280
281 TensorType _target{};
282 SimpleTensor<T> _reference{};
283};
284
285template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
286class GEMMMatrixMultiply3DValidationFixture : public framework::Fixture
287{
288public:
289 template <typename...>
290 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,
291 const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
292 {
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100293 ARM_COMPUTE_UNUSED(broadcast_bias);
294
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100295 // In case of GEMM3D, m is the product between m_w and m_h
296 const unsigned int m = m_w * m_h;
297
298 // Set the tensor shapes for LHS and RHS matrices
299 const TensorShape lhs_shape(k, m, batch_size);
300 const TensorShape rhs_shape(n, k, batch_size);
301 const TensorShape bias_shape(n, 1, 1);
302
303 _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 +0100304 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100305 }
306
307protected:
308 template <typename U>
309 void fill(U &&tensor, int i)
310 {
311 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
312 library->fill(tensor, distribution, i);
313 }
314
315 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,
316 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
317 {
318 // Create tensors
319 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
320 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
321 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
322 TensorType dst;
323
324 const unsigned int m = lhs_shape[1];
325 const unsigned int n = rhs_shape[0];
326 const unsigned int k = lhs_shape[0];
327 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, m_h, false, true);
328
329 // The output tensor will be auto-initialized within the function
330
331 // Create and configure function
332 GEMMFunctionType gemm;
333 gemm.configure(gpu_arch, &lhs, &rhs, &bias, &dst, alpha, beta, false, reshape_info, fp16_mixed_precision, act_info);
334
335 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
336 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
337 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
338
339 // Allocate tensors
340 lhs.allocator()->allocate();
341 rhs.allocator()->allocate();
342 bias.allocator()->allocate();
343 dst.allocator()->allocate();
344
345 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
346 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
347 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
348 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
349
350 // Fill tensors
351 fill(AccessorType(lhs), 0);
352 fill(AccessorType(rhs), 1);
353 fill(AccessorType(bias), 2);
354
355 // Compute GEMM
356 gemm.run();
357
358 return dst;
359 }
360
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100361 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 +0100362 const ActivationLayerInfo &act_info)
363 {
364 TensorShape dst_shape = lhs_shape;
365 dst_shape.set(0, rhs_shape[0]);
366 dst_shape.set(1, lhs_shape[1] / m_h);
367 dst_shape.set(2, m_h);
368 dst_shape.set(3, lhs_shape[2]);
369
370 // Create reference
371 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
372 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
373 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
374
375 const int n = rhs_shape[0];
376 const int m = lhs_shape[1];
377 const int batch_size = lhs_shape[2];
378
379 // Fill reference
380 fill(lhs, 0);
381 fill(rhs, 1);
382 fill(bias, 2);
383
384 // In case of broadcast, we need simply copy the first into the following "M" ones
385 for(int i = 1; i < m * batch_size; i++)
386 {
387 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
388 }
389
390 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
391 }
392
393 TensorType _target{};
394 SimpleTensor<T> _reference{};
395};
396
397template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSFunctionType, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
398class GEMMMatrixMultiplyInterleavedTransposedValidationFixture : public framework::Fixture
399{
400public:
401 template <typename...>
402 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,
403 const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
404 {
405 GEMMLHSMatrixInfo lhs_info;
406 lhs_info.m0 = 4;
407 lhs_info.k0 = 4;
408 lhs_info.v0 = v0;
409 lhs_info.interleave = true;
410 lhs_info.transpose = true;
411
412 GEMMRHSMatrixInfo rhs_info;
413 rhs_info.n0 = 16 / sizeof(T);
414 rhs_info.k0 = 1;
415 rhs_info.h0 = h0;
416 rhs_info.interleave = false;
417 rhs_info.transpose = false;
418
419 // Set the tensor shapes for LHS and RHS matrices
420 const TensorShape lhs_shape(k, m, batch_size);
421 const TensorShape rhs_shape(n, k, batch_size);
422 const TensorShape bias_shape(n,
423 broadcast_bias ? 1 : m,
424 broadcast_bias ? 1 : batch_size);
425
426 _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 +0100427 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100428 }
429
430protected:
431 template <typename U>
432 void fill(U &&tensor, int i)
433 {
434 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
435 library->fill(tensor, distribution, i);
436
437 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
438 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
439 library->fill_borders_with_garbage(tensor, distribution_inf, i);
440 }
441
442 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
443 DataType data_type, float alpha, float beta, bool broadcast_bias, bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
444 {
445 // Create tensors
446 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
447 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
448 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
449 TensorType lhs_reshaped;
450 TensorType rhs_reshaped;
451 TensorType dst;
452
453 const unsigned int m = lhs_shape[1];
454 const unsigned int n = rhs_shape[0];
455 const unsigned int k = lhs_shape[0];
456 GEMMReshapeInfo reshape_info(m, n, k, rhs_info.h0, lhs_info.v0, 0, false, broadcast_bias);
457
458 // The output tensor will be auto-initialized within the function
459
460 // Create and configure function
461 ReshapeLHSFunctionType reshape_lhs;
462 ReshapeRHSFunctionType reshape_rhs;
463 GEMMFunctionType gemm;
464 reshape_lhs.configure(&lhs, &lhs_reshaped, lhs_info);
465 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
466 gemm.configure(gpu_arch, &lhs_reshaped, &rhs_reshaped, &bias, &dst, alpha, beta, true, reshape_info, fp16_mixed_precision, act_info);
467
468 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
469 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
470 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
471
472 // Allocate tensors
473 lhs.allocator()->allocate();
474 rhs.allocator()->allocate();
475 lhs_reshaped.allocator()->allocate();
476 rhs_reshaped.allocator()->allocate();
477 bias.allocator()->allocate();
478 dst.allocator()->allocate();
479
480 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
481 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
482 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
483 ARM_COMPUTE_EXPECT(!lhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
484 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
485 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
486
487 // Fill tensors
488 fill(AccessorType(lhs), 0);
489 fill(AccessorType(rhs), 1);
490 fill(AccessorType(bias), 2);
491
492 // Compute GEMM
493 reshape_lhs.run();
494 reshape_rhs.run();
495 gemm.run();
496
497 return dst;
498 }
499
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100500 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 +0100501 const ActivationLayerInfo &act_info)
502 {
503 TensorShape dst_shape = lhs_shape;
504 dst_shape[0] = rhs_shape[0];
505 dst_shape[1] = lhs_shape[1];
506
507 // Create reference
508 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
509 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
510 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
511
512 const int n = rhs_shape[0];
513 const int m = lhs_shape[1];
514 const int batch_size = lhs_shape[2];
515
516 // Fill reference
517 fill(lhs, 0);
518 fill(rhs, 1);
519 fill(bias, 2);
520
521 if(broadcast_bias)
522 {
523 // In case of broadcast, we need simply copy the first into the following "M" ones
524 for(int i = 1; i < m * batch_size; i++)
525 {
526 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
527 }
528 }
529
530 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
531 }
532
533 TensorType _target{};
534 SimpleTensor<T> _reference{};
535};
536
537template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSFunctionType, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
538class GEMMMatrixMultiplyInterleavedTransposed3DValidationFixture : public framework::Fixture
539{
540public:
541 template <typename...>
542 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,
543 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
544 {
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100545 ARM_COMPUTE_UNUSED(broadcast_bias);
546
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100547 GEMMLHSMatrixInfo lhs_info;
548 lhs_info.m0 = 4;
549 lhs_info.k0 = 4;
550 lhs_info.v0 = v0;
551 lhs_info.interleave = true;
552 lhs_info.transpose = true;
553
554 GEMMRHSMatrixInfo rhs_info;
555 rhs_info.n0 = 16 / sizeof(T);
556 rhs_info.k0 = 1;
557 rhs_info.h0 = h0;
558 rhs_info.interleave = false;
559 rhs_info.transpose = false;
560
561 // In case of GEMM3D, m is the product between m_w and m_h
562 const unsigned int m = m_w * m_h;
563
564 // Set the tensor shapes for LHS and RHS matrices
565 const TensorShape lhs_shape(k, m, batch_size);
566 const TensorShape rhs_shape(n, k, batch_size);
567 const TensorShape bias_shape(n, 1, 1);
568
569 _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 +0100570 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100571 }
572
573protected:
574 template <typename U>
575 void fill(U &&tensor, int i)
576 {
577 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
578 library->fill(tensor, distribution, i);
579 }
580
581 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
582 DataType data_type, float alpha, float beta, unsigned int m_h, bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
583 {
584 // Create tensors
585 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
586 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
587 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
588 TensorType lhs_reshaped;
589 TensorType rhs_reshaped;
590 TensorType dst;
591
592 const unsigned int m = lhs_shape[1];
593 const unsigned int n = rhs_shape[0];
594 const unsigned int k = lhs_shape[0];
595 GEMMReshapeInfo reshape_info(m, n, k, rhs_info.h0, lhs_info.v0, m_h, false, true);
596
597 // The output tensor will be auto-initialized within the function
598
599 // Create and configure function
600 ReshapeLHSFunctionType reshape_lhs;
601 ReshapeRHSFunctionType reshape_rhs;
602 GEMMFunctionType gemm;
603 reshape_lhs.configure(&lhs, &lhs_reshaped, lhs_info);
604 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
605 gemm.configure(gpu_arch, &lhs_reshaped, &rhs_reshaped, &bias, &dst, alpha, beta, true, reshape_info, fp16_mixed_precision, act_info);
606
607 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
608 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
609 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
610
611 // Allocate tensors
612 lhs.allocator()->allocate();
613 rhs.allocator()->allocate();
614 lhs_reshaped.allocator()->allocate();
615 rhs_reshaped.allocator()->allocate();
616 bias.allocator()->allocate();
617 dst.allocator()->allocate();
618
619 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
620 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
621 ARM_COMPUTE_EXPECT(!lhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
622 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
623 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
624 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
625
626 // Fill tensors
627 fill(AccessorType(lhs), 0);
628 fill(AccessorType(rhs), 1);
629 fill(AccessorType(bias), 2);
630
631 // Compute GEMM
632 reshape_lhs.run();
633 reshape_rhs.run();
634 gemm.run();
635
636 return dst;
637 }
638
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100639 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 +0100640 const ActivationLayerInfo &act_info)
641 {
642 TensorShape dst_shape = lhs_shape;
643 dst_shape.set(0, rhs_shape[0]);
644 dst_shape.set(1, lhs_shape[1] / m_h);
645 dst_shape.set(2, m_h);
646 dst_shape.set(3, lhs_shape[2]);
647
648 // Create reference
649 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
650 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
651 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
652
653 const int n = rhs_shape[0];
654 const int m = lhs_shape[1];
655 const int batch_size = lhs_shape[2];
656
657 // Fill reference
658 fill(lhs, 0);
659 fill(rhs, 1);
660 fill(bias, 2);
661
662 // In case of broadcast, we need simply copy the first into the following "M" ones
663 for(int i = 1; i < m * batch_size; i++)
664 {
665 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
666 }
667
668 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
669 }
670
671 TensorType _target{};
672 SimpleTensor<T> _reference{};
673};
674
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100675template <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 +0000676class GEMMMatrixMultiplyReshapedValidationFixture : public framework::Fixture
677{
678public:
679 template <typename...>
680 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 +0100681 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 +0000682 {
683 GEMMLHSMatrixInfo lhs_info;
684 lhs_info.m0 = m0;
685 lhs_info.k0 = k0;
686 lhs_info.v0 = v0;
687 lhs_info.interleave = interleave_lhs;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100688 lhs_info.transpose = lhs_transpose;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000689
690 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodicee3a849a2020-06-10 17:59:30 +0100691 rhs_info.n0 = n0;
692 rhs_info.k0 = k0;
693 rhs_info.h0 = h0;
694 rhs_info.interleave = interleave_rhs;
695 rhs_info.transpose = !lhs_transpose;
696 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000697
698 // Set the tensor shapes for LHS and RHS matrices
699 const TensorShape lhs_shape(k, m, batch_size);
700 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100701 const TensorShape bias_shape(n,
702 broadcast_bias ? 1 : m,
703 broadcast_bias ? 1 : batch_size);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000704
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000705 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
706 if(validate_result)
707 {
708 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
709 }
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000710 }
711
712protected:
713 template <typename U>
714 void fill(U &&tensor, int i)
715 {
716 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
717 library->fill(tensor, distribution, i);
Gian Marco Iodiceb87b95e2019-01-21 17:14:31 +0000718
719 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
720 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
721 library->fill_borders_with_garbage(tensor, distribution_inf, i);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000722 }
723
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100724 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 +0100725 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000726 {
727 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100728 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
729 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
730 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000731 TensorType lhs_reshaped;
732 TensorType rhs_reshaped;
733 TensorType dst;
734
735 const unsigned int M = lhs_shape[1];
736 const unsigned int N = rhs_shape[0];
737 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100738 GEMMKernelInfo kernel_info;
739 kernel_info.m = M;
740 kernel_info.n = N;
741 kernel_info.k = K;
742 kernel_info.depth_output_gemm3d = 0;
743 kernel_info.reinterpret_input_as_3d = false;
744 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100745 kernel_info.activation_info = act_info;
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100746 kernel_info.fp_mixed_precision = fp_mixed_precision;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000747
748 // The output tensor will be auto-initialized within the function
749
750 // Create and configure function
751 ReshapeLHSFunctionType reshape_lhs;
752 ReshapeRHSFunctionType reshape_rhs;
753 GEMMFunctionType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000754
755 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
756 validate_result = validate_result || !rhs_info.export_to_cl_image;
757 if(!validate_result)
758 {
759 return nullptr;
760 }
761
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000762 reshape_lhs.configure(&lhs, &lhs_reshaped, lhs_info);
763 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100764 gemm.configure(&lhs_reshaped, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000765
766 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
767 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100768 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000769
770 // Allocate tensors
771 lhs.allocator()->allocate();
772 rhs.allocator()->allocate();
773 lhs_reshaped.allocator()->allocate();
774 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100775 bias.allocator()->allocate();
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000776 dst.allocator()->allocate();
777
778 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
779 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100780 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000781 ARM_COMPUTE_EXPECT(!lhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
782 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
783 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
784
785 // Fill tensors
786 fill(AccessorType(lhs), 0);
787 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100788 fill(AccessorType(bias), 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000789
790 // Compute GEMM
791 reshape_lhs.run();
792 reshape_rhs.run();
793 gemm.run();
794
795 return dst;
796 }
797
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100798 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 +0100799 const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000800 {
801 TensorShape dst_shape = lhs_shape;
802 dst_shape[0] = rhs_shape[0];
803 dst_shape[1] = lhs_shape[1];
804
805 // Create reference
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000806 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
807 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100808 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
809
810 const int n = rhs_shape[0];
811 const int m = lhs_shape[1];
812 const int batch_size = lhs_shape[2];
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000813
814 // Fill reference
815 fill(lhs, 0);
816 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100817 fill(bias, 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000818
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100819 if(broadcast_bias)
820 {
821 // In case of broadcast, we need simply copy the first into the following "M" ones
822 for(int i = 1; i < m * batch_size; i++)
823 {
824 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
825 }
826 }
827
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100828 if(fp_mixed_precision)
829 {
830 return reference::activation_layer(reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta), act_info);
831 }
832 else
833 {
834 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
835 }
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000836 }
837
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000838 bool validate_result = true;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000839 TensorType _target{};
840 SimpleTensor<T> _reference{};
841};
842
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100843template <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 +0000844class GEMMMatrixMultiplyReshaped3DValidationFixture : public framework::Fixture
845{
846public:
847 template <typename...>
848 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 +0100849 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 +0000850 {
851 GEMMLHSMatrixInfo lhs_info;
852 lhs_info.m0 = m0;
853 lhs_info.k0 = k0;
854 lhs_info.v0 = v0;
855 lhs_info.interleave = interleave_lhs;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100856 lhs_info.transpose = lhs_transpose;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000857
858 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodicee3a849a2020-06-10 17:59:30 +0100859 rhs_info.n0 = n0;
860 rhs_info.k0 = k0;
861 rhs_info.h0 = h0;
862 rhs_info.interleave = interleave_rhs;
863 rhs_info.transpose = !lhs_transpose;
864 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000865
866 // In case of GEMM3D, m is the product between m_w and m_h
867 const unsigned int m = m_w * m_h;
868
869 // Set the tensor shapes for LHS and RHS matrices
870 const TensorShape lhs_shape(k, m, batch_size);
871 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100872 const TensorShape bias_shape(n, 1, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000873
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000874 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info);
875 if(validate_result)
876 {
877 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
878 }
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000879 }
880
881protected:
882 template <typename U>
883 void fill(U &&tensor, int i)
884 {
885 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
886 library->fill(tensor, distribution, i);
887 }
888
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100889 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 +0100890 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000891 {
892 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100893 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
894 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
895 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000896 TensorType lhs_reshaped;
897 TensorType rhs_reshaped;
898 TensorType dst;
899
900 const unsigned int M = lhs_shape[1];
901 const unsigned int N = rhs_shape[0];
902 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100903 GEMMKernelInfo kernel_info;
904 kernel_info.m = M;
905 kernel_info.n = N;
906 kernel_info.k = K;
907 kernel_info.depth_output_gemm3d = m_h;
908 kernel_info.reinterpret_input_as_3d = false;
909 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100910 kernel_info.activation_info = act_info;
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100911 kernel_info.fp_mixed_precision = fp_mixed_precision;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000912
913 // The output tensor will be auto-initialized within the function
914
915 // Create and configure function
916 ReshapeLHSFunctionType reshape_lhs;
917 ReshapeRHSFunctionType reshape_rhs;
918 GEMMFunctionType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +0000919
920 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
921 validate_result = validate_result || !rhs_info.export_to_cl_image;
922 if(!validate_result)
923 {
924 return nullptr;
925 }
926
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000927 reshape_lhs.configure(&lhs, &lhs_reshaped, lhs_info);
928 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100929 gemm.configure(&lhs_reshaped, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000930
931 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
932 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100933 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000934
935 // Allocate tensors
936 lhs.allocator()->allocate();
937 rhs.allocator()->allocate();
938 lhs_reshaped.allocator()->allocate();
939 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100940 bias.allocator()->allocate();
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000941 dst.allocator()->allocate();
942
943 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
944 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
945 ARM_COMPUTE_EXPECT(!lhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
946 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100947 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000948 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
949
950 // Fill tensors
951 fill(AccessorType(lhs), 0);
952 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100953 fill(AccessorType(bias), 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000954
955 // Compute GEMM
956 reshape_lhs.run();
957 reshape_rhs.run();
958 gemm.run();
959
960 return dst;
961 }
962
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100963 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 +0100964 const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000965 {
966 TensorShape dst_shape = lhs_shape;
967 dst_shape.set(0, rhs_shape[0]);
968 dst_shape.set(1, lhs_shape[1] / m_h);
969 dst_shape.set(2, m_h);
970 dst_shape.set(3, lhs_shape[2]);
971
972 // Create reference
973 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
974 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100975 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
976
977 const int n = rhs_shape[0];
978 const int m = lhs_shape[1];
979 const int batch_size = lhs_shape[2];
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000980
981 // Fill reference
982 fill(lhs, 0);
983 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100984 fill(bias, 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000985
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100986 // In case of broadcast, we need simply copy the first into the following "M" ones
987 for(int i = 1; i < m * batch_size; i++)
988 {
989 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
990 }
991
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100992 if(fp_mixed_precision)
993 {
994 return reference::activation_layer(reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta), act_info);
995 }
996 else
997 {
998 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
999 }
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001000 }
1001
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001002 bool validate_result = true;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +00001003 TensorType _target{};
1004 SimpleTensor<T> _reference{};
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +00001005};
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001006
1007template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
1008class GEMMMatrixMultiplyReshapedOnlyRHSValidationFixture : public framework::Fixture
1009{
1010public:
1011 template <typename...>
1012 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 +01001013 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 +00001014 {
1015 GEMMLHSMatrixInfo lhs_info;
1016 lhs_info.m0 = m0;
1017 lhs_info.k0 = k0;
1018
1019 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodice781cba72020-06-19 16:56:57 +01001020 rhs_info.n0 = n0;
1021 rhs_info.k0 = k0;
1022 rhs_info.h0 = h0;
1023 rhs_info.interleave = interleave_rhs;
1024 rhs_info.transpose = transpose_rhs;
1025 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001026
1027 // Set the tensor shapes for LHS and RHS matrices
1028 const TensorShape lhs_shape(k, m, batch_size);
1029 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001030 const TensorShape bias_shape(n,
1031 broadcast_bias ? 1 : m,
1032 broadcast_bias ? 1 : batch_size);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001033
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001034 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
1035 if(validate_result)
1036 {
1037 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
1038 }
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001039 }
1040
1041protected:
1042 template <typename U>
1043 void fill(U &&tensor, int i)
1044 {
1045 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1046 library->fill(tensor, distribution, i);
1047
1048 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
1049 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
1050 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1051 }
1052
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001053 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 +01001054 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001055 {
1056 // Create tensors
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001057 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1058 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1059 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001060 TensorType rhs_reshaped;
1061 TensorType dst;
1062
1063 const unsigned int M = lhs_shape[1];
1064 const unsigned int N = rhs_shape[0];
1065 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001066 GEMMKernelInfo kernel_info;
1067 kernel_info.m = M;
1068 kernel_info.n = N;
1069 kernel_info.k = K;
1070 kernel_info.depth_output_gemm3d = 0;
1071 kernel_info.reinterpret_input_as_3d = false;
1072 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001073 kernel_info.activation_info = act_info;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001074
1075 // The output tensor will be auto-initialized within the function
1076
1077 // Create and configure function
1078 ReshapeRHSFunctionType reshape_rhs;
1079 GEMMFunctionType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001080
1081 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1082 validate_result = validate_result || !rhs_info.export_to_cl_image;
1083 if(!validate_result)
1084 {
1085 return nullptr;
1086 }
1087
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001088 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001089 gemm.configure(&lhs, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001090
1091 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1092 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001093 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001094
1095 // Allocate tensors
1096 lhs.allocator()->allocate();
1097 rhs.allocator()->allocate();
1098 rhs_reshaped.allocator()->allocate();
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001099 bias.allocator()->allocate();
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001100 dst.allocator()->allocate();
1101
1102 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1103 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1104 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001105 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001106 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1107
1108 // Fill tensors
1109 fill(AccessorType(lhs), 0);
1110 fill(AccessorType(rhs), 1);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001111 fill(AccessorType(bias), 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001112
1113 // Compute GEMM
1114 reshape_rhs.run();
1115 gemm.run();
1116
1117 return dst;
1118 }
1119
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001120 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 +01001121 const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001122 {
1123 TensorShape dst_shape = lhs_shape;
1124 dst_shape[0] = rhs_shape[0];
1125 dst_shape[1] = lhs_shape[1];
1126
1127 // Create reference
1128 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1129 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001130 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1131
1132 const int n = rhs_shape[0];
1133 const int m = lhs_shape[1];
1134 const int batch_size = lhs_shape[2];
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001135
1136 // Fill reference
1137 fill(lhs, 0);
1138 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001139 fill(bias, 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001140
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001141 if(broadcast_bias)
1142 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001143 // In case of broadcast, we need simply copy the first into the following "M" ones
1144 for(int i = 1; i < m * batch_size; i++)
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001145 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001146 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001147 }
1148 }
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001149
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001150 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001151 }
1152
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001153 bool validate_result = true;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001154 TensorType _target{};
1155 SimpleTensor<T> _reference{};
1156};
1157
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001158template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
1159class GEMMMatrixMultiplyReshapedOnlyRHS3DValidationFixture : public framework::Fixture
1160{
1161public:
1162 template <typename...>
1163 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 +01001164 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 +01001165 {
1166 GEMMLHSMatrixInfo lhs_info;
1167 lhs_info.m0 = m0;
1168 lhs_info.k0 = k0;
1169
1170 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodice781cba72020-06-19 16:56:57 +01001171 rhs_info.n0 = n0;
1172 rhs_info.k0 = k0;
1173 rhs_info.h0 = h0;
1174 rhs_info.interleave = interleave_rhs;
1175 rhs_info.transpose = transpose_rhs;
1176 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001177
1178 // In case of GEMM3D, m is the product between m_w and m_h
1179 const unsigned int m = m_w * m_h;
1180
1181 // Set the tensor shapes for LHS and RHS matrices
1182 const TensorShape lhs_shape(k, m, batch_size);
1183 const TensorShape rhs_shape(n, k, batch_size);
1184 const TensorShape bias_shape(n, 1, 1);
1185
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001186 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info, has_pad_y);
1187 if(validate_result)
1188 {
1189 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
1190 }
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001191 }
1192
1193protected:
1194 template <typename U>
1195 void fill(U &&tensor, int i)
1196 {
1197 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1198 library->fill(tensor, distribution, i);
1199 }
1200
1201 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
1202 DataType data_type, float alpha, float beta,
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001203 unsigned int m_h, const ActivationLayerInfo &act_info, bool has_pad_y)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001204 {
1205 // Create tensors
1206 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1207 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1208 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
1209 TensorType rhs_reshaped;
1210 TensorType dst;
1211
1212 const unsigned int M = lhs_shape[1];
1213 const unsigned int N = rhs_shape[0];
1214 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001215 GEMMKernelInfo kernel_info;
1216 kernel_info.m = M;
1217 kernel_info.n = N;
1218 kernel_info.k = K;
1219 kernel_info.depth_output_gemm3d = m_h;
1220 kernel_info.reinterpret_input_as_3d = false;
1221 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001222 kernel_info.activation_info = act_info;
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001223 kernel_info.has_pad_y = has_pad_y;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001224
1225 // The output tensor will be auto-initialized within the function
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001226 // Create and configure function
1227 ReshapeRHSFunctionType reshape_rhs;
1228 GEMMFunctionType gemm;
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001229
1230 validate_result = bool(reshape_rhs.validate(rhs.info(), rhs_reshaped.info(), rhs_info));
1231 validate_result = validate_result || !rhs_info.export_to_cl_image;
1232 if(!validate_result)
1233 {
1234 return nullptr;
1235 }
1236
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001237 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001238 gemm.configure(&lhs, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001239
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001240 if(has_pad_y)
1241 {
1242 // Add dummy padding into lhs to validate has_pad_y path
1243 lhs.info()->extend_padding(PaddingSize(2, 0, 2, 0));
1244 dst.info()->extend_padding(PaddingSize(2, 0, 1, 0));
1245 }
1246
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001247 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1248 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1249 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
1250
1251 // Allocate tensors
1252 lhs.allocator()->allocate();
1253 rhs.allocator()->allocate();
1254 rhs_reshaped.allocator()->allocate();
1255 bias.allocator()->allocate();
1256 dst.allocator()->allocate();
1257
1258 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1259 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1260 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
1261 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
1262 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1263
1264 // Fill tensors
1265 fill(AccessorType(lhs), 0);
1266 fill(AccessorType(rhs), 1);
1267 fill(AccessorType(bias), 2);
1268
1269 // Compute GEMM
1270 reshape_rhs.run();
1271 gemm.run();
1272
1273 return dst;
1274 }
1275
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001276 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 +01001277 const ActivationLayerInfo &act_info)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001278 {
1279 TensorShape dst_shape = lhs_shape;
1280 dst_shape.set(0, rhs_shape[0]);
1281 dst_shape.set(1, lhs_shape[1] / m_h);
1282 dst_shape.set(2, m_h);
1283 dst_shape.set(3, lhs_shape[2]);
1284
1285 // Create reference
1286 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1287 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
1288 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1289
1290 const int n = rhs_shape[0];
1291 const int m = lhs_shape[1];
1292 const int batch_size = lhs_shape[2];
1293
1294 // Fill reference
1295 fill(lhs, 0);
1296 fill(rhs, 1);
1297 fill(bias, 2);
1298
1299 // In case of broadcast, we need simply copy the first into the following "M" ones
1300 for(int i = 1; i < m * batch_size; i++)
1301 {
1302 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1303 }
1304
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001305 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001306 }
1307
Sheri Zhangcc3e53c2020-11-16 21:17:28 +00001308 bool validate_result = true;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001309 TensorType _target{};
1310 SimpleTensor<T> _reference{};
1311};
1312
giuros01b3204e72019-04-01 13:50:22 +01001313template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
1314class GEMMMatrixMultiplyNativeValidationFixture : public framework::Fixture
1315{
1316public:
1317 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001318 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,
1319 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001320 {
1321 GEMMLHSMatrixInfo lhs_info;
1322 lhs_info.m0 = m0;
1323 lhs_info.k0 = k0;
1324
1325 GEMMRHSMatrixInfo rhs_info;
1326 rhs_info.n0 = n0;
1327 rhs_info.k0 = k0;
1328
1329 // Set the tensor shapes for LHS and RHS matrices
1330 const TensorShape lhs_shape(k, m, batch_size);
1331 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001332 const TensorShape bias_shape(n,
1333 broadcast_bias ? 1 : m,
1334 broadcast_bias ? 1 : batch_size);
giuros01b3204e72019-04-01 13:50:22 +01001335
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001336 _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 +01001337 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
giuros01b3204e72019-04-01 13:50:22 +01001338 }
1339
1340protected:
1341 template <typename U>
1342 void fill(U &&tensor, int i)
1343 {
1344 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1345 library->fill(tensor, distribution, i);
1346
1347 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
1348 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
1349 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1350 }
1351
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001352 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 +01001353 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001354 {
1355 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001356 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1357 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1358 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01001359 TensorType dst;
1360
1361 const unsigned int M = lhs_shape[1];
1362 const unsigned int N = rhs_shape[0];
1363 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001364 GEMMKernelInfo kernel_info;
1365 kernel_info.m = M;
1366 kernel_info.n = N;
1367 kernel_info.k = K;
1368 kernel_info.depth_output_gemm3d = 0;
1369 kernel_info.reinterpret_input_as_3d = false;
1370 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001371 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01001372
1373 // Create and configure function
1374 GEMMFunctionType gemm;
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001375 gemm.configure(&lhs, &rhs, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01001376
1377 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1378 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001379 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001380
1381 // Allocate tensors
1382 lhs.allocator()->allocate();
1383 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001384 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01001385 dst.allocator()->allocate();
1386
1387 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1388 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001389 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001390 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1391
1392 // Fill tensors
1393 fill(AccessorType(lhs), 0);
1394 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001395 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01001396
1397 // Compute GEMM
1398 gemm.run();
1399
1400 return dst;
1401 }
1402
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001403 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 +01001404 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001405 {
1406 TensorShape dst_shape = lhs_shape;
1407 dst_shape[0] = rhs_shape[0];
1408 dst_shape[1] = lhs_shape[1];
1409
1410 // Create reference
1411 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1412 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001413 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1414
1415 const int n = rhs_shape[0];
1416 const int m = lhs_shape[1];
1417 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01001418
1419 // Fill reference
1420 fill(lhs, 0);
1421 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001422 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01001423
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001424 if(broadcast_bias)
1425 {
1426 // In case of broadcast, we need simply copy the first into the following "M" ones
1427 for(int i = 1; i < m * batch_size; i++)
1428 {
1429 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1430 }
1431 }
1432
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001433 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01001434 }
1435
1436 TensorType _target{};
1437 SimpleTensor<T> _reference{};
1438};
1439
giuros01b3204e72019-04-01 13:50:22 +01001440template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
1441class GEMMMatrixMultiplyNative3DValidationFixture : public framework::Fixture
1442{
1443public:
1444 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001445 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,
1446 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001447 {
1448 GEMMLHSMatrixInfo lhs_info;
1449 lhs_info.m0 = m0;
1450 lhs_info.k0 = k0;
1451
1452 GEMMRHSMatrixInfo rhs_info;
1453 rhs_info.n0 = n0;
1454 rhs_info.k0 = k0;
1455
1456 // In case of GEMM3D, m is the product between m_w and m_h
1457 const unsigned int m = m_w * m_h;
1458
1459 // Set the tensor shapes for LHS and RHS matrices
1460 const TensorShape lhs_shape(k, m, batch_size);
1461 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001462 const TensorShape bias_shape(n, 1, 1);
giuros01b3204e72019-04-01 13:50:22 +01001463
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001464 _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 +01001465 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
giuros01b3204e72019-04-01 13:50:22 +01001466 }
1467
1468protected:
1469 template <typename U>
1470 void fill(U &&tensor, int i)
1471 {
1472 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1473 library->fill(tensor, distribution, i);
1474 }
1475
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001476 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001477 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001478 {
1479 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001480 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1481 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1482 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01001483 TensorType dst;
1484
1485 const unsigned int M = lhs_shape[1];
1486 const unsigned int N = rhs_shape[0];
1487 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001488 GEMMKernelInfo kernel_info;
1489 kernel_info.m = M;
1490 kernel_info.n = N;
1491 kernel_info.k = K;
1492 kernel_info.depth_output_gemm3d = m_h;
1493 kernel_info.reinterpret_input_as_3d = false;
1494 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001495 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01001496
1497 // The output tensor will be auto-initialized within the function
1498
1499 // Create and configure function
1500 GEMMFunctionType gemm;
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001501 gemm.configure(&lhs, &rhs, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01001502
1503 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1504 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001505 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001506
1507 // Allocate tensors
1508 lhs.allocator()->allocate();
1509 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001510 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01001511 dst.allocator()->allocate();
1512
1513 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1514 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001515 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001516 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1517
1518 // Fill tensors
1519 fill(AccessorType(lhs), 0);
1520 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001521 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01001522
1523 // Compute GEMM
1524 gemm.run();
1525
1526 return dst;
1527 }
1528
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001529 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 +01001530 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001531 {
1532 TensorShape dst_shape = lhs_shape;
1533 dst_shape.set(0, rhs_shape[0]);
1534 dst_shape.set(1, lhs_shape[1] / m_h);
1535 dst_shape.set(2, m_h);
1536 dst_shape.set(3, lhs_shape[2]);
1537
1538 // Create reference
1539 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1540 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001541 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1542
1543 const int n = rhs_shape[0];
1544 const int m = lhs_shape[1];
1545 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01001546
1547 // Fill reference
1548 fill(lhs, 0);
1549 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001550 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01001551
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001552 // In case of broadcast, we need simply copy the first into the following "M" ones
1553 for(int i = 1; i < m * batch_size; i++)
1554 {
1555 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1556 }
1557
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001558 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01001559 }
1560
1561 TensorType _target{};
1562 SimpleTensor<T> _reference{};
1563};
1564
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +01001565} // namespace validation
1566} // namespace test
1567} // namespace arm_compute
1568#endif /* ARM_COMPUTE_TEST_GEMM_FIXTURE */