ArmNN
 26.07
NeonBackend.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017-2026 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "NeonBackend.hpp"
7 #include "NeonBackendId.hpp"
10 #include "NeonLayerSupport.hpp"
13 
15 #include <armnn/Descriptors.hpp>
16 
20 
23 
25 
37 
38 #include <Optimizer.hpp>
39 
40 #include <arm_compute/core/Types.h>
41 #include <arm_compute/runtime/Allocator.h>
42 
43 namespace armnn
44 {
45 
47 {
48  static const BackendId s_Id{NeonBackendId()};
49  return s_Id;
50 }
51 
53 {
54  return std::make_unique<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
56 }
57 
59  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager) const
60 {
61  return std::make_unique<NeonWorkloadFactory>(
62  PolymorphicPointerDowncast<NeonMemoryManager>(memoryManager));
63 }
64 
66  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager, const ModelOptions& modelOptions) const
67 {
68  return std::make_unique<NeonWorkloadFactory>(
69  PolymorphicPointerDowncast<NeonMemoryManager>(memoryManager), CreateBackendSpecificModelContext(modelOptions));
70 }
71 
73  class TensorHandleFactoryRegistry& tensorHandleFactoryRegistry) const
74 {
75  auto memoryManager = std::make_shared<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
77 
78  tensorHandleFactoryRegistry.RegisterMemoryManager(memoryManager);
79 
80  auto factory = std::make_unique<NeonTensorHandleFactory>(memoryManager);
81  // Register copy and import factory pair
82  tensorHandleFactoryRegistry.RegisterCopyAndImportFactoryPair(factory->GetId(), factory->GetId());
83  // Register the factory
84  tensorHandleFactoryRegistry.RegisterFactory(std::move(factory));
85 
86 
87  return std::make_unique<NeonWorkloadFactory>(
88  PolymorphicPointerDowncast<NeonMemoryManager>(memoryManager));
89 }
90 
92  TensorHandleFactoryRegistry& tensorHandleFactoryRegistry, const ModelOptions& modelOptions) const
93 {
94  auto memoryManager = std::make_shared<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
96 
97  tensorHandleFactoryRegistry.RegisterMemoryManager(memoryManager);
98 
99  auto factory = std::make_unique<NeonTensorHandleFactory>(memoryManager);
100  // Register copy and import factory pair
101  tensorHandleFactoryRegistry.RegisterCopyAndImportFactoryPair(factory->GetId(), factory->GetId());
102  // Register the factory
103  tensorHandleFactoryRegistry.RegisterFactory(std::move(factory));
104 
105  return std::make_unique<NeonWorkloadFactory>(
106  PolymorphicPointerDowncast<NeonMemoryManager>(memoryManager), CreateBackendSpecificModelContext(modelOptions));
107 }
108 
110 {
111  return IBackendContextPtr{};
112 }
113 
116 {
118 }
119 
121  const ModelOptions& modelOptions) const
122 {
124 }
125 
127 {
128  static ILayerSupportSharedPtr layerSupport
129  {
131  };
132  return layerSupport;
133 }
134 
136 {
138 }
139 
141  const ModelOptions& modelOptions) const
142 {
143  OptimizationViews optimizationViews(modelOptions);
144 
145  auto it = subgraph.end();
146  std::map<LayerGuid, Layer*> untouched;
147 
148  while (it != subgraph.begin())
149  {
150  --it;
151  Layer& base = *(PolymorphicDowncast<Layer*>(*it));
152  untouched.insert({base.GetGuid(), &base});
153  }
154 
155  it = subgraph.end();
156  while (it != subgraph.begin())
157  {
158  --it;
159  Layer& base = *(PolymorphicDowncast<Layer*>(*it));
160 
161  // Fuse activation into previous layer if supported by backend
167  && (base.GetAdditionalInformation<ActivationDescriptor>() == nullptr))
168  {
169  for (auto output = base.BeginOutputSlots(); output != base.EndOutputSlots(); ++output)
170  {
171  if (output->GetNumConnections() == 1)
172  {
173  for (auto&& childInput : output->GetConnections())
174  {
175  if ((childInput->GetOwningLayer().GetType() == LayerType::Activation) &&
176  (checkDataTypeInputandOutput(childInput->GetOwningLayer())))
177  {
178  Layer& child = childInput->GetOwningLayer();
179 
180  auto* activationLayer = PolymorphicDowncast<ActivationLayer*>(&child);
181  // Before we proceed make sure that this activation layer is in the subgraph. It could be
182  // the first layer in the next subgraph.
183  if (untouched.find(activationLayer->GetGuid()) == untouched.end())
184  {
185  // We can't fuse a layer that's outside the subgraph.
186  break;
187  }
188  const std::string name = std::string("fused-") + child.GetName() + std::string("-into-") +
189  base.GetName();
190 
191  // Get params from activation layer
192  ActivationDescriptor activationDesc = activationLayer->GetParameters();
193 
194  if (base.GetType() == LayerType::Convolution2d)
195  {
196  Convolution2dLayer* baseLayer = PolymorphicDowncast<Convolution2dLayer*>(&base);
197 
198  Optional<TensorInfo> biases;
199 
200  if (baseLayer->GetParameters().m_BiasEnabled)
201  {
202  biases = baseLayer->GetInputSlot(2).GetConnectedOutputSlot()->GetTensorInfo();
203  }
204 
207  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
208  baseLayer->GetParameters(),
210  biases,
211  false,
212  &activationDesc);
213 
214  if (status)
215  {
216  FuseConvolution2dLayer<Convolution2dLayer>(optimizationViews,
217  baseLayer,
218  activationLayer,
219  activationDesc,
220  name);
221  untouched.erase(baseLayer->GetGuid());
222  untouched.erase(activationLayer->GetGuid());
223  }
224  }
225  else if (base.GetType() == LayerType::DepthwiseConvolution2d)
226  {
227  DepthwiseConvolution2dLayer* baseLayer =
228  PolymorphicDowncast<DepthwiseConvolution2dLayer*>(&base);
229 
230  Optional<TensorInfo> biases;
231 
232  if (baseLayer->GetParameters().m_BiasEnabled)
233  {
234  biases = baseLayer->GetInputSlot(2).GetConnectedOutputSlot()->GetTensorInfo();
235  }
236 
239  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
240  baseLayer->GetParameters(),
242  biases,
243  &activationDesc);
244 
245  if (status)
246  {
247  FuseDepthwiseConvolution2dLayer<DepthwiseConvolution2dLayer>(optimizationViews,
248  baseLayer,
249  activationLayer,
250  activationDesc,
251  name);
252  untouched.erase(baseLayer->GetGuid());
253  untouched.erase(activationLayer->GetGuid());
254  }
255  }
256  else if (base.GetType() == LayerType::FullyConnected)
257  {
258  FullyConnectedLayer* baseLayer = PolymorphicDowncast<FullyConnectedLayer*>(&base);
259  FullyConnectedDescriptor descriptor = baseLayer->GetParameters();
260 
261  // As bias is optional only try to get TensorInfo from input if bias is enabled.
262  Optional<TensorInfo> biases;
263  if (descriptor.m_BiasEnabled)
264  {
265  biases = baseLayer->GetInputSlot(2).GetConnectedOutputSlot()->GetTensorInfo();
266  }
267 
270  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
272  biases,
273  baseLayer->GetParameters(),
274  &activationDesc);
275 
276  if (status)
277  {
278  FuseFullyConnectedLayer<FullyConnectedLayer>(optimizationViews,
279  baseLayer,
280  activationLayer,
281  activationDesc,
282  name);
283  untouched.erase(baseLayer->GetGuid());
284  untouched.erase(activationLayer->GetGuid());
285  }
286  }
287  else if (base.GetType() == LayerType::BatchNormalization)
288  {
289  BatchNormalizationLayer* baseLayer =
290  PolymorphicDowncast<BatchNormalizationLayer*>(&base);
291 
294  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
295  baseLayer->m_Mean->GetTensorInfo(),
296  baseLayer->m_Variance->GetTensorInfo(),
297  baseLayer->m_Beta->GetTensorInfo(),
298  baseLayer->m_Gamma->GetTensorInfo(),
299  baseLayer->GetParameters(),
300  &activationDesc);
301 
302  if (status)
303  {
304  BatchNormalizationLayer* replacementLayer =
305  FuseBatchNormalizationLayer<BatchNormalizationLayer>(optimizationViews,
306  baseLayer,
307  activationLayer,
308  activationDesc,
309  name);
310 
311  replacementLayer->m_Beta = std::move(baseLayer->m_Beta);
312  replacementLayer->m_Gamma = std::move(baseLayer->m_Gamma);
313  replacementLayer->m_Mean = std::move(baseLayer->m_Mean);
314  replacementLayer->m_Variance = std::move(baseLayer->m_Variance);
315  untouched.erase(baseLayer->GetGuid());
316  untouched.erase(activationLayer->GetGuid());
317  }
318  }
319  else if (base.GetType() == LayerType::Addition)
320  {
321  AdditionLayer* baseLayer = PolymorphicDowncast<AdditionLayer*>(&base);
322 
326  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
327  &activationDesc);
328 
329  if (status)
330  {
331  FuseAdditionLayer<AdditionLayer>(optimizationViews,
332  baseLayer,
333  activationLayer,
334  activationDesc,
335  name);
336  untouched.erase(baseLayer->GetGuid());
337  untouched.erase(activationLayer->GetGuid());
338  }
339  }
340  else if (base.GetType() == LayerType::Division)
341  {
342  DivisionLayer* baseLayer = PolymorphicDowncast<DivisionLayer*>(&base);
343 
347  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
348  &activationDesc);
349 
350  if (status)
351  {
352  FuseDivisionLayer<DivisionLayer>(optimizationViews,
353  baseLayer,
354  activationLayer,
355  activationDesc,
356  name);
357  untouched.erase(baseLayer->GetGuid());
358  untouched.erase(activationLayer->GetGuid());
359  }
360  }
361  else if (base.GetType() == LayerType::Multiplication)
362  {
363  MultiplicationLayer* baseLayer = PolymorphicDowncast<MultiplicationLayer*>(&base);
364 
368  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
369  &activationDesc);
370 
371  if (status)
372  {
373  FuseMultiplicationLayer<MultiplicationLayer>(optimizationViews,
374  baseLayer,
375  activationLayer,
376  activationDesc,
377  name);
378  untouched.erase(baseLayer->GetGuid());
379  untouched.erase(activationLayer->GetGuid());
380  }
381  }
382  else if (base.GetType() == LayerType::Subtraction)
383  {
384  SubtractionLayer* baseLayer = PolymorphicDowncast<SubtractionLayer*>(&base);
385 
389  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
390  &activationDesc);
391 
392  if (status)
393  {
394  FuseSubtractionLayer<SubtractionLayer>(optimizationViews,
395  baseLayer,
396  activationLayer,
397  activationDesc,
398  name);
399  untouched.erase(baseLayer->GetGuid());
400  untouched.erase(activationLayer->GetGuid());
401  }
402  }
403  else if (base.GetType() == LayerType::ElementwiseBinary)
404  {
405  ElementwiseBinaryLayer* baseLayer = PolymorphicDowncast<ElementwiseBinaryLayer*>(&base);
406 
407  if (baseLayer->GetParameters().m_Operation == BinaryOperation::Add)
408  {
412  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
413  &activationDesc);
414 
415  if (status)
416  {
417  FuseElementwiseBinaryLayer<ElementwiseBinaryLayer>(optimizationViews,
418  baseLayer,
419  activationLayer,
420  activationDesc,
422  name);
423  untouched.erase(baseLayer->GetGuid());
424  untouched.erase(activationLayer->GetGuid());
425  }
426  }
427  else if (baseLayer->GetParameters().m_Operation == BinaryOperation::Div)
428  {
432  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
433  &activationDesc);
434 
435  if (status)
436  {
437  FuseElementwiseBinaryLayer<ElementwiseBinaryLayer>(optimizationViews,
438  baseLayer,
439  activationLayer,
440  activationDesc,
442  name);
443  untouched.erase(baseLayer->GetGuid());
444  untouched.erase(activationLayer->GetGuid());
445  }
446  }
447  else if (baseLayer->GetParameters().m_Operation == BinaryOperation::Mul)
448  {
452  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
453  &activationDesc);
454 
455  if (status)
456  {
457  FuseElementwiseBinaryLayer<ElementwiseBinaryLayer>(optimizationViews,
458  baseLayer,
459  activationLayer,
460  activationDesc,
462  name);
463  untouched.erase(baseLayer->GetGuid());
464  untouched.erase(activationLayer->GetGuid());
465  }
466  }
467  else if (baseLayer->GetParameters().m_Operation == BinaryOperation::Sub)
468  {
472  activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
473  &activationDesc);
474 
475  if (status)
476  {
477  FuseElementwiseBinaryLayer<ElementwiseBinaryLayer>(optimizationViews,
478  baseLayer,
479  activationLayer,
480  activationDesc,
482  name);
483  untouched.erase(baseLayer->GetGuid());
484  untouched.erase(activationLayer->GetGuid());
485  }
486  }
487  // No fusion available for other BinaryOperations
488  }
489  }
490  }
491  }
492  }
493  }
494 
495  // Separate reduce layer with multiple axes into multiple reduce layers with 1 axis.
496  if (base.GetType() == LayerType::Reduce)
497  {
498  ReduceLayer* baseLayer = PolymorphicDowncast<ReduceLayer*>(&base);
499  ReduceDescriptor reduceDescriptor = baseLayer->GetParameters();
500 
501  if (!reduceDescriptor.m_vAxis.empty() && reduceDescriptor.m_vAxis.size() > 1)
502  {
503  // Add new layers to the graph and connect them.
504  std::vector<IConnectableLayer*> layers = ChainReduceLayers<ReduceLayer>(optimizationViews,
505  baseLayer,
506  reduceDescriptor);
507 
508  // Replace existing baselayer with new subgraph.
509  ReplaceLayers<ReduceLayer>(optimizationViews, baseLayer, layers);
510  untouched.erase(baseLayer->GetGuid());
511  }
512  }
513 
514  // Remove Reshape where possible
515  if (base.GetType() == LayerType::Reshape)
516  {
517  ReshapeLayer* baseLayer = PolymorphicDowncast<ReshapeLayer*>(&base);
518 
519  // Cannot remove a Reshape if it's connected to any layer that has an NCHW layout
520  if (ConnectedToLayerWithNCHW(baseLayer))
521  {
522  continue;
523  }
524  RemoveReshapeLayer(baseLayer, untouched, optimizationViews);
525  }
526 
527  // Replace Add/Mul/Add where possible
528  Layer* layerList[4] = {nullptr, nullptr, nullptr, nullptr};
529  const std::vector<ActivationFunction> validActivates = { ActivationFunction::ReLu,
531  if (IsLayerSequence<BinaryOperation>(base,
533  layerList,
534  true, // handleValidActivates
535  validActivates))
536  {
537  bool fuseReLu = false;
538  unsigned int numInputs = 0;
539  unsigned int numOutputs = 0;
540  std::vector<TensorInfo> inputInfos;
541  std::vector<TensorInfo> outputInfos;
542  const ActivationDescriptor* activationDescriptor = nullptr;
543 
544  if (BuildAddMulAddTensorInfoLists<Layer>(layerList,
545  numInputs,
546  numOutputs,
547  inputInfos,
548  outputInfos,
549  activationDescriptor,
550  fuseReLu))
551  {
552  // Create the new Add/Mul/Add layer and set the Relu activation function
553  FusedDescriptor fusedDescriptor(numInputs, numOutputs, FusedKernelType::AddMulAdd);
554  arm_compute::Status status = NeonFusedWorkloadValidate({inputInfos.begin(), inputInfos.end()},
555  {outputInfos.begin(), outputInfos.end()},
556  fusedDescriptor,
557  activationDescriptor);
558  if (status)
559  {
560  std::string fusedName;
561  GetFusedName(layerList, fusedName);
562 
563  IConnectableLayer* addMulAddLayer =
564  optimizationViews.GetINetwork()->AddFusedLayer(fusedDescriptor, fusedName.c_str());
565 
566  if (fuseReLu)
567  {
568  FusedLayer* addMulAddFusedLayer = PolymorphicDowncast<FusedLayer*>(addMulAddLayer);
569  addMulAddFusedLayer->SetAdditionalInfoForObject(
570  std::make_shared<ActivationDescriptor>(*activationDescriptor));
571  }
572 
573  // Update the graph
574  std::vector<IConnectableLayer*> originalLayers;
575  for (unsigned int layerIdx = 0; layerIdx < 4; ++layerIdx)
576  {
577  if (layerList[layerIdx])
578  {
579  originalLayers.push_back(layerList[layerIdx]);
580  }
581  }
582 
583  std::vector<SlotList> inputLayersSlotLists, outputLayersSlotLists;
584  BuildAddMulAddSlotLists<SlotList>(fuseReLu,
585  outputInfos.size() > 1,
586  inputLayersSlotLists,
587  outputLayersSlotLists);
588 
589  ReplaceMultipleLayers<FusedLayer>(optimizationViews,
590  originalLayers,
591  PolymorphicDowncast<FusedLayer*>(addMulAddLayer),
592  inputLayersSlotLists,
593  outputLayersSlotLists);
594 
595  // Remove unused layers
596  for (unsigned int layerIdx = 0; layerIdx < 4; ++layerIdx)
597  {
598  if (layerList[layerIdx])
599  {
600  untouched.erase(layerList[layerIdx]->GetGuid());
601  }
602  }
603  }
604  }
605  }
606  }
607 
608  if (optimizationViews.GetSubstitutions().empty() && optimizationViews.GetDeletedSubgraphs().empty())
609  {
610  optimizationViews.AddUntouchedSubgraph(SubgraphView(subgraph));
611  }
612  else
613  {
614  ReportUntouchedLayers(optimizationViews, untouched);
615  }
616 
617  return optimizationViews;
618 }
619 
620 std::vector<ITensorHandleFactory::FactoryId> NeonBackend::GetHandleFactoryPreferences() const
621 {
622  return std::vector<ITensorHandleFactory::FactoryId>() = { NeonTensorHandleFactory::GetIdStatic() };
623 }
624 
626 {
627  auto memoryManager = std::make_shared<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
629 
630  registry.RegisterMemoryManager(memoryManager);
631 
632  auto factory = std::make_unique<NeonTensorHandleFactory>(memoryManager);
633  // Register copy and import factory pair
634  registry.RegisterCopyAndImportFactoryPair(factory->GetId(), factory->GetId());
635  // Register the factory
636  registry.RegisterFactory(std::move(factory));
637 }
638 
639 std::unique_ptr<ICustomAllocator> NeonBackend::GetDefaultAllocator() const
640 {
641  return std::make_unique<DefaultAllocator>();
642 }
643 
644 
645 } // namespace armnn
This layer represents an addition operation.
This layer represents a batch normalization operation.
std::shared_ptr< ConstTensorHandle > m_Mean
A unique pointer to store Mean values.
std::shared_ptr< ConstTensorHandle > m_Gamma
A unique pointer to store Gamma values.
std::shared_ptr< ConstTensorHandle > m_Beta
A unique pointer to store Beta values.
std::shared_ptr< ConstTensorHandle > m_Variance
A unique pointer to store Variance values.
This layer represents a convolution 2d operation.
This layer represents a depthwise convolution 2d operation.
This layer represents a division operation.
This layer represents a elementwiseBinary operation.
This layer represents a fully connected operation.
std::shared_ptr< ILayerSupport > ILayerSupportSharedPtr
std::unique_ptr< IMemoryManager > IMemoryManagerUniquePtr
std::unique_ptr< arm::pipe::IBackendProfiling > IBackendProfilingPtr
std::shared_ptr< IBackendModelContext > IBackendSpecificModelContextPtr
std::shared_ptr< IMemoryManager > IMemoryManagerSharedPtr
std::unique_ptr< IWorkloadFactory > IWorkloadFactoryPtr
std::unique_ptr< IBackendContext > IBackendContextPtr
std::shared_ptr< arm::pipe::IBackendProfilingContext > IBackendProfilingContextPtr
This is the bridge between backend and backend profiling we'll keep it in the backend namespace.
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
Definition: INetwork.hpp:81
IConnectableLayer * AddFusedLayer(const FusedDescriptor &fusedDescriptor, const char *name=nullptr)
Adds a Fused layer to the network.
Definition: Network.cpp:339
const OutputSlot * GetConnectedOutputSlot() const
Definition: Layer.hpp:56
std::vector< OutputSlot >::iterator EndOutputSlots()
Definition: Layer.hpp:267
const char * GetName() const override
Returns the name of the layer.
Definition: Layer.hpp:332
std::vector< OutputSlot >::iterator BeginOutputSlots()
Definition: Layer.hpp:266
LayerGuid GetGuid() const final
Returns the unique id of the layer.
Definition: Layer.hpp:343
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition: Layer.hpp:337
LayerType GetType() const override
Returns the armnn::LayerType of this layer.
Definition: Layer.hpp:286
void SetAdditionalInfoForObject(const AdditionalInfoObjectPtr &additionalInfo)
Definition: Layer.hpp:373
std::shared_ptr< T > GetAdditionalInformation() const
Definition: Layer.hpp:368
const Parameters & GetParameters() const override
If the layer has a descriptor return it.
This layer represents a multiplication operation.
static const BackendId & GetIdStatic()
Definition: NeonBackend.cpp:46
IBackendInternal::IBackendSpecificModelContextPtr CreateBackendSpecificModelContext(const ModelOptions &modelOptions) const override
OptimizationViews OptimizeSubgraphView(const SubgraphView &subgraph, const ModelOptions &modelOptions) const override
void RegisterTensorHandleFactories(class TensorHandleFactoryRegistry &registry) override
(Optional) Register TensorHandleFactories Either this method or CreateMemoryManager() and IWorkloadFa...
std::vector< ITensorHandleFactory::FactoryId > GetHandleFactoryPreferences() const override
(Optional) Returns a vector of supported TensorHandleFactory ids in preference order.
IBackendInternal::IBackendProfilingContextPtr CreateBackendProfilingContext(const IRuntime::CreationOptions &, IBackendProfilingPtr &backendProfiling) override
Create context specifically used for profiling interaction from backends.
IBackendInternal::IBackendContextPtr CreateBackendContext(const IRuntime::CreationOptions &) const override
Create the runtime context of the backend.
IWorkloadFactoryPtr CreateWorkloadFactory(const IBackendInternal::IMemoryManagerSharedPtr &memoryManager=nullptr) const override
Definition: NeonBackend.cpp:58
IBackendInternal::ILayerSupportSharedPtr GetLayerSupport() const override
IBackendInternal::IMemoryManagerUniquePtr CreateMemoryManager() const override
Definition: NeonBackend.cpp:52
std::unique_ptr< ICustomAllocator > GetDefaultAllocator() const override
Returns the default memory allocator for the backend.
The NeonBackendModelContext is used to pass in Neon specific backend ModelOptions.
static const FactoryId & GetIdStatic()
void AddUntouchedSubgraph(SubgraphView &&subgraph)
const Substitutions & GetSubstitutions() const
const Subgraphs & GetDeletedSubgraphs() const
const TensorInfo & GetTensorInfo() const override
Definition: Layer.cpp:100
This layer represents a reduction operation.
Definition: ReduceLayer.hpp:15
This layer represents a reshape operation.
The SubgraphView class represents a subgraph of a Graph.
IConnectableLayerIterator begin()
IConnectableLayerIterator end()
This layer represents a subtraction operation.
void RegisterFactory(std::unique_ptr< ITensorHandleFactory > allocator)
Register a TensorHandleFactory and transfer ownership.
void RegisterMemoryManager(std::shared_ptr< IMemoryManager > memoryManger)
Register a memory manager with shared ownership.
void RegisterCopyAndImportFactoryPair(ITensorHandleFactory::FactoryId copyFactoryId, ITensorHandleFactory::FactoryId importFactoryId)
Register a pair of TensorHandleFactory Id for Memory Copy and TensorHandleFactory Id for Memory Impor...
Copyright (c) 2021 ARM Limited and Contributors.
void GetFusedName(Layer *layerList[4], std::string &fusedName)
arm_compute::Status NeonAdditionWorkloadValidate(const TensorInfo &input0, const TensorInfo &input1, const TensorInfo &output, const ActivationDescriptor *activationDescriptor)
constexpr const char * NeonBackendId()
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)
@ BoundedReLu
min(a, max(b, input)) ReLu1 & ReLu6.
void ReportUntouchedLayers(OptimizationViews &optimizationViews, std::map< LayerGuid, Layer * > untouched)
std::vector< BackendOptions > ModelOptions
arm_compute::Status NeonDepthwiseConvolutionWorkloadValidate(const TensorInfo &input, const TensorInfo &output, const DepthwiseConvolution2dDescriptor &descriptor, const TensorInfo &weights, const Optional< TensorInfo > &biases, const ActivationDescriptor *activationDescriptor)
arm_compute::Status NeonDivisionWorkloadValidate(const TensorInfo &input0, const TensorInfo &input1, const TensorInfo &output, const ActivationDescriptor *activationDescriptor)
Status
enumeration
Definition: Types.hpp:43
arm_compute::Status NeonSubtractionWorkloadValidate(const TensorInfo &input0, const TensorInfo &input1, const TensorInfo &output, const ActivationDescriptor *activationDescriptor)
arm_compute::Status NeonFusedWorkloadValidate(const std::vector< std::reference_wrapper< TensorInfo >> &inputInfos, const std::vector< std::reference_wrapper< TensorInfo >> &outputInfos, const FusedDescriptor &fusedDescriptor, const ActivationDescriptor *activationDescriptor)
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)
bool ConnectedToLayerWithNCHW(Layer *baseLayer)
Checks if the Layer is connected to any Layer that has an NCHW layout.
arm_compute::Status NeonMultiplicationWorkloadValidate(const TensorInfo &input0, const TensorInfo &input1, const TensorInfo &output, const ActivationDescriptor *activationDescriptor)
arm_compute::Status NeonFullyConnectedWorkloadValidate(const TensorInfo &input, const TensorInfo &output, const TensorInfo &weights, const Optional< TensorInfo > &biases, const FullyConnectedDescriptor &descriptor, const ActivationDescriptor *activationDescriptor)
void RemoveReshapeLayer(ReshapeLayer *baseLayer, std::map< LayerGuid, Layer * > &untouched, OptimizationViews &optimizationViews)
An ActivationDescriptor for the ActivationLayer.
Definition: Descriptors.hpp:37
bool m_BiasEnabled
Enable/disable bias.
bool m_BiasEnabled
Enable/disable bias.
BinaryOperation m_Operation
Specifies the elementwiseBinary operation to execute.
A FullyConnectedDescriptor for the FullyConnectedLayer.
bool m_BiasEnabled
Enable/disable bias.
A FusedDescriptor for the FusedLayer.
A ReduceDescriptor for the REDUCE operators.
std::vector< uint32_t > m_vAxis
The indices of the dimensions to reduce.