blob: b2adf2dfc0203ad524611127649d3b6c239b7b4d [file] [log] [blame]
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +01001/*
Gian Marco Iodicee3a849a2020-06-10 17:59:30 +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 Iodiceca1f4602019-07-16 15:46:48 +0100989 bool interleave_rhs, bool transpose_rhs, 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;
996 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
1002 // Set the tensor shapes for LHS and RHS matrices
1003 const TensorShape lhs_shape(k, m, batch_size);
1004 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001005 const TensorShape bias_shape(n,
1006 broadcast_bias ? 1 : m,
1007 broadcast_bias ? 1 : batch_size);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001008
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001009 _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 +01001010 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001011 }
1012
1013protected:
1014 template <typename U>
1015 void fill(U &&tensor, int i)
1016 {
1017 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1018 library->fill(tensor, distribution, i);
1019
1020 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
1021 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
1022 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1023 }
1024
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001025 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 +01001026 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001027 {
1028 // Create tensors
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001029 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1030 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1031 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001032 TensorType rhs_reshaped;
1033 TensorType dst;
1034
1035 const unsigned int M = lhs_shape[1];
1036 const unsigned int N = rhs_shape[0];
1037 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001038 GEMMKernelInfo kernel_info;
1039 kernel_info.m = M;
1040 kernel_info.n = N;
1041 kernel_info.k = K;
1042 kernel_info.depth_output_gemm3d = 0;
1043 kernel_info.reinterpret_input_as_3d = false;
1044 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001045 kernel_info.activation_info = act_info;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001046
1047 // The output tensor will be auto-initialized within the function
1048
1049 // Create and configure function
1050 ReshapeRHSFunctionType reshape_rhs;
1051 GEMMFunctionType gemm;
1052 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001053 gemm.configure(&lhs, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001054
1055 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1056 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001057 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001058
1059 // Allocate tensors
1060 lhs.allocator()->allocate();
1061 rhs.allocator()->allocate();
1062 rhs_reshaped.allocator()->allocate();
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001063 bias.allocator()->allocate();
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001064 dst.allocator()->allocate();
1065
1066 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1067 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1068 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001069 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001070 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1071
1072 // Fill tensors
1073 fill(AccessorType(lhs), 0);
1074 fill(AccessorType(rhs), 1);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001075 fill(AccessorType(bias), 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001076
1077 // Compute GEMM
1078 reshape_rhs.run();
1079 gemm.run();
1080
1081 return dst;
1082 }
1083
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001084 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 +01001085 const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001086 {
1087 TensorShape dst_shape = lhs_shape;
1088 dst_shape[0] = rhs_shape[0];
1089 dst_shape[1] = lhs_shape[1];
1090
1091 // Create reference
1092 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1093 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001094 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1095
1096 const int n = rhs_shape[0];
1097 const int m = lhs_shape[1];
1098 const int batch_size = lhs_shape[2];
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001099
1100 // Fill reference
1101 fill(lhs, 0);
1102 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001103 fill(bias, 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001104
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001105 if(broadcast_bias)
1106 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001107 // In case of broadcast, we need simply copy the first into the following "M" ones
1108 for(int i = 1; i < m * batch_size; i++)
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001109 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001110 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001111 }
1112 }
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001113
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001114 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001115 }
1116
1117 TensorType _target{};
1118 SimpleTensor<T> _reference{};
1119};
1120
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001121template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
1122class GEMMMatrixMultiplyReshapedOnlyRHS3DValidationFixture : public framework::Fixture
1123{
1124public:
1125 template <typename...>
1126 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 Iodiceca1f4602019-07-16 15:46:48 +01001127 bool interleave_rhs, bool transpose_rhs, DataType data_type, float alpha, float beta, const ActivationLayerInfo &act_info)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001128 {
1129 GEMMLHSMatrixInfo lhs_info;
1130 lhs_info.m0 = m0;
1131 lhs_info.k0 = k0;
1132
1133 GEMMRHSMatrixInfo rhs_info;
1134 rhs_info.n0 = n0;
1135 rhs_info.k0 = k0;
1136 rhs_info.h0 = h0;
1137 rhs_info.interleave = interleave_rhs;
1138 rhs_info.transpose = transpose_rhs;
1139
1140 // In case of GEMM3D, m is the product between m_w and m_h
1141 const unsigned int m = m_w * m_h;
1142
1143 // Set the tensor shapes for LHS and RHS matrices
1144 const TensorShape lhs_shape(k, m, batch_size);
1145 const TensorShape rhs_shape(n, k, batch_size);
1146 const TensorShape bias_shape(n, 1, 1);
1147
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001148 _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 +01001149 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001150 }
1151
1152protected:
1153 template <typename U>
1154 void fill(U &&tensor, int i)
1155 {
1156 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1157 library->fill(tensor, distribution, i);
1158 }
1159
1160 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
1161 DataType data_type, float alpha, float beta,
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001162 unsigned int m_h, const ActivationLayerInfo &act_info)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001163 {
1164 // Create tensors
1165 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1166 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1167 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
1168 TensorType rhs_reshaped;
1169 TensorType dst;
1170
1171 const unsigned int M = lhs_shape[1];
1172 const unsigned int N = rhs_shape[0];
1173 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001174 GEMMKernelInfo kernel_info;
1175 kernel_info.m = M;
1176 kernel_info.n = N;
1177 kernel_info.k = K;
1178 kernel_info.depth_output_gemm3d = m_h;
1179 kernel_info.reinterpret_input_as_3d = false;
1180 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001181 kernel_info.activation_info = act_info;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001182
1183 // The output tensor will be auto-initialized within the function
1184
1185 // Create and configure function
1186 ReshapeRHSFunctionType reshape_rhs;
1187 GEMMFunctionType gemm;
1188 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001189 gemm.configure(&lhs, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001190
1191 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1192 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1193 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
1194
1195 // Allocate tensors
1196 lhs.allocator()->allocate();
1197 rhs.allocator()->allocate();
1198 rhs_reshaped.allocator()->allocate();
1199 bias.allocator()->allocate();
1200 dst.allocator()->allocate();
1201
1202 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1203 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1204 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
1205 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
1206 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1207
1208 // Fill tensors
1209 fill(AccessorType(lhs), 0);
1210 fill(AccessorType(rhs), 1);
1211 fill(AccessorType(bias), 2);
1212
1213 // Compute GEMM
1214 reshape_rhs.run();
1215 gemm.run();
1216
1217 return dst;
1218 }
1219
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001220 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 +01001221 const ActivationLayerInfo &act_info)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001222 {
1223 TensorShape dst_shape = lhs_shape;
1224 dst_shape.set(0, rhs_shape[0]);
1225 dst_shape.set(1, lhs_shape[1] / m_h);
1226 dst_shape.set(2, m_h);
1227 dst_shape.set(3, lhs_shape[2]);
1228
1229 // Create reference
1230 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1231 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
1232 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1233
1234 const int n = rhs_shape[0];
1235 const int m = lhs_shape[1];
1236 const int batch_size = lhs_shape[2];
1237
1238 // Fill reference
1239 fill(lhs, 0);
1240 fill(rhs, 1);
1241 fill(bias, 2);
1242
1243 // In case of broadcast, we need simply copy the first into the following "M" ones
1244 for(int i = 1; i < m * batch_size; i++)
1245 {
1246 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1247 }
1248
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001249 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001250 }
1251
1252 TensorType _target{};
1253 SimpleTensor<T> _reference{};
1254};
1255
giuros01b3204e72019-04-01 13:50:22 +01001256template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
1257class GEMMMatrixMultiplyNativeValidationFixture : public framework::Fixture
1258{
1259public:
1260 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001261 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,
1262 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001263 {
1264 GEMMLHSMatrixInfo lhs_info;
1265 lhs_info.m0 = m0;
1266 lhs_info.k0 = k0;
1267
1268 GEMMRHSMatrixInfo rhs_info;
1269 rhs_info.n0 = n0;
1270 rhs_info.k0 = k0;
1271
1272 // Set the tensor shapes for LHS and RHS matrices
1273 const TensorShape lhs_shape(k, m, batch_size);
1274 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001275 const TensorShape bias_shape(n,
1276 broadcast_bias ? 1 : m,
1277 broadcast_bias ? 1 : batch_size);
giuros01b3204e72019-04-01 13:50:22 +01001278
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001279 _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 +01001280 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
giuros01b3204e72019-04-01 13:50:22 +01001281 }
1282
1283protected:
1284 template <typename U>
1285 void fill(U &&tensor, int i)
1286 {
1287 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1288 library->fill(tensor, distribution, i);
1289
1290 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
1291 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
1292 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1293 }
1294
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001295 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 +01001296 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001297 {
1298 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001299 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1300 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1301 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01001302 TensorType dst;
1303
1304 const unsigned int M = lhs_shape[1];
1305 const unsigned int N = rhs_shape[0];
1306 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001307 GEMMKernelInfo kernel_info;
1308 kernel_info.m = M;
1309 kernel_info.n = N;
1310 kernel_info.k = K;
1311 kernel_info.depth_output_gemm3d = 0;
1312 kernel_info.reinterpret_input_as_3d = false;
1313 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001314 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01001315
1316 // Create and configure function
1317 GEMMFunctionType gemm;
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001318 gemm.configure(&lhs, &rhs, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01001319
1320 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1321 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001322 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001323
1324 // Allocate tensors
1325 lhs.allocator()->allocate();
1326 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001327 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01001328 dst.allocator()->allocate();
1329
1330 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1331 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001332 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001333 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1334
1335 // Fill tensors
1336 fill(AccessorType(lhs), 0);
1337 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001338 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01001339
1340 // Compute GEMM
1341 gemm.run();
1342
1343 return dst;
1344 }
1345
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001346 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 +01001347 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001348 {
1349 TensorShape dst_shape = lhs_shape;
1350 dst_shape[0] = rhs_shape[0];
1351 dst_shape[1] = lhs_shape[1];
1352
1353 // Create reference
1354 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1355 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001356 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1357
1358 const int n = rhs_shape[0];
1359 const int m = lhs_shape[1];
1360 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01001361
1362 // Fill reference
1363 fill(lhs, 0);
1364 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001365 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01001366
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001367 if(broadcast_bias)
1368 {
1369 // In case of broadcast, we need simply copy the first into the following "M" ones
1370 for(int i = 1; i < m * batch_size; i++)
1371 {
1372 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1373 }
1374 }
1375
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001376 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01001377 }
1378
1379 TensorType _target{};
1380 SimpleTensor<T> _reference{};
1381};
1382
giuros01b3204e72019-04-01 13:50:22 +01001383template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
1384class GEMMMatrixMultiplyNative3DValidationFixture : public framework::Fixture
1385{
1386public:
1387 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001388 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,
1389 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001390 {
1391 GEMMLHSMatrixInfo lhs_info;
1392 lhs_info.m0 = m0;
1393 lhs_info.k0 = k0;
1394
1395 GEMMRHSMatrixInfo rhs_info;
1396 rhs_info.n0 = n0;
1397 rhs_info.k0 = k0;
1398
1399 // In case of GEMM3D, m is the product between m_w and m_h
1400 const unsigned int m = m_w * m_h;
1401
1402 // Set the tensor shapes for LHS and RHS matrices
1403 const TensorShape lhs_shape(k, m, batch_size);
1404 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001405 const TensorShape bias_shape(n, 1, 1);
giuros01b3204e72019-04-01 13:50:22 +01001406
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001407 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info);
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001408 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
giuros01b3204e72019-04-01 13:50:22 +01001409 }
1410
1411protected:
1412 template <typename U>
1413 void fill(U &&tensor, int i)
1414 {
1415 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1416 library->fill(tensor, distribution, i);
1417 }
1418
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001419 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 +01001420 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001421 {
1422 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001423 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1424 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1425 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01001426 TensorType dst;
1427
1428 const unsigned int M = lhs_shape[1];
1429 const unsigned int N = rhs_shape[0];
1430 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001431 GEMMKernelInfo kernel_info;
1432 kernel_info.m = M;
1433 kernel_info.n = N;
1434 kernel_info.k = K;
1435 kernel_info.depth_output_gemm3d = m_h;
1436 kernel_info.reinterpret_input_as_3d = false;
1437 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001438 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01001439
1440 // The output tensor will be auto-initialized within the function
1441
1442 // Create and configure function
1443 GEMMFunctionType gemm;
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001444 gemm.configure(&lhs, &rhs, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01001445
1446 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1447 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001448 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001449
1450 // Allocate tensors
1451 lhs.allocator()->allocate();
1452 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001453 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01001454 dst.allocator()->allocate();
1455
1456 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1457 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001458 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001459 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1460
1461 // Fill tensors
1462 fill(AccessorType(lhs), 0);
1463 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001464 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01001465
1466 // Compute GEMM
1467 gemm.run();
1468
1469 return dst;
1470 }
1471
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001472 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 +01001473 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001474 {
1475 TensorShape dst_shape = lhs_shape;
1476 dst_shape.set(0, rhs_shape[0]);
1477 dst_shape.set(1, lhs_shape[1] / m_h);
1478 dst_shape.set(2, m_h);
1479 dst_shape.set(3, lhs_shape[2]);
1480
1481 // Create reference
1482 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1483 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001484 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1485
1486 const int n = rhs_shape[0];
1487 const int m = lhs_shape[1];
1488 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01001489
1490 // Fill reference
1491 fill(lhs, 0);
1492 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001493 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01001494
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001495 // In case of broadcast, we need simply copy the first into the following "M" ones
1496 for(int i = 1; i < m * batch_size; i++)
1497 {
1498 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1499 }
1500
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001501 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01001502 }
1503
1504 TensorType _target{};
1505 SimpleTensor<T> _reference{};
1506};
1507
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +01001508} // namespace validation
1509} // namespace test
1510} // namespace arm_compute
1511#endif /* ARM_COMPUTE_TEST_GEMM_FIXTURE */