ArmNN
 21.02
NeonBackend.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 "NeonBackend.hpp"
7 #include "NeonBackendId.hpp"
10 #include "NeonLayerSupport.hpp"
12 
14 #include <armnn/Descriptors.hpp>
15 
19 
22 
24 
33 
34 #include <Optimizer.hpp>
35 
36 #include <arm_compute/core/Types.h>
37 #include <arm_compute/runtime/Allocator.h>
38 
39 namespace armnn
40 {
41 
43 {
44  static const BackendId s_Id{NeonBackendId()};
45  return s_Id;
46 }
47 
49 {
50  return std::make_unique<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
52 }
53 
55  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager) const
56 {
57  return std::make_unique<NeonWorkloadFactory>(
58  PolymorphicPointerDowncast<NeonMemoryManager>(memoryManager));
59 }
60 
62  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager, const ModelOptions& modelOptions) const
63 {
64  return std::make_unique<NeonWorkloadFactory>(
65  PolymorphicPointerDowncast<NeonMemoryManager>(memoryManager), CreateBackendSpecificModelContext(modelOptions));
66 }
67 
69  class TensorHandleFactoryRegistry& tensorHandleFactoryRegistry) const
70 {
71  auto memoryManager = std::make_shared<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
73 
74  tensorHandleFactoryRegistry.RegisterMemoryManager(memoryManager);
75  tensorHandleFactoryRegistry.RegisterFactory(std::make_unique<NeonTensorHandleFactory>(memoryManager));
76 
77  return std::make_unique<NeonWorkloadFactory>(
78  PolymorphicPointerDowncast<NeonMemoryManager>(memoryManager));
79 }
80 
82  TensorHandleFactoryRegistry& tensorHandleFactoryRegistry, const ModelOptions& modelOptions) const
83 {
84  auto memoryManager = std::make_shared<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
86 
87  tensorHandleFactoryRegistry.RegisterMemoryManager(memoryManager);
88  tensorHandleFactoryRegistry.RegisterFactory(std::make_unique<NeonTensorHandleFactory>(memoryManager));
89 
90  return std::make_unique<NeonWorkloadFactory>(
91  PolymorphicPointerDowncast<NeonMemoryManager>(memoryManager), CreateBackendSpecificModelContext(modelOptions));
92 }
93 
95 {
96  return IBackendContextPtr{};
97 }
98 
101 {
103 }
104 
106 {
107  return Optimizations{};
108 }
109 
111  const ModelOptions& modelOptions) const
112 {
114 }
115 
117 {
118  static ILayerSupportSharedPtr layerSupport
119  {
121  };
122  return layerSupport;
123 }
124 
126 {
127  static ILayerSupportSharedPtr layerSupport
128  {
130  };
131  return layerSupport;
132 }
133 
135 {
136  OptimizationViews optimizationViews;
137 
138  auto it = subgraph.end();
139  std::map<LayerGuid, Layer*> untouched;
140 
141  while (it != subgraph.begin())
142  {
143  --it;
144  Layer& base = **it;
145  untouched.insert({base.GetGuid(), &base});
146  }
147 
148  it = subgraph.end();
149  while (it != subgraph.begin())
150  {
151  --it;
152  Layer& base = **it;
153 
157  || base.GetType() == LayerType::Subtraction || base.GetType() == LayerType::Division)
158  && (base.GetAdditionalInformation<ActivationDescriptor>() == nullptr))
159  {
160  for (auto output = base.BeginOutputSlots(); output != base.EndOutputSlots(); ++output)
161  {
162  if (output->GetNumConnections() == 1)
163  {
164  for (auto&& childInput : output->GetConnections())
165  {
166  if ((childInput->GetOwningLayer().GetType() == LayerType::Activation) &&
167  (checkDataTypeInputandOutput(childInput->GetOwningLayer())))
168  {
169  Layer& child = childInput->GetOwningLayer();
170 
171  auto* activationLayer = PolymorphicDowncast<ActivationLayer*>(&child);
172 
173  const std::string name = std::string("fused-") + child.GetName() + std::string("-into-") +
174  base.GetName();
175 
176  // Get params from activation layer
177  ActivationDescriptor activationDesc = activationLayer->GetParameters();
178 
179  if (base.GetType() == LayerType::Convolution2d)
180  {
181  Convolution2dLayer* baseLayer = PolymorphicDowncast<Convolution2dLayer*>(&base);
182 
183  Optional<TensorInfo> biases;
184 
185  if (baseLayer->GetParameters().m_BiasEnabled)
186  {
187  biases = baseLayer->m_Bias->GetTensorInfo();
188  }
189 
192  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
193  baseLayer->GetParameters(),
194  baseLayer->m_Weight->GetTensorInfo(),
195  biases,
196  false,
197  &activationDesc);
198 
199  if (status)
200  {
201  FuseLayerWithWeightsAndBiases<Convolution2dLayer>(optimizationViews,
202  baseLayer,
203  activationLayer,
204  activationDesc,
205  name);
206  untouched.erase(baseLayer->GetGuid());
207  untouched.erase(activationLayer->GetGuid());
208  }
209  }
210  else if (base.GetType() == LayerType::DepthwiseConvolution2d)
211  {
212  DepthwiseConvolution2dLayer* baseLayer =
213  PolymorphicDowncast<DepthwiseConvolution2dLayer*>(&base);
214 
215  Optional<TensorInfo> biases;
216 
217  if (baseLayer->GetParameters().m_BiasEnabled)
218  {
219  biases = baseLayer->m_Bias->GetTensorInfo();
220  }
221 
224  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
225  baseLayer->GetParameters(),
226  baseLayer->m_Weight->GetTensorInfo(),
227  biases,
228  &activationDesc);
229 
230  if (status)
231  {
232  FuseLayerWithWeightsAndBiases<DepthwiseConvolution2dLayer>(optimizationViews,
233  baseLayer,
234  activationLayer,
235  activationDesc,
236  name);
237  untouched.erase(baseLayer->GetGuid());
238  untouched.erase(activationLayer->GetGuid());
239  }
240  }
241  else if (base.GetType() == LayerType::FullyConnected)
242  {
243  FullyConnectedLayer* baseLayer = PolymorphicDowncast<FullyConnectedLayer*>(&base);
244 
247  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
248  baseLayer->m_Weight->GetTensorInfo(),
249  baseLayer->m_Bias->GetTensorInfo(),
250  baseLayer->GetParameters(),
251  &activationDesc);
252 
253  if (status)
254  {
255  FuseLayerWithWeightsAndBiases<FullyConnectedLayer>(optimizationViews,
256  baseLayer,
257  activationLayer,
258  activationDesc,
259  name);
260  untouched.erase(baseLayer->GetGuid());
261  untouched.erase(activationLayer->GetGuid());
262  }
263  }
264  else if (base.GetType() == LayerType::BatchNormalization)
265  {
266  BatchNormalizationLayer* baseLayer =
267  PolymorphicDowncast<BatchNormalizationLayer*>(&base);
268 
271  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
272  baseLayer->m_Mean->GetTensorInfo(),
273  baseLayer->m_Variance->GetTensorInfo(),
274  baseLayer->m_Beta->GetTensorInfo(),
275  baseLayer->m_Gamma->GetTensorInfo(),
276  baseLayer->GetParameters(),
277  &activationDesc);
278 
279  if (status)
280  {
281  BatchNormalizationLayer* replacementLayer =
282  FuseLayerWithParameters<BatchNormalizationLayer>(
283  optimizationViews,
284  baseLayer,
285  activationLayer,
286  activationDesc,
287  name);
288 
289  replacementLayer->m_Beta = std::move(baseLayer->m_Beta);
290  replacementLayer->m_Gamma = std::move(baseLayer->m_Gamma);
291  replacementLayer->m_Mean = std::move(baseLayer->m_Mean);
292  replacementLayer->m_Variance = std::move(baseLayer->m_Variance);
293  untouched.erase(baseLayer->GetGuid());
294  untouched.erase(activationLayer->GetGuid());
295  }
296  }
297  else if (base.GetType() == LayerType::Addition)
298  {
299  AdditionLayer* baseLayer = PolymorphicDowncast<AdditionLayer*>(&base);
300 
304  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
305  &activationDesc);
306 
307  if (status)
308  {
309  FuseLayerWithoutParameters<AdditionLayer>(optimizationViews,
310  baseLayer,
311  activationLayer,
312  activationDesc,
313  name);
314  untouched.erase(baseLayer->GetGuid());
315  untouched.erase(activationLayer->GetGuid());
316  }
317  }
318  else if (base.GetType() == LayerType::Division)
319  {
320  DivisionLayer* baseLayer = PolymorphicDowncast<DivisionLayer*>(&base);
321 
325  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
326  &activationDesc);
327 
328  if (status)
329  {
330  FuseLayerWithoutParameters<DivisionLayer>(optimizationViews,
331  baseLayer,
332  activationLayer,
333  activationDesc,
334  name);
335  untouched.erase(baseLayer->GetGuid());
336  untouched.erase(activationLayer->GetGuid());
337  }
338  }
339  else if (base.GetType() == LayerType::Multiplication)
340  {
341  MultiplicationLayer* baseLayer = PolymorphicDowncast<MultiplicationLayer*>(&base);
342 
346  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
347  &activationDesc);
348 
349  if (status)
350  {
351  FuseLayerWithoutParameters<MultiplicationLayer>(optimizationViews,
352  baseLayer,
353  activationLayer,
354  activationDesc,
355  name);
356  untouched.erase(baseLayer->GetGuid());
357  untouched.erase(activationLayer->GetGuid());
358  }
359  }
360  else if (base.GetType() == LayerType::Subtraction)
361  {
362  SubtractionLayer* baseLayer = PolymorphicDowncast<SubtractionLayer*>(&base);
363 
367  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
368  &activationDesc);
369 
370  if (status)
371  {
372  FuseLayerWithoutParameters<SubtractionLayer>(optimizationViews,
373  baseLayer,
374  activationLayer,
375  activationDesc,
376  name);
377  untouched.erase(baseLayer->GetGuid());
378  untouched.erase(activationLayer->GetGuid());
379  }
380  }
381  }
382  }
383  }
384  }
385  }
386  }
387 
388  if (optimizationViews.GetSubstitutions().empty())
389  {
390  optimizationViews.AddUntouchedSubgraph(SubgraphView(subgraph));
391  }
392  else
393  {
394  ReportUntouchedLayers(optimizationViews, untouched);
395  }
396 
397  return optimizationViews;
398 }
399 
400 std::vector<ITensorHandleFactory::FactoryId> NeonBackend::GetHandleFactoryPreferences() const
401 {
402  return std::vector<ITensorHandleFactory::FactoryId>() = { NeonTensorHandleFactory::GetIdStatic() };
403 }
404 
406 {
407  auto memoryManager = std::make_shared<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
409 
410  registry.RegisterMemoryManager(memoryManager);
411  registry.RegisterFactory(std::make_unique<NeonTensorHandleFactory>(memoryManager));
412 }
413 
414 } // namespace armnn
bool m_BiasEnabled
Enable/disable bias.
void RegisterMemoryManager(std::shared_ptr< IMemoryManager > memoryManger)
Register a memory manager with shared ownership.
This layer represents a batch normalization operation.
std::unique_ptr< IWorkloadFactory > IWorkloadFactoryPtr
bool m_BiasEnabled
Enable/disable bias.
std::vector< OptimizationPtr > Optimizations
const Parameters & GetParameters() const
IBackendInternal::IBackendProfilingContextPtr CreateBackendProfilingContext(const IRuntime::CreationOptions &, IBackendProfilingPtr &backendProfiling) override
Create context specifically used for profiling interaction from backends.
Definition: NeonBackend.cpp:99
std::unique_ptr< ScopedCpuTensorHandle > m_Weight
A unique pointer to store Weight values.
arm_compute::Status NeonBatchNormalizationValidate(const TensorInfo &input, const TensorInfo &output, const TensorInfo &mean, const TensorInfo &var, const TensorInfo &beta, const TensorInfo &gamma, const BatchNormalizationDescriptor &descriptor, const ActivationDescriptor *activationDescriptor)
std::vector< ITensorHandleFactory::FactoryId > GetHandleFactoryPreferences() const override
(Optional) Returns a vector of supported TensorHandleFactory ids in preference order.
This layer represents a depthwise convolution 2d operation.
std::unique_ptr< ScopedCpuTensorHandle > m_Bias
A unique pointer to store Bias values.
OptimizationViews OptimizeSubgraphView(const SubgraphView &subgraph) const override
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 NeonDepthwiseConvolutionWorkloadValidate(const TensorInfo &input, const TensorInfo &output, const DepthwiseConvolution2dDescriptor &descriptor, const TensorInfo &weights, const Optional< TensorInfo > &biases, const ActivationDescriptor *activationDescriptor)
IWorkloadFactoryPtr CreateWorkloadFactory(const IBackendInternal::IMemoryManagerSharedPtr &memoryManager=nullptr) const override
Definition: NeonBackend.cpp:54
constexpr const char * NeonBackendId()
std::unique_ptr< ScopedCpuTensorHandle > m_Gamma
A unique pointer to store Gamma values.
IBackendInternal::IBackendContextPtr CreateBackendContext(const IRuntime::CreationOptions &) const override
Create the runtime context of the backend.
Definition: NeonBackend.cpp:94
std::unique_ptr< ScopedCpuTensorHandle > m_Variance
A unique pointer to store Variance values.
arm_compute::Status NeonFullyConnectedWorkloadValidate(const TensorInfo &input, const TensorInfo &output, const TensorInfo &weights, const TensorInfo &biases, const FullyConnectedDescriptor &descriptor, const ActivationDescriptor *activationDescriptor)
Copyright (c) 2021 ARM Limited and Contributors.
std::unique_ptr< IMemoryManager > IMemoryManagerUniquePtr
arm_compute::Status NeonAdditionWorkloadValidate(const TensorInfo &input0, const TensorInfo &input1, const TensorInfo &output, const ActivationDescriptor *activationDescriptor)
The NeonBackendModelContext is used to pass in Neon specific backend ModelOptions.
std::unique_ptr< ScopedCpuTensorHandle > m_Beta
A unique pointer to store Beta values.
The SubgraphView class represents a subgraph of a Graph.
arm_compute::Status NeonSubtractionWorkloadValidate(const TensorInfo &input0, const TensorInfo &input1, const TensorInfo &output, const ActivationDescriptor *activationDescriptor)
void RegisterTensorHandleFactories(class TensorHandleFactoryRegistry &registry) override
(Optional) Register TensorHandleFactories Either this method or CreateMemoryManager() and IWorkloadFa...
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
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::ILayerSupportSharedPtr GetLayerSupport() const override
std::unique_ptr< ScopedCpuTensorHandle > m_Weight
A unique pointer to store Weight values.
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
IBackendInternal::IBackendSpecificModelContextPtr CreateBackendSpecificModelContext(const ModelOptions &modelOptions) const override
arm_compute::Status NeonConvolution2dWorkloadValidate(const TensorInfo &input, const TensorInfo &output, const Convolution2dDescriptor &descriptor, const TensorInfo &weights, const Optional< TensorInfo > &biases, bool isFastMathEnabled, const ActivationDescriptor *activationDescriptor)
An ActivationDescriptor for the ActivationLayer.
Definition: Descriptors.hpp:25
void AddUntouchedSubgraph(SubgraphView &&subgraph)
arm_compute::Status NeonDivisionWorkloadValidate(const TensorInfo &input0, const TensorInfo &input1, const TensorInfo &output, const ActivationDescriptor *activationDescriptor)
This layer represents an addition operation.
std::shared_ptr< ILayerSupport > ILayerSupportSharedPtr
const Substitutions & GetSubstitutions() const
This layer represents a subtraction operation.
IBackendInternal::Optimizations GetOptimizations() const override
std::vector< OutputSlot >::iterator BeginOutputSlots()
Definition: Layer.hpp:245
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
static const BackendId & GetIdStatic()
Definition: NeonBackend.cpp:42
static const FactoryId & GetIdStatic()
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.
This layer represents a multiplication operation.
const TensorInfo & GetTensorInfo() const override
Definition: Layer.cpp:63
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...
arm_compute::Status NeonMultiplicationWorkloadValidate(const TensorInfo &input0, const TensorInfo &input1, const TensorInfo &output, const ActivationDescriptor *activationDescriptor)
std::shared_ptr< T > GetAdditionalInformation() const
Definition: Layer.hpp:342
IBackendInternal::IMemoryManagerUniquePtr CreateMemoryManager() const override
Definition: NeonBackend.cpp:48
LayerGuid GetGuid() const final
Returns the unique id of the layer.
Definition: Layer.hpp:322
std::unique_ptr< IBackendContext > IBackendContextPtr