blob: e78395f1deb8c861600ae9d7ed31944fc4a8f3e1 [file] [log] [blame]
Anthony Barbier871448e2017-03-24 14:54:29 +00001/*
Jenkins514be652019-02-28 12:25:18 +00002 * Copyright (c) 2017-2019 ARM Limited.
Anthony Barbier871448e2017-03-24 14:54:29 +00003 *
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
Jenkins4ba87db2019-05-23 17:11:51 +010026#include "arm_compute/core/CL/ICLGEMMKernelConfiguration.h"
Anthony Barbier871448e2017-03-24 14:54:29 +000027#include "arm_compute/core/CL/ICLTensor.h"
Jenkins4ba87db2019-05-23 17:11:51 +010028#include "arm_compute/core/CL/gemm/reshaped/CLGEMMReshapedKernelConfiguration.h"
29#include "arm_compute/core/CL/gemm/reshaped_only_rhs/CLGEMMReshapedOnlyRHSKernelConfiguration.h"
Anthony Barbier871448e2017-03-24 14:54:29 +000030#include "arm_compute/core/Error.h"
Jenkinsb3a371b2018-05-23 11:36:53 +010031#include "arm_compute/core/GPUTarget.h"
Anthony Barbier871448e2017-03-24 14:54:29 +000032#include "arm_compute/core/Helpers.h"
Jenkins975dfe12019-09-02 11:47:54 +010033#include "arm_compute/core/KernelDescriptors.h"
Anthony Barbier871448e2017-03-24 14:54:29 +000034#include "arm_compute/core/TensorInfo.h"
35#include "arm_compute/core/Types.h"
Jenkinsb3a371b2018-05-23 11:36:53 +010036#include "arm_compute/core/Utils.h"
Anthony Barbier871448e2017-03-24 14:54:29 +000037#include "arm_compute/core/Validate.h"
Jenkins975dfe12019-09-02 11:47:54 +010038#include "arm_compute/core/utils/helpers/float_ops.h"
Jenkinsb3a371b2018-05-23 11:36:53 +010039#include "arm_compute/core/utils/misc/ShapeCalculator.h"
Anthony Barbier871448e2017-03-24 14:54:29 +000040#include "arm_compute/runtime/CL/CLScheduler.h"
41#include "arm_compute/runtime/ITensorAllocator.h"
42
Jenkins514be652019-02-28 12:25:18 +000043namespace arm_compute
44{
Jenkinsb3a371b2018-05-23 11:36:53 +010045using namespace arm_compute::misc::shape_calculator;
Jenkins514be652019-02-28 12:25:18 +000046using namespace arm_compute::cl_gemm;
Anthony Barbier871448e2017-03-24 14:54:29 +000047
Kaizen8938bd32017-09-28 14:38:23 +010048CLGEMM::CLGEMM(std::shared_ptr<IMemoryManager> memory_manager)
Jenkinsb9abeae2018-11-22 11:58:08 +000049 : _memory_group(std::move(memory_manager)),
Jenkinsb9abeae2018-11-22 11:58:08 +000050 _mm_kernel(),
Jenkins514be652019-02-28 12:25:18 +000051 _reshape_lhs_kernel(),
52 _reshape_rhs_kernel(),
53 _mm_reshaped_kernel(),
Jenkins4ba87db2019-05-23 17:11:51 +010054 _mm_reshaped_only_rhs_kernel(),
Jenkinsb9abeae2018-11-22 11:58:08 +000055 _tmp_a(),
56 _tmp_b(),
57 _original_b(nullptr),
Jenkinsb9abeae2018-11-22 11:58:08 +000058 _reshape_b_only_on_first_run(false),
Jenkins514be652019-02-28 12:25:18 +000059 _is_prepared(false),
Jenkins4ba87db2019-05-23 17:11:51 +010060 _gemm_type(GEMMType::NATIVE)
Anthony Barbier871448e2017-03-24 14:54:29 +000061{
62}
63
Jenkins4ba87db2019-05-23 17:11:51 +010064CLGEMM::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 Barbier871448e2017-03-24 14:54:29 +000065{
Jenkins4ba87db2019-05-23 17:11:51 +010066 GEMMType gemm_type = GEMMType::RESHAPED_V1;
Anthony Barbier871448e2017-03-24 14:54:29 +000067
Jenkins4ba87db2019-05-23 17:11:51 +010068 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 }
Jenkinsb3a371b2018-05-23 11:36:53 +010095
Jenkins4ba87db2019-05-23 17:11:51 +010096 const auto workload = static_cast<float>((m * n) / 20.0f);
Kaizen8938bd32017-09-28 14:38:23 +010097
Jenkins4ba87db2019-05-23 17:11:51 +010098 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 }
Kaizen8938bd32017-09-28 14:38:23 +0100105
Jenkins4ba87db2019-05-23 17:11:51 +0100106 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();
Anthony Barbier06ea0482018-02-22 15:45:35 +0000115
116 // Set the target for the kernels
Anthony Barbier06ea0482018-02-22 15:45:35 +0000117 _mm_kernel.set_target(gpu_target);
118
Jenkins975dfe12019-09-02 11:47:54 +0100119 GEMMReshapeInfo reshape_info(m, n, k, 1, 1, gemm_info.depth_output_gemm3d(), gemm_info.reinterpret_input_as_3d(), gemm_info.broadcast_bias());
Jenkins4ba87db2019-05-23 17:11:51 +0100120
121 // Configure and tune matrix multiply kernel
Jenkins975dfe12019-09-02 11:47:54 +0100122 _mm_kernel.configure(a, b, c, output, alpha, beta, false, reshape_info, gemm_info.fp_mixed_precision(), gemm_info.activation_info());
Jenkins4ba87db2019-05-23 17:11:51 +0100123
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{
Jenkins514be652019-02-28 12:25:18 +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);
Jenkins514be652019-02-28 12:25:18 +0000134 const int depth_output_gemm3d = gemm_info.depth_output_gemm3d();
Jenkins4ba87db2019-05-23 17:11:51 +0100135 const GPUTarget gpu_target = CLScheduler::get().target();
Jenkins514be652019-02-28 12:25:18 +0000136 int mult_transpose1xW_width = 1;
137 int mult_interleave4x4_height = 1;
Anthony Barbier06ea0482018-02-22 15:45:35 +0000138
Jenkins4ba87db2019-05-23 17:11:51 +0100139 // Set the target for the kernels
140 _reshape_lhs_kernel.set_target(gpu_target);
141 _mm_kernel.set_target(gpu_target);
142
Jenkinsb3a371b2018-05-23 11:36:53 +0100143 if(get_arch_from_target(gpu_target) == GPUTarget::BIFROST)
Anthony Barbier06ea0482018-02-22 15:45:35 +0000144 {
145 mult_transpose1xW_width = 4;
146 mult_interleave4x4_height = 2;
147 }
Jenkins4ba87db2019-05-23 17:11:51 +0100148
Jenkins514be652019-02-28 12:25:18 +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;
155
156 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;
Anthony Barbier06ea0482018-02-22 15:45:35 +0000162
Jenkins975dfe12019-09-02 11:47:54 +0100163 GEMMReshapeInfo reshape_info(m, n, k, mult_transpose1xW_width, mult_interleave4x4_height, depth_output_gemm3d, false, gemm_info.broadcast_bias());
Anthony Barbier8140e1e2017-12-14 23:48:46 +0000164
Jenkins4ba87db2019-05-23 17:11:51 +0100165 _memory_group.manage(&_tmp_a);
166 if(!_reshape_b_only_on_first_run)
Jenkins52ba29e2018-08-29 15:32:11 +0000167 {
Jenkins4ba87db2019-05-23 17:11:51 +0100168 _memory_group.manage(&_tmp_b);
Kaizen8938bd32017-09-28 14:38:23 +0100169 }
Anthony Barbier871448e2017-03-24 14:54:29 +0000170
Jenkins4ba87db2019-05-23 17:11:51 +0100171 // Configure interleave kernel
172 _reshape_lhs_kernel.configure(a, &_tmp_a, lhs_info, reinterpret_input_as_3d);
Kaizen8938bd32017-09-28 14:38:23 +0100173
Jenkins4ba87db2019-05-23 17:11:51 +0100174 // Configure transpose kernel
175 _reshape_rhs_kernel.configure(b, &_tmp_b, rhs_info);
Anthony Barbier871448e2017-03-24 14:54:29 +0000176
Jenkins4ba87db2019-05-23 17:11:51 +0100177 // Configure and tune matrix multiply kernel
Jenkins975dfe12019-09-02 11:47:54 +0100178 _mm_kernel.configure(&_tmp_a, &_tmp_b, c, output, alpha, beta, true, reshape_info, gemm_info.fp_mixed_precision(), gemm_info.activation_info());
Jenkins4ba87db2019-05-23 17:11:51 +0100179
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 Barbier871448e2017-03-24 14:54:29 +0000185 {
Jenkins4ba87db2019-05-23 17:11:51 +0100186 _tmp_b.allocator()->allocate();
Anthony Barbier871448e2017-03-24 14:54:29 +0000187 }
188}
189
Jenkins4ba87db2019-05-23 17:11:51 +0100190void CLGEMM::configure_reshaped_v2(const ICLTensor *a, const ICLTensor *b, const ICLTensor *c, ICLTensor *output, float alpha, float beta, const GEMMInfo &gemm_info)
191{
Jenkins4ba87db2019-05-23 17:11:51 +0100192 DataType data_type = a->info()->data_type();
193 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
194 const unsigned int m = reinterpret_input_as_3d ? (a->info()->dimension(1) * a->info()->dimension(2)) : a->info()->dimension(1);
195 const unsigned int n = b->info()->dimension(0);
196 const unsigned int k = a->info()->dimension(0);
197 const unsigned int batch_size = reinterpret_input_as_3d ? a->info()->dimension(3) : a->info()->dimension(2);
198 const int depth_output_gemm3d = gemm_info.depth_output_gemm3d();
199 const GPUTarget gpu_target = CLScheduler::get().target();
Jenkins975dfe12019-09-02 11:47:54 +0100200 bool broadcast_bias = gemm_info.broadcast_bias();
201
202 GEMMKernelInfo kernel_info;
203 kernel_info.m = m;
204 kernel_info.n = n;
205 kernel_info.k = k;
206 kernel_info.depth_output_gemm3d = depth_output_gemm3d;
207 kernel_info.reinterpret_input_as_3d = false;
208 kernel_info.broadcast_bias = broadcast_bias;
209 kernel_info.activation_info = gemm_info.activation_info();
Jenkins4ba87db2019-05-23 17:11:51 +0100210
211 // Set the target for the kernels
212 _reshape_lhs_kernel.set_target(gpu_target);
213 _mm_kernel.set_target(gpu_target);
214
Jenkins4ba87db2019-05-23 17:11:51 +0100215 // Manage intermediate buffers
216 _memory_group.manage(&_tmp_a);
217 if(!_reshape_b_only_on_first_run)
218 {
219 _memory_group.manage(&_tmp_b);
220 }
221 // _tmp_a and _tmp_b will be auto configured in _interleave_kernel and in _transpose_kernel
222
223 GEMMLHSMatrixInfo lhs_info{};
224 GEMMRHSMatrixInfo rhs_info{};
225
226 // Pick up the GEMM configuration
227 std::unique_ptr<ICLGEMMKernelConfiguration> gemm_config = CLGEMMReshapedKernelConfigurationFactory::create(gpu_target);
228 ARM_COMPUTE_ERROR_ON_NULLPTR(gemm_config.get());
229
230 // Configure lhs_info and rhs_info
231 std::tie(lhs_info, rhs_info) = gemm_config->configure(m, n, k, batch_size, data_type);
232
233 _reshape_lhs_kernel.configure(a, &_tmp_a, lhs_info, gemm_info.reinterpret_input_as_3d());
234 _reshape_rhs_kernel.configure(b, &_tmp_b, rhs_info);
235
236 // Configure and tune matrix multiply kernel
Jenkins975dfe12019-09-02 11:47:54 +0100237 _mm_reshaped_kernel.configure(&_tmp_a, &_tmp_b, c, output, alpha, beta, lhs_info, rhs_info, kernel_info);
Jenkins4ba87db2019-05-23 17:11:51 +0100238
239 // Allocate intermediate tensors
240 _tmp_a.allocator()->allocate();
241 if(!_reshape_b_only_on_first_run)
242 {
243 _tmp_b.allocator()->allocate();
244 }
245}
246
247void CLGEMM::configure_reshaped_only_rhs(const ICLTensor *a, const ICLTensor *b, const ICLTensor *c, ICLTensor *output, float alpha, float beta, const GEMMInfo &gemm_info)
248{
Jenkins4ba87db2019-05-23 17:11:51 +0100249 DataType data_type = a->info()->data_type();
250 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
251 const unsigned int m = reinterpret_input_as_3d ? (a->info()->dimension(1) * a->info()->dimension(2)) : a->info()->dimension(1);
252 const unsigned int n = b->info()->dimension(0);
253 const unsigned int k = a->info()->dimension(0);
254 const unsigned int batch_size = reinterpret_input_as_3d ? a->info()->dimension(3) : a->info()->dimension(2);
255 const int depth_output_gemm3d = gemm_info.depth_output_gemm3d();
256 const GPUTarget gpu_target = CLScheduler::get().target();
Jenkins975dfe12019-09-02 11:47:54 +0100257 bool broadcast_bias = gemm_info.broadcast_bias();
258
259 GEMMKernelInfo kernel_info;
260 kernel_info.m = m;
261 kernel_info.n = n;
262 kernel_info.k = k;
263 kernel_info.depth_output_gemm3d = depth_output_gemm3d;
264 kernel_info.reinterpret_input_as_3d = reinterpret_input_as_3d;
265 kernel_info.broadcast_bias = broadcast_bias;
266 kernel_info.activation_info = gemm_info.activation_info();
Jenkins4ba87db2019-05-23 17:11:51 +0100267
268 // Set the target for the kernels
269 _mm_kernel.set_target(gpu_target);
270
Jenkins4ba87db2019-05-23 17:11:51 +0100271 // Manage intermediate buffers
272 if(!_reshape_b_only_on_first_run)
273 {
274 _memory_group.manage(&_tmp_b);
275 }
276
277 GEMMLHSMatrixInfo lhs_info{};
278 GEMMRHSMatrixInfo rhs_info{};
279
280 // Pick up the GEMM configuration
281 std::unique_ptr<ICLGEMMKernelConfiguration> gemm_config = CLGEMMReshapedOnlyRHSKernelConfigurationFactory::create(gpu_target);
282 ARM_COMPUTE_ERROR_ON_NULLPTR(gemm_config.get());
283
284 // Configure lhs_info and rhs_info
285 std::tie(lhs_info, rhs_info) = gemm_config->configure(m, n, k, batch_size, data_type);
286
287 _reshape_rhs_kernel.configure(b, &_tmp_b, rhs_info);
288
289 // Configure and tune matrix multiply kernel
Jenkins975dfe12019-09-02 11:47:54 +0100290 _mm_reshaped_only_rhs_kernel.configure(a, &_tmp_b, c, output, alpha, beta, lhs_info, rhs_info, kernel_info);
Jenkins4ba87db2019-05-23 17:11:51 +0100291
292 if(!_reshape_b_only_on_first_run)
293 {
294 _tmp_b.allocator()->allocate();
295 }
296}
297
298Status CLGEMM::validate_native(const ITensorInfo *a, const ITensorInfo *b, const ITensorInfo *c, const ITensorInfo *output, float alpha, float beta, const GEMMInfo &gemm_info)
Anthony Barbier06ea0482018-02-22 15:45:35 +0000299{
Jenkinsb3a371b2018-05-23 11:36:53 +0100300 ARM_COMPUTE_UNUSED(alpha);
Jenkins52ba29e2018-08-29 15:32:11 +0000301 ARM_COMPUTE_UNUSED(output);
Jenkinsb3a371b2018-05-23 11:36:53 +0100302
Jenkins4ba87db2019-05-23 17:11:51 +0100303 // Get the GPU target
304 const GPUTarget gpu_target = CLScheduler::get().target();
305 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
306 const unsigned int m = reinterpret_input_as_3d ? (a->dimension(1) * a->dimension(2)) : a->dimension(1);
307 const unsigned int n = b->dimension(0);
308 const unsigned int k = a->dimension(0);
309 const int depth_output_gemm3d = gemm_info.depth_output_gemm3d();
Jenkinsb3a371b2018-05-23 11:36:53 +0100310
Jenkins975dfe12019-09-02 11:47:54 +0100311 const GEMMReshapeInfo reshape_info = GEMMReshapeInfo(m, n, k, 1, 1, depth_output_gemm3d, reinterpret_input_as_3d, gemm_info.broadcast_bias());
Jenkins4ba87db2019-05-23 17:11:51 +0100312
313 // Validate matrix multiply
Jenkins975dfe12019-09-02 11:47:54 +0100314 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMMatrixMultiplyKernel::validate(a, b, c, output, alpha, beta,
315 false, reshape_info, gpu_target, gemm_info.fp_mixed_precision(), gemm_info.activation_info()));
Jenkins4ba87db2019-05-23 17:11:51 +0100316
317 return Status{};
318}
319
320Status CLGEMM::validate_reshaped_v1(const ITensorInfo *a, const ITensorInfo *b, const ITensorInfo *c, const ITensorInfo *output, float alpha, float beta, const GEMMInfo &gemm_info)
321{
322 ARM_COMPUTE_UNUSED(alpha);
323 ARM_COMPUTE_UNUSED(output);
Jenkinsb3a371b2018-05-23 11:36:53 +0100324
325 TensorInfo tmp_a_info{};
326 TensorInfo tmp_b_info{};
Jenkinsb3a371b2018-05-23 11:36:53 +0100327
328 // Get the GPU target
Jenkins4ba87db2019-05-23 17:11:51 +0100329 const GPUTarget gpu_target = CLScheduler::get().target();
330 const unsigned int m = gemm_info.reinterpret_input_as_3d() ? (a->dimension(1) * a->dimension(2)) : a->dimension(1);
Jenkins514be652019-02-28 12:25:18 +0000331 const unsigned int n = b->dimension(0);
332 const unsigned int k = a->dimension(0);
Jenkins514be652019-02-28 12:25:18 +0000333 int mult_transpose1xW_width = 1;
334 int mult_interleave4x4_height = 1;
335 const int depth_output_gemm3d = gemm_info.depth_output_gemm3d();
Jenkinsb3a371b2018-05-23 11:36:53 +0100336
337 if(get_arch_from_target(gpu_target) == GPUTarget::BIFROST)
338 {
339 mult_transpose1xW_width = 4;
340 mult_interleave4x4_height = 2;
341 }
342
Jenkins514be652019-02-28 12:25:18 +0000343 GEMMRHSMatrixInfo rhs_info;
344 rhs_info.n0 = 16 / b->element_size();
345 rhs_info.k0 = 1;
346 rhs_info.h0 = mult_transpose1xW_width;
347 rhs_info.interleave = false;
348 rhs_info.transpose = false;
349
350 GEMMLHSMatrixInfo lhs_info;
351 lhs_info.m0 = 4;
352 lhs_info.k0 = 4;
353 lhs_info.v0 = mult_interleave4x4_height;
354 lhs_info.interleave = true;
355 lhs_info.transpose = true;
356
Jenkins975dfe12019-09-02 11:47:54 +0100357 const GEMMReshapeInfo reshape_info = GEMMReshapeInfo(m, n, k, mult_transpose1xW_width, mult_interleave4x4_height, depth_output_gemm3d, false, gemm_info.broadcast_bias());
Jenkinsb3a371b2018-05-23 11:36:53 +0100358
Jenkins4ba87db2019-05-23 17:11:51 +0100359 // Validate interleave kernel
360 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())));
361 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMReshapeLHSMatrixKernel::validate(a, &tmp_a_info, lhs_info, gemm_info.reinterpret_input_as_3d()));
Jenkins514be652019-02-28 12:25:18 +0000362
Jenkins4ba87db2019-05-23 17:11:51 +0100363 // Validate transpose kernel
364 auto_init_if_empty(tmp_b_info, b->clone()->set_tensor_shape(compute_rhs_reshaped_shape(*b, rhs_info)));
365 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMReshapeRHSMatrixKernel::validate(b, &tmp_b_info, rhs_info));
Jenkins514be652019-02-28 12:25:18 +0000366
Jenkins4ba87db2019-05-23 17:11:51 +0100367 // Validate matrix multiply
Jenkins975dfe12019-09-02 11:47:54 +0100368 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMMatrixMultiplyKernel::validate(&tmp_a_info, &tmp_b_info, c, output, alpha, beta,
369 true, reshape_info, gpu_target, gemm_info.fp_mixed_precision(), gemm_info.activation_info()));
Jenkinsb3a371b2018-05-23 11:36:53 +0100370
Anthony Barbier06ea0482018-02-22 15:45:35 +0000371 return Status{};
372}
373
Jenkins4ba87db2019-05-23 17:11:51 +0100374Status CLGEMM::validate_reshaped_v2(const ITensorInfo *a, const ITensorInfo *b, const ITensorInfo *c, const ITensorInfo *output, float alpha, float beta, const GEMMInfo &gemm_info)
375{
376 ARM_COMPUTE_UNUSED(alpha);
377 ARM_COMPUTE_UNUSED(output);
378
379 TensorInfo tmp_a_info{};
380 TensorInfo tmp_b_info{};
381
382 // Get the GPU target
383 const GPUTarget gpu_target = CLScheduler::get().target();
384 DataType data_type = a->data_type();
385 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
386 const unsigned int m = reinterpret_input_as_3d ? (a->dimension(1) * a->dimension(2)) : a->dimension(1);
387 const unsigned int n = b->dimension(0);
388 const unsigned int k = a->dimension(0);
389 const unsigned int batch_size = reinterpret_input_as_3d ? a->dimension(3) : a->dimension(2);
390 const int depth_output_gemm3d = gemm_info.depth_output_gemm3d();
Jenkins975dfe12019-09-02 11:47:54 +0100391 const bool broadcast_bias = gemm_info.broadcast_bias();
Jenkins4ba87db2019-05-23 17:11:51 +0100392
Jenkins975dfe12019-09-02 11:47:54 +0100393 GEMMKernelInfo kernel_info;
394 kernel_info.m = m;
395 kernel_info.n = n;
396 kernel_info.k = k;
397 kernel_info.depth_output_gemm3d = depth_output_gemm3d;
398 kernel_info.reinterpret_input_as_3d = false;
399 kernel_info.broadcast_bias = broadcast_bias;
400 kernel_info.activation_info = gemm_info.activation_info();
Jenkins4ba87db2019-05-23 17:11:51 +0100401
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
Jenkins975dfe12019-09-02 11:47:54 +0100419 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMMatrixMultiplyReshapedKernel::validate(&tmp_a_info, &tmp_b_info, c, output, alpha, beta, lhs_info, rhs_info, kernel_info));
Jenkins4ba87db2019-05-23 17:11:51 +0100420
421 return Status{};
422}
423
424Status 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)
425{
426 ARM_COMPUTE_UNUSED(alpha);
427 ARM_COMPUTE_UNUSED(output);
428
429 TensorInfo tmp_b_info{};
430
431 // Get the GPU target
432 const GPUTarget gpu_target = CLScheduler::get().target();
433 const DataType data_type = a->data_type();
434 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
435 const unsigned int m = reinterpret_input_as_3d ? (a->dimension(1) * a->dimension(2)) : a->dimension(1);
436 const unsigned int n = b->dimension(0);
437 const unsigned int k = a->dimension(0);
438 const unsigned int batch_size = reinterpret_input_as_3d ? a->dimension(3) : a->dimension(2);
439 const int depth_output_gemm3d = gemm_info.depth_output_gemm3d();
Jenkins975dfe12019-09-02 11:47:54 +0100440 const bool broadcast_bias = gemm_info.broadcast_bias();
Jenkins4ba87db2019-05-23 17:11:51 +0100441
Jenkins975dfe12019-09-02 11:47:54 +0100442 GEMMKernelInfo kernel_info;
443 kernel_info.m = m;
444 kernel_info.n = n;
445 kernel_info.k = k;
446 kernel_info.depth_output_gemm3d = depth_output_gemm3d;
447 kernel_info.reinterpret_input_as_3d = reinterpret_input_as_3d;
448 kernel_info.broadcast_bias = broadcast_bias;
449 kernel_info.activation_info = gemm_info.activation_info();
Jenkins4ba87db2019-05-23 17:11:51 +0100450
451 GEMMLHSMatrixInfo lhs_info;
452 GEMMRHSMatrixInfo rhs_info;
453
454 // Pick up the GEMM configuration
455 std::unique_ptr<ICLGEMMKernelConfiguration> gemm_config = CLGEMMReshapedOnlyRHSKernelConfigurationFactory::create(gpu_target);
456 ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(gemm_config.get());
457
458 // Configure lhs_info and rhs_info
459 std::tie(lhs_info, rhs_info) = gemm_config->configure(m, n, k, batch_size, data_type);
460
461 auto_init_if_empty(tmp_b_info, b->clone()->set_tensor_shape(compute_rhs_reshaped_shape(*b, rhs_info)));
462 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMReshapeRHSMatrixKernel::validate(b, &tmp_b_info, rhs_info));
463
464 // Validate matrix multiply
Jenkins975dfe12019-09-02 11:47:54 +0100465 ARM_COMPUTE_RETURN_ON_ERROR(CLGEMMMatrixMultiplyReshapedOnlyRHSKernel::validate(a, &tmp_b_info, c, output, alpha, beta, lhs_info, rhs_info, kernel_info));
Jenkins4ba87db2019-05-23 17:11:51 +0100466
467 return Status{};
468}
469
470void CLGEMM::configure(const ICLTensor *a, const ICLTensor *b, const ICLTensor *c, ICLTensor *output, float alpha, float beta, const GEMMInfo &gemm_info)
471{
472 ARM_COMPUTE_ERROR_ON_NULLPTR(a, b, output);
473
474 // Perform validation step
475 ARM_COMPUTE_ERROR_THROW_ON(validate(a->info(), b->info(), c != nullptr ? c->info() : nullptr, output->info(), alpha, beta, gemm_info));
476
477 // Check if we need to reshape the matrix B only on the first run
478 _reshape_b_only_on_first_run = gemm_info.reshape_b_only_on_first_run();
479 _is_prepared = gemm_info.retain_internal_weights();
480 _original_b = b;
481
482 // Get the GPU target
483 const GPUTarget gpu_target = CLScheduler::get().target();
484 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
485 const unsigned int m = reinterpret_input_as_3d ? (a->info()->dimension(1) * a->info()->dimension(2)) : a->info()->dimension(1);
486 const unsigned int n = b->info()->dimension(0);
487 const unsigned int k = a->info()->dimension(0);
488
489 // Select GEMMType
490 _gemm_type = select_gemm_type(m, n, k, a->info()->data_type(), _reshape_b_only_on_first_run, gpu_target);
491
Jenkins975dfe12019-09-02 11:47:54 +0100492 const bool fuse_add_c = (!(helpers::float_ops::is_zero(beta)) && c != nullptr);
493
494 const ICLTensor *c_to_use = fuse_add_c ? c : nullptr;
Jenkins4ba87db2019-05-23 17:11:51 +0100495
496 switch(_gemm_type)
497 {
498 case GEMMType::NATIVE:
499 {
Jenkins975dfe12019-09-02 11:47:54 +0100500 configure_native(a, b, c_to_use, output, alpha, beta, gemm_info);
Jenkins4ba87db2019-05-23 17:11:51 +0100501 break;
502 }
503 case GEMMType::RESHAPED_V1:
504 {
Jenkins975dfe12019-09-02 11:47:54 +0100505 configure_reshaped_v1(a, b, c_to_use, output, alpha, beta, gemm_info);
Jenkins4ba87db2019-05-23 17:11:51 +0100506 break;
507 }
508 case GEMMType::RESHAPED_V2:
509 {
Jenkins975dfe12019-09-02 11:47:54 +0100510 configure_reshaped_v2(a, b, c_to_use, output, alpha, beta, gemm_info);
Jenkins4ba87db2019-05-23 17:11:51 +0100511 break;
512 }
513 case GEMMType::RESHAPED_ONLY_RHS:
514 {
Jenkins975dfe12019-09-02 11:47:54 +0100515 configure_reshaped_only_rhs(a, b, c_to_use, output, alpha, beta, gemm_info);
Jenkins4ba87db2019-05-23 17:11:51 +0100516 break;
517 }
518 default:
519 {
520 ARM_COMPUTE_ERROR("GEMMType not supported");
521 }
522 }
Jenkins4ba87db2019-05-23 17:11:51 +0100523}
524
525Status CLGEMM::validate(const ITensorInfo *a, const ITensorInfo *b, const ITensorInfo *c, const ITensorInfo *output, float alpha, float beta, const GEMMInfo &gemm_info)
526{
527 // Get the GPU target
528 const GPUTarget gpu_target = CLScheduler::get().target();
529 bool reinterpret_input_as_3d = gemm_info.reinterpret_input_as_3d();
530 const unsigned int m = reinterpret_input_as_3d ? (a->dimension(1) * a->dimension(2)) : a->dimension(1);
531 const unsigned int n = b->dimension(0);
532 const unsigned int k = a->dimension(0);
533
534 // Select GEMMType
535 GEMMType gemm_type = select_gemm_type(m, n, k, a->data_type(), gemm_info.reshape_b_only_on_first_run(), gpu_target);
536
Jenkins975dfe12019-09-02 11:47:54 +0100537 const bool fuse_add_c = (!(helpers::float_ops::is_zero(beta)) && c != nullptr);
538
539 const ITensorInfo *c_to_use = fuse_add_c ? c : nullptr;
540
Jenkins4ba87db2019-05-23 17:11:51 +0100541 switch(gemm_type)
542 {
543 case GEMMType::NATIVE:
544 {
Jenkins975dfe12019-09-02 11:47:54 +0100545 ARM_COMPUTE_RETURN_ON_ERROR(validate_native(a, b, c_to_use, output, alpha, beta, gemm_info));
Jenkins4ba87db2019-05-23 17:11:51 +0100546 break;
547 }
548 case GEMMType::RESHAPED_V1:
549 {
Jenkins975dfe12019-09-02 11:47:54 +0100550 ARM_COMPUTE_RETURN_ON_ERROR(validate_reshaped_v1(a, b, c_to_use, output, alpha, beta, gemm_info));
Jenkins4ba87db2019-05-23 17:11:51 +0100551 break;
552 }
553 case GEMMType::RESHAPED_V2:
554 {
Jenkins975dfe12019-09-02 11:47:54 +0100555 ARM_COMPUTE_RETURN_ON_ERROR(validate_reshaped_v2(a, b, c_to_use, output, alpha, beta, gemm_info));
Jenkins4ba87db2019-05-23 17:11:51 +0100556 break;
557 }
558 case GEMMType::RESHAPED_ONLY_RHS:
559 {
Jenkins975dfe12019-09-02 11:47:54 +0100560 ARM_COMPUTE_RETURN_ON_ERROR(validate_reshaped_only_rhs(a, b, c_to_use, output, alpha, beta, gemm_info));
Jenkins4ba87db2019-05-23 17:11:51 +0100561 break;
562 }
563 default:
564 {
565 ARM_COMPUTE_RETURN_ERROR_MSG("GEMMType not supported");
566 }
567 }
568
569 return Status{};
570}
571
Anthony Barbier871448e2017-03-24 14:54:29 +0000572void CLGEMM::run()
573{
Jenkinsb3a371b2018-05-23 11:36:53 +0100574 prepare();
575
Jenkins4ba87db2019-05-23 17:11:51 +0100576 MemoryGroupResourceScope scope_mg(_memory_group);
Anthony Barbier871448e2017-03-24 14:54:29 +0000577
578 // Run matrix multiply kernel
Jenkins4ba87db2019-05-23 17:11:51 +0100579 switch(_gemm_type)
Jenkins514be652019-02-28 12:25:18 +0000580 {
Jenkins4ba87db2019-05-23 17:11:51 +0100581 case GEMMType::NATIVE:
582 {
Jenkins975dfe12019-09-02 11:47:54 +0100583 CLScheduler::get().enqueue(_mm_kernel, true);
Jenkins4ba87db2019-05-23 17:11:51 +0100584 break;
585 }
586 case GEMMType::RESHAPED_V1:
587 {
588 // Run interleave kernel
589 CLScheduler::get().enqueue(_reshape_lhs_kernel, false);
590
591 if(!_reshape_b_only_on_first_run)
592 {
593 // Run transpose kernel
594 CLScheduler::get().enqueue(_reshape_rhs_kernel, false);
595 }
596
Jenkins975dfe12019-09-02 11:47:54 +0100597 CLScheduler::get().enqueue(_mm_kernel, true);
Jenkins4ba87db2019-05-23 17:11:51 +0100598 break;
599 }
600 case GEMMType::RESHAPED_V2:
601 {
602 // Run interleave kernel
603 CLScheduler::get().enqueue(_reshape_lhs_kernel, false);
604
605 if(!_reshape_b_only_on_first_run)
606 {
607 // Run transpose kernel
608 CLScheduler::get().enqueue(_reshape_rhs_kernel, false);
609 }
610
Jenkins975dfe12019-09-02 11:47:54 +0100611 CLScheduler::get().enqueue(_mm_reshaped_kernel, true);
Jenkins4ba87db2019-05-23 17:11:51 +0100612 break;
613 }
614 case GEMMType::RESHAPED_ONLY_RHS:
615 {
616 if(!_reshape_b_only_on_first_run)
617 {
618 // Run transpose kernel
619 CLScheduler::get().enqueue(_reshape_rhs_kernel, false);
620 }
621
Jenkins975dfe12019-09-02 11:47:54 +0100622 CLScheduler::get().enqueue(_mm_reshaped_only_rhs_kernel, true);
Jenkins4ba87db2019-05-23 17:11:51 +0100623 break;
624 }
625 default:
626 {
627 ARM_COMPUTE_ERROR("GEMMType not supported");
628 }
Jenkins514be652019-02-28 12:25:18 +0000629 }
Anthony Barbier871448e2017-03-24 14:54:29 +0000630}
Jenkinsb3a371b2018-05-23 11:36:53 +0100631
632void CLGEMM::prepare()
633{
634 if(!_is_prepared)
635 {
Jenkins4ba87db2019-05-23 17:11:51 +0100636 if(_gemm_type != GEMMType::NATIVE && _reshape_b_only_on_first_run)
Jenkinsb3a371b2018-05-23 11:36:53 +0100637 {
Jenkins52ba29e2018-08-29 15:32:11 +0000638 // Run transpose kernel and mark original weights tensor as unused
Jenkinsb3a371b2018-05-23 11:36:53 +0100639 _tmp_b.allocator()->allocate();
Jenkins514be652019-02-28 12:25:18 +0000640 CLScheduler::get().enqueue(_reshape_rhs_kernel, false);
Jenkinsb3a371b2018-05-23 11:36:53 +0100641 _original_b->mark_as_unused();
642 }
643 CLScheduler::get().queue().finish();
644 _is_prepared = true;
645 }
646}
Jenkins514be652019-02-28 12:25:18 +0000647} // namespace arm_compute