blob: efe75670758941566371cd8ccd29753992f0ac28 [file] [log] [blame]
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +01001/*
Gian Marco Iodiceb87b95e2019-01-21 17:14:31 +00002 * Copyright (c) 2017-2019 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,
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100681 bool interleave_rhs, 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;
691 rhs_info.n0 = n0;
692 rhs_info.k0 = k0;
693 rhs_info.h0 = h0;
694 rhs_info.interleave = interleave_rhs;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100695 rhs_info.transpose = !lhs_transpose;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000696
697 // Set the tensor shapes for LHS and RHS matrices
698 const TensorShape lhs_shape(k, m, batch_size);
699 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100700 const TensorShape bias_shape(n,
701 broadcast_bias ? 1 : m,
702 broadcast_bias ? 1 : batch_size);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000703
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100704 _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 +0100705 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000706 }
707
708protected:
709 template <typename U>
710 void fill(U &&tensor, int i)
711 {
712 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
713 library->fill(tensor, distribution, i);
Gian Marco Iodiceb87b95e2019-01-21 17:14:31 +0000714
715 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
716 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
717 library->fill_borders_with_garbage(tensor, distribution_inf, i);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000718 }
719
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100720 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 +0100721 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000722 {
723 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100724 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
725 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
726 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000727 TensorType lhs_reshaped;
728 TensorType rhs_reshaped;
729 TensorType dst;
730
731 const unsigned int M = lhs_shape[1];
732 const unsigned int N = rhs_shape[0];
733 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100734 GEMMKernelInfo kernel_info;
735 kernel_info.m = M;
736 kernel_info.n = N;
737 kernel_info.k = K;
738 kernel_info.depth_output_gemm3d = 0;
739 kernel_info.reinterpret_input_as_3d = false;
740 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100741 kernel_info.activation_info = act_info;
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100742 kernel_info.fp_mixed_precision = fp_mixed_precision;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000743
744 // The output tensor will be auto-initialized within the function
745
746 // Create and configure function
747 ReshapeLHSFunctionType reshape_lhs;
748 ReshapeRHSFunctionType reshape_rhs;
749 GEMMFunctionType gemm;
750 reshape_lhs.configure(&lhs, &lhs_reshaped, lhs_info);
751 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100752 gemm.configure(&lhs_reshaped, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000753
754 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
755 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100756 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000757
758 // Allocate tensors
759 lhs.allocator()->allocate();
760 rhs.allocator()->allocate();
761 lhs_reshaped.allocator()->allocate();
762 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100763 bias.allocator()->allocate();
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000764 dst.allocator()->allocate();
765
766 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
767 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100768 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000769 ARM_COMPUTE_EXPECT(!lhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
770 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
771 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
772
773 // Fill tensors
774 fill(AccessorType(lhs), 0);
775 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100776 fill(AccessorType(bias), 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000777
778 // Compute GEMM
779 reshape_lhs.run();
780 reshape_rhs.run();
781 gemm.run();
782
783 return dst;
784 }
785
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100786 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 +0100787 const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000788 {
789 TensorShape dst_shape = lhs_shape;
790 dst_shape[0] = rhs_shape[0];
791 dst_shape[1] = lhs_shape[1];
792
793 // Create reference
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000794 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
795 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100796 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
797
798 const int n = rhs_shape[0];
799 const int m = lhs_shape[1];
800 const int batch_size = lhs_shape[2];
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000801
802 // Fill reference
803 fill(lhs, 0);
804 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100805 fill(bias, 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000806
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100807 if(broadcast_bias)
808 {
809 // In case of broadcast, we need simply copy the first into the following "M" ones
810 for(int i = 1; i < m * batch_size; i++)
811 {
812 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
813 }
814 }
815
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100816 if(fp_mixed_precision)
817 {
818 return reference::activation_layer(reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta), act_info);
819 }
820 else
821 {
822 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
823 }
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000824 }
825
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000826 TensorType _target{};
827 SimpleTensor<T> _reference{};
828};
829
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100830template <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 +0000831class GEMMMatrixMultiplyReshaped3DValidationFixture : public framework::Fixture
832{
833public:
834 template <typename...>
835 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,
836 bool interleave_lhs,
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100837 bool interleave_rhs, 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;
847 rhs_info.n0 = n0;
848 rhs_info.k0 = k0;
849 rhs_info.h0 = h0;
850 rhs_info.interleave = interleave_rhs;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100851 rhs_info.transpose = !lhs_transpose;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000852
853 // In case of GEMM3D, m is the product between m_w and m_h
854 const unsigned int m = m_w * m_h;
855
856 // Set the tensor shapes for LHS and RHS matrices
857 const TensorShape lhs_shape(k, m, batch_size);
858 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100859 const TensorShape bias_shape(n, 1, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000860
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100861 _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 +0100862 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000863 }
864
865protected:
866 template <typename U>
867 void fill(U &&tensor, int i)
868 {
869 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
870 library->fill(tensor, distribution, i);
871 }
872
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100873 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 +0100874 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000875 {
876 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100877 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
878 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
879 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000880 TensorType lhs_reshaped;
881 TensorType rhs_reshaped;
882 TensorType dst;
883
884 const unsigned int M = lhs_shape[1];
885 const unsigned int N = rhs_shape[0];
886 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100887 GEMMKernelInfo kernel_info;
888 kernel_info.m = M;
889 kernel_info.n = N;
890 kernel_info.k = K;
891 kernel_info.depth_output_gemm3d = m_h;
892 kernel_info.reinterpret_input_as_3d = false;
893 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100894 kernel_info.activation_info = act_info;
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100895 kernel_info.fp_mixed_precision = fp_mixed_precision;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000896
897 // The output tensor will be auto-initialized within the function
898
899 // Create and configure function
900 ReshapeLHSFunctionType reshape_lhs;
901 ReshapeRHSFunctionType reshape_rhs;
902 GEMMFunctionType gemm;
903 reshape_lhs.configure(&lhs, &lhs_reshaped, lhs_info);
904 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100905 gemm.configure(&lhs_reshaped, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000906
907 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
908 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100909 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000910
911 // Allocate tensors
912 lhs.allocator()->allocate();
913 rhs.allocator()->allocate();
914 lhs_reshaped.allocator()->allocate();
915 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100916 bias.allocator()->allocate();
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000917 dst.allocator()->allocate();
918
919 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
920 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
921 ARM_COMPUTE_EXPECT(!lhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
922 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100923 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000924 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
925
926 // Fill tensors
927 fill(AccessorType(lhs), 0);
928 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100929 fill(AccessorType(bias), 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000930
931 // Compute GEMM
932 reshape_lhs.run();
933 reshape_rhs.run();
934 gemm.run();
935
936 return dst;
937 }
938
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100939 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 +0100940 const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000941 {
942 TensorShape dst_shape = lhs_shape;
943 dst_shape.set(0, rhs_shape[0]);
944 dst_shape.set(1, lhs_shape[1] / m_h);
945 dst_shape.set(2, m_h);
946 dst_shape.set(3, lhs_shape[2]);
947
948 // Create reference
949 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
950 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100951 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
952
953 const int n = rhs_shape[0];
954 const int m = lhs_shape[1];
955 const int batch_size = lhs_shape[2];
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000956
957 // Fill reference
958 fill(lhs, 0);
959 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100960 fill(bias, 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000961
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100962 // In case of broadcast, we need simply copy the first into the following "M" ones
963 for(int i = 1; i < m * batch_size; i++)
964 {
965 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
966 }
967
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100968 if(fp_mixed_precision)
969 {
970 return reference::activation_layer(reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta), act_info);
971 }
972 else
973 {
974 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
975 }
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000976 }
977
978 TensorType _target{};
979 SimpleTensor<T> _reference{};
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000980};
Gian Marco Iodiceadc53952019-02-15 11:10:31 +0000981
982template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
983class GEMMMatrixMultiplyReshapedOnlyRHSValidationFixture : public framework::Fixture
984{
985public:
986 template <typename...>
987 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 +0100988 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 +0000989 {
990 GEMMLHSMatrixInfo lhs_info;
991 lhs_info.m0 = m0;
992 lhs_info.k0 = k0;
993
994 GEMMRHSMatrixInfo rhs_info;
995 rhs_info.n0 = n0;
996 rhs_info.k0 = k0;
997 rhs_info.h0 = h0;
998 rhs_info.interleave = interleave_rhs;
999 rhs_info.transpose = transpose_rhs;
1000
1001 // Set the tensor shapes for LHS and RHS matrices
1002 const TensorShape lhs_shape(k, m, batch_size);
1003 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001004 const TensorShape bias_shape(n,
1005 broadcast_bias ? 1 : m,
1006 broadcast_bias ? 1 : batch_size);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001007
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001008 _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 +01001009 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001010 }
1011
1012protected:
1013 template <typename U>
1014 void fill(U &&tensor, int i)
1015 {
1016 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1017 library->fill(tensor, distribution, i);
1018
1019 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
1020 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
1021 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1022 }
1023
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001024 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 +01001025 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001026 {
1027 // Create tensors
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001028 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1029 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1030 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001031 TensorType rhs_reshaped;
1032 TensorType dst;
1033
1034 const unsigned int M = lhs_shape[1];
1035 const unsigned int N = rhs_shape[0];
1036 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001037 GEMMKernelInfo kernel_info;
1038 kernel_info.m = M;
1039 kernel_info.n = N;
1040 kernel_info.k = K;
1041 kernel_info.depth_output_gemm3d = 0;
1042 kernel_info.reinterpret_input_as_3d = false;
1043 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001044 kernel_info.activation_info = act_info;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001045
1046 // The output tensor will be auto-initialized within the function
1047
1048 // Create and configure function
1049 ReshapeRHSFunctionType reshape_rhs;
1050 GEMMFunctionType gemm;
1051 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001052 gemm.configure(&lhs, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001053
1054 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1055 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001056 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001057
1058 // Allocate tensors
1059 lhs.allocator()->allocate();
1060 rhs.allocator()->allocate();
1061 rhs_reshaped.allocator()->allocate();
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001062 bias.allocator()->allocate();
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001063 dst.allocator()->allocate();
1064
1065 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1066 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1067 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001068 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001069 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1070
1071 // Fill tensors
1072 fill(AccessorType(lhs), 0);
1073 fill(AccessorType(rhs), 1);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001074 fill(AccessorType(bias), 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001075
1076 // Compute GEMM
1077 reshape_rhs.run();
1078 gemm.run();
1079
1080 return dst;
1081 }
1082
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001083 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 +01001084 const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001085 {
1086 TensorShape dst_shape = lhs_shape;
1087 dst_shape[0] = rhs_shape[0];
1088 dst_shape[1] = lhs_shape[1];
1089
1090 // Create reference
1091 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1092 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001093 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1094
1095 const int n = rhs_shape[0];
1096 const int m = lhs_shape[1];
1097 const int batch_size = lhs_shape[2];
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001098
1099 // Fill reference
1100 fill(lhs, 0);
1101 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001102 fill(bias, 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001103
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001104 if(broadcast_bias)
1105 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001106 // In case of broadcast, we need simply copy the first into the following "M" ones
1107 for(int i = 1; i < m * batch_size; i++)
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001108 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001109 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001110 }
1111 }
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001112
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001113 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001114 }
1115
1116 TensorType _target{};
1117 SimpleTensor<T> _reference{};
1118};
1119
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001120template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
1121class GEMMMatrixMultiplyReshapedOnlyRHS3DValidationFixture : public framework::Fixture
1122{
1123public:
1124 template <typename...>
1125 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 +01001126 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 +01001127 {
1128 GEMMLHSMatrixInfo lhs_info;
1129 lhs_info.m0 = m0;
1130 lhs_info.k0 = k0;
1131
1132 GEMMRHSMatrixInfo rhs_info;
1133 rhs_info.n0 = n0;
1134 rhs_info.k0 = k0;
1135 rhs_info.h0 = h0;
1136 rhs_info.interleave = interleave_rhs;
1137 rhs_info.transpose = transpose_rhs;
1138
1139 // In case of GEMM3D, m is the product between m_w and m_h
1140 const unsigned int m = m_w * m_h;
1141
1142 // Set the tensor shapes for LHS and RHS matrices
1143 const TensorShape lhs_shape(k, m, batch_size);
1144 const TensorShape rhs_shape(n, k, batch_size);
1145 const TensorShape bias_shape(n, 1, 1);
1146
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001147 _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 +01001148 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001149 }
1150
1151protected:
1152 template <typename U>
1153 void fill(U &&tensor, int i)
1154 {
1155 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1156 library->fill(tensor, distribution, i);
1157 }
1158
1159 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
1160 DataType data_type, float alpha, float beta,
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001161 unsigned int m_h, const ActivationLayerInfo &act_info)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001162 {
1163 // Create tensors
1164 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1165 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1166 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
1167 TensorType rhs_reshaped;
1168 TensorType dst;
1169
1170 const unsigned int M = lhs_shape[1];
1171 const unsigned int N = rhs_shape[0];
1172 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001173 GEMMKernelInfo kernel_info;
1174 kernel_info.m = M;
1175 kernel_info.n = N;
1176 kernel_info.k = K;
1177 kernel_info.depth_output_gemm3d = m_h;
1178 kernel_info.reinterpret_input_as_3d = false;
1179 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001180 kernel_info.activation_info = act_info;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001181
1182 // The output tensor will be auto-initialized within the function
1183
1184 // Create and configure function
1185 ReshapeRHSFunctionType reshape_rhs;
1186 GEMMFunctionType gemm;
1187 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001188 gemm.configure(&lhs, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001189
1190 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1191 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1192 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
1193
1194 // Allocate tensors
1195 lhs.allocator()->allocate();
1196 rhs.allocator()->allocate();
1197 rhs_reshaped.allocator()->allocate();
1198 bias.allocator()->allocate();
1199 dst.allocator()->allocate();
1200
1201 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1202 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1203 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
1204 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
1205 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1206
1207 // Fill tensors
1208 fill(AccessorType(lhs), 0);
1209 fill(AccessorType(rhs), 1);
1210 fill(AccessorType(bias), 2);
1211
1212 // Compute GEMM
1213 reshape_rhs.run();
1214 gemm.run();
1215
1216 return dst;
1217 }
1218
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001219 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 +01001220 const ActivationLayerInfo &act_info)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001221 {
1222 TensorShape dst_shape = lhs_shape;
1223 dst_shape.set(0, rhs_shape[0]);
1224 dst_shape.set(1, lhs_shape[1] / m_h);
1225 dst_shape.set(2, m_h);
1226 dst_shape.set(3, lhs_shape[2]);
1227
1228 // Create reference
1229 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1230 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
1231 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1232
1233 const int n = rhs_shape[0];
1234 const int m = lhs_shape[1];
1235 const int batch_size = lhs_shape[2];
1236
1237 // Fill reference
1238 fill(lhs, 0);
1239 fill(rhs, 1);
1240 fill(bias, 2);
1241
1242 // In case of broadcast, we need simply copy the first into the following "M" ones
1243 for(int i = 1; i < m * batch_size; i++)
1244 {
1245 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1246 }
1247
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001248 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001249 }
1250
1251 TensorType _target{};
1252 SimpleTensor<T> _reference{};
1253};
1254
giuros01b3204e72019-04-01 13:50:22 +01001255template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
1256class GEMMMatrixMultiplyNativeValidationFixture : public framework::Fixture
1257{
1258public:
1259 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001260 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,
1261 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001262 {
1263 GEMMLHSMatrixInfo lhs_info;
1264 lhs_info.m0 = m0;
1265 lhs_info.k0 = k0;
1266
1267 GEMMRHSMatrixInfo rhs_info;
1268 rhs_info.n0 = n0;
1269 rhs_info.k0 = k0;
1270
1271 // Set the tensor shapes for LHS and RHS matrices
1272 const TensorShape lhs_shape(k, m, batch_size);
1273 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001274 const TensorShape bias_shape(n,
1275 broadcast_bias ? 1 : m,
1276 broadcast_bias ? 1 : batch_size);
giuros01b3204e72019-04-01 13:50:22 +01001277
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001278 _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 +01001279 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, broadcast_bias, act_info);
giuros01b3204e72019-04-01 13:50:22 +01001280 }
1281
1282protected:
1283 template <typename U>
1284 void fill(U &&tensor, int i)
1285 {
1286 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1287 library->fill(tensor, distribution, i);
1288
1289 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
1290 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
1291 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1292 }
1293
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001294 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 +01001295 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001296 {
1297 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001298 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1299 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1300 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01001301 TensorType dst;
1302
1303 const unsigned int M = lhs_shape[1];
1304 const unsigned int N = rhs_shape[0];
1305 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001306 GEMMKernelInfo kernel_info;
1307 kernel_info.m = M;
1308 kernel_info.n = N;
1309 kernel_info.k = K;
1310 kernel_info.depth_output_gemm3d = 0;
1311 kernel_info.reinterpret_input_as_3d = false;
1312 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001313 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01001314
1315 // Create and configure function
1316 GEMMFunctionType gemm;
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001317 gemm.configure(&lhs, &rhs, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01001318
1319 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1320 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001321 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001322
1323 // Allocate tensors
1324 lhs.allocator()->allocate();
1325 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001326 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01001327 dst.allocator()->allocate();
1328
1329 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1330 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
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 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1333
1334 // Fill tensors
1335 fill(AccessorType(lhs), 0);
1336 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001337 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01001338
1339 // Compute GEMM
1340 gemm.run();
1341
1342 return dst;
1343 }
1344
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001345 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 +01001346 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001347 {
1348 TensorShape dst_shape = lhs_shape;
1349 dst_shape[0] = rhs_shape[0];
1350 dst_shape[1] = lhs_shape[1];
1351
1352 // Create reference
1353 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1354 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001355 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1356
1357 const int n = rhs_shape[0];
1358 const int m = lhs_shape[1];
1359 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01001360
1361 // Fill reference
1362 fill(lhs, 0);
1363 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001364 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01001365
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001366 if(broadcast_bias)
1367 {
1368 // In case of broadcast, we need simply copy the first into the following "M" ones
1369 for(int i = 1; i < m * batch_size; i++)
1370 {
1371 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1372 }
1373 }
1374
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001375 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01001376 }
1377
1378 TensorType _target{};
1379 SimpleTensor<T> _reference{};
1380};
1381
giuros01b3204e72019-04-01 13:50:22 +01001382template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
1383class GEMMMatrixMultiplyNative3DValidationFixture : public framework::Fixture
1384{
1385public:
1386 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001387 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,
1388 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001389 {
1390 GEMMLHSMatrixInfo lhs_info;
1391 lhs_info.m0 = m0;
1392 lhs_info.k0 = k0;
1393
1394 GEMMRHSMatrixInfo rhs_info;
1395 rhs_info.n0 = n0;
1396 rhs_info.k0 = k0;
1397
1398 // In case of GEMM3D, m is the product between m_w and m_h
1399 const unsigned int m = m_w * m_h;
1400
1401 // Set the tensor shapes for LHS and RHS matrices
1402 const TensorShape lhs_shape(k, m, batch_size);
1403 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001404 const TensorShape bias_shape(n, 1, 1);
giuros01b3204e72019-04-01 13:50:22 +01001405
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001406 _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 +01001407 _reference = compute_reference(lhs_shape, rhs_shape, data_type, alpha, beta, m_h, act_info);
giuros01b3204e72019-04-01 13:50:22 +01001408 }
1409
1410protected:
1411 template <typename U>
1412 void fill(U &&tensor, int i)
1413 {
1414 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1415 library->fill(tensor, distribution, i);
1416 }
1417
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001418 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 +01001419 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001420 {
1421 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001422 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1423 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1424 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01001425 TensorType dst;
1426
1427 const unsigned int M = lhs_shape[1];
1428 const unsigned int N = rhs_shape[0];
1429 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001430 GEMMKernelInfo kernel_info;
1431 kernel_info.m = M;
1432 kernel_info.n = N;
1433 kernel_info.k = K;
1434 kernel_info.depth_output_gemm3d = m_h;
1435 kernel_info.reinterpret_input_as_3d = false;
1436 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001437 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01001438
1439 // The output tensor will be auto-initialized within the function
1440
1441 // Create and configure function
1442 GEMMFunctionType gemm;
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001443 gemm.configure(&lhs, &rhs, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01001444
1445 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1446 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001447 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001448
1449 // Allocate tensors
1450 lhs.allocator()->allocate();
1451 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001452 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01001453 dst.allocator()->allocate();
1454
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 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1459
1460 // Fill tensors
1461 fill(AccessorType(lhs), 0);
1462 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001463 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01001464
1465 // Compute GEMM
1466 gemm.run();
1467
1468 return dst;
1469 }
1470
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001471 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 +01001472 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001473 {
1474 TensorShape dst_shape = lhs_shape;
1475 dst_shape.set(0, rhs_shape[0]);
1476 dst_shape.set(1, lhs_shape[1] / m_h);
1477 dst_shape.set(2, m_h);
1478 dst_shape.set(3, lhs_shape[2]);
1479
1480 // Create reference
1481 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1482 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001483 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1484
1485 const int n = rhs_shape[0];
1486 const int m = lhs_shape[1];
1487 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01001488
1489 // Fill reference
1490 fill(lhs, 0);
1491 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001492 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01001493
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001494 // In case of broadcast, we need simply copy the first into the following "M" ones
1495 for(int i = 1; i < m * batch_size; i++)
1496 {
1497 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1498 }
1499
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001500 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01001501 }
1502
1503 TensorType _target{};
1504 SimpleTensor<T> _reference{};
1505};
1506
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +01001507} // namespace validation
1508} // namespace test
1509} // namespace arm_compute
1510#endif /* ARM_COMPUTE_TEST_GEMM_FIXTURE */