blob: 762b00177cf833fa091f826a75f3063ed4e1747e [file] [log] [blame]
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001/*
giuros011c9efeb2019-01-11 14:04:43 +00002 * Copyright (c) 2017-2019 ARM Limited.
Anthony Barbier6ff3b192017-09-04 18:44:23 +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#include "arm_compute/runtime/CL/functions/CLGEMM.h"
25
Gian Marco Iodice926afe12019-03-19 11:44:13 +000026#include "arm_compute/core/CL/ICLGEMMKernelConfiguration.h"
Anthony Barbier6ff3b192017-09-04 18:44:23 +010027#include "arm_compute/core/CL/ICLTensor.h"
Gian Marco Iodice926afe12019-03-19 11:44:13 +000028#include "arm_compute/core/CL/gemm/reshaped/CLGEMMReshapedKernelConfiguration.h"
29#include "arm_compute/core/CL/gemm/reshaped_only_rhs/CLGEMMReshapedOnlyRHSKernelConfiguration.h"
Anthony Barbier6ff3b192017-09-04 18:44:23 +010030#include "arm_compute/core/Error.h"
Gian Marco Iodice750641d2018-05-08 12:01:57 +010031#include "arm_compute/core/GPUTarget.h"
Anthony Barbier6ff3b192017-09-04 18:44:23 +010032#include "arm_compute/core/Helpers.h"
Gian Marco Iodice7026b302019-06-26 17:18:11 +010033#include "arm_compute/core/KernelDescriptors.h"
Anthony Barbier6ff3b192017-09-04 18:44:23 +010034#include "arm_compute/core/TensorInfo.h"
35#include "arm_compute/core/Types.h"
Gian Marco Iodicebb36a8e2018-04-19 12:05:08 +010036#include "arm_compute/core/Utils.h"
Anthony Barbier6ff3b192017-09-04 18:44:23 +010037#include "arm_compute/core/Validate.h"
Gian Marco Iodicee16c8902019-06-14 16:11:10 +010038#include "arm_compute/core/utils/helpers/float_ops.h"
Gian Marco Iodice750641d2018-05-08 12:01:57 +010039#include "arm_compute/core/utils/misc/ShapeCalculator.h"
Anthony Barbier6ff3b192017-09-04 18:44:23 +010040#include "arm_compute/runtime/CL/CLScheduler.h"
41#include "arm_compute/runtime/ITensorAllocator.h"
42
giuros011c9efeb2019-01-11 14:04:43 +000043namespace arm_compute
44{
Gian Marco Iodice750641d2018-05-08 12:01:57 +010045using namespace arm_compute::misc::shape_calculator;
Gian Marco Iodice90313eb2019-01-16 15:40:25 +000046using namespace arm_compute::cl_gemm;
Anthony Barbier6ff3b192017-09-04 18:44:23 +010047
Georgios Pinitas8a94e7c2017-09-15 19:06:47 +010048CLGEMM::CLGEMM(std::shared_ptr<IMemoryManager> memory_manager)
Georgios Pinitasebf6b8a2018-09-24 16:31:08 +010049 : _memory_group(std::move(memory_manager)),
Georgios Pinitasebf6b8a2018-09-24 16:31:08 +010050 _mm_kernel(),
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +000051 _reshape_lhs_kernel(),
52 _reshape_rhs_kernel(),
53 _mm_reshaped_kernel(),
Gian Marco Iodice926afe12019-03-19 11:44:13 +000054 _mm_reshaped_only_rhs_kernel(),
Georgios Pinitasebf6b8a2018-09-24 16:31:08 +010055 _tmp_a(),
56 _tmp_b(),
57 _original_b(nullptr),
Georgios Pinitasebf6b8a2018-09-24 16:31:08 +010058 _reshape_b_only_on_first_run(false),
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +000059 _is_prepared(false),
Gian Marco Iodice926afe12019-03-19 11:44:13 +000060 _gemm_type(GEMMType::NATIVE)
Anthony Barbier6ff3b192017-09-04 18:44:23 +010061{
62}
63
Gian Marco Iodice926afe12019-03-19 11:44:13 +000064CLGEMM::GEMMType CLGEMM::select_gemm_type(unsigned int m, unsigned int n, unsigned int k, DataType data_type, bool reshape_b_only_on_first_run, GPUTarget gpu_target)
Anthony Barbier6ff3b192017-09-04 18:44:23 +010065{
Gian Marco Iodice926afe12019-03-19 11:44:13 +000066 GEMMType gemm_type = GEMMType::RESHAPED_V1;
Anthony Barbier6ff3b192017-09-04 18:44:23 +010067
Gian Marco Iodice05639f62019-09-24 12:05:06 +010068 if(gpu_target_is_in(gpu_target, GPUTarget::G51, GPUTarget::G51BIG, GPUTarget::G51LIT,
69 GPUTarget::G52, GPUTarget::G52LIT, GPUTarget::G71, GPUTarget::G72,
70 GPUTarget::G76, GPUTarget::G77))
Gian Marco Iodice926afe12019-03-19 11:44:13 +000071 {
Gian Marco Iodice05639f62019-09-24 12:05:06 +010072 if(data_type == DataType::F32)
Gian Marco Iodice926afe12019-03-19 11:44:13 +000073 {
Gian Marco Iodice05639f62019-09-24 12:05:06 +010074 if((m > 1) && (n < 16))
Gian Marco Iodice926afe12019-03-19 11:44:13 +000075 {
Gian Marco Iodice05639f62019-09-24 12:05:06 +010076 gemm_type = GEMMType::RESHAPED_V1;
77 }
78 else if(m == 1)
79 {
80 gemm_type = GEMMType::RESHAPED_ONLY_RHS;
Gian Marco Iodice926afe12019-03-19 11:44:13 +000081 }
82 else
83 {
Gian Marco Iodice05639f62019-09-24 12:05:06 +010084 // COMPMID-852
85 if((k > 256) && (m > 4) && reshape_b_only_on_first_run)
86 {
87 constexpr float alpha = 3.2f;
88 constexpr float fact0 = 1.51f;
89 constexpr float fact1 = 1.66f;
90 constexpr float ops = 12.0f;
91 const float scale = k > 1024 ? 1.07f : 1.0f;
92 gemm_type = (alpha + ((n * fact0) / ops) < ((fact1 * n * scale) / ops)) ? GEMMType::RESHAPED_V1 : GEMMType::NATIVE;
93 }
94 else
95 {
96 gemm_type = GEMMType::NATIVE;
97 }
98 }
99
100 const auto workload = static_cast<float>((m * n) / 20.0f);
101
102 gemm_type = ((workload > 1600.0f) && (gemm_type == GEMMType::RESHAPED_V1) && (data_type == DataType::F32)) ? GEMMType::RESHAPED_V2 : gemm_type;
103 }
104 else
105 {
106 if((m == 1) || (!reshape_b_only_on_first_run))
107 {
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000108 gemm_type = GEMMType::NATIVE;
109 }
Gian Marco Iodice05639f62019-09-24 12:05:06 +0100110 else
111 {
112 gemm_type = GEMMType::RESHAPED_V2;
113 }
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000114 }
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000115 }
116 else
117 {
118 // We reshape the matrices only if we do not have the vector-by-matrix case and we reshape the matrix B only once
119 gemm_type = ((m != 1) && reshape_b_only_on_first_run) ? GEMMType::RESHAPED_V1 : GEMMType::NATIVE;
120 }
Gian Marco Iodiceedfa9f42017-08-15 11:45:22 +0100121
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000122 return gemm_type;
123}
124
125void CLGEMM::configure_native(const ICLTensor *a, const ICLTensor *b, const ICLTensor *c, ICLTensor *output, float alpha, float beta, const GEMMInfo &gemm_info)
126{
127 const unsigned int m = gemm_info.reinterpret_input_as_3d() ? (a->info()->dimension(1) * a->info()->dimension(2)) : a->info()->dimension(1);
128 const unsigned int n = b->info()->dimension(0);
129 const unsigned int k = a->info()->dimension(0);
130 const GPUTarget gpu_target = CLScheduler::get().target();
Gian Marco36a0a462018-01-12 10:21:40 +0000131
132 // Set the target for the kernels
Gian Marco36a0a462018-01-12 10:21:40 +0000133 _mm_kernel.set_target(gpu_target);
134
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100135 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, gemm_info.depth_output_gemm3d(), gemm_info.reinterpret_input_as_3d(), gemm_info.broadcast_bias());
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000136
137 // Configure and tune matrix multiply kernel
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100138 _mm_kernel.configure(a, b, c, output, alpha, beta, false, reshape_info, gemm_info.fp_mixed_precision(), gemm_info.activation_info());
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000139
140 // Tune kernel statically
141 CLScheduler::get().tune_kernel_static(_mm_kernel);
142}
143
144void CLGEMM::configure_reshaped_v1(const ICLTensor *a, const ICLTensor *b, const ICLTensor *c, ICLTensor *output, float alpha, float beta, const GEMMInfo &gemm_info)
145{
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000146 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
147 const unsigned int m = reinterpret_input_as_3d ? (a->info()->dimension(1) * a->info()->dimension(2)) : a->info()->dimension(1);
148 const unsigned int n = b->info()->dimension(0);
149 const unsigned int k = a->info()->dimension(0);
150 const int depth_output_gemm3d = gemm_info.depth_output_gemm3d();
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000151 const GPUTarget gpu_target = CLScheduler::get().target();
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000152 int mult_transpose1xW_width = 1;
153 int mult_interleave4x4_height = 1;
Gian Marco36a0a462018-01-12 10:21:40 +0000154
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000155 // Set the target for the kernels
156 _reshape_lhs_kernel.set_target(gpu_target);
157 _mm_kernel.set_target(gpu_target);
158
Gian Marco Iodice750641d2018-05-08 12:01:57 +0100159 if(get_arch_from_target(gpu_target) == GPUTarget::BIFROST)
Gian Marco36a0a462018-01-12 10:21:40 +0000160 {
161 mult_transpose1xW_width = 4;
162 mult_interleave4x4_height = 2;
163 }
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000164
giuros018b6b4a92018-12-18 19:01:33 +0000165 GEMMRHSMatrixInfo rhs_info;
166 rhs_info.n0 = 16 / b->info()->element_size();
167 rhs_info.k0 = 1;
168 rhs_info.h0 = mult_transpose1xW_width;
169 rhs_info.interleave = false;
170 rhs_info.transpose = false;
Gian Marco36a0a462018-01-12 10:21:40 +0000171
giuros011c9efeb2019-01-11 14:04:43 +0000172 GEMMLHSMatrixInfo lhs_info;
173 lhs_info.m0 = 4;
174 lhs_info.k0 = 4;
175 lhs_info.v0 = mult_interleave4x4_height;
176 lhs_info.interleave = true;
177 lhs_info.transpose = true;
178
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100179 GEMMReshapeInfo reshape_info(m, n, k, mult_transpose1xW_width, mult_interleave4x4_height, depth_output_gemm3d, false, gemm_info.broadcast_bias());
Gian Marcob5311a62017-12-13 12:48:03 +0000180
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000181 _memory_group.manage(&_tmp_a);
182 if(!_reshape_b_only_on_first_run)
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100183 {
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000184 _memory_group.manage(&_tmp_b);
Gian Marco Iodiceedfa9f42017-08-15 11:45:22 +0100185 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100186
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000187 // Configure interleave kernel
188 _reshape_lhs_kernel.configure(a, &_tmp_a, lhs_info, reinterpret_input_as_3d);
Gian Marco Iodiceedfa9f42017-08-15 11:45:22 +0100189
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000190 // Configure transpose kernel
191 _reshape_rhs_kernel.configure(b, &_tmp_b, rhs_info);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100192
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000193 // Configure and tune matrix multiply kernel
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100194 _mm_kernel.configure(&_tmp_a, &_tmp_b, c, output, alpha, beta, true, reshape_info, gemm_info.fp_mixed_precision(), gemm_info.activation_info());
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000195
196 CLScheduler::get().tune_kernel_static(_mm_kernel);
197
198 // Allocate intermediate tensors
199 _tmp_a.allocator()->allocate();
200 if(!_reshape_b_only_on_first_run)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100201 {
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000202 _tmp_b.allocator()->allocate();
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100203 }
204}
205
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000206void CLGEMM::configure_reshaped_v2(const ICLTensor *a, const ICLTensor *b, const ICLTensor *c, ICLTensor *output, float alpha, float beta, const GEMMInfo &gemm_info)
207{
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000208 DataType data_type = a->info()->data_type();
209 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
210 const unsigned int m = reinterpret_input_as_3d ? (a->info()->dimension(1) * a->info()->dimension(2)) : a->info()->dimension(1);
211 const unsigned int n = b->info()->dimension(0);
212 const unsigned int k = a->info()->dimension(0);
213 const unsigned int batch_size = reinterpret_input_as_3d ? a->info()->dimension(3) : a->info()->dimension(2);
214 const int depth_output_gemm3d = gemm_info.depth_output_gemm3d();
215 const GPUTarget gpu_target = CLScheduler::get().target();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100216 bool broadcast_bias = gemm_info.broadcast_bias();
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100217
218 GEMMKernelInfo kernel_info;
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100219 kernel_info.m = m;
220 kernel_info.n = n;
221 kernel_info.k = k;
222 kernel_info.depth_output_gemm3d = depth_output_gemm3d;
223 kernel_info.reinterpret_input_as_3d = false;
224 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100225 kernel_info.activation_info = gemm_info.activation_info();
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000226
227 // Set the target for the kernels
228 _reshape_lhs_kernel.set_target(gpu_target);
229 _mm_kernel.set_target(gpu_target);
230
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000231 // Manage intermediate buffers
232 _memory_group.manage(&_tmp_a);
233 if(!_reshape_b_only_on_first_run)
234 {
235 _memory_group.manage(&_tmp_b);
236 }
237 // _tmp_a and _tmp_b will be auto configured in _interleave_kernel and in _transpose_kernel
238
239 GEMMLHSMatrixInfo lhs_info{};
240 GEMMRHSMatrixInfo rhs_info{};
241
242 // Pick up the GEMM configuration
243 std::unique_ptr<ICLGEMMKernelConfiguration> gemm_config = CLGEMMReshapedKernelConfigurationFactory::create(gpu_target);
244 ARM_COMPUTE_ERROR_ON_NULLPTR(gemm_config.get());
245
246 // Configure lhs_info and rhs_info
247 std::tie(lhs_info, rhs_info) = gemm_config->configure(m, n, k, batch_size, data_type);
248
249 _reshape_lhs_kernel.configure(a, &_tmp_a, lhs_info, gemm_info.reinterpret_input_as_3d());
250 _reshape_rhs_kernel.configure(b, &_tmp_b, rhs_info);
251
252 // Configure and tune matrix multiply kernel
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100253 _mm_reshaped_kernel.configure(&_tmp_a, &_tmp_b, c, output, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000254
255 // Allocate intermediate tensors
256 _tmp_a.allocator()->allocate();
257 if(!_reshape_b_only_on_first_run)
258 {
259 _tmp_b.allocator()->allocate();
260 }
261}
262
263void CLGEMM::configure_reshaped_only_rhs(const ICLTensor *a, const ICLTensor *b, const ICLTensor *c, ICLTensor *output, float alpha, float beta, const GEMMInfo &gemm_info)
264{
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000265 DataType data_type = a->info()->data_type();
266 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
267 const unsigned int m = reinterpret_input_as_3d ? (a->info()->dimension(1) * a->info()->dimension(2)) : a->info()->dimension(1);
268 const unsigned int n = b->info()->dimension(0);
269 const unsigned int k = a->info()->dimension(0);
270 const unsigned int batch_size = reinterpret_input_as_3d ? a->info()->dimension(3) : a->info()->dimension(2);
271 const int depth_output_gemm3d = gemm_info.depth_output_gemm3d();
272 const GPUTarget gpu_target = CLScheduler::get().target();
Georgios Pinitasb0f342e2019-05-21 13:32:43 +0100273 bool broadcast_bias = gemm_info.broadcast_bias();
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100274
275 GEMMKernelInfo kernel_info;
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100276 kernel_info.m = m;
277 kernel_info.n = n;
278 kernel_info.k = k;
279 kernel_info.depth_output_gemm3d = depth_output_gemm3d;
280 kernel_info.reinterpret_input_as_3d = reinterpret_input_as_3d;
281 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100282 kernel_info.activation_info = gemm_info.activation_info();
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000283
284 // Set the target for the kernels
285 _mm_kernel.set_target(gpu_target);
286
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000287 // Manage intermediate buffers
288 if(!_reshape_b_only_on_first_run)
289 {
290 _memory_group.manage(&_tmp_b);
291 }
292
293 GEMMLHSMatrixInfo lhs_info{};
294 GEMMRHSMatrixInfo rhs_info{};
295
296 // Pick up the GEMM configuration
297 std::unique_ptr<ICLGEMMKernelConfiguration> gemm_config = CLGEMMReshapedOnlyRHSKernelConfigurationFactory::create(gpu_target);
298 ARM_COMPUTE_ERROR_ON_NULLPTR(gemm_config.get());
299
300 // Configure lhs_info and rhs_info
301 std::tie(lhs_info, rhs_info) = gemm_config->configure(m, n, k, batch_size, data_type);
302
303 _reshape_rhs_kernel.configure(b, &_tmp_b, rhs_info);
304
305 // Configure and tune matrix multiply kernel
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100306 _mm_reshaped_only_rhs_kernel.configure(a, &_tmp_b, c, output, alpha, beta, lhs_info, rhs_info, kernel_info);
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000307
308 if(!_reshape_b_only_on_first_run)
309 {
310 _tmp_b.allocator()->allocate();
311 }
312}
313
314Status CLGEMM::validate_native(const ITensorInfo *a, const ITensorInfo *b, const ITensorInfo *c, const ITensorInfo *output, float alpha, float beta, const GEMMInfo &gemm_info)
Georgios Pinitas78c00902018-01-09 17:33:11 +0000315{
Gian Marco Iodice750641d2018-05-08 12:01:57 +0100316 ARM_COMPUTE_UNUSED(alpha);
Gian Marco Iodice215b4ea2018-06-28 16:29:29 +0100317 ARM_COMPUTE_UNUSED(output);
Gian Marco Iodice750641d2018-05-08 12:01:57 +0100318
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000319 // Get the GPU target
320 const GPUTarget gpu_target = CLScheduler::get().target();
321 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
322 const unsigned int m = reinterpret_input_as_3d ? (a->dimension(1) * a->dimension(2)) : a->dimension(1);
323 const unsigned int n = b->dimension(0);
324 const unsigned int k = a->dimension(0);
325 const int depth_output_gemm3d = gemm_info.depth_output_gemm3d();
Gian Marco Iodice750641d2018-05-08 12:01:57 +0100326
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100327 const GEMMReshapeInfo reshape_info = GEMMReshapeInfo(m, n, k, 1, 1, depth_output_gemm3d, reinterpret_input_as_3d, gemm_info.broadcast_bias());
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000328
329 // Validate matrix multiply
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100330 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMMatrixMultiplyKernel::validate(a, b, c, output, alpha, beta,
331 false, reshape_info, gpu_target, gemm_info.fp_mixed_precision(), gemm_info.activation_info()));
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000332
333 return Status{};
334}
335
336Status CLGEMM::validate_reshaped_v1(const ITensorInfo *a, const ITensorInfo *b, const ITensorInfo *c, const ITensorInfo *output, float alpha, float beta, const GEMMInfo &gemm_info)
337{
338 ARM_COMPUTE_UNUSED(alpha);
339 ARM_COMPUTE_UNUSED(output);
Gian Marco Iodice750641d2018-05-08 12:01:57 +0100340
341 TensorInfo tmp_a_info{};
342 TensorInfo tmp_b_info{};
Gian Marco Iodice750641d2018-05-08 12:01:57 +0100343
344 // Get the GPU target
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000345 const GPUTarget gpu_target = CLScheduler::get().target();
346 const unsigned int m = gemm_info.reinterpret_input_as_3d() ? (a->dimension(1) * a->dimension(2)) : a->dimension(1);
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000347 const unsigned int n = b->dimension(0);
348 const unsigned int k = a->dimension(0);
349 int mult_transpose1xW_width = 1;
350 int mult_interleave4x4_height = 1;
351 const int depth_output_gemm3d = gemm_info.depth_output_gemm3d();
Gian Marco Iodice750641d2018-05-08 12:01:57 +0100352
353 if(get_arch_from_target(gpu_target) == GPUTarget::BIFROST)
354 {
355 mult_transpose1xW_width = 4;
356 mult_interleave4x4_height = 2;
357 }
358
giuros018b6b4a92018-12-18 19:01:33 +0000359 GEMMRHSMatrixInfo rhs_info;
360 rhs_info.n0 = 16 / b->element_size();
361 rhs_info.k0 = 1;
362 rhs_info.h0 = mult_transpose1xW_width;
363 rhs_info.interleave = false;
364 rhs_info.transpose = false;
365
giuros011c9efeb2019-01-11 14:04:43 +0000366 GEMMLHSMatrixInfo lhs_info;
367 lhs_info.m0 = 4;
368 lhs_info.k0 = 4;
369 lhs_info.v0 = mult_interleave4x4_height;
370 lhs_info.interleave = true;
371 lhs_info.transpose = true;
372
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100373 const GEMMReshapeInfo reshape_info = GEMMReshapeInfo(m, n, k, mult_transpose1xW_width, mult_interleave4x4_height, depth_output_gemm3d, false, gemm_info.broadcast_bias());
Gian Marco Iodice750641d2018-05-08 12:01:57 +0100374
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000375 // Validate interleave kernel
376 auto_init_if_empty(tmp_a_info, a->clone()->set_tensor_shape(compute_lhs_reshaped_shape(*a, lhs_info, gemm_info.reinterpret_input_as_3d())));
377 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMReshapeLHSMatrixKernel::validate(a, &tmp_a_info, lhs_info, gemm_info.reinterpret_input_as_3d()));
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000378
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000379 // Validate transpose kernel
380 auto_init_if_empty(tmp_b_info, b->clone()->set_tensor_shape(compute_rhs_reshaped_shape(*b, rhs_info)));
381 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMReshapeRHSMatrixKernel::validate(b, &tmp_b_info, rhs_info));
Michele Di Giorgioebc3a902018-11-16 16:04:25 +0000382
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000383 // Validate matrix multiply
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100384 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMMatrixMultiplyKernel::validate(&tmp_a_info, &tmp_b_info, c, output, alpha, beta,
385 true, reshape_info, gpu_target, gemm_info.fp_mixed_precision(), gemm_info.activation_info()));
Gian Marco Iodice750641d2018-05-08 12:01:57 +0100386
Georgios Pinitas78c00902018-01-09 17:33:11 +0000387 return Status{};
388}
389
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000390Status CLGEMM::validate_reshaped_v2(const ITensorInfo *a, const ITensorInfo *b, const ITensorInfo *c, const ITensorInfo *output, float alpha, float beta, const GEMMInfo &gemm_info)
391{
392 ARM_COMPUTE_UNUSED(alpha);
393 ARM_COMPUTE_UNUSED(output);
394
395 TensorInfo tmp_a_info{};
396 TensorInfo tmp_b_info{};
397
398 // Get the GPU target
399 const GPUTarget gpu_target = CLScheduler::get().target();
400 DataType data_type = a->data_type();
401 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
402 const unsigned int m = reinterpret_input_as_3d ? (a->dimension(1) * a->dimension(2)) : a->dimension(1);
403 const unsigned int n = b->dimension(0);
404 const unsigned int k = a->dimension(0);
405 const unsigned int batch_size = reinterpret_input_as_3d ? a->dimension(3) : a->dimension(2);
406 const int depth_output_gemm3d = gemm_info.depth_output_gemm3d();
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100407 const bool broadcast_bias = gemm_info.broadcast_bias();
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100408
409 GEMMKernelInfo kernel_info;
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100410 kernel_info.m = m;
411 kernel_info.n = n;
412 kernel_info.k = k;
413 kernel_info.depth_output_gemm3d = depth_output_gemm3d;
414 kernel_info.reinterpret_input_as_3d = false;
415 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100416 kernel_info.activation_info = gemm_info.activation_info();
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000417
418 GEMMLHSMatrixInfo lhs_info;
419 GEMMRHSMatrixInfo rhs_info;
420
421 // Pick up the GEMM configuration
422 std::unique_ptr<ICLGEMMKernelConfiguration> gemm_config = CLGEMMReshapedKernelConfigurationFactory::create(gpu_target);
423 ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(gemm_config.get());
424
425 // Configure lhs_info and rhs_info
426 std::tie(lhs_info, rhs_info) = gemm_config->configure(m, n, k, batch_size, data_type);
427
428 auto_init_if_empty(tmp_a_info, a->clone()->set_tensor_shape(compute_lhs_reshaped_shape(*a, lhs_info, gemm_info.reinterpret_input_as_3d())));
429 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMReshapeLHSMatrixKernel::validate(a, &tmp_a_info, lhs_info, gemm_info.reinterpret_input_as_3d()));
430
431 auto_init_if_empty(tmp_b_info, b->clone()->set_tensor_shape(compute_rhs_reshaped_shape(*b, rhs_info)));
432 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMReshapeRHSMatrixKernel::validate(b, &tmp_b_info, rhs_info));
433
434 // Validate matrix multiply
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100435 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMMatrixMultiplyReshapedKernel::validate(&tmp_a_info, &tmp_b_info, c, output, alpha, beta, lhs_info, rhs_info, kernel_info));
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000436
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000437 return Status{};
438}
439
440Status CLGEMM::validate_reshaped_only_rhs(const ITensorInfo *a, const ITensorInfo *b, const ITensorInfo *c, const ITensorInfo *output, float alpha, float beta, const GEMMInfo &gemm_info)
441{
442 ARM_COMPUTE_UNUSED(alpha);
443 ARM_COMPUTE_UNUSED(output);
444
445 TensorInfo tmp_b_info{};
446
447 // Get the GPU target
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100448 const GPUTarget gpu_target = CLScheduler::get().target();
449 const DataType data_type = a->data_type();
450 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
451 const unsigned int m = reinterpret_input_as_3d ? (a->dimension(1) * a->dimension(2)) : a->dimension(1);
452 const unsigned int n = b->dimension(0);
453 const unsigned int k = a->dimension(0);
454 const unsigned int batch_size = reinterpret_input_as_3d ? a->dimension(3) : a->dimension(2);
455 const int depth_output_gemm3d = gemm_info.depth_output_gemm3d();
456 const bool broadcast_bias = gemm_info.broadcast_bias();
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100457
458 GEMMKernelInfo kernel_info;
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100459 kernel_info.m = m;
460 kernel_info.n = n;
461 kernel_info.k = k;
462 kernel_info.depth_output_gemm3d = depth_output_gemm3d;
463 kernel_info.reinterpret_input_as_3d = reinterpret_input_as_3d;
464 kernel_info.broadcast_bias = broadcast_bias;
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100465 kernel_info.activation_info = gemm_info.activation_info();
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000466
467 GEMMLHSMatrixInfo lhs_info;
468 GEMMRHSMatrixInfo rhs_info;
469
470 // Pick up the GEMM configuration
471 std::unique_ptr<ICLGEMMKernelConfiguration> gemm_config = CLGEMMReshapedOnlyRHSKernelConfigurationFactory::create(gpu_target);
472 ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(gemm_config.get());
473
474 // Configure lhs_info and rhs_info
475 std::tie(lhs_info, rhs_info) = gemm_config->configure(m, n, k, batch_size, data_type);
476
477 auto_init_if_empty(tmp_b_info, b->clone()->set_tensor_shape(compute_rhs_reshaped_shape(*b, rhs_info)));
478 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMReshapeRHSMatrixKernel::validate(b, &tmp_b_info, rhs_info));
479
480 // Validate matrix multiply
Gian Marco Iodice7026b302019-06-26 17:18:11 +0100481 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMMatrixMultiplyReshapedOnlyRHSKernel::validate(a, &tmp_b_info, c, output, alpha, beta, lhs_info, rhs_info, kernel_info));
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000482
483 return Status{};
484}
485
486void CLGEMM::configure(const ICLTensor *a, const ICLTensor *b, const ICLTensor *c, ICLTensor *output, float alpha, float beta, const GEMMInfo &gemm_info)
487{
488 ARM_COMPUTE_ERROR_ON_NULLPTR(a, b, output);
489
490 // Perform validation step
491 ARM_COMPUTE_ERROR_THROW_ON(validate(a->info(), b->info(), c != nullptr ? c->info() : nullptr, output->info(), alpha, beta, gemm_info));
492
493 // Check if we need to reshape the matrix B only on the first run
494 _reshape_b_only_on_first_run = gemm_info.reshape_b_only_on_first_run();
495 _is_prepared = gemm_info.retain_internal_weights();
496 _original_b = b;
497
498 // Get the GPU target
499 const GPUTarget gpu_target = CLScheduler::get().target();
500 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
501 const unsigned int m = reinterpret_input_as_3d ? (a->info()->dimension(1) * a->info()->dimension(2)) : a->info()->dimension(1);
502 const unsigned int n = b->info()->dimension(0);
503 const unsigned int k = a->info()->dimension(0);
504
505 // Select GEMMType
506 _gemm_type = select_gemm_type(m, n, k, a->info()->data_type(), _reshape_b_only_on_first_run, gpu_target);
507
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100508 const bool fuse_add_c = (!(helpers::float_ops::is_zero(beta)) && c != nullptr);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100509
510 const ICLTensor *c_to_use = fuse_add_c ? c : nullptr;
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000511
512 switch(_gemm_type)
513 {
514 case GEMMType::NATIVE:
515 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100516 configure_native(a, b, c_to_use, output, alpha, beta, gemm_info);
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000517 break;
518 }
519 case GEMMType::RESHAPED_V1:
520 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100521 configure_reshaped_v1(a, b, c_to_use, output, alpha, beta, gemm_info);
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000522 break;
523 }
524 case GEMMType::RESHAPED_V2:
525 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100526 configure_reshaped_v2(a, b, c_to_use, output, alpha, beta, gemm_info);
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000527 break;
528 }
529 case GEMMType::RESHAPED_ONLY_RHS:
530 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100531 configure_reshaped_only_rhs(a, b, c_to_use, output, alpha, beta, gemm_info);
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000532 break;
533 }
534 default:
535 {
536 ARM_COMPUTE_ERROR("GEMMType not supported");
537 }
538 }
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000539}
540
541Status CLGEMM::validate(const ITensorInfo *a, const ITensorInfo *b, const ITensorInfo *c, const ITensorInfo *output, float alpha, float beta, const GEMMInfo &gemm_info)
542{
543 // Get the GPU target
544 const GPUTarget gpu_target = CLScheduler::get().target();
545 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
546 const unsigned int m = reinterpret_input_as_3d ? (a->dimension(1) * a->dimension(2)) : a->dimension(1);
547 const unsigned int n = b->dimension(0);
548 const unsigned int k = a->dimension(0);
549
550 // Select GEMMType
551 GEMMType gemm_type = select_gemm_type(m, n, k, a->data_type(), gemm_info.reshape_b_only_on_first_run(), gpu_target);
552
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100553 const bool fuse_add_c = (!(helpers::float_ops::is_zero(beta)) && c != nullptr);
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100554
555 const ITensorInfo *c_to_use = fuse_add_c ? c : nullptr;
556
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000557 switch(gemm_type)
558 {
559 case GEMMType::NATIVE:
560 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100561 ARM_COMPUTE_RETURN_ON_ERROR(validate_native(a, b, c_to_use, output, alpha, beta, gemm_info));
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000562 break;
563 }
564 case GEMMType::RESHAPED_V1:
565 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100566 ARM_COMPUTE_RETURN_ON_ERROR(validate_reshaped_v1(a, b, c_to_use, output, alpha, beta, gemm_info));
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000567 break;
568 }
569 case GEMMType::RESHAPED_V2:
570 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100571 ARM_COMPUTE_RETURN_ON_ERROR(validate_reshaped_v2(a, b, c_to_use, output, alpha, beta, gemm_info));
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000572 break;
573 }
574 case GEMMType::RESHAPED_ONLY_RHS:
575 {
Gian Marco Iodicee16c8902019-06-14 16:11:10 +0100576 ARM_COMPUTE_RETURN_ON_ERROR(validate_reshaped_only_rhs(a, b, c_to_use, output, alpha, beta, gemm_info));
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000577 break;
578 }
579 default:
580 {
581 ARM_COMPUTE_RETURN_ERROR_MSG("GEMMType not supported");
582 }
583 }
584
585 return Status{};
586}
587
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100588void CLGEMM::run()
589{
Georgios Pinitase0437672018-05-02 14:07:55 +0100590 prepare();
591
Georgios Pinitasda953f22019-04-02 17:27:03 +0100592 MemoryGroupResourceScope scope_mg(_memory_group);
Georgios Pinitas8a94e7c2017-09-15 19:06:47 +0100593
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100594 // Run matrix multiply kernel
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000595 switch(_gemm_type)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000596 {
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000597 case GEMMType::NATIVE:
598 {
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100599 CLScheduler::get().enqueue(_mm_kernel, true);
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000600 break;
601 }
602 case GEMMType::RESHAPED_V1:
603 {
604 // Run interleave kernel
605 CLScheduler::get().enqueue(_reshape_lhs_kernel, false);
606
607 if(!_reshape_b_only_on_first_run)
608 {
609 // Run transpose kernel
610 CLScheduler::get().enqueue(_reshape_rhs_kernel, false);
611 }
612
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100613 CLScheduler::get().enqueue(_mm_kernel, true);
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000614 break;
615 }
616 case GEMMType::RESHAPED_V2:
617 {
618 // Run interleave kernel
619 CLScheduler::get().enqueue(_reshape_lhs_kernel, false);
620
621 if(!_reshape_b_only_on_first_run)
622 {
623 // Run transpose kernel
624 CLScheduler::get().enqueue(_reshape_rhs_kernel, false);
625 }
626
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100627 CLScheduler::get().enqueue(_mm_reshaped_kernel, true);
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000628 break;
629 }
630 case GEMMType::RESHAPED_ONLY_RHS:
631 {
632 if(!_reshape_b_only_on_first_run)
633 {
634 // Run transpose kernel
635 CLScheduler::get().enqueue(_reshape_rhs_kernel, false);
636 }
637
Gian Marco Iodicef3622be2019-07-29 14:27:16 +0100638 CLScheduler::get().enqueue(_mm_reshaped_only_rhs_kernel, true);
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000639 break;
640 }
641 default:
642 {
643 ARM_COMPUTE_ERROR("GEMMType not supported");
644 }
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000645 }
Georgios Pinitase0437672018-05-02 14:07:55 +0100646}
Georgios Pinitas82b51482018-04-24 15:14:12 +0100647
Georgios Pinitase0437672018-05-02 14:07:55 +0100648void CLGEMM::prepare()
649{
650 if(!_is_prepared)
651 {
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000652 if(_gemm_type != GEMMType::NATIVE && _reshape_b_only_on_first_run)
Georgios Pinitase0437672018-05-02 14:07:55 +0100653 {
Georgios Pinitas72219332018-06-05 14:56:06 +0100654 // Run transpose kernel and mark original weights tensor as unused
Georgios Pinitase0437672018-05-02 14:07:55 +0100655 _tmp_b.allocator()->allocate();
giuros018b6b4a92018-12-18 19:01:33 +0000656 CLScheduler::get().enqueue(_reshape_rhs_kernel, false);
Georgios Pinitase0437672018-05-02 14:07:55 +0100657 _original_b->mark_as_unused();
658 }
659 CLScheduler::get().queue().finish();
660 _is_prepared = true;
661 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100662}
giuros011c9efeb2019-01-11 14:04:43 +0000663} // namespace arm_compute