blob: 33aff2731d460ab05c2c9a23381aa78344683594 [file] [log] [blame]
arovir014424b0a2018-10-04 10:46:04 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "ClBackend.hpp"
David Beck3e9e1152018-10-17 14:17:50 +01007#include "ClBackendId.hpp"
Sadik Armagan045f6be2020-09-10 13:37:32 +01008#include "ClBackendModelContext.hpp"
arovir01a0944792018-10-11 15:00:58 +01009#include "ClWorkloadFactory.hpp"
David Beck1b61be52018-11-08 09:19:14 +000010#include "ClBackendContext.hpp"
David Beck111b5d92018-11-12 14:59:37 +000011#include "ClLayerSupport.hpp"
Jan Eilerse9f0f0f2019-08-16 10:28:37 +010012#include "ClTensorHandleFactory.hpp"
arovir01a0944792018-10-11 15:00:58 +010013
Matteo Martincighc601aa62019-10-29 15:03:22 +000014#include <armnn/BackendRegistry.hpp>
Mike Kelly07810fc2020-11-12 10:58:48 +000015#include <armnn/Descriptors.hpp>
Matteo Martincighc601aa62019-10-29 15:03:22 +000016
Mike Kelly07810fc2020-11-12 10:58:48 +000017#include <aclCommon/ArmComputeSubgraphUtils.hpp>
18#include <aclCommon/ArmComputeUtils.hpp>
Aron Virginas-Tar56055192018-11-12 18:10:43 +000019#include <aclCommon/BaseMemoryManager.hpp>
20
Matteo Martincighe5b8eb92019-11-28 15:45:42 +000021#include <armnn/backends/IBackendContext.hpp>
22#include <armnn/backends/IMemoryManager.hpp>
Jan Eilers3c9e0452020-04-10 13:00:44 +010023#include <armnn/utility/PolymorphicDowncast.hpp>
24
Mike Kelly07810fc2020-11-12 10:58:48 +000025#include "workloads/ClAdditionWorkload.hpp"
26#include "workloads/ClBatchNormalizationFloatWorkload.hpp"
27#include "workloads/ClConvolution2dWorkload.hpp"
28#include "workloads/ClDepthwiseConvolutionWorkload.hpp"
29#include "workloads/ClDivisionFloatWorkload.hpp"
30#include "workloads/ClFullyConnectedWorkload.hpp"
31#include "workloads/ClMultiplicationWorkload.hpp"
32#include "workloads/ClSubtractionWorkload.hpp"
33
David Beck263e3492018-11-09 14:46:40 +000034#include <Optimizer.hpp>
arovir014424b0a2018-10-04 10:46:04 +010035
Mike Kelly07810fc2020-11-12 10:58:48 +000036#include <arm_compute/core/Types.h>
Aron Virginas-Tar56055192018-11-12 18:10:43 +000037#include <arm_compute/runtime/CL/CLBufferAllocator.h>
38
arovir014424b0a2018-10-04 10:46:04 +010039namespace armnn
40{
41
David Beck3cc9a622018-10-12 10:38:31 +010042const BackendId& ClBackend::GetIdStatic()
arovir014424b0a2018-10-04 10:46:04 +010043{
David Beck3e9e1152018-10-17 14:17:50 +010044 static const BackendId s_Id{ClBackendId()};
arovir014424b0a2018-10-04 10:46:04 +010045 return s_Id;
46}
47
Aron Virginas-Tar56055192018-11-12 18:10:43 +000048IBackendInternal::IMemoryManagerUniquePtr ClBackend::CreateMemoryManager() const
arovir014424b0a2018-10-04 10:46:04 +010049{
Aron Virginas-Tar56055192018-11-12 18:10:43 +000050 return std::make_unique<ClMemoryManager>(std::make_unique<arm_compute::CLBufferAllocator>());
51}
52
53IBackendInternal::IWorkloadFactoryPtr ClBackend::CreateWorkloadFactory(
54 const IBackendInternal::IMemoryManagerSharedPtr& memoryManager) const
55{
56 return std::make_unique<ClWorkloadFactory>(
Jan Eilers3c9e0452020-04-10 13:00:44 +010057 PolymorphicPointerDowncast<ClMemoryManager>(memoryManager));
arovir014424b0a2018-10-04 10:46:04 +010058}
59
Jan Eilerse9f0f0f2019-08-16 10:28:37 +010060IBackendInternal::IWorkloadFactoryPtr ClBackend::CreateWorkloadFactory(
Sadik Armagan04a72972020-09-14 15:44:18 +010061 const IBackendInternal::IMemoryManagerSharedPtr& memoryManager, const ModelOptions& modelOptions) const
62{
63 return std::make_unique<ClWorkloadFactory>(
64 PolymorphicPointerDowncast<ClMemoryManager>(memoryManager), CreateBackendSpecificModelContext(modelOptions));
65}
66
67IBackendInternal::IWorkloadFactoryPtr ClBackend::CreateWorkloadFactory(
Jan Eilerse9f0f0f2019-08-16 10:28:37 +010068 TensorHandleFactoryRegistry& registry) const
69{
70 auto memoryManager = std::make_shared<ClMemoryManager>(std::make_unique<arm_compute::CLBufferAllocator>());
71
72 registry.RegisterMemoryManager(memoryManager);
Narumol Prangnawarat549cb7a2020-07-10 17:50:53 +010073 registry.RegisterFactory(std::make_unique<ClTensorHandleFactory>(memoryManager));
Jan Eilerse9f0f0f2019-08-16 10:28:37 +010074
75 return std::make_unique<ClWorkloadFactory>(
Jan Eilers3c9e0452020-04-10 13:00:44 +010076 PolymorphicPointerDowncast<ClMemoryManager>(memoryManager));
Jan Eilerse9f0f0f2019-08-16 10:28:37 +010077}
78
Sadik Armagan04a72972020-09-14 15:44:18 +010079IBackendInternal::IWorkloadFactoryPtr ClBackend::CreateWorkloadFactory(
80 TensorHandleFactoryRegistry& registry, const ModelOptions& modelOptions) const
81{
82 auto memoryManager = std::make_shared<ClMemoryManager>(std::make_unique<arm_compute::CLBufferAllocator>());
83
84 registry.RegisterMemoryManager(memoryManager);
85 registry.RegisterFactory(std::make_unique<ClTensorHandleFactory>(memoryManager));
86
87 return std::make_unique<ClWorkloadFactory>(
88 PolymorphicPointerDowncast<ClMemoryManager>(memoryManager), CreateBackendSpecificModelContext(modelOptions));
89}
90
Jan Eilerse9f0f0f2019-08-16 10:28:37 +010091std::vector<ITensorHandleFactory::FactoryId> ClBackend::GetHandleFactoryPreferences() const
92{
93 return std::vector<ITensorHandleFactory::FactoryId> {ClTensorHandleFactory::GetIdStatic()};
94}
95
96void ClBackend::RegisterTensorHandleFactories(TensorHandleFactoryRegistry& registry)
97{
98 auto mgr = std::make_shared<ClMemoryManager>(std::make_unique<arm_compute::CLBufferAllocator>());
99
100 registry.RegisterMemoryManager(mgr);
101 registry.RegisterFactory(std::make_unique<ClTensorHandleFactory>(mgr));
102}
103
Sadik Armagan045f6be2020-09-10 13:37:32 +0100104IBackendInternal::IBackendContextPtr ClBackend::CreateBackendContext(const IRuntime::CreationOptions& options) const
David Beck1b61be52018-11-08 09:19:14 +0000105{
106 return IBackendContextPtr{new ClBackendContext{options}};
107}
108
Colm Donelane49755b2020-01-29 15:22:43 +0000109IBackendInternal::IBackendProfilingContextPtr ClBackend::CreateBackendProfilingContext(
Colm Donelan1aff3932020-02-05 17:48:59 +0000110 const IRuntime::CreationOptions&, IBackendProfilingPtr&)
Colm Donelane49755b2020-01-29 15:22:43 +0000111{
112 return IBackendProfilingContextPtr{};
113}
114
David Beck263e3492018-11-09 14:46:40 +0000115IBackendInternal::Optimizations ClBackend::GetOptimizations() const
116{
117 return Optimizations{};
118}
David Beck1b61be52018-11-08 09:19:14 +0000119
Sadik Armagan045f6be2020-09-10 13:37:32 +0100120IBackendInternal::IBackendSpecificModelContextPtr ClBackend::CreateBackendSpecificModelContext(
121 const ModelOptions& modelOptions) const
122{
123 return IBackendSpecificModelContextPtr{new ClBackendModelContext{modelOptions}};
124}
125
David Beck111b5d92018-11-12 14:59:37 +0000126IBackendInternal::ILayerSupportSharedPtr ClBackend::GetLayerSupport() const
127{
Sadik Armagan045f6be2020-09-10 13:37:32 +0100128 static ILayerSupportSharedPtr layerSupport
129 {
130 new ClLayerSupport(IBackendInternal::IBackendSpecificModelContextPtr{})
131 };
132 return layerSupport;
133}
134
135IBackendInternal::ILayerSupportSharedPtr ClBackend::GetLayerSupport(const ModelOptions& modelOptions) const
136{
137 static ILayerSupportSharedPtr layerSupport
138 {
139 new ClLayerSupport(CreateBackendSpecificModelContext(modelOptions))
140 };
David Beck111b5d92018-11-12 14:59:37 +0000141 return layerSupport;
142}
143
Sadik Armaganaede8ca2021-03-31 16:12:13 +0100144bool ClBackend::HasCapability(BackendCapability capabilityClass) const
145{
146 auto search = gpuAccCapabilities.find(capabilityClass);
147 if (search != gpuAccCapabilities.end())
148 {
149 return true;
150 }
151 return false;
152}
153
Mike Kelly07810fc2020-11-12 10:58:48 +0000154OptimizationViews ClBackend::OptimizeSubgraphView(const SubgraphView& subgraph,
155 const ModelOptions& modelOptions) const
Matteo Martincighadddddb2019-01-24 14:06:23 +0000156{
Matteo Martincighc3ba50e2019-05-22 14:28:16 +0100157 OptimizationViews optimizationViews;
Matteo Martincighadddddb2019-01-24 14:06:23 +0000158
Mike Kelly07810fc2020-11-12 10:58:48 +0000159 auto it = subgraph.end();
160 bool isFastMathEnabled = false;
Mike Kelly1ac690a2020-11-17 11:41:38 +0000161 std::map<LayerGuid, Layer*> untouched;
Mike Kelly07810fc2020-11-12 10:58:48 +0000162
Mike Kelly1ac690a2020-11-17 11:41:38 +0000163 while (it != subgraph.begin())
164 {
165 --it;
166 Layer& base = **it;
167 untouched.insert({base.GetGuid(), &base});
168 }
169
170 it = subgraph.end();
Mike Kelly07810fc2020-11-12 10:58:48 +0000171#if defined(ARMCOMPUTECL_ENABLED)
172 IBackendInternal::IBackendSpecificModelContextPtr modelContextPtr = CreateBackendSpecificModelContext(modelOptions);
173
174 if (modelContextPtr)
175 {
176 auto clModelOptions = dynamic_cast<ClBackendModelContext*>(modelContextPtr.get());
177 if (clModelOptions)
178 {
179 isFastMathEnabled = clModelOptions->IsFastMathEnabled();
180 }
181 }
182#endif
Mike Kelly07810fc2020-11-12 10:58:48 +0000183 while (it != subgraph.begin())
184 {
185 --it;
186 Layer& base = **it;
187
188 if ((base.GetType() == LayerType::DepthwiseConvolution2d || base.GetType() == LayerType::Convolution2d
189 || base.GetType() == LayerType::BatchNormalization || base.GetType() == LayerType::FullyConnected
190 || base.GetType() == LayerType::Addition || base.GetType() == LayerType::Multiplication
191 || base.GetType() == LayerType::Subtraction || base.GetType() == LayerType::Division)
192 && (base.GetAdditionalInformation<ActivationDescriptor>() == nullptr))
193 {
194 for (auto output = base.BeginOutputSlots(); output != base.EndOutputSlots(); ++output)
195 {
196 if (output->GetNumConnections() == 1)
197 {
198 for (auto&& childInput : output->GetConnections())
199 {
Teresa Charlind672f5d2021-01-18 18:07:57 +0000200 if ((childInput->GetOwningLayer().GetType() == LayerType::Activation) &&
201 (checkDataTypeInputandOutput(childInput->GetOwningLayer())))
Mike Kelly07810fc2020-11-12 10:58:48 +0000202 {
203 Layer& child = childInput->GetOwningLayer();
204
205 auto* activationLayer = PolymorphicDowncast<ActivationLayer*>(&child);
206
207 const std::string name = std::string("fused-") + child.GetName() + std::string("-into-") +
208 base.GetName();
209
210 // Get params from activation layer
211 ActivationDescriptor activationDesc = activationLayer->GetParameters();
212
213 if (base.GetType() == LayerType::Convolution2d)
214 {
215 Convolution2dLayer* baseLayer = PolymorphicDowncast<Convolution2dLayer*>(&base);
216
217 Optional<TensorInfo> biases;
218
219 if (baseLayer->GetParameters().m_BiasEnabled)
220 {
Mike Kelly1ac690a2020-11-17 11:41:38 +0000221 biases = baseLayer->m_Bias->GetTensorInfo();
Mike Kelly07810fc2020-11-12 10:58:48 +0000222 }
223
224 arm_compute::Status status = ClConvolution2dWorkloadValidate(
225 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
226 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
227 baseLayer->GetParameters(),
228 baseLayer->m_Weight->GetTensorInfo(),
229 biases,
230 isFastMathEnabled,
231 &activationDesc);
232
233 if (status)
234 {
235 FuseLayerWithWeightsAndBiases<Convolution2dLayer>(optimizationViews,
236 baseLayer,
237 activationLayer,
238 activationDesc,
239 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000240 untouched.erase(baseLayer->GetGuid());
241 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000242 }
243 }
244 else if (base.GetType() == LayerType::DepthwiseConvolution2d)
245 {
246 DepthwiseConvolution2dLayer* baseLayer =
247 PolymorphicDowncast<DepthwiseConvolution2dLayer*>(&base);
248
249 Optional<TensorInfo> biases;
250
251 if (baseLayer->GetParameters().m_BiasEnabled)
252 {
Mike Kelly1ac690a2020-11-17 11:41:38 +0000253 biases = baseLayer->m_Bias->GetTensorInfo();
Mike Kelly07810fc2020-11-12 10:58:48 +0000254 }
255
256 arm_compute::Status status = ClDepthwiseConvolutionWorkloadValidate(
257 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
258 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
259 baseLayer->GetParameters(),
260 baseLayer->m_Weight->GetTensorInfo(),
261 biases,
262 &activationDesc);
263
264 if (status)
265 {
266 FuseLayerWithWeightsAndBiases<DepthwiseConvolution2dLayer>(optimizationViews,
267 baseLayer,
268 activationLayer,
269 activationDesc,
270 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000271 untouched.erase(baseLayer->GetGuid());
272 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000273 }
274 }
275 else if (base.GetType() == LayerType::FullyConnected)
276 {
277 FullyConnectedLayer* baseLayer = PolymorphicDowncast<FullyConnectedLayer*>(&base);
278
279 arm_compute::Status status = ClFullyConnectedWorkloadValidate(
280 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
281 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
282 baseLayer->m_Weight->GetTensorInfo(),
283 baseLayer->m_Bias->GetTensorInfo(),
284 baseLayer->GetParameters(),
285 &activationDesc);
286
287 if (status)
288 {
289 FuseLayerWithWeightsAndBiases<FullyConnectedLayer>(optimizationViews,
290 baseLayer,
291 activationLayer,
292 activationDesc,
293 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000294 untouched.erase(baseLayer->GetGuid());
295 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000296 }
297 }
298 else if (base.GetType() == LayerType::BatchNormalization)
299 {
300 BatchNormalizationLayer* baseLayer =
301 PolymorphicDowncast<BatchNormalizationLayer*>(&base);
302
303 arm_compute::Status status = ClBatchNormalizationValidate(
304 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
305 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
306 baseLayer->m_Mean->GetTensorInfo(),
307 baseLayer->m_Variance->GetTensorInfo(),
308 baseLayer->m_Beta->GetTensorInfo(),
309 baseLayer->m_Gamma->GetTensorInfo(),
310 baseLayer->GetParameters(),
311 &activationDesc);
312
313 if (status)
314 {
315 BatchNormalizationLayer* replacementLayer =
316 FuseLayerWithParameters<BatchNormalizationLayer>(optimizationViews,
317 baseLayer,
318 activationLayer,
319 activationDesc,
320 name);
321
322 replacementLayer->m_Beta = std::move(baseLayer->m_Beta);
323 replacementLayer->m_Gamma = std::move(baseLayer->m_Gamma);
324 replacementLayer->m_Mean = std::move(baseLayer->m_Mean);
325 replacementLayer->m_Variance = std::move(baseLayer->m_Variance);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000326 untouched.erase(baseLayer->GetGuid());
327 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000328 }
329 }
330 else if (base.GetType() == LayerType::Addition)
331 {
332 AdditionLayer* baseLayer = PolymorphicDowncast<AdditionLayer*>(&base);
333
334 arm_compute::Status status = ClAdditionValidate(
335 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
336 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
337 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
338 &activationDesc);
339
340 if (status)
341 {
342 FuseLayerWithoutParameters<AdditionLayer>(optimizationViews,
343 baseLayer,
344 activationLayer,
345 activationDesc,
346 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000347 untouched.erase(baseLayer->GetGuid());
348 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000349 }
350 }
351 else if (base.GetType() == LayerType::Division)
352 {
353 DivisionLayer* baseLayer = PolymorphicDowncast<DivisionLayer*>(&base);
354
355 arm_compute::Status status = ClDivisionWorkloadValidate(
356 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
357 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
358 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
359 &activationDesc);
360
361 if (status)
362 {
363 FuseLayerWithoutParameters<DivisionLayer>(optimizationViews,
364 baseLayer,
365 activationLayer,
366 activationDesc,
367 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000368 untouched.erase(baseLayer->GetGuid());
369 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000370 }
371 }
372 else if (base.GetType() == LayerType::Multiplication)
373 {
374 MultiplicationLayer* baseLayer = PolymorphicDowncast<MultiplicationLayer*>(&base);
375
376 arm_compute::Status status = ClMultiplicationWorkloadValidate(
377 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
378 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
379 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
380 &activationDesc);
381
382 if (status)
383 {
384 FuseLayerWithoutParameters<MultiplicationLayer>(optimizationViews,
385 baseLayer,
386 activationLayer,
387 activationDesc,
388 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000389 untouched.erase(baseLayer->GetGuid());
390 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000391 }
392 }
393 else if (base.GetType() == LayerType::Subtraction)
394 {
395 SubtractionLayer* baseLayer = PolymorphicDowncast<SubtractionLayer*>(&base);
396
397 arm_compute::Status status = ClSubtractionValidate(
398 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
399 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
400 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
401 &activationDesc);
402
403 if (status)
404 {
405 FuseLayerWithoutParameters<SubtractionLayer>(optimizationViews,
406 baseLayer,
407 activationLayer,
408 activationDesc,
409 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000410 untouched.erase(baseLayer->GetGuid());
411 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000412 }
413 }
414 }
415 }
416 }
417 }
418 }
419 }
Mike Kelly1ac690a2020-11-17 11:41:38 +0000420
Mike Kelly07810fc2020-11-12 10:58:48 +0000421 if (optimizationViews.GetSubstitutions().empty())
422 {
423 optimizationViews.AddUntouchedSubgraph(SubgraphView(subgraph));
424 }
Mike Kelly1ac690a2020-11-17 11:41:38 +0000425 else
426 {
427 ReportUntouchedLayers(optimizationViews, untouched);
428 }
Matteo Martincighc3ba50e2019-05-22 14:28:16 +0100429
430 return optimizationViews;
Matteo Martincighadddddb2019-01-24 14:06:23 +0000431}
432
David Beck9efb57d2018-11-05 13:40:33 +0000433} // namespace armnn