ArmNN
 20.11
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  {
168  Layer& child = childInput->GetOwningLayer();
169 
170  auto* activationLayer = PolymorphicDowncast<ActivationLayer*>(&child);
171 
172  const std::string name = std::string("fused-") + child.GetName() + std::string("-into-") +
173  base.GetName();
174 
175  // Get params from activation layer
176  ActivationDescriptor activationDesc = activationLayer->GetParameters();
177 
178  if (base.GetType() == LayerType::Convolution2d)
179  {
180  Convolution2dLayer* baseLayer = PolymorphicDowncast<Convolution2dLayer*>(&base);
181 
182  Optional<TensorInfo> biases;
183 
184  if (baseLayer->GetParameters().m_BiasEnabled)
185  {
186  biases = baseLayer->m_Bias->GetTensorInfo();
187  }
188 
191  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
192  baseLayer->GetParameters(),
193  baseLayer->m_Weight->GetTensorInfo(),
194  biases,
195  false,
196  &activationDesc);
197 
198  if (status)
199  {
200  FuseLayerWithWeightsAndBiases<Convolution2dLayer>(optimizationViews,
201  baseLayer,
202  activationLayer,
203  activationDesc,
204  name);
205  untouched.erase(baseLayer->GetGuid());
206  untouched.erase(activationLayer->GetGuid());
207  }
208  }
209  else if (base.GetType() == LayerType::DepthwiseConvolution2d)
210  {
211  DepthwiseConvolution2dLayer* baseLayer =
212  PolymorphicDowncast<DepthwiseConvolution2dLayer*>(&base);
213 
214  Optional<TensorInfo> biases;
215 
216  if (baseLayer->GetParameters().m_BiasEnabled)
217  {
218  biases = baseLayer->m_Bias->GetTensorInfo();
219  }
220 
223  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
224  baseLayer->GetParameters(),
225  baseLayer->m_Weight->GetTensorInfo(),
226  biases,
227  &activationDesc);
228 
229  if (status)
230  {
231  FuseLayerWithWeightsAndBiases<DepthwiseConvolution2dLayer>(optimizationViews,
232  baseLayer,
233  activationLayer,
234  activationDesc,
235  name);
236  untouched.erase(baseLayer->GetGuid());
237  untouched.erase(activationLayer->GetGuid());
238  }
239  }
240  else if (base.GetType() == LayerType::FullyConnected)
241  {
242  FullyConnectedLayer* baseLayer = PolymorphicDowncast<FullyConnectedLayer*>(&base);
243 
246  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
247  baseLayer->m_Weight->GetTensorInfo(),
248  baseLayer->m_Bias->GetTensorInfo(),
249  baseLayer->GetParameters(),
250  &activationDesc);
251 
252  if (status)
253  {
254  FuseLayerWithWeightsAndBiases<FullyConnectedLayer>(optimizationViews,
255  baseLayer,
256  activationLayer,
257  activationDesc,
258  name);
259  untouched.erase(baseLayer->GetGuid());
260  untouched.erase(activationLayer->GetGuid());
261  }
262  }
263  else if (base.GetType() == LayerType::BatchNormalization)
264  {
265  BatchNormalizationLayer* baseLayer =
266  PolymorphicDowncast<BatchNormalizationLayer*>(&base);
267 
270  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
271  baseLayer->m_Mean->GetTensorInfo(),
272  baseLayer->m_Variance->GetTensorInfo(),
273  baseLayer->m_Beta->GetTensorInfo(),
274  baseLayer->m_Gamma->GetTensorInfo(),
275  baseLayer->GetParameters(),
276  &activationDesc);
277 
278  if (status)
279  {
280  BatchNormalizationLayer* replacementLayer =
281  FuseLayerWithParameters<BatchNormalizationLayer>(
282  optimizationViews,
283  baseLayer,
284  activationLayer,
285  activationDesc,
286  name);
287 
288  replacementLayer->m_Beta = std::move(baseLayer->m_Beta);
289  replacementLayer->m_Gamma = std::move(baseLayer->m_Gamma);
290  replacementLayer->m_Mean = std::move(baseLayer->m_Mean);
291  replacementLayer->m_Variance = std::move(baseLayer->m_Variance);
292  untouched.erase(baseLayer->GetGuid());
293  untouched.erase(activationLayer->GetGuid());
294  }
295  }
296  else if (base.GetType() == LayerType::Addition)
297  {
298  AdditionLayer* baseLayer = PolymorphicDowncast<AdditionLayer*>(&base);
299 
303  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
304  &activationDesc);
305 
306  if (status)
307  {
308  FuseLayerWithoutParameters<AdditionLayer>(optimizationViews,
309  baseLayer,
310  activationLayer,
311  activationDesc,
312  name);
313  untouched.erase(baseLayer->GetGuid());
314  untouched.erase(activationLayer->GetGuid());
315  }
316  }
317  else if (base.GetType() == LayerType::Division)
318  {
319  DivisionLayer* baseLayer = PolymorphicDowncast<DivisionLayer*>(&base);
320 
324  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
325  &activationDesc);
326 
327  if (status)
328  {
329  FuseLayerWithoutParameters<DivisionLayer>(optimizationViews,
330  baseLayer,
331  activationLayer,
332  activationDesc,
333  name);
334  untouched.erase(baseLayer->GetGuid());
335  untouched.erase(activationLayer->GetGuid());
336  }
337  }
338  else if (base.GetType() == LayerType::Multiplication)
339  {
340  MultiplicationLayer* baseLayer = PolymorphicDowncast<MultiplicationLayer*>(&base);
341 
345  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
346  &activationDesc);
347 
348  if (status)
349  {
350  FuseLayerWithoutParameters<MultiplicationLayer>(optimizationViews,
351  baseLayer,
352  activationLayer,
353  activationDesc,
354  name);
355  untouched.erase(baseLayer->GetGuid());
356  untouched.erase(activationLayer->GetGuid());
357  }
358  }
359  else if (base.GetType() == LayerType::Subtraction)
360  {
361  SubtractionLayer* baseLayer = PolymorphicDowncast<SubtractionLayer*>(&base);
362 
366  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
367  &activationDesc);
368 
369  if (status)
370  {
371  FuseLayerWithoutParameters<SubtractionLayer>(optimizationViews,
372  baseLayer,
373  activationLayer,
374  activationDesc,
375  name);
376  untouched.erase(baseLayer->GetGuid());
377  untouched.erase(activationLayer->GetGuid());
378  }
379  }
380  }
381  }
382  }
383  }
384  }
385  }
386 
387  if (optimizationViews.GetSubstitutions().empty())
388  {
389  optimizationViews.AddUntouchedSubgraph(SubgraphView(subgraph));
390  }
391  else
392  {
393  ReportUntouchedLayers(optimizationViews, untouched);
394  }
395 
396  return optimizationViews;
397 }
398 
399 std::vector<ITensorHandleFactory::FactoryId> NeonBackend::GetHandleFactoryPreferences() const
400 {
401  return std::vector<ITensorHandleFactory::FactoryId>() = { NeonTensorHandleFactory::GetIdStatic() };
402 }
403 
405 {
406  auto memoryManager = std::make_shared<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
408 
409  registry.RegisterMemoryManager(memoryManager);
410  registry.RegisterFactory(std::make_unique<NeonTensorHandleFactory>(memoryManager));
411 }
412 
413 } // 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) 2020 ARM Limited.
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:313
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.
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:20
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:242
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:243
LayerType GetType() const
Definition: Layer.hpp:262
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:308
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:339
IBackendInternal::IMemoryManagerUniquePtr CreateMemoryManager() const override
Definition: NeonBackend.cpp:48
LayerGuid GetGuid() const final
Returns the unique id of the layer.
Definition: Layer.hpp:319
std::unique_ptr< IBackendContext > IBackendContextPtr