blob: bf919c9b0919fb410a6f814b0a4f46f1aab5adef [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 Iodice0c17aa22019-09-27 09:23:15 +0100670template <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 +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,
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100676 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 +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;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100683 lhs_info.transpose = lhs_transpose;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000684
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;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100690 rhs_info.transpose = !lhs_transpose;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000691
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 Iodice0c17aa22019-09-27 09:23:15 +0100737 kernel_info.fp_mixed_precision = fp_mixed_precision;
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000738
739 // The output tensor will be auto-initialized within the function
740
741 // Create and configure function
742 ReshapeLHSFunctionType reshape_lhs;
743 ReshapeRHSFunctionType reshape_rhs;
744 GEMMFunctionType gemm;
745 reshape_lhs.configure(&lhs, &lhs_reshaped, lhs_info);
746 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100747 gemm.configure(&lhs_reshaped, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000748
749 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
750 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100751 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000752
753 // Allocate tensors
754 lhs.allocator()->allocate();
755 rhs.allocator()->allocate();
756 lhs_reshaped.allocator()->allocate();
757 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100758 bias.allocator()->allocate();
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000759 dst.allocator()->allocate();
760
761 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
762 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100763 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000764 ARM_COMPUTE_EXPECT(!lhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
765 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
766 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
767
768 // Fill tensors
769 fill(AccessorType(lhs), 0);
770 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100771 fill(AccessorType(bias), 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000772
773 // Compute GEMM
774 reshape_lhs.run();
775 reshape_rhs.run();
776 gemm.run();
777
778 return dst;
779 }
780
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100781 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,
782 const ActivationLayerInfo &act_info)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000783 {
784 TensorShape dst_shape = lhs_shape;
785 dst_shape[0] = rhs_shape[0];
786 dst_shape[1] = lhs_shape[1];
787
788 // Create reference
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000789 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
790 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100791 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
792
793 const int n = rhs_shape[0];
794 const int m = lhs_shape[1];
795 const int batch_size = lhs_shape[2];
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000796
797 // Fill reference
798 fill(lhs, 0);
799 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100800 fill(bias, 2);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000801
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100802 if(broadcast_bias)
803 {
804 // In case of broadcast, we need simply copy the first into the following "M" ones
805 for(int i = 1; i < m * batch_size; i++)
806 {
807 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
808 }
809 }
810
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100811 if(fp_mixed_precision)
812 {
813 return reference::activation_layer(reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta), act_info);
814 }
815 else
816 {
817 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
818 }
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000819 }
820
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000821 TensorType _target{};
822 SimpleTensor<T> _reference{};
823};
824
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100825template <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 +0000826class GEMMMatrixMultiplyReshaped3DValidationFixture : public framework::Fixture
827{
828public:
829 template <typename...>
830 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,
831 bool interleave_lhs,
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100832 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 +0000833 {
834 GEMMLHSMatrixInfo lhs_info;
835 lhs_info.m0 = m0;
836 lhs_info.k0 = k0;
837 lhs_info.v0 = v0;
838 lhs_info.interleave = interleave_lhs;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100839 lhs_info.transpose = lhs_transpose;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000840
841 GEMMRHSMatrixInfo rhs_info;
842 rhs_info.n0 = n0;
843 rhs_info.k0 = k0;
844 rhs_info.h0 = h0;
845 rhs_info.interleave = interleave_rhs;
Giorgio Arenaae99b6e2019-08-01 14:22:12 +0100846 rhs_info.transpose = !lhs_transpose;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000847
848 // In case of GEMM3D, m is the product between m_w and m_h
849 const unsigned int m = m_w * m_h;
850
851 // Set the tensor shapes for LHS and RHS matrices
852 const TensorShape lhs_shape(k, m, batch_size);
853 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100854 const TensorShape bias_shape(n, 1, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000855
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100856 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info);
857 _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 +0000858 }
859
860protected:
861 template <typename U>
862 void fill(U &&tensor, int i)
863 {
864 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
865 library->fill(tensor, distribution, i);
866 }
867
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100868 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 +0100869 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000870 {
871 // Create tensors
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100872 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
873 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
874 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000875 TensorType lhs_reshaped;
876 TensorType rhs_reshaped;
877 TensorType dst;
878
879 const unsigned int M = lhs_shape[1];
880 const unsigned int N = rhs_shape[0];
881 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100882 GEMMKernelInfo kernel_info;
883 kernel_info.m = M;
884 kernel_info.n = N;
885 kernel_info.k = K;
886 kernel_info.depth_output_gemm3d = m_h;
887 kernel_info.reinterpret_input_as_3d = false;
888 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100889 kernel_info.activation_info = act_info;
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100890 kernel_info.fp_mixed_precision = fp_mixed_precision;
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000891
892 // The output tensor will be auto-initialized within the function
893
894 // Create and configure function
895 ReshapeLHSFunctionType reshape_lhs;
896 ReshapeRHSFunctionType reshape_rhs;
897 GEMMFunctionType gemm;
898 reshape_lhs.configure(&lhs, &lhs_reshaped, lhs_info);
899 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100900 gemm.configure(&lhs_reshaped, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000901
902 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
903 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100904 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000905
906 // Allocate tensors
907 lhs.allocator()->allocate();
908 rhs.allocator()->allocate();
909 lhs_reshaped.allocator()->allocate();
910 rhs_reshaped.allocator()->allocate();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100911 bias.allocator()->allocate();
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000912 dst.allocator()->allocate();
913
914 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
915 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
916 ARM_COMPUTE_EXPECT(!lhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
917 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100918 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000919 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
920
921 // Fill tensors
922 fill(AccessorType(lhs), 0);
923 fill(AccessorType(rhs), 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100924 fill(AccessorType(bias), 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000925
926 // Compute GEMM
927 reshape_lhs.run();
928 reshape_rhs.run();
929 gemm.run();
930
931 return dst;
932 }
933
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +0100934 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,
935 const ActivationLayerInfo &act_info)
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000936 {
937 TensorShape dst_shape = lhs_shape;
938 dst_shape.set(0, rhs_shape[0]);
939 dst_shape.set(1, lhs_shape[1] / m_h);
940 dst_shape.set(2, m_h);
941 dst_shape.set(3, lhs_shape[2]);
942
943 // Create reference
944 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
945 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100946 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
947
948 const int n = rhs_shape[0];
949 const int m = lhs_shape[1];
950 const int batch_size = lhs_shape[2];
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000951
952 // Fill reference
953 fill(lhs, 0);
954 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100955 fill(bias, 2);
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000956
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100957 // In case of broadcast, we need simply copy the first into the following "M" ones
958 for(int i = 1; i < m * batch_size; i++)
959 {
960 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
961 }
962
Gian Marco Iodice0c17aa22019-09-27 09:23:15 +0100963 if(fp_mixed_precision)
964 {
965 return reference::activation_layer(reference::gemm_mixed_precision<T>(lhs, rhs, bias, alpha, beta), act_info);
966 }
967 else
968 {
969 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
970 }
Gian Marco Iodice9382ab32018-12-17 15:12:07 +0000971 }
972
973 TensorType _target{};
974 SimpleTensor<T> _reference{};
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000975};
Gian Marco Iodiceadc53952019-02-15 11:10:31 +0000976
977template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
978class GEMMMatrixMultiplyReshapedOnlyRHSValidationFixture : public framework::Fixture
979{
980public:
981 template <typename...>
982 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 +0100983 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 +0000984 {
985 GEMMLHSMatrixInfo lhs_info;
986 lhs_info.m0 = m0;
987 lhs_info.k0 = k0;
988
989 GEMMRHSMatrixInfo rhs_info;
990 rhs_info.n0 = n0;
991 rhs_info.k0 = k0;
992 rhs_info.h0 = h0;
993 rhs_info.interleave = interleave_rhs;
994 rhs_info.transpose = transpose_rhs;
995
996 // Set the tensor shapes for LHS and RHS matrices
997 const TensorShape lhs_shape(k, m, batch_size);
998 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100999 const TensorShape bias_shape(n,
1000 broadcast_bias ? 1 : m,
1001 broadcast_bias ? 1 : batch_size);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001002
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001003 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
1004 _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 +00001005 }
1006
1007protected:
1008 template <typename U>
1009 void fill(U &&tensor, int i)
1010 {
1011 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1012 library->fill(tensor, distribution, i);
1013
1014 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
1015 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
1016 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1017 }
1018
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001019 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 +01001020 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001021 {
1022 // Create tensors
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001023 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1024 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1025 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001026 TensorType rhs_reshaped;
1027 TensorType dst;
1028
1029 const unsigned int M = lhs_shape[1];
1030 const unsigned int N = rhs_shape[0];
1031 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001032 GEMMKernelInfo kernel_info;
1033 kernel_info.m = M;
1034 kernel_info.n = N;
1035 kernel_info.k = K;
1036 kernel_info.depth_output_gemm3d = 0;
1037 kernel_info.reinterpret_input_as_3d = false;
1038 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001039 kernel_info.activation_info = act_info;
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001040
1041 // The output tensor will be auto-initialized within the function
1042
1043 // Create and configure function
1044 ReshapeRHSFunctionType reshape_rhs;
1045 GEMMFunctionType gemm;
1046 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001047 gemm.configure(&lhs, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001048
1049 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1050 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001051 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001052
1053 // Allocate tensors
1054 lhs.allocator()->allocate();
1055 rhs.allocator()->allocate();
1056 rhs_reshaped.allocator()->allocate();
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001057 bias.allocator()->allocate();
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001058 dst.allocator()->allocate();
1059
1060 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1061 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1062 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001063 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001064 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1065
1066 // Fill tensors
1067 fill(AccessorType(lhs), 0);
1068 fill(AccessorType(rhs), 1);
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001069 fill(AccessorType(bias), 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001070
1071 // Compute GEMM
1072 reshape_rhs.run();
1073 gemm.run();
1074
1075 return dst;
1076 }
1077
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001078 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,
1079 const ActivationLayerInfo &act_info)
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001080 {
1081 TensorShape dst_shape = lhs_shape;
1082 dst_shape[0] = rhs_shape[0];
1083 dst_shape[1] = lhs_shape[1];
1084
1085 // Create reference
1086 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1087 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001088 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1089
1090 const int n = rhs_shape[0];
1091 const int m = lhs_shape[1];
1092 const int batch_size = lhs_shape[2];
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001093
1094 // Fill reference
1095 fill(lhs, 0);
1096 fill(rhs, 1);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001097 fill(bias, 2);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001098
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001099 if(broadcast_bias)
1100 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001101 // In case of broadcast, we need simply copy the first into the following "M" ones
1102 for(int i = 1; i < m * batch_size; i++)
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001103 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001104 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001105 }
1106 }
Georgios Pinitasb0f342e2019-05-21 13:32:43 +01001107
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001108 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodiceadc53952019-02-15 11:10:31 +00001109 }
1110
1111 TensorType _target{};
1112 SimpleTensor<T> _reference{};
1113};
1114
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001115template <typename TensorType, typename AccessorType, typename T, typename ReshapeRHSFunctionType, typename GEMMFunctionType>
1116class GEMMMatrixMultiplyReshapedOnlyRHS3DValidationFixture : public framework::Fixture
1117{
1118public:
1119 template <typename...>
1120 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 +01001121 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 +01001122 {
1123 GEMMLHSMatrixInfo lhs_info;
1124 lhs_info.m0 = m0;
1125 lhs_info.k0 = k0;
1126
1127 GEMMRHSMatrixInfo rhs_info;
1128 rhs_info.n0 = n0;
1129 rhs_info.k0 = k0;
1130 rhs_info.h0 = h0;
1131 rhs_info.interleave = interleave_rhs;
1132 rhs_info.transpose = transpose_rhs;
1133
1134 // In case of GEMM3D, m is the product between m_w and m_h
1135 const unsigned int m = m_w * m_h;
1136
1137 // Set the tensor shapes for LHS and RHS matrices
1138 const TensorShape lhs_shape(k, m, batch_size);
1139 const TensorShape rhs_shape(n, k, batch_size);
1140 const TensorShape bias_shape(n, 1, 1);
1141
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001142 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info);
1143 _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 +01001144 }
1145
1146protected:
1147 template <typename U>
1148 void fill(U &&tensor, int i)
1149 {
1150 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1151 library->fill(tensor, distribution, i);
1152 }
1153
1154 TensorType compute_target(const TensorShape &lhs_shape, const TensorShape &rhs_shape, const TensorShape &bias_shape, const GEMMLHSMatrixInfo &lhs_info, const GEMMRHSMatrixInfo &rhs_info,
1155 DataType data_type, float alpha, float beta,
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001156 unsigned int m_h, const ActivationLayerInfo &act_info)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001157 {
1158 // Create tensors
1159 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1160 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1161 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
1162 TensorType rhs_reshaped;
1163 TensorType dst;
1164
1165 const unsigned int M = lhs_shape[1];
1166 const unsigned int N = rhs_shape[0];
1167 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001168 GEMMKernelInfo kernel_info;
1169 kernel_info.m = M;
1170 kernel_info.n = N;
1171 kernel_info.k = K;
1172 kernel_info.depth_output_gemm3d = m_h;
1173 kernel_info.reinterpret_input_as_3d = false;
1174 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001175 kernel_info.activation_info = act_info;
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001176
1177 // The output tensor will be auto-initialized within the function
1178
1179 // Create and configure function
1180 ReshapeRHSFunctionType reshape_rhs;
1181 GEMMFunctionType gemm;
1182 reshape_rhs.configure(&rhs, &rhs_reshaped, rhs_info);
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001183 gemm.configure(&lhs, &rhs_reshaped, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001184
1185 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1186 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1187 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
1188
1189 // Allocate tensors
1190 lhs.allocator()->allocate();
1191 rhs.allocator()->allocate();
1192 rhs_reshaped.allocator()->allocate();
1193 bias.allocator()->allocate();
1194 dst.allocator()->allocate();
1195
1196 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1197 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1198 ARM_COMPUTE_EXPECT(!rhs_reshaped.info()->is_resizable(), framework::LogLevel::ERRORS);
1199 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
1200 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1201
1202 // Fill tensors
1203 fill(AccessorType(lhs), 0);
1204 fill(AccessorType(rhs), 1);
1205 fill(AccessorType(bias), 2);
1206
1207 // Compute GEMM
1208 reshape_rhs.run();
1209 gemm.run();
1210
1211 return dst;
1212 }
1213
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001214 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,
1215 const ActivationLayerInfo &act_info)
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001216 {
1217 TensorShape dst_shape = lhs_shape;
1218 dst_shape.set(0, rhs_shape[0]);
1219 dst_shape.set(1, lhs_shape[1] / m_h);
1220 dst_shape.set(2, m_h);
1221 dst_shape.set(3, lhs_shape[2]);
1222
1223 // Create reference
1224 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1225 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
1226 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1227
1228 const int n = rhs_shape[0];
1229 const int m = lhs_shape[1];
1230 const int batch_size = lhs_shape[2];
1231
1232 // Fill reference
1233 fill(lhs, 0);
1234 fill(rhs, 1);
1235 fill(bias, 2);
1236
1237 // In case of broadcast, we need simply copy the first into the following "M" ones
1238 for(int i = 1; i < m * batch_size; i++)
1239 {
1240 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1241 }
1242
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001243 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +01001244 }
1245
1246 TensorType _target{};
1247 SimpleTensor<T> _reference{};
1248};
1249
giuros01b3204e72019-04-01 13:50:22 +01001250template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
1251class GEMMMatrixMultiplyNativeValidationFixture : public framework::Fixture
1252{
1253public:
1254 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001255 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,
1256 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001257 {
1258 GEMMLHSMatrixInfo lhs_info;
1259 lhs_info.m0 = m0;
1260 lhs_info.k0 = k0;
1261
1262 GEMMRHSMatrixInfo rhs_info;
1263 rhs_info.n0 = n0;
1264 rhs_info.k0 = k0;
1265
1266 // Set the tensor shapes for LHS and RHS matrices
1267 const TensorShape lhs_shape(k, m, batch_size);
1268 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001269 const TensorShape bias_shape(n,
1270 broadcast_bias ? 1 : m,
1271 broadcast_bias ? 1 : batch_size);
giuros01b3204e72019-04-01 13:50:22 +01001272
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001273 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, broadcast_bias, act_info);
1274 _reference = compute_reference(lhs_shape, rhs_shape, bias_shape, data_type, alpha, beta, broadcast_bias, act_info);
giuros01b3204e72019-04-01 13:50:22 +01001275 }
1276
1277protected:
1278 template <typename U>
1279 void fill(U &&tensor, int i)
1280 {
1281 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1282 library->fill(tensor, distribution, i);
1283
1284 // Fill border with infinity in order to check the presence of NaN values (i.e. inf * 0)
1285 std::uniform_real_distribution<> distribution_inf(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
1286 library->fill_borders_with_garbage(tensor, distribution_inf, i);
1287 }
1288
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001289 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 +01001290 DataType data_type, float alpha, float beta, bool broadcast_bias, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001291 {
1292 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001293 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1294 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1295 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01001296 TensorType dst;
1297
1298 const unsigned int M = lhs_shape[1];
1299 const unsigned int N = rhs_shape[0];
1300 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001301 GEMMKernelInfo kernel_info;
1302 kernel_info.m = M;
1303 kernel_info.n = N;
1304 kernel_info.k = K;
1305 kernel_info.depth_output_gemm3d = 0;
1306 kernel_info.reinterpret_input_as_3d = false;
1307 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001308 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01001309
1310 // Create and configure function
1311 GEMMFunctionType gemm;
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001312 gemm.configure(&lhs, &rhs, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01001313
1314 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1315 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001316 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001317
1318 // Allocate tensors
1319 lhs.allocator()->allocate();
1320 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001321 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01001322 dst.allocator()->allocate();
1323
1324 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1325 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001326 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001327 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1328
1329 // Fill tensors
1330 fill(AccessorType(lhs), 0);
1331 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001332 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01001333
1334 // Compute GEMM
1335 gemm.run();
1336
1337 return dst;
1338 }
1339
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001340 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,
1341 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001342 {
1343 TensorShape dst_shape = lhs_shape;
1344 dst_shape[0] = rhs_shape[0];
1345 dst_shape[1] = lhs_shape[1];
1346
1347 // Create reference
1348 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1349 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001350 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1351
1352 const int n = rhs_shape[0];
1353 const int m = lhs_shape[1];
1354 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01001355
1356 // Fill reference
1357 fill(lhs, 0);
1358 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001359 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01001360
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001361 if(broadcast_bias)
1362 {
1363 // In case of broadcast, we need simply copy the first into the following "M" ones
1364 for(int i = 1; i < m * batch_size; i++)
1365 {
1366 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1367 }
1368 }
1369
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001370 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01001371 }
1372
1373 TensorType _target{};
1374 SimpleTensor<T> _reference{};
1375};
1376
giuros01b3204e72019-04-01 13:50:22 +01001377template <typename TensorType, typename AccessorType, typename T, typename GEMMFunctionType>
1378class GEMMMatrixMultiplyNative3DValidationFixture : public framework::Fixture
1379{
1380public:
1381 template <typename...>
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001382 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,
1383 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001384 {
1385 GEMMLHSMatrixInfo lhs_info;
1386 lhs_info.m0 = m0;
1387 lhs_info.k0 = k0;
1388
1389 GEMMRHSMatrixInfo rhs_info;
1390 rhs_info.n0 = n0;
1391 rhs_info.k0 = k0;
1392
1393 // In case of GEMM3D, m is the product between m_w and m_h
1394 const unsigned int m = m_w * m_h;
1395
1396 // Set the tensor shapes for LHS and RHS matrices
1397 const TensorShape lhs_shape(k, m, batch_size);
1398 const TensorShape rhs_shape(n, k, batch_size);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001399 const TensorShape bias_shape(n, 1, 1);
giuros01b3204e72019-04-01 13:50:22 +01001400
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001401 _target = compute_target(lhs_shape, rhs_shape, bias_shape, lhs_info, rhs_info, data_type, alpha, beta, m_h, act_info);
1402 _reference = compute_reference(lhs_shape, rhs_shape, bias_shape, data_type, alpha, beta, m_h, act_info);
giuros01b3204e72019-04-01 13:50:22 +01001403 }
1404
1405protected:
1406 template <typename U>
1407 void fill(U &&tensor, int i)
1408 {
1409 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
1410 library->fill(tensor, distribution, i);
1411 }
1412
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001413 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 +01001414 DataType data_type, float alpha, float beta, unsigned int m_h, const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001415 {
1416 // Create tensors
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001417 TensorType lhs = create_tensor<TensorType>(lhs_shape, data_type, 1);
1418 TensorType rhs = create_tensor<TensorType>(rhs_shape, data_type, 1);
1419 TensorType bias = create_tensor<TensorType>(bias_shape, data_type, 1);
giuros01b3204e72019-04-01 13:50:22 +01001420 TensorType dst;
1421
1422 const unsigned int M = lhs_shape[1];
1423 const unsigned int N = rhs_shape[0];
1424 const unsigned int K = lhs_shape[0];
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001425 GEMMKernelInfo kernel_info;
1426 kernel_info.m = M;
1427 kernel_info.n = N;
1428 kernel_info.k = K;
1429 kernel_info.depth_output_gemm3d = m_h;
1430 kernel_info.reinterpret_input_as_3d = false;
1431 kernel_info.broadcast_bias = true;
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001432 kernel_info.activation_info = act_info;
giuros01b3204e72019-04-01 13:50:22 +01001433
1434 // The output tensor will be auto-initialized within the function
1435
1436 // Create and configure function
1437 GEMMFunctionType gemm;
Gian Marco Iodice7026b302019-06-26 17:18:11 +01001438 gemm.configure(&lhs, &rhs, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
giuros01b3204e72019-04-01 13:50:22 +01001439
1440 ARM_COMPUTE_EXPECT(lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1441 ARM_COMPUTE_EXPECT(rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001442 ARM_COMPUTE_EXPECT(bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001443
1444 // Allocate tensors
1445 lhs.allocator()->allocate();
1446 rhs.allocator()->allocate();
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001447 bias.allocator()->allocate();
giuros01b3204e72019-04-01 13:50:22 +01001448 dst.allocator()->allocate();
1449
1450 ARM_COMPUTE_EXPECT(!lhs.info()->is_resizable(), framework::LogLevel::ERRORS);
1451 ARM_COMPUTE_EXPECT(!rhs.info()->is_resizable(), framework::LogLevel::ERRORS);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001452 ARM_COMPUTE_EXPECT(!bias.info()->is_resizable(), framework::LogLevel::ERRORS);
giuros01b3204e72019-04-01 13:50:22 +01001453 ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
1454
1455 // Fill tensors
1456 fill(AccessorType(lhs), 0);
1457 fill(AccessorType(rhs), 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001458 fill(AccessorType(bias), 2);
giuros01b3204e72019-04-01 13:50:22 +01001459
1460 // Compute GEMM
1461 gemm.run();
1462
1463 return dst;
1464 }
1465
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001466 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,
1467 const ActivationLayerInfo &act_info)
giuros01b3204e72019-04-01 13:50:22 +01001468 {
1469 TensorShape dst_shape = lhs_shape;
1470 dst_shape.set(0, rhs_shape[0]);
1471 dst_shape.set(1, lhs_shape[1] / m_h);
1472 dst_shape.set(2, m_h);
1473 dst_shape.set(3, lhs_shape[2]);
1474
1475 // Create reference
1476 SimpleTensor<T> lhs{ lhs_shape, data_type, 1 };
1477 SimpleTensor<T> rhs{ rhs_shape, data_type, 1 };
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001478 SimpleTensor<T> bias{ dst_shape, data_type, 1 };
1479
1480 const int n = rhs_shape[0];
1481 const int m = lhs_shape[1];
1482 const int batch_size = lhs_shape[2];
giuros01b3204e72019-04-01 13:50:22 +01001483
1484 // Fill reference
1485 fill(lhs, 0);
1486 fill(rhs, 1);
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001487 fill(bias, 2);
giuros01b3204e72019-04-01 13:50:22 +01001488
Gian Marco Iodice944170e2019-06-24 14:40:30 +01001489 // In case of broadcast, we need simply copy the first into the following "M" ones
1490 for(int i = 1; i < m * batch_size; i++)
1491 {
1492 memcpy(bias.data() + i * n, bias.data(), n * sizeof(T));
1493 }
1494
Gian Marco Iodiceca1f4602019-07-16 15:46:48 +01001495 return reference::activation_layer(reference::gemm<T>(lhs, rhs, bias, alpha, beta), act_info);
giuros01b3204e72019-04-01 13:50:22 +01001496 }
1497
1498 TensorType _target{};
1499 SimpleTensor<T> _reference{};
1500};
1501
Moritz Pflanzer4dfc2352017-08-02 14:51:36 +01001502} // namespace validation
1503} // namespace test
1504} // namespace arm_compute
1505#endif /* ARM_COMPUTE_TEST_GEMM_FIXTURE */