blob: 21a9fce233a2ee4576289a24125da61746f8d101 [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"
33#include "arm_compute/core/TensorInfo.h"
34#include "arm_compute/core/Types.h"
Gian Marco Iodicebb36a8e2018-04-19 12:05:08 +010035#include "arm_compute/core/Utils.h"
Anthony Barbier6ff3b192017-09-04 18:44:23 +010036#include "arm_compute/core/Validate.h"
Gian Marco Iodice750641d2018-05-08 12:01:57 +010037#include "arm_compute/core/utils/misc/ShapeCalculator.h"
Anthony Barbier6ff3b192017-09-04 18:44:23 +010038#include "arm_compute/runtime/CL/CLScheduler.h"
39#include "arm_compute/runtime/ITensorAllocator.h"
40
giuros011c9efeb2019-01-11 14:04:43 +000041namespace arm_compute
42{
Gian Marco Iodice750641d2018-05-08 12:01:57 +010043using namespace arm_compute::misc::shape_calculator;
Gian Marco Iodice90313eb2019-01-16 15:40:25 +000044using namespace arm_compute::cl_gemm;
Anthony Barbier6ff3b192017-09-04 18:44:23 +010045
Georgios Pinitas8a94e7c2017-09-15 19:06:47 +010046CLGEMM::CLGEMM(std::shared_ptr<IMemoryManager> memory_manager)
Georgios Pinitasebf6b8a2018-09-24 16:31:08 +010047 : _memory_group(std::move(memory_manager)),
Georgios Pinitasebf6b8a2018-09-24 16:31:08 +010048 _mm_kernel(),
49 _ma_kernel(),
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +000050 _reshape_lhs_kernel(),
51 _reshape_rhs_kernel(),
52 _mm_reshaped_kernel(),
Gian Marco Iodice926afe12019-03-19 11:44:13 +000053 _mm_reshaped_only_rhs_kernel(),
Georgios Pinitasebf6b8a2018-09-24 16:31:08 +010054 _tmp_a(),
55 _tmp_b(),
56 _original_b(nullptr),
Georgios Pinitasebf6b8a2018-09-24 16:31:08 +010057 _run_addition(false),
58 _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 Iodice926afe12019-03-19 11:44:13 +000068 if(gpu_target_is_in(gpu_target, GPUTarget::G52, GPUTarget::G52LIT, GPUTarget::G71, GPUTarget::G72, GPUTarget::G76))
69 {
70 if((m > 1) && (n < 16))
71 {
72 gemm_type = GEMMType::RESHAPED_V1;
73 }
74 else if((m == 1) && (data_type == DataType::F32))
75 {
76 gemm_type = GEMMType::RESHAPED_ONLY_RHS;
77 }
78 else
79 {
80 // COMPMID-852
81 if((k > 256) && (m > 4) && is_data_type_float(data_type) && reshape_b_only_on_first_run)
82 {
83 constexpr float alpha = 3.2f;
84 constexpr float fact0 = 1.51f;
85 constexpr float fact1 = 1.66f;
86 constexpr float ops = 12.0f;
87 const float scale = k > 1024 ? 1.07f : 1.0f;
88 gemm_type = (alpha + ((n * fact0) / ops) < ((fact1 * n * scale) / ops)) ? GEMMType::RESHAPED_V1 : GEMMType::NATIVE;
89 }
90 else
91 {
92 gemm_type = GEMMType::NATIVE;
93 }
94 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +010095
Gian Marco Iodice926afe12019-03-19 11:44:13 +000096 const auto workload = static_cast<float>((m * n) / 20.0f);
Gian Marco Iodice1246b632017-08-16 18:38:32 +010097
Gian Marco Iodice926afe12019-03-19 11:44:13 +000098 gemm_type = ((workload > 1600.0f) && (gemm_type == GEMMType::RESHAPED_V1) && (data_type == DataType::F32)) ? GEMMType::RESHAPED_V2 : gemm_type;
99 }
100 else
101 {
102 // We reshape the matrices only if we do not have the vector-by-matrix case and we reshape the matrix B only once
103 gemm_type = ((m != 1) && reshape_b_only_on_first_run) ? GEMMType::RESHAPED_V1 : GEMMType::NATIVE;
104 }
Gian Marco Iodiceedfa9f42017-08-15 11:45:22 +0100105
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000106 return gemm_type;
107}
108
109void CLGEMM::configure_native(const ICLTensor *a, const ICLTensor *b, const ICLTensor *c, ICLTensor *output, float alpha, float beta, const GEMMInfo &gemm_info)
110{
111 const unsigned int m = gemm_info.reinterpret_input_as_3d() ? (a->info()->dimension(1) * a->info()->dimension(2)) : a->info()->dimension(1);
112 const unsigned int n = b->info()->dimension(0);
113 const unsigned int k = a->info()->dimension(0);
114 const GPUTarget gpu_target = CLScheduler::get().target();
Gian Marco36a0a462018-01-12 10:21:40 +0000115
116 // Set the target for the kernels
Gian Marco36a0a462018-01-12 10:21:40 +0000117 _mm_kernel.set_target(gpu_target);
118
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000119 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, gemm_info.depth_output_gemm3d(), gemm_info.reinterpret_input_as_3d());
120
121 // Configure and tune matrix multiply kernel
122 _mm_kernel.configure(a, b, c, output, alpha, beta, false, reshape_info, gemm_info.fp_mixed_precision());
123
124 // Tune kernel statically
125 CLScheduler::get().tune_kernel_static(_mm_kernel);
126}
127
128void CLGEMM::configure_reshaped_v1(const ICLTensor *a, const ICLTensor *b, const ICLTensor *c, ICLTensor *output, float alpha, float beta, const GEMMInfo &gemm_info)
129{
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000130 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
131 const unsigned int m = reinterpret_input_as_3d ? (a->info()->dimension(1) * a->info()->dimension(2)) : a->info()->dimension(1);
132 const unsigned int n = b->info()->dimension(0);
133 const unsigned int k = a->info()->dimension(0);
134 const int depth_output_gemm3d = gemm_info.depth_output_gemm3d();
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000135 const GPUTarget gpu_target = CLScheduler::get().target();
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000136 int mult_transpose1xW_width = 1;
137 int mult_interleave4x4_height = 1;
Gian Marco36a0a462018-01-12 10:21:40 +0000138
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000139 // Set the target for the kernels
140 _reshape_lhs_kernel.set_target(gpu_target);
141 _mm_kernel.set_target(gpu_target);
142
Gian Marco Iodice750641d2018-05-08 12:01:57 +0100143 if(get_arch_from_target(gpu_target) == GPUTarget::BIFROST)
Gian Marco36a0a462018-01-12 10:21:40 +0000144 {
145 mult_transpose1xW_width = 4;
146 mult_interleave4x4_height = 2;
147 }
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000148
giuros018b6b4a92018-12-18 19:01:33 +0000149 GEMMRHSMatrixInfo rhs_info;
150 rhs_info.n0 = 16 / b->info()->element_size();
151 rhs_info.k0 = 1;
152 rhs_info.h0 = mult_transpose1xW_width;
153 rhs_info.interleave = false;
154 rhs_info.transpose = false;
Gian Marco36a0a462018-01-12 10:21:40 +0000155
giuros011c9efeb2019-01-11 14:04:43 +0000156 GEMMLHSMatrixInfo lhs_info;
157 lhs_info.m0 = 4;
158 lhs_info.k0 = 4;
159 lhs_info.v0 = mult_interleave4x4_height;
160 lhs_info.interleave = true;
161 lhs_info.transpose = true;
162
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000163 GEMMReshapeInfo reshape_info(m, n, k, mult_transpose1xW_width, mult_interleave4x4_height, depth_output_gemm3d, false);
Gian Marcob5311a62017-12-13 12:48:03 +0000164
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000165 _memory_group.manage(&_tmp_a);
166 if(!_reshape_b_only_on_first_run)
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100167 {
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000168 _memory_group.manage(&_tmp_b);
Gian Marco Iodiceedfa9f42017-08-15 11:45:22 +0100169 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100170
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000171 // Configure interleave kernel
172 _reshape_lhs_kernel.configure(a, &_tmp_a, lhs_info, reinterpret_input_as_3d);
Gian Marco Iodiceedfa9f42017-08-15 11:45:22 +0100173
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000174 // Configure transpose kernel
175 _reshape_rhs_kernel.configure(b, &_tmp_b, rhs_info);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100176
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000177 // Configure and tune matrix multiply kernel
178 _mm_kernel.configure(&_tmp_a, &_tmp_b, c, output, alpha, beta, true, reshape_info, gemm_info.fp_mixed_precision());
179
180 CLScheduler::get().tune_kernel_static(_mm_kernel);
181
182 // Allocate intermediate tensors
183 _tmp_a.allocator()->allocate();
184 if(!_reshape_b_only_on_first_run)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100185 {
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000186 _tmp_b.allocator()->allocate();
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100187 }
188}
189
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000190void CLGEMM::configure_reshaped_v2(const ICLTensor *a, const ICLTensor *b, const ICLTensor *c, ICLTensor *output, float alpha, float beta, const GEMMInfo &gemm_info)
191{
192 ARM_COMPUTE_ERROR_ON(c != nullptr);
193 ARM_COMPUTE_UNUSED(beta);
194 ARM_COMPUTE_UNUSED(c);
195
196 DataType data_type = a->info()->data_type();
197 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
198 const unsigned int m = reinterpret_input_as_3d ? (a->info()->dimension(1) * a->info()->dimension(2)) : a->info()->dimension(1);
199 const unsigned int n = b->info()->dimension(0);
200 const unsigned int k = a->info()->dimension(0);
201 const unsigned int batch_size = reinterpret_input_as_3d ? a->info()->dimension(3) : a->info()->dimension(2);
202 const int depth_output_gemm3d = gemm_info.depth_output_gemm3d();
203 const GPUTarget gpu_target = CLScheduler::get().target();
204
205 // Set the target for the kernels
206 _reshape_lhs_kernel.set_target(gpu_target);
207 _mm_kernel.set_target(gpu_target);
208
giuros0146a49a02019-04-01 13:50:22 +0100209 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, depth_output_gemm3d, false);
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000210
211 // Manage intermediate buffers
212 _memory_group.manage(&_tmp_a);
213 if(!_reshape_b_only_on_first_run)
214 {
215 _memory_group.manage(&_tmp_b);
216 }
217 // _tmp_a and _tmp_b will be auto configured in _interleave_kernel and in _transpose_kernel
218
219 GEMMLHSMatrixInfo lhs_info{};
220 GEMMRHSMatrixInfo rhs_info{};
221
222 // Pick up the GEMM configuration
223 std::unique_ptr<ICLGEMMKernelConfiguration> gemm_config = CLGEMMReshapedKernelConfigurationFactory::create(gpu_target);
224 ARM_COMPUTE_ERROR_ON_NULLPTR(gemm_config.get());
225
226 // Configure lhs_info and rhs_info
227 std::tie(lhs_info, rhs_info) = gemm_config->configure(m, n, k, batch_size, data_type);
228
229 _reshape_lhs_kernel.configure(a, &_tmp_a, lhs_info, gemm_info.reinterpret_input_as_3d());
230 _reshape_rhs_kernel.configure(b, &_tmp_b, rhs_info);
231
232 // Configure and tune matrix multiply kernel
233 _mm_reshaped_kernel.configure(&_tmp_a, &_tmp_b, output, alpha, lhs_info, rhs_info, reshape_info);
234
235 // Allocate intermediate tensors
236 _tmp_a.allocator()->allocate();
237 if(!_reshape_b_only_on_first_run)
238 {
239 _tmp_b.allocator()->allocate();
240 }
241}
242
243void CLGEMM::configure_reshaped_only_rhs(const ICLTensor *a, const ICLTensor *b, const ICLTensor *c, ICLTensor *output, float alpha, float beta, const GEMMInfo &gemm_info)
244{
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000245 DataType data_type = a->info()->data_type();
246 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
247 const unsigned int m = reinterpret_input_as_3d ? (a->info()->dimension(1) * a->info()->dimension(2)) : a->info()->dimension(1);
248 const unsigned int n = b->info()->dimension(0);
249 const unsigned int k = a->info()->dimension(0);
250 const unsigned int batch_size = reinterpret_input_as_3d ? a->info()->dimension(3) : a->info()->dimension(2);
251 const int depth_output_gemm3d = gemm_info.depth_output_gemm3d();
252 const GPUTarget gpu_target = CLScheduler::get().target();
Georgios Pinitasb0f342e2019-05-21 13:32:43 +0100253 bool broadcast_bias = gemm_info.broadcast_bias();
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000254
255 // Set the target for the kernels
256 _mm_kernel.set_target(gpu_target);
257
Georgios Pinitasb0f342e2019-05-21 13:32:43 +0100258 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, depth_output_gemm3d, reinterpret_input_as_3d, broadcast_bias);
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000259
260 // Manage intermediate buffers
261 if(!_reshape_b_only_on_first_run)
262 {
263 _memory_group.manage(&_tmp_b);
264 }
265
266 GEMMLHSMatrixInfo lhs_info{};
267 GEMMRHSMatrixInfo rhs_info{};
268
269 // Pick up the GEMM configuration
270 std::unique_ptr<ICLGEMMKernelConfiguration> gemm_config = CLGEMMReshapedOnlyRHSKernelConfigurationFactory::create(gpu_target);
271 ARM_COMPUTE_ERROR_ON_NULLPTR(gemm_config.get());
272
273 // Configure lhs_info and rhs_info
274 std::tie(lhs_info, rhs_info) = gemm_config->configure(m, n, k, batch_size, data_type);
275
276 _reshape_rhs_kernel.configure(b, &_tmp_b, rhs_info);
277
278 // Configure and tune matrix multiply kernel
Georgios Pinitasb0f342e2019-05-21 13:32:43 +0100279 _mm_reshaped_only_rhs_kernel.configure(a, &_tmp_b, c, output, alpha, beta, lhs_info, rhs_info, reshape_info);
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000280
281 if(!_reshape_b_only_on_first_run)
282 {
283 _tmp_b.allocator()->allocate();
284 }
285}
286
287Status 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 +0000288{
Gian Marco Iodice750641d2018-05-08 12:01:57 +0100289 ARM_COMPUTE_UNUSED(alpha);
Gian Marco Iodice215b4ea2018-06-28 16:29:29 +0100290 ARM_COMPUTE_UNUSED(output);
Gian Marco Iodice750641d2018-05-08 12:01:57 +0100291
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000292 // Get the GPU target
293 const GPUTarget gpu_target = CLScheduler::get().target();
294 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
295 const unsigned int m = reinterpret_input_as_3d ? (a->dimension(1) * a->dimension(2)) : a->dimension(1);
296 const unsigned int n = b->dimension(0);
297 const unsigned int k = a->dimension(0);
298 const int depth_output_gemm3d = gemm_info.depth_output_gemm3d();
299 const bool add_c = (beta != 0.f && c != nullptr);
300 const bool is_beta_one = std::abs(1.0f - beta) < 0.00001f;
301 const bool fuse_add = is_beta_one && (c != nullptr && c->num_dimensions() == 1);
Gian Marco Iodice750641d2018-05-08 12:01:57 +0100302
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000303 const GEMMReshapeInfo reshape_info = GEMMReshapeInfo(m, n, k, 1, 1, depth_output_gemm3d, reinterpret_input_as_3d);
304
305 // Validate matrix multiply
306 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMMatrixMultiplyKernel::validate(a, b, (add_c && fuse_add) ? c : nullptr, output, alpha, beta,
307 false, reshape_info, gpu_target, gemm_info.fp_mixed_precision()));
308
309 if(add_c && !fuse_add)
310 {
311 // Validate matrix addition kernel
312 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMMatrixAdditionKernel::validate(c, output, beta));
313 }
314
315 return Status{};
316}
317
318Status CLGEMM::validate_reshaped_v1(const ITensorInfo *a, const ITensorInfo *b, const ITensorInfo *c, const ITensorInfo *output, float alpha, float beta, const GEMMInfo &gemm_info)
319{
320 ARM_COMPUTE_UNUSED(alpha);
321 ARM_COMPUTE_UNUSED(output);
Gian Marco Iodice750641d2018-05-08 12:01:57 +0100322
323 TensorInfo tmp_a_info{};
324 TensorInfo tmp_b_info{};
Gian Marco Iodice750641d2018-05-08 12:01:57 +0100325
326 // Get the GPU target
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000327 const GPUTarget gpu_target = CLScheduler::get().target();
328 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 +0000329 const unsigned int n = b->dimension(0);
330 const unsigned int k = a->dimension(0);
331 int mult_transpose1xW_width = 1;
332 int mult_interleave4x4_height = 1;
333 const int depth_output_gemm3d = gemm_info.depth_output_gemm3d();
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000334 const bool add_c = (beta != 0.f && c != nullptr);
335 const bool is_beta_one = std::abs(1.0f - beta) < 0.00001f;
336 const bool fuse_add = is_beta_one && (c != nullptr && c->num_dimensions() == 1);
Gian Marco Iodice750641d2018-05-08 12:01:57 +0100337
338 if(get_arch_from_target(gpu_target) == GPUTarget::BIFROST)
339 {
340 mult_transpose1xW_width = 4;
341 mult_interleave4x4_height = 2;
342 }
343
giuros018b6b4a92018-12-18 19:01:33 +0000344 GEMMRHSMatrixInfo rhs_info;
345 rhs_info.n0 = 16 / b->element_size();
346 rhs_info.k0 = 1;
347 rhs_info.h0 = mult_transpose1xW_width;
348 rhs_info.interleave = false;
349 rhs_info.transpose = false;
350
giuros011c9efeb2019-01-11 14:04:43 +0000351 GEMMLHSMatrixInfo lhs_info;
352 lhs_info.m0 = 4;
353 lhs_info.k0 = 4;
354 lhs_info.v0 = mult_interleave4x4_height;
355 lhs_info.interleave = true;
356 lhs_info.transpose = true;
357
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000358 const GEMMReshapeInfo reshape_info = GEMMReshapeInfo(m, n, k, mult_transpose1xW_width, mult_interleave4x4_height, depth_output_gemm3d, false);
Gian Marco Iodice750641d2018-05-08 12:01:57 +0100359
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000360 // Validate interleave kernel
361 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())));
362 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 +0000363
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000364 // Validate transpose kernel
365 auto_init_if_empty(tmp_b_info, b->clone()->set_tensor_shape(compute_rhs_reshaped_shape(*b, rhs_info)));
366 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMReshapeRHSMatrixKernel::validate(b, &tmp_b_info, rhs_info));
Michele Di Giorgioebc3a902018-11-16 16:04:25 +0000367
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000368 // Validate matrix multiply
369 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMMatrixMultiplyKernel::validate(&tmp_a_info, &tmp_b_info, (add_c && fuse_add) ? c : nullptr, output, alpha, beta,
370 true, reshape_info, gpu_target, gemm_info.fp_mixed_precision()));
Gian Marco Iodice68a3f562018-07-26 11:44:03 +0100371
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000372 if(add_c && !fuse_add)
Gian Marco Iodice750641d2018-05-08 12:01:57 +0100373 {
374 // Validate matrix addition kernel
Giorgio Arena0f170392018-07-18 16:13:12 +0100375 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMMatrixAdditionKernel::validate(c, output, beta));
Gian Marco Iodice750641d2018-05-08 12:01:57 +0100376 }
377
Georgios Pinitas78c00902018-01-09 17:33:11 +0000378 return Status{};
379}
380
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000381Status CLGEMM::validate_reshaped_v2(const ITensorInfo *a, const ITensorInfo *b, const ITensorInfo *c, const ITensorInfo *output, float alpha, float beta, const GEMMInfo &gemm_info)
382{
383 ARM_COMPUTE_UNUSED(alpha);
384 ARM_COMPUTE_UNUSED(output);
385
386 TensorInfo tmp_a_info{};
387 TensorInfo tmp_b_info{};
388
389 // Get the GPU target
390 const GPUTarget gpu_target = CLScheduler::get().target();
391 DataType data_type = a->data_type();
392 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
393 const unsigned int m = reinterpret_input_as_3d ? (a->dimension(1) * a->dimension(2)) : a->dimension(1);
394 const unsigned int n = b->dimension(0);
395 const unsigned int k = a->dimension(0);
396 const unsigned int batch_size = reinterpret_input_as_3d ? a->dimension(3) : a->dimension(2);
397 const int depth_output_gemm3d = gemm_info.depth_output_gemm3d();
398 const bool add_c = (beta != 0.f && c != nullptr);
399
400 const GEMMReshapeInfo reshape_info = GEMMReshapeInfo(m, n, k, 1, 1, depth_output_gemm3d, false);
401
402 GEMMLHSMatrixInfo lhs_info;
403 GEMMRHSMatrixInfo rhs_info;
404
405 // Pick up the GEMM configuration
406 std::unique_ptr<ICLGEMMKernelConfiguration> gemm_config = CLGEMMReshapedKernelConfigurationFactory::create(gpu_target);
407 ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(gemm_config.get());
408
409 // Configure lhs_info and rhs_info
410 std::tie(lhs_info, rhs_info) = gemm_config->configure(m, n, k, batch_size, data_type);
411
412 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())));
413 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMReshapeLHSMatrixKernel::validate(a, &tmp_a_info, lhs_info, gemm_info.reinterpret_input_as_3d()));
414
415 auto_init_if_empty(tmp_b_info, b->clone()->set_tensor_shape(compute_rhs_reshaped_shape(*b, rhs_info)));
416 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMReshapeRHSMatrixKernel::validate(b, &tmp_b_info, rhs_info));
417
418 // Validate matrix multiply
419 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMMatrixMultiplyReshapedKernel::validate(&tmp_a_info, &tmp_b_info, output, alpha, lhs_info, rhs_info, reshape_info));
420
421 if(add_c)
422 {
423 // Validate matrix addition kernel
424 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMMatrixAdditionKernel::validate(c, output, beta));
425 }
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000426 return Status{};
427}
428
429Status 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)
430{
431 ARM_COMPUTE_UNUSED(alpha);
432 ARM_COMPUTE_UNUSED(output);
433
434 TensorInfo tmp_b_info{};
435
436 // Get the GPU target
Georgios Pinitasb0f342e2019-05-21 13:32:43 +0100437 const GPUTarget gpu_target = CLScheduler::get().target();
438 const DataType data_type = a->data_type();
439 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
440 const unsigned int m = reinterpret_input_as_3d ? (a->dimension(1) * a->dimension(2)) : a->dimension(1);
441 const unsigned int n = b->dimension(0);
442 const unsigned int k = a->dimension(0);
443 const unsigned int batch_size = reinterpret_input_as_3d ? a->dimension(3) : a->dimension(2);
444 const int depth_output_gemm3d = gemm_info.depth_output_gemm3d();
445 const bool broadcast_bias = gemm_info.broadcast_bias();
446 const GEMMReshapeInfo reshape_info = GEMMReshapeInfo(m, n, k, 1, 1, depth_output_gemm3d, reinterpret_input_as_3d, broadcast_bias);
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000447
448 GEMMLHSMatrixInfo lhs_info;
449 GEMMRHSMatrixInfo rhs_info;
450
451 // Pick up the GEMM configuration
452 std::unique_ptr<ICLGEMMKernelConfiguration> gemm_config = CLGEMMReshapedOnlyRHSKernelConfigurationFactory::create(gpu_target);
453 ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(gemm_config.get());
454
455 // Configure lhs_info and rhs_info
456 std::tie(lhs_info, rhs_info) = gemm_config->configure(m, n, k, batch_size, data_type);
457
458 auto_init_if_empty(tmp_b_info, b->clone()->set_tensor_shape(compute_rhs_reshaped_shape(*b, rhs_info)));
459 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMReshapeRHSMatrixKernel::validate(b, &tmp_b_info, rhs_info));
460
461 // Validate matrix multiply
Georgios Pinitasb0f342e2019-05-21 13:32:43 +0100462 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMMatrixMultiplyReshapedOnlyRHSKernel::validate(a, &tmp_b_info, c, output, alpha, beta, lhs_info, rhs_info, reshape_info));
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000463
464 return Status{};
465}
466
467void CLGEMM::configure(const ICLTensor *a, const ICLTensor *b, const ICLTensor *c, ICLTensor *output, float alpha, float beta, const GEMMInfo &gemm_info)
468{
469 ARM_COMPUTE_ERROR_ON_NULLPTR(a, b, output);
470
471 // Perform validation step
472 ARM_COMPUTE_ERROR_THROW_ON(validate(a->info(), b->info(), c != nullptr ? c->info() : nullptr, output->info(), alpha, beta, gemm_info));
473
474 // Check if we need to reshape the matrix B only on the first run
475 _reshape_b_only_on_first_run = gemm_info.reshape_b_only_on_first_run();
476 _is_prepared = gemm_info.retain_internal_weights();
477 _original_b = b;
478
479 // Get the GPU target
480 const GPUTarget gpu_target = CLScheduler::get().target();
481 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
482 const unsigned int m = reinterpret_input_as_3d ? (a->info()->dimension(1) * a->info()->dimension(2)) : a->info()->dimension(1);
483 const unsigned int n = b->info()->dimension(0);
484 const unsigned int k = a->info()->dimension(0);
485
486 // Select GEMMType
487 _gemm_type = select_gemm_type(m, n, k, a->info()->data_type(), _reshape_b_only_on_first_run, gpu_target);
488
Georgios Pinitasb0f342e2019-05-21 13:32:43 +0100489 const bool is_gemm_reshaped_only_rhs = _gemm_type == GEMMType::RESHAPED_ONLY_RHS;
490 const bool add_c = (beta != 0.f && c != nullptr);
491 const bool is_beta_one = std::abs(1.0f - beta) < 0.00001f;
492 const bool fuse_add = (is_beta_one && (c != nullptr && c->info()->num_dimensions() == 1)) || is_gemm_reshaped_only_rhs;
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000493
494 switch(_gemm_type)
495 {
496 case GEMMType::NATIVE:
497 {
498 configure_native(a, b, (add_c && fuse_add) ? c : nullptr, output, alpha, beta, gemm_info);
499 break;
500 }
501 case GEMMType::RESHAPED_V1:
502 {
503 configure_reshaped_v1(a, b, (add_c && fuse_add) ? c : nullptr, output, alpha, beta, gemm_info);
504 break;
505 }
506 case GEMMType::RESHAPED_V2:
507 {
508 configure_reshaped_v2(a, b, (add_c && fuse_add) ? c : nullptr, output, alpha, beta, gemm_info);
509 break;
510 }
511 case GEMMType::RESHAPED_ONLY_RHS:
512 {
513 configure_reshaped_only_rhs(a, b, (add_c && fuse_add) ? c : nullptr, output, alpha, beta, gemm_info);
514 break;
515 }
516 default:
517 {
518 ARM_COMPUTE_ERROR("GEMMType not supported");
519 }
520 }
521
522 // Configure matrix addition kernel
523 if(add_c && !fuse_add)
524 {
525 _ma_kernel.configure(c, output, beta);
526 _run_addition = true;
527 }
528}
529
530Status CLGEMM::validate(const ITensorInfo *a, const ITensorInfo *b, const ITensorInfo *c, const ITensorInfo *output, float alpha, float beta, const GEMMInfo &gemm_info)
531{
532 // Get the GPU target
533 const GPUTarget gpu_target = CLScheduler::get().target();
534 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
535 const unsigned int m = reinterpret_input_as_3d ? (a->dimension(1) * a->dimension(2)) : a->dimension(1);
536 const unsigned int n = b->dimension(0);
537 const unsigned int k = a->dimension(0);
538
539 // Select GEMMType
540 GEMMType gemm_type = select_gemm_type(m, n, k, a->data_type(), gemm_info.reshape_b_only_on_first_run(), gpu_target);
541
542 switch(gemm_type)
543 {
544 case GEMMType::NATIVE:
545 {
546 ARM_COMPUTE_RETURN_ON_ERROR(validate_native(a, b, c, output, alpha, beta, gemm_info));
547 break;
548 }
549 case GEMMType::RESHAPED_V1:
550 {
551 ARM_COMPUTE_RETURN_ON_ERROR(validate_reshaped_v1(a, b, c, output, alpha, beta, gemm_info));
552 break;
553 }
554 case GEMMType::RESHAPED_V2:
555 {
556 ARM_COMPUTE_RETURN_ON_ERROR(validate_reshaped_v2(a, b, c, output, alpha, beta, gemm_info));
557 break;
558 }
559 case GEMMType::RESHAPED_ONLY_RHS:
560 {
561 ARM_COMPUTE_RETURN_ON_ERROR(validate_reshaped_only_rhs(a, b, c, output, alpha, beta, gemm_info));
562 break;
563 }
564 default:
565 {
566 ARM_COMPUTE_RETURN_ERROR_MSG("GEMMType not supported");
567 }
568 }
569
570 return Status{};
571}
572
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100573void CLGEMM::run()
574{
Georgios Pinitase0437672018-05-02 14:07:55 +0100575 prepare();
576
Georgios Pinitasda953f22019-04-02 17:27:03 +0100577 MemoryGroupResourceScope scope_mg(_memory_group);
Georgios Pinitas8a94e7c2017-09-15 19:06:47 +0100578
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100579 // Run matrix multiply kernel
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000580 switch(_gemm_type)
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000581 {
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000582 case GEMMType::NATIVE:
583 {
584 CLScheduler::get().enqueue(_mm_kernel, !_run_addition);
585 break;
586 }
587 case GEMMType::RESHAPED_V1:
588 {
589 // Run interleave kernel
590 CLScheduler::get().enqueue(_reshape_lhs_kernel, false);
591
592 if(!_reshape_b_only_on_first_run)
593 {
594 // Run transpose kernel
595 CLScheduler::get().enqueue(_reshape_rhs_kernel, false);
596 }
597
598 CLScheduler::get().enqueue(_mm_kernel, !_run_addition);
599 break;
600 }
601 case GEMMType::RESHAPED_V2:
602 {
603 // Run interleave kernel
604 CLScheduler::get().enqueue(_reshape_lhs_kernel, false);
605
606 if(!_reshape_b_only_on_first_run)
607 {
608 // Run transpose kernel
609 CLScheduler::get().enqueue(_reshape_rhs_kernel, false);
610 }
611
612 CLScheduler::get().enqueue(_mm_reshaped_kernel, !_run_addition);
613 break;
614 }
615 case GEMMType::RESHAPED_ONLY_RHS:
616 {
617 if(!_reshape_b_only_on_first_run)
618 {
619 // Run transpose kernel
620 CLScheduler::get().enqueue(_reshape_rhs_kernel, false);
621 }
622
623 CLScheduler::get().enqueue(_mm_reshaped_only_rhs_kernel, !_run_addition);
624 break;
625 }
626 default:
627 {
628 ARM_COMPUTE_ERROR("GEMMType not supported");
629 }
Gian Marco Iodicebf9731e2018-12-12 10:18:04 +0000630 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100631
632 // Run matrix addition kernel
633 if(_run_addition)
634 {
635 CLScheduler::get().enqueue(_ma_kernel);
636 }
Georgios Pinitase0437672018-05-02 14:07:55 +0100637}
Georgios Pinitas82b51482018-04-24 15:14:12 +0100638
Georgios Pinitase0437672018-05-02 14:07:55 +0100639void CLGEMM::prepare()
640{
641 if(!_is_prepared)
642 {
Gian Marco Iodice926afe12019-03-19 11:44:13 +0000643 if(_gemm_type != GEMMType::NATIVE && _reshape_b_only_on_first_run)
Georgios Pinitase0437672018-05-02 14:07:55 +0100644 {
Georgios Pinitas72219332018-06-05 14:56:06 +0100645 // Run transpose kernel and mark original weights tensor as unused
Georgios Pinitase0437672018-05-02 14:07:55 +0100646 _tmp_b.allocator()->allocate();
giuros018b6b4a92018-12-18 19:01:33 +0000647 CLScheduler::get().enqueue(_reshape_rhs_kernel, false);
Georgios Pinitase0437672018-05-02 14:07:55 +0100648 _original_b->mark_as_unused();
649 }
650 CLScheduler::get().queue().finish();
651 _is_prepared = true;
652 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100653}
giuros011c9efeb2019-01-11 14:04:43 +0000654} // namespace arm_compute