blob: a04a901b1ca4517016bac5a4afd660f933e0585a [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 {
Pablo Tello0e37b5c2018-10-30 11:18:37 +000054 _target = compute_target(shape_a, shape_b, shape_c, output_shape, alpha, beta, pretranspose, data_type);
Vidhya Sudhan Loganathan014333d2018-07-02 09:13:49 +010055 _reference = compute_reference(shape_a, shape_b, shape_c, output_shape, alpha, beta, data_type);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010056 }
57
58protected:
59 template <typename U>
Pablo Tello0e37b5c2018-10-30 11:18:37 +000060 void fill(U &&tensor, int i, float lo = -1.f, float hi = 1.f)
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010061 {
62 switch(tensor.data_type())
63 {
64 case DataType::F16:
65 case DataType::F32:
66 {
Pablo Tello0e37b5c2018-10-30 11:18:37 +000067 std::uniform_real_distribution<> distribution(lo, hi);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010068 library->fill(tensor, distribution, i);
69 break;
70 }
71 default:
72 library->fill_tensor_uniform(tensor, i);
73 }
74 }
75
76 TensorType compute_target(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &shape_c, const TensorShape &output_shape, float alpha, float beta,
Pablo Tello0e37b5c2018-10-30 11:18:37 +000077 bool pretranspose, DataType data_type)
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010078 {
79 // Create tensors
Vidhya Sudhan Loganathan014333d2018-07-02 09:13:49 +010080 TensorType a = create_tensor<TensorType>(shape_a, data_type, 1);
81 TensorType b = create_tensor<TensorType>(shape_b, data_type, 1);
82 TensorType c = create_tensor<TensorType>(shape_c, data_type, 1);
83 TensorType dst = create_tensor<TensorType>(output_shape, data_type, 1);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010084
85 // Create and configure function
86 FunctionType gemm;
Isabella Gottardi8e74f442018-03-01 16:42:00 +000087 // The GEMMinfo includes the values of the depth in case of reinterpreted 3d output.
Gian Marco Iodice3139f032018-11-05 14:26:32 +000088 // 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 +000089 // 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 +010090 gemm.configure(&a,
91 &b,
92 (disable_c) ? nullptr : &c,
93 &dst,
94 alpha, beta,
95 GEMMInfo(false, false, false, (reinterpret_output_as_3d ? output_shape[2] : 0), reinterpret_input_as_3d, false, GEMMLowpOutputStageInfo(), false, (reinterpret_input_as_3d
96 || reinterpret_output_as_3d)));
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +010097 ARM_COMPUTE_EXPECT(a.info()->is_resizable(), framework::LogLevel::ERRORS);
98 ARM_COMPUTE_EXPECT(b.info()->is_resizable(), framework::LogLevel::ERRORS);
99 ARM_COMPUTE_EXPECT(c.info()->is_resizable(), framework::LogLevel::ERRORS);
100 ARM_COMPUTE_EXPECT(dst.info()->is_resizable(), framework::LogLevel::ERRORS);
101
102 // Allocate tensors
103 a.allocator()->allocate();
104 b.allocator()->allocate();
105 c.allocator()->allocate();
106 dst.allocator()->allocate();
107
108 ARM_COMPUTE_EXPECT(!a.info()->is_resizable(), framework::LogLevel::ERRORS);
109 ARM_COMPUTE_EXPECT(!b.info()->is_resizable(), framework::LogLevel::ERRORS);
110 ARM_COMPUTE_EXPECT(!c.info()->is_resizable(), framework::LogLevel::ERRORS);
111 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
112
113 // Fill tensors
114 fill(AccessorType(a), 0);
115 fill(AccessorType(b), 1);
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000116 if(!disable_c)
117 {
118 fill(AccessorType(c), 2);
119 }
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100120
121 // Compute GEMM function
122 gemm.run();
123
124 return dst;
125 }
126
127 SimpleTensor<T> compute_reference(const TensorShape &shape_a, const TensorShape &shape_b, const TensorShape &shape_c, const TensorShape &output_shape, float alpha, float beta,
Vidhya Sudhan Loganathan014333d2018-07-02 09:13:49 +0100128 DataType data_type)
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100129 {
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100130 TensorShape shape_a_to_use = shape_a;
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100131
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100132 if(reinterpret_input_as_3d)
133 {
134 // Collapse the second and third dimension if the input is 3D
135 shape_a_to_use.collapse(2U, 1U);
136 }
137
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100138 // Create reference
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100139 SimpleTensor<T> a{ shape_a_to_use, data_type, 1 };
Vidhya Sudhan Loganathan014333d2018-07-02 09:13:49 +0100140 SimpleTensor<T> b{ shape_b, data_type, 1 };
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100141 SimpleTensor<T> c{ output_shape, data_type, 1 };
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100142
143 // Fill reference
144 fill(a, 0);
145 fill(b, 1);
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100146 fill(c, 2);
147
148 if(reinterpret_input_as_3d || reinterpret_output_as_3d)
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000149 {
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100150 const int n = shape_b[0];
151 const int m = reinterpret_output_as_3d ? output_shape[1] * output_shape[2] : output_shape[1];
152 const int batch_size = reinterpret_output_as_3d ? output_shape[3] : output_shape[2];
153
154 // In case of broadcast, we need simply copy the first into the following "M" ones
155 for(int i = 1; i < m * batch_size; i++)
156 {
157 memcpy(c.data() + i * n, c.data(), n * sizeof(T));
158 }
Pablo Tello0e37b5c2018-10-30 11:18:37 +0000159 }
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100160
161 // Setting beta to 0 will effectively disable C for the
162 // computation of the reference: alpha * A * B + 0 * C
163 return reference::gemm<T>(a, b, c, alpha, disable_c ? 0.f : beta);
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100164 }
165
166 TensorType _target{};
167 SimpleTensor<T> _reference{};
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +0100168};
169
Gian Marco Iodiced1f54762019-07-19 09:54:47 +0100170template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
171class GEMMMatrixMultiplyValidationFixture : public framework::Fixture
172{
173public:
174 template <typename...>
175 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,
176 DataType data_type, GPUTarget gpu_arch)
177 {
178 // Set the tensor shapes for LHS and RHS matrices
179 const TensorShape lhs_shape(k, m, batch_size);
180 const TensorShape rhs_shape(n, k, batch_size);
181 const TensorShape bias_shape(n,
182 broadcast_bias ? 1 : m,
183 broadcast_bias ? 1 : batch_size);
184
185 _target = compute_target(lhs_shape, rhs_shape, bias_shape, data_type, alpha, beta, broadcast_bias, fp16_mixed_precision, act_info, gpu_arch);
186 _reference = compute_reference(lhs_shape, rhs_shape, bias_shape, data_type, alpha, beta, broadcast_bias, act_info);
187 }
188
189protected:
190 template <typename U>
191 void fill(U &&tensor, int i)
192 {
193 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
194 library->fill(tensor, distribution, i);
195
196 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
197 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
198 library->fill_borders_with_garbage(tensor, distribution_inf, i);
199 }
200
201 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,
202 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
203 {
204 // Create tensors
205 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
206 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
207 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
208 TensorType dst;
209
210 const unsigned int m = lhs_shape[1];
211 const unsigned int n = rhs_shape[0];
212 const unsigned int k = lhs_shape[0];
213 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, 0, false, broadcast_bias);
214
215 // The output tensor will be auto-initialized within the function
216
217 // Create and configure function
218 GEMMFunctionType gemm;
219 gemm.configure(gpu_arch, &lhs, &rhs, &bias, &dst, alpha, beta, false, reshape_info, fp16_mixed_precision, act_info);
220
221 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
222 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
223 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
224
225 // Allocate tensors
226 lhs.allocator()->allocate();
227 rhs.allocator()->allocate();
228 bias.allocator()->allocate();
229 dst.allocator()->allocate();
230
231 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
232 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
233 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
234 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
235
236 // Fill tensors
237 fill(AccessorType(lhs), 0);
238 fill(AccessorType(rhs), 1);
239 fill(AccessorType(bias), 2);
240
241 // Compute GEMM
242 gemm.run();
243
244 return dst;
245 }
246
247 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
248 const ActivationLayerInfo &act_info)
249 {
250 TensorShape dst_shape = lhs_shape;
251 dst_shape[0] = rhs_shape[0];
252 dst_shape[1] = lhs_shape[1];
253
254 // Create reference
255 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
256 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
257 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
258
259 const int n = rhs_shape[0];
260 const int m = lhs_shape[1];
261 const int batch_size = lhs_shape[2];
262
263 // Fill reference
264 fill(lhs, 0);
265 fill(rhs, 1);
266 fill(bias, 2);
267
268 if(broadcast_bias)
269 {
270 // In case of broadcast, we need simply copy the first into the following "M" ones
271 for(int i = 1; i < m * batch_size; i++)
272 {
273 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
274 }
275 }
276
277 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
278 }
279
280 TensorType _target{};
281 SimpleTensor<T> _reference{};
282};
283
284template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
285class GEMMMatrixMultiply3DValidationFixture : public framework::Fixture
286{
287public:
288 template <typename...>
289 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,
290 const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
291 {
292 // In case of GEMM3D, m is the product between m_w and m_h
293 const unsigned int m = m_w * m_h;
294
295 // Set the tensor shapes for LHS and RHS matrices
296 const TensorShape lhs_shape(k, m, batch_size);
297 const TensorShape rhs_shape(n, k, batch_size);
298 const TensorShape bias_shape(n, 1, 1);
299
300 _target = compute_target(lhs_shape, rhs_shape, bias_shape, data_type, alpha, beta, m_h, fp16_mixed_precision, act_info, gpu_arch);
301 _reference = compute_reference(lhs_shape, rhs_shape, bias_shape, data_type, alpha, beta, m_h, act_info);
302 }
303
304protected:
305 template <typename U>
306 void fill(U &&tensor, int i)
307 {
308 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
309 library->fill(tensor, distribution, i);
310 }
311
312 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,
313 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
314 {
315 // Create tensors
316 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
317 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
318 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
319 TensorType dst;
320
321 const unsigned int m = lhs_shape[1];
322 const unsigned int n = rhs_shape[0];
323 const unsigned int k = lhs_shape[0];
324 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, m_h, false, true);
325
326 // The output tensor will be auto-initialized within the function
327
328 // Create and configure function
329 GEMMFunctionType gemm;
330 gemm.configure(gpu_arch, &lhs, &rhs, &bias, &dst, alpha, beta, false, reshape_info, fp16_mixed_precision, act_info);
331
332 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
333 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
334 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
335
336 // Allocate tensors
337 lhs.allocator()->allocate();
338 rhs.allocator()->allocate();
339 bias.allocator()->allocate();
340 dst.allocator()->allocate();
341
342 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
343 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
344 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
345 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
346
347 // Fill tensors
348 fill(AccessorType(lhs), 0);
349 fill(AccessorType(rhs), 1);
350 fill(AccessorType(bias), 2);
351
352 // Compute GEMM
353 gemm.run();
354
355 return dst;
356 }
357
358 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, DataType data_type, float alpha, float beta, unsigned int m_h,
359 const ActivationLayerInfo &act_info)
360 {
361 TensorShape dst_shape = lhs_shape;
362 dst_shape.set(0, rhs_shape[0]);
363 dst_shape.set(1, lhs_shape[1] / m_h);
364 dst_shape.set(2, m_h);
365 dst_shape.set(3, lhs_shape[2]);
366
367 // Create reference
368 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
369 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
370 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
371
372 const int n = rhs_shape[0];
373 const int m = lhs_shape[1];
374 const int batch_size = lhs_shape[2];
375
376 // Fill reference
377 fill(lhs, 0);
378 fill(rhs, 1);
379 fill(bias, 2);
380
381 // In case of broadcast, we need simply copy the first into the following "M" ones
382 for(int i = 1; i < m * batch_size; i++)
383 {
384 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
385 }
386
387 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
388 }
389
390 TensorType _target{};
391 SimpleTensor<T> _reference{};
392};
393
394template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSFunctionType, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
395class GEMMMatrixMultiplyInterleavedTransposedValidationFixture : public framework::Fixture
396{
397public:
398 template <typename...>
399 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,
400 const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
401 {
402 GEMMLHSMatrixInfo lhs_info;
403 lhs_info.m0 = 4;
404 lhs_info.k0 = 4;
405 lhs_info.v0 = v0;
406 lhs_info.interleave = true;
407 lhs_info.transpose = true;
408
409 GEMMRHSMatrixInfo rhs_info;
410 rhs_info.n0 = 16 / sizeof(T);
411 rhs_info.k0 = 1;
412 rhs_info.h0 = h0;
413 rhs_info.interleave = false;
414 rhs_info.transpose = false;
415
416 // Set the tensor shapes for LHS and RHS matrices
417 const TensorShape lhs_shape(k, m, batch_size);
418 const TensorShape rhs_shape(n, k, batch_size);
419 const TensorShape bias_shape(n,
420 broadcast_bias ? 1 : m,
421 broadcast_bias ? 1 : batch_size);
422
423 _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);
424 _reference = compute_reference(lhs_shape, rhs_shape, bias_shape, data_type, alpha, beta, broadcast_bias, act_info);
425 }
426
427protected:
428 template <typename U>
429 void fill(U &&tensor, int i)
430 {
431 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
432 library->fill(tensor, distribution, i);
433
434 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
435 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
436 library->fill_borders_with_garbage(tensor, distribution_inf, i);
437 }
438
439 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
440 DataType data_type, float alpha, float beta, bool broadcast_bias, bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
441 {
442 // Create tensors
443 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
444 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
445 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
446 TensorType lhs_reshaped;
447 TensorType rhs_reshaped;
448 TensorType dst;
449
450 const unsigned int m = lhs_shape[1];
451 const unsigned int n = rhs_shape[0];
452 const unsigned int k = lhs_shape[0];
453 GEMMReshapeInfo reshape_info(m, n, k, rhs_info.h0, lhs_info.v0, 0, false, broadcast_bias);
454
455 // The output tensor will be auto-initialized within the function
456
457 // Create and configure function
458 ReshapeLHSFunctionType reshape_lhs;
459 ReshapeRHSFunctionType reshape_rhs;
460 GEMMFunctionType gemm;
461 reshape_lhs.configure(&lhs, &lhs_reshaped, lhs_info);
462 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
463 gemm.configure(gpu_arch, &lhs_reshaped, &rhs_reshaped, &bias, &dst, alpha, beta, true, reshape_info, fp16_mixed_precision, act_info);
464
465 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
466 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
467 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
468
469 // Allocate tensors
470 lhs.allocator()->allocate();
471 rhs.allocator()->allocate();
472 lhs_reshaped.allocator()->allocate();
473 rhs_reshaped.allocator()->allocate();
474 bias.allocator()->allocate();
475 dst.allocator()->allocate();
476
477 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
478 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
479 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
480 ARM_COMPUTE_EXPECT(!lhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
481 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
482 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
483
484 // Fill tensors
485 fill(AccessorType(lhs), 0);
486 fill(AccessorType(rhs), 1);
487 fill(AccessorType(bias), 2);
488
489 // Compute GEMM
490 reshape_lhs.run();
491 reshape_rhs.run();
492 gemm.run();
493
494 return dst;
495 }
496
497 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
498 const ActivationLayerInfo &act_info)
499 {
500 TensorShape dst_shape = lhs_shape;
501 dst_shape[0] = rhs_shape[0];
502 dst_shape[1] = lhs_shape[1];
503
504 // Create reference
505 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
506 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
507 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
508
509 const int n = rhs_shape[0];
510 const int m = lhs_shape[1];
511 const int batch_size = lhs_shape[2];
512
513 // Fill reference
514 fill(lhs, 0);
515 fill(rhs, 1);
516 fill(bias, 2);
517
518 if(broadcast_bias)
519 {
520 // In case of broadcast, we need simply copy the first into the following "M" ones
521 for(int i = 1; i < m * batch_size; i++)
522 {
523 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
524 }
525 }
526
527 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
528 }
529
530 TensorType _target{};
531 SimpleTensor<T> _reference{};
532};
533
534template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSFunctionType, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
535class GEMMMatrixMultiplyInterleavedTransposed3DValidationFixture : public framework::Fixture
536{
537public:
538 template <typename...>
539 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,
540 bool fp16_mixed_precision, const ActivationLayerInfo &act_info, DataType data_type, GPUTarget gpu_arch)
541 {
542 GEMMLHSMatrixInfo lhs_info;
543 lhs_info.m0 = 4;
544 lhs_info.k0 = 4;
545 lhs_info.v0 = v0;
546 lhs_info.interleave = true;
547 lhs_info.transpose = true;
548
549 GEMMRHSMatrixInfo rhs_info;
550 rhs_info.n0 = 16 / sizeof(T);
551 rhs_info.k0 = 1;
552 rhs_info.h0 = h0;
553 rhs_info.interleave = false;
554 rhs_info.transpose = false;
555
556 // In case of GEMM3D, m is the product between m_w and m_h
557 const unsigned int m = m_w * m_h;
558
559 // Set the tensor shapes for LHS and RHS matrices
560 const TensorShape lhs_shape(k, m, batch_size);
561 const TensorShape rhs_shape(n, k, batch_size);
562 const TensorShape bias_shape(n, 1, 1);
563
564 _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);
565 _reference = compute_reference(lhs_shape, rhs_shape, bias_shape, data_type, alpha, beta, m_h, act_info);
566 }
567
568protected:
569 template <typename U>
570 void fill(U &&tensor, int i)
571 {
572 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
573 library->fill(tensor, distribution, i);
574 }
575
576 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
577 DataType data_type, float alpha, float beta, unsigned int m_h, bool fp16_mixed_precision, const ActivationLayerInfo &act_info, GPUTarget gpu_arch)
578 {
579 // Create tensors
580 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
581 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
582 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
583 TensorType lhs_reshaped;
584 TensorType rhs_reshaped;
585 TensorType dst;
586
587 const unsigned int m = lhs_shape[1];
588 const unsigned int n = rhs_shape[0];
589 const unsigned int k = lhs_shape[0];
590 GEMMReshapeInfo reshape_info(m, n, k, rhs_info.h0, lhs_info.v0, m_h, false, true);
591
592 // The output tensor will be auto-initialized within the function
593
594 // Create and configure function
595 ReshapeLHSFunctionType reshape_lhs;
596 ReshapeRHSFunctionType reshape_rhs;
597 GEMMFunctionType gemm;
598 reshape_lhs.configure(&lhs, &lhs_reshaped, lhs_info);
599 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
600 gemm.configure(gpu_arch, &lhs_reshaped, &rhs_reshaped, &bias, &dst, alpha, beta, true, reshape_info, fp16_mixed_precision, act_info);
601
602 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
603 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
604 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
605
606 // Allocate tensors
607 lhs.allocator()->allocate();
608 rhs.allocator()->allocate();
609 lhs_reshaped.allocator()->allocate();
610 rhs_reshaped.allocator()->allocate();
611 bias.allocator()->allocate();
612 dst.allocator()->allocate();
613
614 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
615 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
616 ARM_COMPUTE_EXPECT(!lhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
617 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
618 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
619 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
620
621 // Fill tensors
622 fill(AccessorType(lhs), 0);
623 fill(AccessorType(rhs), 1);
624 fill(AccessorType(bias), 2);
625
626 // Compute GEMM
627 reshape_lhs.run();
628 reshape_rhs.run();
629 gemm.run();
630
631 return dst;
632 }
633
634 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, DataType data_type, float alpha, float beta, unsigned int m_h,
635 const ActivationLayerInfo &act_info)
636 {
637 TensorShape dst_shape = lhs_shape;
638 dst_shape.set(0, rhs_shape[0]);
639 dst_shape.set(1, lhs_shape[1] / m_h);
640 dst_shape.set(2, m_h);
641 dst_shape.set(3, lhs_shape[2]);
642
643 // Create reference
644 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
645 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
646 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
647
648 const int n = rhs_shape[0];
649 const int m = lhs_shape[1];
650 const int batch_size = lhs_shape[2];
651
652 // Fill reference
653 fill(lhs, 0);
654 fill(rhs, 1);
655 fill(bias, 2);
656
657 // In case of broadcast, we need simply copy the first into the following "M" ones
658 for(int i = 1; i < m * batch_size; i++)
659 {
660 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
661 }
662
663 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
664 }
665
666 TensorType _target{};
667 SimpleTensor<T> _reference{};
668};
669
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000670template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSFunctionType, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000671class GEMMMatrixMultiplyReshapedValidationFixture : public framework::Fixture
672{
673public:
674 template <typename...>
675 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 Iodiceca1f4602019-07-16 15:46:48 +0100676 bool interleave_rhs, DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000677 {
678 GEMMLHSMatrixInfo lhs_info;
679 lhs_info.m0 = m0;
680 lhs_info.k0 = k0;
681 lhs_info.v0 = v0;
682 lhs_info.interleave = interleave_lhs;
683 lhs_info.transpose = false;
684
685 GEMMRHSMatrixInfo rhs_info;
686 rhs_info.n0 = n0;
687 rhs_info.k0 = k0;
688 rhs_info.h0 = h0;
689 rhs_info.interleave = interleave_rhs;
690 rhs_info.transpose = true;
691
692 // Set the tensor shapes for LHS and RHS matrices
693 const TensorShape lhs_shape(k, m, batch_size);
694 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100695 const TensorShape bias_shape(n,
696 broadcast_bias ? 1 : m,
697 broadcast_bias ? 1 : batch_size);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000698
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100699 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
700 _reference = compute_reference(lhs_shape, rhs_shape, bias_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000701 }
702
703protected:
704 template <typename U>
705 void fill(U &&tensor, int i)
706 {
707 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
708 library->fill(tensor, distribution, i);
Gian Marco Iodiceb87b95e2019-01-21 17:14:31 +0000709
710 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
711 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
712 library->fill_borders_with_garbage(tensor, distribution_inf, i);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000713 }
714
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100715 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 +0100716 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000717 {
718 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100719 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
720 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
721 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000722 TensorType lhs_reshaped;
723 TensorType rhs_reshaped;
724 TensorType dst;
725
726 const unsigned int M = lhs_shape[1];
727 const unsigned int N = rhs_shape[0];
728 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100729 GEMMKernelInfo kernel_info;
730 kernel_info.m = M;
731 kernel_info.n = N;
732 kernel_info.k = K;
733 kernel_info.depth_output_gemm3d = 0;
734 kernel_info.reinterpret_input_as_3d = false;
735 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100736 kernel_info.activation_info = act_info;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000737
738 // The output tensor will be auto-initialized within the function
739
740 // Create and configure function
741 ReshapeLHSFunctionType reshape_lhs;
742 ReshapeRHSFunctionType reshape_rhs;
743 GEMMFunctionType gemm;
744 reshape_lhs.configure(&lhs, &lhs_reshaped, lhs_info);
745 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100746 gemm.configure(&lhs_reshaped, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000747
748 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
749 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100750 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000751
752 // Allocate tensors
753 lhs.allocator()->allocate();
754 rhs.allocator()->allocate();
755 lhs_reshaped.allocator()->allocate();
756 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100757 bias.allocator()->allocate();
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000758 dst.allocator()->allocate();
759
760 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
761 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100762 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000763 ARM_COMPUTE_EXPECT(!lhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
764 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
765 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
766
767 // Fill tensors
768 fill(AccessorType(lhs), 0);
769 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100770 fill(AccessorType(bias), 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000771
772 // Compute GEMM
773 reshape_lhs.run();
774 reshape_rhs.run();
775 gemm.run();
776
777 return dst;
778 }
779
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100780 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
781 const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000782 {
783 TensorShape dst_shape = lhs_shape;
784 dst_shape[0] = rhs_shape[0];
785 dst_shape[1] = lhs_shape[1];
786
787 // Create reference
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000788 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
789 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100790 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
791
792 const int n = rhs_shape[0];
793 const int m = lhs_shape[1];
794 const int batch_size = lhs_shape[2];
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000795
796 // Fill reference
797 fill(lhs, 0);
798 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100799 fill(bias, 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000800
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100801 if(broadcast_bias)
802 {
803 // In case of broadcast, we need simply copy the first into the following "M" ones
804 for(int i = 1; i < m * batch_size; i++)
805 {
806 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
807 }
808 }
809
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100810 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000811 }
812
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000813 TensorType _target{};
814 SimpleTensor<T> _reference{};
815};
816
817template <typename TensorType, typename AccessorType, typename T, typename ReshapeLHSFunctionType, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
818class GEMMMatrixMultiplyReshaped3DValidationFixture : public framework::Fixture
819{
820public:
821 template <typename...>
822 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,
823 bool interleave_lhs,
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100824 bool interleave_rhs, DataType data_type, float alpha, float beta, const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000825 {
826 GEMMLHSMatrixInfo lhs_info;
827 lhs_info.m0 = m0;
828 lhs_info.k0 = k0;
829 lhs_info.v0 = v0;
830 lhs_info.interleave = interleave_lhs;
831 lhs_info.transpose = false;
832
833 GEMMRHSMatrixInfo rhs_info;
834 rhs_info.n0 = n0;
835 rhs_info.k0 = k0;
836 rhs_info.h0 = h0;
837 rhs_info.interleave = interleave_rhs;
838 rhs_info.transpose = true;
839
840 // In case of GEMM3D, m is the product between m_w and m_h
841 const unsigned int m = m_w * m_h;
842
843 // Set the tensor shapes for LHS and RHS matrices
844 const TensorShape lhs_shape(k, m, batch_size);
845 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100846 const TensorShape bias_shape(n, 1, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000847
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100848 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info);
849 _reference = compute_reference(lhs_shape, rhs_shape, bias_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000850 }
851
852protected:
853 template <typename U>
854 void fill(U &&tensor, int i)
855 {
856 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
857 library->fill(tensor, distribution, i);
858 }
859
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100860 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 +0100861 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000862 {
863 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100864 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
865 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
866 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000867 TensorType lhs_reshaped;
868 TensorType rhs_reshaped;
869 TensorType dst;
870
871 const unsigned int M = lhs_shape[1];
872 const unsigned int N = rhs_shape[0];
873 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100874 GEMMKernelInfo kernel_info;
875 kernel_info.m = M;
876 kernel_info.n = N;
877 kernel_info.k = K;
878 kernel_info.depth_output_gemm3d = m_h;
879 kernel_info.reinterpret_input_as_3d = false;
880 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100881 kernel_info.activation_info = act_info;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000882
883 // The output tensor will be auto-initialized within the function
884
885 // Create and configure function
886 ReshapeLHSFunctionType reshape_lhs;
887 ReshapeRHSFunctionType reshape_rhs;
888 GEMMFunctionType gemm;
889 reshape_lhs.configure(&lhs, &lhs_reshaped, lhs_info);
890 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100891 gemm.configure(&lhs_reshaped, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000892
893 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
894 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100895 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000896
897 // Allocate tensors
898 lhs.allocator()->allocate();
899 rhs.allocator()->allocate();
900 lhs_reshaped.allocator()->allocate();
901 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100902 bias.allocator()->allocate();
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000903 dst.allocator()->allocate();
904
905 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
906 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
907 ARM_COMPUTE_EXPECT(!lhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
908 ARM_COMPUTE_EXPECT(!rhs_reshaped.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 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
911
912 // Fill tensors
913 fill(AccessorType(lhs), 0);
914 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100915 fill(AccessorType(bias), 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000916
917 // Compute GEMM
918 reshape_lhs.run();
919 reshape_rhs.run();
920 gemm.run();
921
922 return dst;
923 }
924
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100925 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, DataType data_type, float alpha, float beta, unsigned int m_h,
926 const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000927 {
928 TensorShape dst_shape = lhs_shape;
929 dst_shape.set(0, rhs_shape[0]);
930 dst_shape.set(1, lhs_shape[1] / m_h);
931 dst_shape.set(2, m_h);
932 dst_shape.set(3, lhs_shape[2]);
933
934 // Create reference
935 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
936 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100937 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
938
939 const int n = rhs_shape[0];
940 const int m = lhs_shape[1];
941 const int batch_size = lhs_shape[2];
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000942
943 // Fill reference
944 fill(lhs, 0);
945 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100946 fill(bias, 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000947
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100948 // In case of broadcast, we need simply copy the first into the following "M" ones
949 for(int i = 1; i < m * batch_size; i++)
950 {
951 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
952 }
953
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100954 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000955 }
956
957 TensorType _target{};
958 SimpleTensor<T> _reference{};
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000959};
Gian Marco Iodiceadc53952019-02-15 11:10:31 +0000960
961template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
962class GEMMMatrixMultiplyReshapedOnlyRHSValidationFixture : public framework::Fixture
963{
964public:
965 template <typename...>
966 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 +0100967 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 +0000968 {
969 GEMMLHSMatrixInfo lhs_info;
970 lhs_info.m0 = m0;
971 lhs_info.k0 = k0;
972
973 GEMMRHSMatrixInfo rhs_info;
974 rhs_info.n0 = n0;
975 rhs_info.k0 = k0;
976 rhs_info.h0 = h0;
977 rhs_info.interleave = interleave_rhs;
978 rhs_info.transpose = transpose_rhs;
979
980 // Set the tensor shapes for LHS and RHS matrices
981 const TensorShape lhs_shape(k, m, batch_size);
982 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100983 const TensorShape bias_shape(n,
984 broadcast_bias ? 1 : m,
985 broadcast_bias ? 1 : batch_size);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +0100986
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100987 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
988 _reference = compute_reference(lhs_shape, rhs_shape, bias_shape, data_type, alpha, beta, broadcast_bias, act_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +0000989 }
990
991protected:
992 template <typename U>
993 void fill(U &&tensor, int i)
994 {
995 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
996 library->fill(tensor, distribution, i);
997
998 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
999 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
1000 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1001 }
1002
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001003 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 +01001004 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001005 {
1006 // Create tensors
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001007 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1008 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1009 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001010 TensorType rhs_reshaped;
1011 TensorType dst;
1012
1013 const unsigned int M = lhs_shape[1];
1014 const unsigned int N = rhs_shape[0];
1015 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001016 GEMMKernelInfo kernel_info;
1017 kernel_info.m = M;
1018 kernel_info.n = N;
1019 kernel_info.k = K;
1020 kernel_info.depth_output_gemm3d = 0;
1021 kernel_info.reinterpret_input_as_3d = false;
1022 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001023 kernel_info.activation_info = act_info;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001024
1025 // The output tensor will be auto-initialized within the function
1026
1027 // Create and configure function
1028 ReshapeRHSFunctionType reshape_rhs;
1029 GEMMFunctionType gemm;
1030 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001031 gemm.configure(&lhs, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001032
1033 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1034 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001035 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001036
1037 // Allocate tensors
1038 lhs.allocator()->allocate();
1039 rhs.allocator()->allocate();
1040 rhs_reshaped.allocator()->allocate();
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001041 bias.allocator()->allocate();
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001042 dst.allocator()->allocate();
1043
1044 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1045 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1046 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001047 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001048 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1049
1050 // Fill tensors
1051 fill(AccessorType(lhs), 0);
1052 fill(AccessorType(rhs), 1);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001053 fill(AccessorType(bias), 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001054
1055 // Compute GEMM
1056 reshape_rhs.run();
1057 gemm.run();
1058
1059 return dst;
1060 }
1061
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001062 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
1063 const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001064 {
1065 TensorShape dst_shape = lhs_shape;
1066 dst_shape[0] = rhs_shape[0];
1067 dst_shape[1] = lhs_shape[1];
1068
1069 // Create reference
1070 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1071 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001072 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1073
1074 const int n = rhs_shape[0];
1075 const int m = lhs_shape[1];
1076 const int batch_size = lhs_shape[2];
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001077
1078 // Fill reference
1079 fill(lhs, 0);
1080 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001081 fill(bias, 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001082
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001083 if(broadcast_bias)
1084 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001085 // In case of broadcast, we need simply copy the first into the following "M" ones
1086 for(int i = 1; i < m * batch_size; i++)
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001087 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001088 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001089 }
1090 }
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001091
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001092 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001093 }
1094
1095 TensorType _target{};
1096 SimpleTensor<T> _reference{};
1097};
1098
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001099template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
1100class GEMMMatrixMultiplyReshapedOnlyRHS3DValidationFixture : public framework::Fixture
1101{
1102public:
1103 template <typename...>
1104 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 +01001105 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 +01001106 {
1107 GEMMLHSMatrixInfo lhs_info;
1108 lhs_info.m0 = m0;
1109 lhs_info.k0 = k0;
1110
1111 GEMMRHSMatrixInfo rhs_info;
1112 rhs_info.n0 = n0;
1113 rhs_info.k0 = k0;
1114 rhs_info.h0 = h0;
1115 rhs_info.interleave = interleave_rhs;
1116 rhs_info.transpose = transpose_rhs;
1117
1118 // In case of GEMM3D, m is the product between m_w and m_h
1119 const unsigned int m = m_w * m_h;
1120
1121 // Set the tensor shapes for LHS and RHS matrices
1122 const TensorShape lhs_shape(k, m, batch_size);
1123 const TensorShape rhs_shape(n, k, batch_size);
1124 const TensorShape bias_shape(n, 1, 1);
1125
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001126 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info);
1127 _reference = compute_reference(lhs_shape, rhs_shape, bias_shape, data_type, alpha, beta, m_h, act_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001128 }
1129
1130protected:
1131 template <typename U>
1132 void fill(U &&tensor, int i)
1133 {
1134 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1135 library->fill(tensor, distribution, i);
1136 }
1137
1138 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
1139 DataType data_type, float alpha, float beta,
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001140 unsigned int m_h, const ActivationLayerInfo &act_info)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001141 {
1142 // Create tensors
1143 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1144 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1145 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
1146 TensorType rhs_reshaped;
1147 TensorType dst;
1148
1149 const unsigned int M = lhs_shape[1];
1150 const unsigned int N = rhs_shape[0];
1151 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001152 GEMMKernelInfo kernel_info;
1153 kernel_info.m = M;
1154 kernel_info.n = N;
1155 kernel_info.k = K;
1156 kernel_info.depth_output_gemm3d = m_h;
1157 kernel_info.reinterpret_input_as_3d = false;
1158 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001159 kernel_info.activation_info = act_info;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001160
1161 // The output tensor will be auto-initialized within the function
1162
1163 // Create and configure function
1164 ReshapeRHSFunctionType reshape_rhs;
1165 GEMMFunctionType gemm;
1166 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001167 gemm.configure(&lhs, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001168
1169 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1170 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1171 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
1172
1173 // Allocate tensors
1174 lhs.allocator()->allocate();
1175 rhs.allocator()->allocate();
1176 rhs_reshaped.allocator()->allocate();
1177 bias.allocator()->allocate();
1178 dst.allocator()->allocate();
1179
1180 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1181 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1182 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
1183 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
1184 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1185
1186 // Fill tensors
1187 fill(AccessorType(lhs), 0);
1188 fill(AccessorType(rhs), 1);
1189 fill(AccessorType(bias), 2);
1190
1191 // Compute GEMM
1192 reshape_rhs.run();
1193 gemm.run();
1194
1195 return dst;
1196 }
1197
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001198 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, DataType data_type, float alpha, float beta, unsigned int m_h,
1199 const ActivationLayerInfo &act_info)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001200 {
1201 TensorShape dst_shape = lhs_shape;
1202 dst_shape.set(0, rhs_shape[0]);
1203 dst_shape.set(1, lhs_shape[1] / m_h);
1204 dst_shape.set(2, m_h);
1205 dst_shape.set(3, lhs_shape[2]);
1206
1207 // Create reference
1208 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1209 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
1210 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1211
1212 const int n = rhs_shape[0];
1213 const int m = lhs_shape[1];
1214 const int batch_size = lhs_shape[2];
1215
1216 // Fill reference
1217 fill(lhs, 0);
1218 fill(rhs, 1);
1219 fill(bias, 2);
1220
1221 // In case of broadcast, we need simply copy the first into the following "M" ones
1222 for(int i = 1; i < m * batch_size; i++)
1223 {
1224 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1225 }
1226
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001227 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001228 }
1229
1230 TensorType _target{};
1231 SimpleTensor<T> _reference{};
1232};
1233
giuros01b3204e72019-04-01 13:50:22 +01001234template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
1235class GEMMMatrixMultiplyNativeValidationFixture : public framework::Fixture
1236{
1237public:
1238 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001239 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,
1240 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001241 {
1242 GEMMLHSMatrixInfo lhs_info;
1243 lhs_info.m0 = m0;
1244 lhs_info.k0 = k0;
1245
1246 GEMMRHSMatrixInfo rhs_info;
1247 rhs_info.n0 = n0;
1248 rhs_info.k0 = k0;
1249
1250 // Set the tensor shapes for LHS and RHS matrices
1251 const TensorShape lhs_shape(k, m, batch_size);
1252 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001253 const TensorShape bias_shape(n,
1254 broadcast_bias ? 1 : m,
1255 broadcast_bias ? 1 : batch_size);
giuros01b3204e72019-04-01 13:50:22 +01001256
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001257 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
1258 _reference = compute_reference(lhs_shape, rhs_shape, bias_shape, data_type, alpha, beta, broadcast_bias, act_info);
giuros01b3204e72019-04-01 13:50:22 +01001259 }
1260
1261protected:
1262 template <typename U>
1263 void fill(U &&tensor, int i)
1264 {
1265 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1266 library->fill(tensor, distribution, i);
1267
1268 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
1269 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
1270 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1271 }
1272
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001273 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 +01001274 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001275 {
1276 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001277 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1278 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1279 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01001280 TensorType dst;
1281
1282 const unsigned int M = lhs_shape[1];
1283 const unsigned int N = rhs_shape[0];
1284 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001285 GEMMKernelInfo kernel_info;
1286 kernel_info.m = M;
1287 kernel_info.n = N;
1288 kernel_info.k = K;
1289 kernel_info.depth_output_gemm3d = 0;
1290 kernel_info.reinterpret_input_as_3d = false;
1291 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001292 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01001293
1294 // Create and configure function
1295 GEMMFunctionType gemm;
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001296 gemm.configure(&lhs, &rhs, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01001297
1298 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1299 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001300 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001301
1302 // Allocate tensors
1303 lhs.allocator()->allocate();
1304 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001305 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01001306 dst.allocator()->allocate();
1307
1308 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1309 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001310 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001311 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1312
1313 // Fill tensors
1314 fill(AccessorType(lhs), 0);
1315 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001316 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01001317
1318 // Compute GEMM
1319 gemm.run();
1320
1321 return dst;
1322 }
1323
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001324 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, DataType data_type, float alpha, float beta, bool broadcast_bias,
1325 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001326 {
1327 TensorShape dst_shape = lhs_shape;
1328 dst_shape[0] = rhs_shape[0];
1329 dst_shape[1] = lhs_shape[1];
1330
1331 // Create reference
1332 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1333 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001334 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1335
1336 const int n = rhs_shape[0];
1337 const int m = lhs_shape[1];
1338 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01001339
1340 // Fill reference
1341 fill(lhs, 0);
1342 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001343 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01001344
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001345 if(broadcast_bias)
1346 {
1347 // In case of broadcast, we need simply copy the first into the following "M" ones
1348 for(int i = 1; i < m * batch_size; i++)
1349 {
1350 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1351 }
1352 }
1353
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001354 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01001355 }
1356
1357 TensorType _target{};
1358 SimpleTensor<T> _reference{};
1359};
1360
giuros01b3204e72019-04-01 13:50:22 +01001361template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
1362class GEMMMatrixMultiplyNative3DValidationFixture : public framework::Fixture
1363{
1364public:
1365 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001366 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,
1367 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001368 {
1369 GEMMLHSMatrixInfo lhs_info;
1370 lhs_info.m0 = m0;
1371 lhs_info.k0 = k0;
1372
1373 GEMMRHSMatrixInfo rhs_info;
1374 rhs_info.n0 = n0;
1375 rhs_info.k0 = k0;
1376
1377 // In case of GEMM3D, m is the product between m_w and m_h
1378 const unsigned int m = m_w * m_h;
1379
1380 // Set the tensor shapes for LHS and RHS matrices
1381 const TensorShape lhs_shape(k, m, batch_size);
1382 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001383 const TensorShape bias_shape(n, 1, 1);
giuros01b3204e72019-04-01 13:50:22 +01001384
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001385 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info);
1386 _reference = compute_reference(lhs_shape, rhs_shape, bias_shape, data_type, alpha, beta, m_h, act_info);
giuros01b3204e72019-04-01 13:50:22 +01001387 }
1388
1389protected:
1390 template <typename U>
1391 void fill(U &&tensor, int i)
1392 {
1393 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1394 library->fill(tensor, distribution, i);
1395 }
1396
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001397 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 +01001398 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001399 {
1400 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001401 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1402 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1403 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01001404 TensorType dst;
1405
1406 const unsigned int M = lhs_shape[1];
1407 const unsigned int N = rhs_shape[0];
1408 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001409 GEMMKernelInfo kernel_info;
1410 kernel_info.m = M;
1411 kernel_info.n = N;
1412 kernel_info.k = K;
1413 kernel_info.depth_output_gemm3d = m_h;
1414 kernel_info.reinterpret_input_as_3d = false;
1415 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001416 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01001417
1418 // The output tensor will be auto-initialized within the function
1419
1420 // Create and configure function
1421 GEMMFunctionType gemm;
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001422 gemm.configure(&lhs, &rhs, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01001423
1424 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1425 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001426 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001427
1428 // Allocate tensors
1429 lhs.allocator()->allocate();
1430 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001431 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01001432 dst.allocator()->allocate();
1433
1434 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1435 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001436 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001437 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1438
1439 // Fill tensors
1440 fill(AccessorType(lhs), 0);
1441 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001442 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01001443
1444 // Compute GEMM
1445 gemm.run();
1446
1447 return dst;
1448 }
1449
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001450 SimpleTensor<T> compute_reference(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, DataType data_type, float alpha, float beta, unsigned int m_h,
1451 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001452 {
1453 TensorShape dst_shape = lhs_shape;
1454 dst_shape.set(0, rhs_shape[0]);
1455 dst_shape.set(1, lhs_shape[1] / m_h);
1456 dst_shape.set(2, m_h);
1457 dst_shape.set(3, lhs_shape[2]);
1458
1459 // Create reference
1460 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1461 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001462 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1463
1464 const int n = rhs_shape[0];
1465 const int m = lhs_shape[1];
1466 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01001467
1468 // Fill reference
1469 fill(lhs, 0);
1470 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001471 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01001472
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001473 // In case of broadcast, we need simply copy the first into the following "M" ones
1474 for(int i = 1; i < m * batch_size; i++)
1475 {
1476 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1477 }
1478
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001479 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01001480 }
1481
1482 TensorType _target{};
1483 SimpleTensor<T> _reference{};
1484};
1485
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +01001486} // namespace validation
1487} // namespace test
1488} // namespace arm_compute
1489#endif /* ARM_COMPUTE_TEST_GEMM_FIXTURE */