blob: 6288b6b970015ca56a8d08bb845e671d246ff856 [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
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100705 _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 +0100706 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000707 }
708
709protected:
710 template <typename U>
711 void fill(U &&tensor, int i)
712 {
713 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
714 library->fill(tensor, distribution, i);
Gian Marco Iodiceb87b95e2019-01-21 17:14:31 +0000715
716 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
717 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
718 library->fill_borders_with_garbage(tensor, distribution_inf, i);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000719 }
720
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100721 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 +0100722 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000723 {
724 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100725 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
726 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
727 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000728 TensorType lhs_reshaped;
729 TensorType rhs_reshaped;
730 TensorType dst;
731
732 const unsigned int M = lhs_shape[1];
733 const unsigned int N = rhs_shape[0];
734 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100735 GEMMKernelInfo kernel_info;
736 kernel_info.m = M;
737 kernel_info.n = N;
738 kernel_info.k = K;
739 kernel_info.depth_output_gemm3d = 0;
740 kernel_info.reinterpret_input_as_3d = false;
741 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100742 kernel_info.activation_info = act_info;
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100743 kernel_info.fp_mixed_precision = fp_mixed_precision;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000744
745 // The output tensor will be auto-initialized within the function
746
747 // Create and configure function
748 ReshapeLHSFunctionType reshape_lhs;
749 ReshapeRHSFunctionType reshape_rhs;
750 GEMMFunctionType gemm;
751 reshape_lhs.configure(&lhs, &lhs_reshaped, lhs_info);
752 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100753 gemm.configure(&lhs_reshaped, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000754
755 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
756 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100757 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000758
759 // Allocate tensors
760 lhs.allocator()->allocate();
761 rhs.allocator()->allocate();
762 lhs_reshaped.allocator()->allocate();
763 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100764 bias.allocator()->allocate();
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000765 dst.allocator()->allocate();
766
767 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
768 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100769 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000770 ARM_COMPUTE_EXPECT(!lhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
771 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
772 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
773
774 // Fill tensors
775 fill(AccessorType(lhs), 0);
776 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100777 fill(AccessorType(bias), 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000778
779 // Compute GEMM
780 reshape_lhs.run();
781 reshape_rhs.run();
782 gemm.run();
783
784 return dst;
785 }
786
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100787 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 +0100788 const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000789 {
790 TensorShape dst_shape = lhs_shape;
791 dst_shape[0] = rhs_shape[0];
792 dst_shape[1] = lhs_shape[1];
793
794 // Create reference
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000795 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
796 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100797 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
798
799 const int n = rhs_shape[0];
800 const int m = lhs_shape[1];
801 const int batch_size = lhs_shape[2];
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000802
803 // Fill reference
804 fill(lhs, 0);
805 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100806 fill(bias, 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000807
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100808 if(broadcast_bias)
809 {
810 // In case of broadcast, we need simply copy the first into the following "M" ones
811 for(int i = 1; i < m * batch_size; i++)
812 {
813 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
814 }
815 }
816
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100817 if(fp_mixed_precision)
818 {
819 return reference::activation_layer(reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta), act_info);
820 }
821 else
822 {
823 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
824 }
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000825 }
826
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000827 TensorType _target{};
828 SimpleTensor<T> _reference{};
829};
830
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100831template <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 +0000832class GEMMMatrixMultiplyReshaped3DValidationFixture : public framework::Fixture
833{
834public:
835 template <typename...>
836 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 +0100837 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 +0000838 {
839 GEMMLHSMatrixInfo lhs_info;
840 lhs_info.m0 = m0;
841 lhs_info.k0 = k0;
842 lhs_info.v0 = v0;
843 lhs_info.interleave = interleave_lhs;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100844 lhs_info.transpose = lhs_transpose;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000845
846 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodicee3a849a2020-06-10 17:59:30 +0100847 rhs_info.n0 = n0;
848 rhs_info.k0 = k0;
849 rhs_info.h0 = h0;
850 rhs_info.interleave = interleave_rhs;
851 rhs_info.transpose = !lhs_transpose;
852 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000853
854 // In case of GEMM3D, m is the product between m_w and m_h
855 const unsigned int m = m_w * m_h;
856
857 // Set the tensor shapes for LHS and RHS matrices
858 const TensorShape lhs_shape(k, m, batch_size);
859 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100860 const TensorShape bias_shape(n, 1, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000861
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100862 _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 +0100863 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000864 }
865
866protected:
867 template <typename U>
868 void fill(U &&tensor, int i)
869 {
870 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
871 library->fill(tensor, distribution, i);
872 }
873
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100874 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 +0100875 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000876 {
877 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100878 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
879 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
880 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000881 TensorType lhs_reshaped;
882 TensorType rhs_reshaped;
883 TensorType dst;
884
885 const unsigned int M = lhs_shape[1];
886 const unsigned int N = rhs_shape[0];
887 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100888 GEMMKernelInfo kernel_info;
889 kernel_info.m = M;
890 kernel_info.n = N;
891 kernel_info.k = K;
892 kernel_info.depth_output_gemm3d = m_h;
893 kernel_info.reinterpret_input_as_3d = false;
894 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100895 kernel_info.activation_info = act_info;
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100896 kernel_info.fp_mixed_precision = fp_mixed_precision;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000897
898 // The output tensor will be auto-initialized within the function
899
900 // Create and configure function
901 ReshapeLHSFunctionType reshape_lhs;
902 ReshapeRHSFunctionType reshape_rhs;
903 GEMMFunctionType gemm;
904 reshape_lhs.configure(&lhs, &lhs_reshaped, lhs_info);
905 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100906 gemm.configure(&lhs_reshaped, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000907
908 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
909 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100910 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000911
912 // Allocate tensors
913 lhs.allocator()->allocate();
914 rhs.allocator()->allocate();
915 lhs_reshaped.allocator()->allocate();
916 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100917 bias.allocator()->allocate();
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000918 dst.allocator()->allocate();
919
920 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
921 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
922 ARM_COMPUTE_EXPECT(!lhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
923 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100924 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000925 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
926
927 // Fill tensors
928 fill(AccessorType(lhs), 0);
929 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100930 fill(AccessorType(bias), 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000931
932 // Compute GEMM
933 reshape_lhs.run();
934 reshape_rhs.run();
935 gemm.run();
936
937 return dst;
938 }
939
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100940 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 +0100941 const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000942 {
943 TensorShape dst_shape = lhs_shape;
944 dst_shape.set(0, rhs_shape[0]);
945 dst_shape.set(1, lhs_shape[1] / m_h);
946 dst_shape.set(2, m_h);
947 dst_shape.set(3, lhs_shape[2]);
948
949 // Create reference
950 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
951 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100952 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
953
954 const int n = rhs_shape[0];
955 const int m = lhs_shape[1];
956 const int batch_size = lhs_shape[2];
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000957
958 // Fill reference
959 fill(lhs, 0);
960 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100961 fill(bias, 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000962
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100963 // In case of broadcast, we need simply copy the first into the following "M" ones
964 for(int i = 1; i < m * batch_size; i++)
965 {
966 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
967 }
968
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100969 if(fp_mixed_precision)
970 {
971 return reference::activation_layer(reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta), act_info);
972 }
973 else
974 {
975 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
976 }
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000977 }
978
979 TensorType _target{};
980 SimpleTensor<T> _reference{};
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000981};
Gian Marco Iodiceadc53952019-02-15 11:10:31 +0000982
983template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
984class GEMMMatrixMultiplyReshapedOnlyRHSValidationFixture : public framework::Fixture
985{
986public:
987 template <typename...>
988 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 +0100989 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 +0000990 {
991 GEMMLHSMatrixInfo lhs_info;
992 lhs_info.m0 = m0;
993 lhs_info.k0 = k0;
994
995 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodice781cba72020-06-19 16:56:57 +0100996 rhs_info.n0 = n0;
997 rhs_info.k0 = k0;
998 rhs_info.h0 = h0;
999 rhs_info.interleave = interleave_rhs;
1000 rhs_info.transpose = transpose_rhs;
1001 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001002
1003 // Set the tensor shapes for LHS and RHS matrices
1004 const TensorShape lhs_shape(k, m, batch_size);
1005 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001006 const TensorShape bias_shape(n,
1007 broadcast_bias ? 1 : m,
1008 broadcast_bias ? 1 : batch_size);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001009
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001010 _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 +01001011 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001012 }
1013
1014protected:
1015 template <typename U>
1016 void fill(U &&tensor, int i)
1017 {
1018 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1019 library->fill(tensor, distribution, i);
1020
1021 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
1022 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
1023 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1024 }
1025
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001026 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 +01001027 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001028 {
1029 // Create tensors
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001030 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1031 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1032 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001033 TensorType rhs_reshaped;
1034 TensorType dst;
1035
1036 const unsigned int M = lhs_shape[1];
1037 const unsigned int N = rhs_shape[0];
1038 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001039 GEMMKernelInfo kernel_info;
1040 kernel_info.m = M;
1041 kernel_info.n = N;
1042 kernel_info.k = K;
1043 kernel_info.depth_output_gemm3d = 0;
1044 kernel_info.reinterpret_input_as_3d = false;
1045 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001046 kernel_info.activation_info = act_info;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001047
1048 // The output tensor will be auto-initialized within the function
1049
1050 // Create and configure function
1051 ReshapeRHSFunctionType reshape_rhs;
1052 GEMMFunctionType gemm;
1053 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001054 gemm.configure(&lhs, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001055
1056 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1057 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001058 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001059
1060 // Allocate tensors
1061 lhs.allocator()->allocate();
1062 rhs.allocator()->allocate();
1063 rhs_reshaped.allocator()->allocate();
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001064 bias.allocator()->allocate();
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001065 dst.allocator()->allocate();
1066
1067 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1068 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1069 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001070 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001071 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1072
1073 // Fill tensors
1074 fill(AccessorType(lhs), 0);
1075 fill(AccessorType(rhs), 1);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001076 fill(AccessorType(bias), 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001077
1078 // Compute GEMM
1079 reshape_rhs.run();
1080 gemm.run();
1081
1082 return dst;
1083 }
1084
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001085 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 +01001086 const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001087 {
1088 TensorShape dst_shape = lhs_shape;
1089 dst_shape[0] = rhs_shape[0];
1090 dst_shape[1] = lhs_shape[1];
1091
1092 // Create reference
1093 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1094 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001095 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1096
1097 const int n = rhs_shape[0];
1098 const int m = lhs_shape[1];
1099 const int batch_size = lhs_shape[2];
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001100
1101 // Fill reference
1102 fill(lhs, 0);
1103 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001104 fill(bias, 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001105
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001106 if(broadcast_bias)
1107 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001108 // In case of broadcast, we need simply copy the first into the following "M" ones
1109 for(int i = 1; i < m * batch_size; i++)
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001110 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001111 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001112 }
1113 }
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001114
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001115 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001116 }
1117
1118 TensorType _target{};
1119 SimpleTensor<T> _reference{};
1120};
1121
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001122template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
1123class GEMMMatrixMultiplyReshapedOnlyRHS3DValidationFixture : public framework::Fixture
1124{
1125public:
1126 template <typename...>
1127 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 +01001128 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 +01001129 {
1130 GEMMLHSMatrixInfo lhs_info;
1131 lhs_info.m0 = m0;
1132 lhs_info.k0 = k0;
1133
1134 GEMMRHSMatrixInfo rhs_info;
Gian Marco Iodice781cba72020-06-19 16:56:57 +01001135 rhs_info.n0 = n0;
1136 rhs_info.k0 = k0;
1137 rhs_info.h0 = h0;
1138 rhs_info.interleave = interleave_rhs;
1139 rhs_info.transpose = transpose_rhs;
1140 rhs_info.export_to_cl_image = export_to_cl_image;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001141
1142 // In case of GEMM3D, m is the product between m_w and m_h
1143 const unsigned int m = m_w * m_h;
1144
1145 // Set the tensor shapes for LHS and RHS matrices
1146 const TensorShape lhs_shape(k, m, batch_size);
1147 const TensorShape rhs_shape(n, k, batch_size);
1148 const TensorShape bias_shape(n, 1, 1);
1149
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001150 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info, has_pad_y);
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001151 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001152 }
1153
1154protected:
1155 template <typename U>
1156 void fill(U &&tensor, int i)
1157 {
1158 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1159 library->fill(tensor, distribution, i);
1160 }
1161
1162 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
1163 DataType data_type, float alpha, float beta,
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001164 unsigned int m_h, const ActivationLayerInfo &act_info, bool has_pad_y)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001165 {
1166 // Create tensors
1167 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1168 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1169 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
1170 TensorType rhs_reshaped;
1171 TensorType dst;
1172
1173 const unsigned int M = lhs_shape[1];
1174 const unsigned int N = rhs_shape[0];
1175 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001176 GEMMKernelInfo kernel_info;
1177 kernel_info.m = M;
1178 kernel_info.n = N;
1179 kernel_info.k = K;
1180 kernel_info.depth_output_gemm3d = m_h;
1181 kernel_info.reinterpret_input_as_3d = false;
1182 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001183 kernel_info.activation_info = act_info;
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001184 kernel_info.has_pad_y = has_pad_y;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001185
1186 // The output tensor will be auto-initialized within the function
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001187 // Create and configure function
1188 ReshapeRHSFunctionType reshape_rhs;
1189 GEMMFunctionType gemm;
1190 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001191 gemm.configure(&lhs, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001192
Gian Marco Iodice9ae06d42020-10-22 16:37:12 +01001193 if(has_pad_y)
1194 {
1195 // Add dummy padding into lhs to validate has_pad_y path
1196 lhs.info()->extend_padding(PaddingSize(2, 0, 2, 0));
1197 dst.info()->extend_padding(PaddingSize(2, 0, 1, 0));
1198 }
1199
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001200 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1201 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1202 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
1203
1204 // Allocate tensors
1205 lhs.allocator()->allocate();
1206 rhs.allocator()->allocate();
1207 rhs_reshaped.allocator()->allocate();
1208 bias.allocator()->allocate();
1209 dst.allocator()->allocate();
1210
1211 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1212 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1213 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
1214 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
1215 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1216
1217 // Fill tensors
1218 fill(AccessorType(lhs), 0);
1219 fill(AccessorType(rhs), 1);
1220 fill(AccessorType(bias), 2);
1221
1222 // Compute GEMM
1223 reshape_rhs.run();
1224 gemm.run();
1225
1226 return dst;
1227 }
1228
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001229 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 +01001230 const ActivationLayerInfo &act_info)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001231 {
1232 TensorShape dst_shape = lhs_shape;
1233 dst_shape.set(0, rhs_shape[0]);
1234 dst_shape.set(1, lhs_shape[1] / m_h);
1235 dst_shape.set(2, m_h);
1236 dst_shape.set(3, lhs_shape[2]);
1237
1238 // Create reference
1239 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1240 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
1241 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1242
1243 const int n = rhs_shape[0];
1244 const int m = lhs_shape[1];
1245 const int batch_size = lhs_shape[2];
1246
1247 // Fill reference
1248 fill(lhs, 0);
1249 fill(rhs, 1);
1250 fill(bias, 2);
1251
1252 // In case of broadcast, we need simply copy the first into the following "M" ones
1253 for(int i = 1; i < m * batch_size; i++)
1254 {
1255 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1256 }
1257
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001258 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001259 }
1260
1261 TensorType _target{};
1262 SimpleTensor<T> _reference{};
1263};
1264
giuros01b3204e72019-04-01 13:50:22 +01001265template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
1266class GEMMMatrixMultiplyNativeValidationFixture : public framework::Fixture
1267{
1268public:
1269 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001270 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,
1271 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001272 {
1273 GEMMLHSMatrixInfo lhs_info;
1274 lhs_info.m0 = m0;
1275 lhs_info.k0 = k0;
1276
1277 GEMMRHSMatrixInfo rhs_info;
1278 rhs_info.n0 = n0;
1279 rhs_info.k0 = k0;
1280
1281 // Set the tensor shapes for LHS and RHS matrices
1282 const TensorShape lhs_shape(k, m, batch_size);
1283 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001284 const TensorShape bias_shape(n,
1285 broadcast_bias ? 1 : m,
1286 broadcast_bias ? 1 : batch_size);
giuros01b3204e72019-04-01 13:50:22 +01001287
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001288 _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 +01001289 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
giuros01b3204e72019-04-01 13:50:22 +01001290 }
1291
1292protected:
1293 template <typename U>
1294 void fill(U &&tensor, int i)
1295 {
1296 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1297 library->fill(tensor, distribution, i);
1298
1299 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
1300 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
1301 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1302 }
1303
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001304 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 +01001305 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001306 {
1307 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001308 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1309 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1310 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01001311 TensorType dst;
1312
1313 const unsigned int M = lhs_shape[1];
1314 const unsigned int N = rhs_shape[0];
1315 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001316 GEMMKernelInfo kernel_info;
1317 kernel_info.m = M;
1318 kernel_info.n = N;
1319 kernel_info.k = K;
1320 kernel_info.depth_output_gemm3d = 0;
1321 kernel_info.reinterpret_input_as_3d = false;
1322 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001323 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01001324
1325 // Create and configure function
1326 GEMMFunctionType gemm;
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001327 gemm.configure(&lhs, &rhs, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01001328
1329 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1330 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001331 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001332
1333 // Allocate tensors
1334 lhs.allocator()->allocate();
1335 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001336 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01001337 dst.allocator()->allocate();
1338
1339 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1340 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001341 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001342 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1343
1344 // Fill tensors
1345 fill(AccessorType(lhs), 0);
1346 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001347 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01001348
1349 // Compute GEMM
1350 gemm.run();
1351
1352 return dst;
1353 }
1354
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001355 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 +01001356 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001357 {
1358 TensorShape dst_shape = lhs_shape;
1359 dst_shape[0] = rhs_shape[0];
1360 dst_shape[1] = lhs_shape[1];
1361
1362 // Create reference
1363 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1364 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001365 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1366
1367 const int n = rhs_shape[0];
1368 const int m = lhs_shape[1];
1369 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01001370
1371 // Fill reference
1372 fill(lhs, 0);
1373 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001374 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01001375
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001376 if(broadcast_bias)
1377 {
1378 // In case of broadcast, we need simply copy the first into the following "M" ones
1379 for(int i = 1; i < m * batch_size; i++)
1380 {
1381 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1382 }
1383 }
1384
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001385 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01001386 }
1387
1388 TensorType _target{};
1389 SimpleTensor<T> _reference{};
1390};
1391
giuros01b3204e72019-04-01 13:50:22 +01001392template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
1393class GEMMMatrixMultiplyNative3DValidationFixture : public framework::Fixture
1394{
1395public:
1396 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001397 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,
1398 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001399 {
1400 GEMMLHSMatrixInfo lhs_info;
1401 lhs_info.m0 = m0;
1402 lhs_info.k0 = k0;
1403
1404 GEMMRHSMatrixInfo rhs_info;
1405 rhs_info.n0 = n0;
1406 rhs_info.k0 = k0;
1407
1408 // In case of GEMM3D, m is the product between m_w and m_h
1409 const unsigned int m = m_w * m_h;
1410
1411 // Set the tensor shapes for LHS and RHS matrices
1412 const TensorShape lhs_shape(k, m, batch_size);
1413 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001414 const TensorShape bias_shape(n, 1, 1);
giuros01b3204e72019-04-01 13:50:22 +01001415
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001416 _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 +01001417 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
giuros01b3204e72019-04-01 13:50:22 +01001418 }
1419
1420protected:
1421 template <typename U>
1422 void fill(U &&tensor, int i)
1423 {
1424 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1425 library->fill(tensor, distribution, i);
1426 }
1427
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001428 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 +01001429 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001430 {
1431 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001432 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1433 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1434 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01001435 TensorType dst;
1436
1437 const unsigned int M = lhs_shape[1];
1438 const unsigned int N = rhs_shape[0];
1439 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001440 GEMMKernelInfo kernel_info;
1441 kernel_info.m = M;
1442 kernel_info.n = N;
1443 kernel_info.k = K;
1444 kernel_info.depth_output_gemm3d = m_h;
1445 kernel_info.reinterpret_input_as_3d = false;
1446 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001447 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01001448
1449 // The output tensor will be auto-initialized within the function
1450
1451 // Create and configure function
1452 GEMMFunctionType gemm;
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001453 gemm.configure(&lhs, &rhs, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01001454
1455 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1456 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001457 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001458
1459 // Allocate tensors
1460 lhs.allocator()->allocate();
1461 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001462 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01001463 dst.allocator()->allocate();
1464
1465 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1466 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001467 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001468 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1469
1470 // Fill tensors
1471 fill(AccessorType(lhs), 0);
1472 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001473 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01001474
1475 // Compute GEMM
1476 gemm.run();
1477
1478 return dst;
1479 }
1480
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001481 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 +01001482 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001483 {
1484 TensorShape dst_shape = lhs_shape;
1485 dst_shape.set(0, rhs_shape[0]);
1486 dst_shape.set(1, lhs_shape[1] / m_h);
1487 dst_shape.set(2, m_h);
1488 dst_shape.set(3, lhs_shape[2]);
1489
1490 // Create reference
1491 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1492 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001493 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1494
1495 const int n = rhs_shape[0];
1496 const int m = lhs_shape[1];
1497 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01001498
1499 // Fill reference
1500 fill(lhs, 0);
1501 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001502 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01001503
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001504 // In case of broadcast, we need simply copy the first into the following "M" ones
1505 for(int i = 1; i < m * batch_size; i++)
1506 {
1507 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1508 }
1509
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001510 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01001511 }
1512
1513 TensorType _target{};
1514 SimpleTensor<T> _reference{};
1515};
1516
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +01001517} // namespace validation
1518} // namespace test
1519} // namespace arm_compute
1520#endif /* ARM_COMPUTE_TEST_GEMM_FIXTURE */