ArmNN
 21.02
ClBackend.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "ClBackend.hpp"
7 #include "ClBackendId.hpp"
9 #include "ClWorkloadFactory.hpp"
10 #include "ClBackendContext.hpp"
11 #include "ClLayerSupport.hpp"
13 
15 #include <armnn/Descriptors.hpp>
16 
20 
24 
33 
34 #include <Optimizer.hpp>
35 
36 #include <arm_compute/core/Types.h>
37 #include <arm_compute/runtime/CL/CLBufferAllocator.h>
38 
39 namespace armnn
40 {
41 
43 {
44  static const BackendId s_Id{ClBackendId()};
45  return s_Id;
46 }
47 
49 {
50  return std::make_unique<ClMemoryManager>(std::make_unique<arm_compute::CLBufferAllocator>());
51 }
52 
54  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager) const
55 {
56  return std::make_unique<ClWorkloadFactory>(
57  PolymorphicPointerDowncast<ClMemoryManager>(memoryManager));
58 }
59 
61  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager, const ModelOptions& modelOptions) const
62 {
63  return std::make_unique<ClWorkloadFactory>(
64  PolymorphicPointerDowncast<ClMemoryManager>(memoryManager), CreateBackendSpecificModelContext(modelOptions));
65 }
66 
68  TensorHandleFactoryRegistry& registry) const
69 {
70  auto memoryManager = std::make_shared<ClMemoryManager>(std::make_unique<arm_compute::CLBufferAllocator>());
71 
72  registry.RegisterMemoryManager(memoryManager);
73  registry.RegisterFactory(std::make_unique<ClTensorHandleFactory>(memoryManager));
74 
75  return std::make_unique<ClWorkloadFactory>(
76  PolymorphicPointerDowncast<ClMemoryManager>(memoryManager));
77 }
78 
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 
91 std::vector<ITensorHandleFactory::FactoryId> ClBackend::GetHandleFactoryPreferences() const
92 {
93  return std::vector<ITensorHandleFactory::FactoryId> {ClTensorHandleFactory::GetIdStatic()};
94 }
95 
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 
105 {
106  return IBackendContextPtr{new ClBackendContext{options}};
107 }
108 
111 {
113 }
114 
116 {
117  return Optimizations{};
118 }
119 
121  const ModelOptions& modelOptions) const
122 {
123  return IBackendSpecificModelContextPtr{new ClBackendModelContext{modelOptions}};
124 }
125 
127 {
128  static ILayerSupportSharedPtr layerSupport
129  {
131  };
132  return layerSupport;
133 }
134 
136 {
137  static ILayerSupportSharedPtr layerSupport
138  {
140  };
141  return layerSupport;
142 }
143 
145  const ModelOptions& modelOptions) const
146 {
147  OptimizationViews optimizationViews;
148 
149  auto it = subgraph.end();
150  bool isFastMathEnabled = false;
151  std::map<LayerGuid, Layer*> untouched;
152 
153  while (it != subgraph.begin())
154  {
155  --it;
156  Layer& base = **it;
157  untouched.insert({base.GetGuid(), &base});
158  }
159 
160  it = subgraph.end();
161 #if defined(ARMCOMPUTECL_ENABLED)
163 
164  if (modelContextPtr)
165  {
166  auto clModelOptions = dynamic_cast<ClBackendModelContext*>(modelContextPtr.get());
167  if (clModelOptions)
168  {
169  isFastMathEnabled = clModelOptions->IsFastMathEnabled();
170  }
171  }
172 #endif
173  while (it != subgraph.begin())
174  {
175  --it;
176  Layer& base = **it;
177 
181  || base.GetType() == LayerType::Subtraction || base.GetType() == LayerType::Division)
182  && (base.GetAdditionalInformation<ActivationDescriptor>() == nullptr))
183  {
184  for (auto output = base.BeginOutputSlots(); output != base.EndOutputSlots(); ++output)
185  {
186  if (output->GetNumConnections() == 1)
187  {
188  for (auto&& childInput : output->GetConnections())
189  {
190  if ((childInput->GetOwningLayer().GetType() == LayerType::Activation) &&
191  (checkDataTypeInputandOutput(childInput->GetOwningLayer())))
192  {
193  Layer& child = childInput->GetOwningLayer();
194 
195  auto* activationLayer = PolymorphicDowncast<ActivationLayer*>(&child);
196 
197  const std::string name = std::string("fused-") + child.GetName() + std::string("-into-") +
198  base.GetName();
199 
200  // Get params from activation layer
201  ActivationDescriptor activationDesc = activationLayer->GetParameters();
202 
203  if (base.GetType() == LayerType::Convolution2d)
204  {
205  Convolution2dLayer* baseLayer = PolymorphicDowncast<Convolution2dLayer*>(&base);
206 
207  Optional<TensorInfo> biases;
208 
209  if (baseLayer->GetParameters().m_BiasEnabled)
210  {
211  biases = baseLayer->m_Bias->GetTensorInfo();
212  }
213 
216  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
217  baseLayer->GetParameters(),
218  baseLayer->m_Weight->GetTensorInfo(),
219  biases,
220  isFastMathEnabled,
221  &activationDesc);
222 
223  if (status)
224  {
225  FuseLayerWithWeightsAndBiases<Convolution2dLayer>(optimizationViews,
226  baseLayer,
227  activationLayer,
228  activationDesc,
229  name);
230  untouched.erase(baseLayer->GetGuid());
231  untouched.erase(activationLayer->GetGuid());
232  }
233  }
234  else if (base.GetType() == LayerType::DepthwiseConvolution2d)
235  {
236  DepthwiseConvolution2dLayer* baseLayer =
237  PolymorphicDowncast<DepthwiseConvolution2dLayer*>(&base);
238 
239  Optional<TensorInfo> biases;
240 
241  if (baseLayer->GetParameters().m_BiasEnabled)
242  {
243  biases = baseLayer->m_Bias->GetTensorInfo();
244  }
245 
248  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
249  baseLayer->GetParameters(),
250  baseLayer->m_Weight->GetTensorInfo(),
251  biases,
252  &activationDesc);
253 
254  if (status)
255  {
256  FuseLayerWithWeightsAndBiases<DepthwiseConvolution2dLayer>(optimizationViews,
257  baseLayer,
258  activationLayer,
259  activationDesc,
260  name);
261  untouched.erase(baseLayer->GetGuid());
262  untouched.erase(activationLayer->GetGuid());
263  }
264  }
265  else if (base.GetType() == LayerType::FullyConnected)
266  {
267  FullyConnectedLayer* baseLayer = PolymorphicDowncast<FullyConnectedLayer*>(&base);
268 
271  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
272  baseLayer->m_Weight->GetTensorInfo(),
273  baseLayer->m_Bias->GetTensorInfo(),
274  baseLayer->GetParameters(),
275  &activationDesc);
276 
277  if (status)
278  {
279  FuseLayerWithWeightsAndBiases<FullyConnectedLayer>(optimizationViews,
280  baseLayer,
281  activationLayer,
282  activationDesc,
283  name);
284  untouched.erase(baseLayer->GetGuid());
285  untouched.erase(activationLayer->GetGuid());
286  }
287  }
288  else if (base.GetType() == LayerType::BatchNormalization)
289  {
290  BatchNormalizationLayer* baseLayer =
291  PolymorphicDowncast<BatchNormalizationLayer*>(&base);
292 
295  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
296  baseLayer->m_Mean->GetTensorInfo(),
297  baseLayer->m_Variance->GetTensorInfo(),
298  baseLayer->m_Beta->GetTensorInfo(),
299  baseLayer->m_Gamma->GetTensorInfo(),
300  baseLayer->GetParameters(),
301  &activationDesc);
302 
303  if (status)
304  {
305  BatchNormalizationLayer* replacementLayer =
306  FuseLayerWithParameters<BatchNormalizationLayer>(optimizationViews,
307  baseLayer,
308  activationLayer,
309  activationDesc,
310  name);
311 
312  replacementLayer->m_Beta = std::move(baseLayer->m_Beta);
313  replacementLayer->m_Gamma = std::move(baseLayer->m_Gamma);
314  replacementLayer->m_Mean = std::move(baseLayer->m_Mean);
315  replacementLayer->m_Variance = std::move(baseLayer->m_Variance);
316  untouched.erase(baseLayer->GetGuid());
317  untouched.erase(activationLayer->GetGuid());
318  }
319  }
320  else if (base.GetType() == LayerType::Addition)
321  {
322  AdditionLayer* baseLayer = PolymorphicDowncast<AdditionLayer*>(&base);
323 
327  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
328  &activationDesc);
329 
330  if (status)
331  {
332  FuseLayerWithoutParameters<AdditionLayer>(optimizationViews,
333  baseLayer,
334  activationLayer,
335  activationDesc,
336  name);
337  untouched.erase(baseLayer->GetGuid());
338  untouched.erase(activationLayer->GetGuid());
339  }
340  }
341  else if (base.GetType() == LayerType::Division)
342  {
343  DivisionLayer* baseLayer = PolymorphicDowncast<DivisionLayer*>(&base);
344 
348  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
349  &activationDesc);
350 
351  if (status)
352  {
353  FuseLayerWithoutParameters<DivisionLayer>(optimizationViews,
354  baseLayer,
355  activationLayer,
356  activationDesc,
357  name);
358  untouched.erase(baseLayer->GetGuid());
359  untouched.erase(activationLayer->GetGuid());
360  }
361  }
362  else if (base.GetType() == LayerType::Multiplication)
363  {
364  MultiplicationLayer* baseLayer = PolymorphicDowncast<MultiplicationLayer*>(&base);
365 
369  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
370  &activationDesc);
371 
372  if (status)
373  {
374  FuseLayerWithoutParameters<MultiplicationLayer>(optimizationViews,
375  baseLayer,
376  activationLayer,
377  activationDesc,
378  name);
379  untouched.erase(baseLayer->GetGuid());
380  untouched.erase(activationLayer->GetGuid());
381  }
382  }
383  else if (base.GetType() == LayerType::Subtraction)
384  {
385  SubtractionLayer* baseLayer = PolymorphicDowncast<SubtractionLayer*>(&base);
386 
390  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
391  &activationDesc);
392 
393  if (status)
394  {
395  FuseLayerWithoutParameters<SubtractionLayer>(optimizationViews,
396  baseLayer,
397  activationLayer,
398  activationDesc,
399  name);
400  untouched.erase(baseLayer->GetGuid());
401  untouched.erase(activationLayer->GetGuid());
402  }
403  }
404  }
405  }
406  }
407  }
408  }
409  }
410 
411  if (optimizationViews.GetSubstitutions().empty())
412  {
413  optimizationViews.AddUntouchedSubgraph(SubgraphView(subgraph));
414  }
415  else
416  {
417  ReportUntouchedLayers(optimizationViews, untouched);
418  }
419 
420  return optimizationViews;
421 }
422 
423 } // namespace armnn
arm_compute::Status ClAdditionValidate(const TensorInfo &input0, const TensorInfo &input1, const TensorInfo &output, const ActivationDescriptor *activationDescriptor)
bool m_BiasEnabled
Enable/disable bias.
void RegisterMemoryManager(std::shared_ptr< IMemoryManager > memoryManger)
Register a memory manager with shared ownership.
arm_compute::Status ClFullyConnectedWorkloadValidate(const TensorInfo &input, const TensorInfo &output, const TensorInfo &weights, const TensorInfo &biases, const FullyConnectedDescriptor &descriptor, const ActivationDescriptor *activationDescriptor)
static const FactoryId & GetIdStatic()
This layer represents a batch normalization operation.
std::unique_ptr< IWorkloadFactory > IWorkloadFactoryPtr
bool m_BiasEnabled
Enable/disable bias.
std::vector< OptimizationPtr > Optimizations
arm_compute::Status ClDivisionWorkloadValidate(const TensorInfo &input0, const TensorInfo &input1, const TensorInfo &output, const ActivationDescriptor *activationDescriptor)
const Parameters & GetParameters() const
std::unique_ptr< ScopedCpuTensorHandle > m_Weight
A unique pointer to store Weight values.
This layer represents a depthwise convolution 2d operation.
std::unique_ptr< ScopedCpuTensorHandle > m_Bias
A unique pointer to store Bias values.
constexpr const char * ClBackendId()
Definition: ClBackendId.hpp:10
std::unique_ptr< ScopedCpuTensorHandle > m_Bias
A unique pointer to store Bias values.
std::vector< BackendOptions > ModelOptions
void RegisterFactory(std::unique_ptr< ITensorHandleFactory > allocator)
Register a TensorHandleFactory and transfer ownership.
void ReportUntouchedLayers(OptimizationViews &optimizationViews, std::map< LayerGuid, Layer *> untouched)
arm_compute::Status ClSubtractionValidate(const TensorInfo &input0, const TensorInfo &input1, const TensorInfo &output, const ActivationDescriptor *activationDescriptor)
std::unique_ptr< ScopedCpuTensorHandle > m_Gamma
A unique pointer to store Gamma values.
std::unique_ptr< ScopedCpuTensorHandle > m_Variance
A unique pointer to store Variance values.
Copyright (c) 2021 ARM Limited and Contributors.
arm_compute::Status ClConvolution2dWorkloadValidate(const TensorInfo &input, const TensorInfo &output, const Convolution2dDescriptor &descriptor, const TensorInfo &weights, const Optional< TensorInfo > &biases, bool isFastMathEnabled, const ActivationDescriptor *activationDescriptor)
std::unique_ptr< IMemoryManager > IMemoryManagerUniquePtr
IBackendInternal::IMemoryManagerUniquePtr CreateMemoryManager() const override
Definition: ClBackend.cpp:48
void RegisterTensorHandleFactories(TensorHandleFactoryRegistry &registry) override
(Optional) Register TensorHandleFactories Either this method or CreateMemoryManager() and IWorkloadFa...
Definition: ClBackend.cpp:96
std::unique_ptr< ScopedCpuTensorHandle > m_Beta
A unique pointer to store Beta values.
The SubgraphView class represents a subgraph of a Graph.
IBackendInternal::IBackendSpecificModelContextPtr CreateBackendSpecificModelContext(const ModelOptions &modelOptions) const override
Definition: ClBackend.cpp:120
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition: Layer.hpp:316
std::unique_ptr< armnn::profiling::IBackendProfiling > IBackendProfilingPtr
OptimizationViews OptimizeSubgraphView(const SubgraphView &subgraph, const ModelOptions &modelOptions) const override
Definition: ClBackend.cpp:144
This layer represents a fully connected operation.
std::unique_ptr< ScopedCpuTensorHandle > m_Mean
A unique pointer to store Mean values.
std::shared_ptr< IBackendModelContext > IBackendSpecificModelContextPtr
std::shared_ptr< IMemoryManager > IMemoryManagerSharedPtr
IBackendInternal::IBackendContextPtr CreateBackendContext(const IRuntime::CreationOptions &) const override
Create the runtime context of the backend.
Definition: ClBackend.cpp:104
std::unique_ptr< ScopedCpuTensorHandle > m_Weight
A unique pointer to store Weight values.
arm_compute::Status ClMultiplicationWorkloadValidate(const TensorInfo &input0, const TensorInfo &input1, const TensorInfo &output, const ActivationDescriptor *activationDescriptor)
std::vector< ITensorHandleFactory::FactoryId > GetHandleFactoryPreferences() const override
(Optional) Returns a vector of supported TensorHandleFactory ids in preference order.
Definition: ClBackend.cpp:91
LayerType GetType() const override
Returns the armnn::LayerType of this layer.
Definition: Layer.hpp:265
Status
enumeration
Definition: Types.hpp:26
const OutputSlot * GetConnectedOutputSlot() const
Definition: Layer.hpp:55
An ActivationDescriptor for the ActivationLayer.
Definition: Descriptors.hpp:25
void AddUntouchedSubgraph(SubgraphView &&subgraph)
IBackendInternal::IWorkloadFactoryPtr CreateWorkloadFactory(const IBackendInternal::IMemoryManagerSharedPtr &memoryManager=nullptr) const override
Definition: ClBackend.cpp:53
This layer represents an addition operation.
std::shared_ptr< ILayerSupport > ILayerSupportSharedPtr
const Substitutions & GetSubstitutions() const
This layer represents a subtraction operation.
std::vector< OutputSlot >::iterator BeginOutputSlots()
Definition: Layer.hpp:245
IBackendInternal::ILayerSupportSharedPtr GetLayerSupport() const override
Definition: ClBackend.cpp:126
IBackendInternal::IBackendProfilingContextPtr CreateBackendProfilingContext(const IRuntime::CreationOptions &, IBackendProfilingPtr &backendProfiling) override
Create context specifically used for profiling interaction from backends.
Definition: ClBackend.cpp:109
std::unique_ptr< ScopedCpuTensorHandle > m_Bias
A unique pointer to store Bias values.
This layer represents a division operation.
std::vector< OutputSlot >::iterator EndOutputSlots()
Definition: Layer.hpp:246
arm_compute::Status ClBatchNormalizationValidate(const TensorInfo &input, const TensorInfo &output, const TensorInfo &mean, const TensorInfo &var, const TensorInfo &beta, const TensorInfo &gamma, const BatchNormalizationDescriptor &desc, const ActivationDescriptor *activationDescriptor)
const char * GetName() const override
Returns the name of the layer.
Definition: Layer.hpp:311
This layer represents a convolution 2d operation.
std::unique_ptr< ScopedCpuTensorHandle > m_Weight
A unique pointer to store Weight values.
The ClBackendModelContext is used to pass in CL specific backend ModelOptions.
This layer represents a multiplication operation.
IBackendInternal::Optimizations GetOptimizations() const override
Definition: ClBackend.cpp:115
const TensorInfo & GetTensorInfo() const override
Definition: Layer.cpp:63
static const BackendId & GetIdStatic()
Definition: ClBackend.cpp:42
arm_compute::Status ClDepthwiseConvolutionWorkloadValidate(const TensorInfo &input, const TensorInfo &output, const DepthwiseConvolution2dDescriptor &descriptor, const TensorInfo &weights, const Optional< TensorInfo > &biases, const ActivationDescriptor *activationDescriptor)
std::shared_ptr< armnn::profiling::IBackendProfilingContext > IBackendProfilingContextPtr
This is the bridge between backend and backend profiling we&#39;ll keep it in the backend namespace...
std::shared_ptr< T > GetAdditionalInformation() const
Definition: Layer.hpp:342
LayerGuid GetGuid() const final
Returns the unique id of the layer.
Definition: Layer.hpp:322
std::unique_ptr< IBackendContext > IBackendContextPtr