ArmNN
 26.07
NeonWorkloadFactory.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017-2024, 2026 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "NeonBackendId.hpp"
8 #include "NeonTensorHandle.hpp"
10 
11 #include <Layer.hpp>
12 
13 #include <armnn/Utils.hpp>
17 
22 
25 
26 namespace armnn
27 {
28 
29 namespace
30 {
31 static const BackendId s_Id{NeonBackendId()};
32 }
33 
35  Optional<DataType> dataType,
36  std::string& outReasonIfUnsupported)
37 {
38  return IWorkloadFactory::IsLayerSupported(s_Id, layer, dataType, outReasonIfUnsupported);
39 }
40 
42  Optional<DataType> dataType,
43  std::string& outReasonIfUnsupported,
44  const ModelOptions& modelOptions)
45 {
46  return IWorkloadFactory::IsLayerSupported(s_Id, layer, dataType, outReasonIfUnsupported, modelOptions);
47 }
48 
50 {
51  return s_Id;
52 }
53 
54 void NeonWorkloadFactory::SetNumberOfThreads()
55 {
56  if (m_ModelContextPtr)
57  {
58  const unsigned int MIN_THREADS = 1;
59  const unsigned int MAX_THREADS = 64;
60 
61  // Set the number of threads to be used if the user has set NumberOfThreads param
62  // Only set if within limit or valid input
63  auto modelOptions = dynamic_cast<NeonBackendModelContext*>(m_ModelContextPtr.get());
64  auto numberOfThreads = modelOptions->GetNumberOfThreads();
65 
66  modelOptions->ApplyAclIsaPolicy();
67 
68  if (numberOfThreads != 0 && numberOfThreads >= MIN_THREADS && numberOfThreads <= MAX_THREADS)
69  {
70  arm_compute::Scheduler::get().set_num_threads(numberOfThreads);
71  }
72  }
73 }
74 
75 NeonWorkloadFactory::NeonWorkloadFactory(const std::shared_ptr<NeonMemoryManager>& memoryManager)
76  : m_MemoryManager(memoryManager), m_ModelContextPtr(IBackendInternal::IBackendSpecificModelContextPtr{})
77 {
78  SetNumberOfThreads();
79 }
80 
81 NeonWorkloadFactory::NeonWorkloadFactory(const std::shared_ptr<NeonMemoryManager>& memoryManager,
83  : m_MemoryManager(memoryManager), m_ModelContextPtr(modelContextPtr)
84 {
85  SetNumberOfThreads();
86 }
87 
88 std::unique_ptr<ITensorHandle> NeonWorkloadFactory::CreateSubTensorHandle(ITensorHandle& parent,
89  TensorShape const& subTensorShape,
90  unsigned int const* subTensorOrigin) const
91 {
92  const arm_compute::TensorShape shape = armcomputetensorutils::BuildArmComputeTensorShape(subTensorShape);
93 
95  coords.set_num_dimensions(subTensorShape.GetNumDimensions());
96  for (unsigned int i = 0; i < subTensorShape.GetNumDimensions(); i++)
97  {
98  // Arm compute indexes tensor coords in reverse order.
99  unsigned int revertedIndex = subTensorShape.GetNumDimensions() - i - 1;
100  coords.set(i, armnn::numeric_cast<int>(subTensorOrigin[revertedIndex]));
101  }
102 
103  const arm_compute::TensorShape parentShape = armcomputetensorutils::BuildArmComputeTensorShape(parent.GetShape());
104  if (!::arm_compute::error_on_invalid_subtensor(__func__, __FILE__, __LINE__, parentShape, coords, shape))
105  {
106  return nullptr;
107  }
108 
109  return std::make_unique<NeonSubTensorHandle>(
110  PolymorphicDowncast<IAclTensorHandle*>(&parent), shape, coords);
111 }
112 
113 std::unique_ptr<ITensorHandle> NeonWorkloadFactory::CreateTensorHandle(const TensorInfo& tensorInfo,
114  const bool IsMemoryManaged) const
115 {
116  auto tensorHandle = std::make_unique<NeonTensorHandle>(tensorInfo);
117  if (IsMemoryManaged)
118  {
119  tensorHandle->SetMemoryGroup(m_MemoryManager->GetInterLayerMemoryGroup());
120  }
121  return tensorHandle;
122 }
123 
124 std::unique_ptr<ITensorHandle> NeonWorkloadFactory::CreateTensorHandle(const TensorInfo& tensorInfo,
125  DataLayout dataLayout,
126  const bool IsMemoryManaged) const
127 {
128  auto tensorHandle = std::make_unique<NeonTensorHandle>(tensorInfo, dataLayout);
129  if (IsMemoryManaged)
130  {
131  tensorHandle->SetMemoryGroup(m_MemoryManager->GetInterLayerMemoryGroup());
132  }
133  return tensorHandle;
134 }
135 
136 std::unique_ptr<IWorkload> NeonWorkloadFactory::CreateWorkload(LayerType type,
137  const QueueDescriptor& descriptor,
138  const WorkloadInfo& info) const
139 {
140  switch(type)
141  {
142  case LayerType::Activation :
143  {
144  auto activationQueueDescriptor = PolymorphicDowncast<const ActivationQueueDescriptor*>(&descriptor);
145  return std::make_unique<NeonActivationWorkload>(*activationQueueDescriptor, info);
146  }
147  case LayerType::Addition :
148  {
149  auto additionQueueDescriptor = PolymorphicDowncast<const AdditionQueueDescriptor*>(&descriptor);
150  return std::make_unique<NeonAdditionWorkload>(*additionQueueDescriptor, info);
151  }
152  case LayerType::ArgMinMax :
153  {
154  auto argMinMaxQueueDescriptor = PolymorphicDowncast<const ArgMinMaxQueueDescriptor*>(&descriptor);
155  return std::make_unique<NeonArgMinMaxWorkload>(*argMinMaxQueueDescriptor, info);
156  }
158  {
159  auto batchMatMulQueueDescriptor = PolymorphicDowncast<const BatchMatMulQueueDescriptor*>(&descriptor);
160  bool isFastMathEnabled = false;
161  if (m_ModelContextPtr)
162  {
163  if (m_ModelContextPtr.get() != nullptr)
164  {
165  auto modelOptions = dynamic_cast<NeonBackendModelContext*>(m_ModelContextPtr.get());
166  if (modelOptions)
167  {
168  isFastMathEnabled = modelOptions->IsFastMathEnabled();
169  }
170  }
171  }
172  return std::make_unique<NeonBatchMatMulWorkload>(*batchMatMulQueueDescriptor, info, isFastMathEnabled);
173  }
175  {
176  auto batchNormalizationQueueDescriptor
177  = PolymorphicDowncast<const BatchNormalizationQueueDescriptor*>(&descriptor);
178  return std::make_unique<NeonBatchNormalizationWorkload>(*batchNormalizationQueueDescriptor, info);
179  }
181  {
182  auto batchToSpaceNdQueueDescriptor
183  = PolymorphicDowncast<const BatchToSpaceNdQueueDescriptor*>(&descriptor);
184  return std::make_unique<NeonBatchToSpaceNdWorkload>(*batchToSpaceNdQueueDescriptor, info);
185  }
186  case LayerType::Cast :
187  {
188  auto castQueueDescriptor = PolymorphicDowncast<const CastQueueDescriptor*>(&descriptor);
189  return std::make_unique<NeonCastWorkload>(*castQueueDescriptor, info);
190  }
192  {
193  auto channelShuffleQueueDescriptor = PolymorphicDowncast<const ChannelShuffleQueueDescriptor*>(&descriptor);
194  return std::make_unique<NeonChannelShuffleWorkload>(*channelShuffleQueueDescriptor, info);
195  }
196  case LayerType::Comparison :
197  {
198  auto comparisonQueueDescriptor = PolymorphicDowncast<const ComparisonQueueDescriptor*>(&descriptor);
199  return std::make_unique<NeonComparisonWorkload>(*comparisonQueueDescriptor, info);
200  }
201  case LayerType::Concat :
202  {
203  auto concatQueueDescriptor = PolymorphicDowncast<const ConcatQueueDescriptor*>(&descriptor);
204  return std::make_unique<NeonConcatWorkload>(*concatQueueDescriptor, info);
205  }
206  case LayerType::Constant :
207  {
208  auto constantQueueDescriptor = PolymorphicDowncast<const ConstantQueueDescriptor*>(&descriptor);
209  return std::make_unique<NeonConstantWorkload>(*constantQueueDescriptor, info);
210  }
212  {
213  auto convertFp16ToFp32QueueDescriptor
214  = PolymorphicDowncast<const ConvertFp16ToFp32QueueDescriptor*>(&descriptor);
215  return std::make_unique<NeonConvertFp16ToFp32Workload>(*convertFp16ToFp32QueueDescriptor, info);
216  }
218  {
219  auto convertFp32ToFp16QueueDescriptor
220  = PolymorphicDowncast<const ConvertFp32ToFp16QueueDescriptor*>(&descriptor);
221  return std::make_unique<NeonConvertFp32ToFp16Workload>(*convertFp32ToFp16QueueDescriptor, info);
222  }
224  {
225  auto convolution2dQueueDescriptor = PolymorphicDowncast<const Convolution2dQueueDescriptor*>(&descriptor);
226  bool isFastMathEnabled = false;
227  if (m_ModelContextPtr)
228  {
229  if (m_ModelContextPtr.get() != nullptr)
230  {
231  auto modelOptions = dynamic_cast<NeonBackendModelContext*>(m_ModelContextPtr.get());
232  if (modelOptions)
233  {
234  isFastMathEnabled = modelOptions->IsFastMathEnabled();
235  }
236  }
237  }
238  return std::make_unique<NeonConvolution2dWorkload>(*convolution2dQueueDescriptor,
239  info,
240  m_MemoryManager->GetIntraLayerManager(),
241  isFastMathEnabled);
242  }
244  {
245  auto convolution3dQueueDescriptor = PolymorphicDowncast<const Convolution3dQueueDescriptor*>(&descriptor);
246  bool isFastMathEnabled = false;
247  if (m_ModelContextPtr)
248  {
249  if (m_ModelContextPtr.get() != nullptr)
250  {
251  auto modelOptions = dynamic_cast<NeonBackendModelContext*>(m_ModelContextPtr.get());
252  if (modelOptions)
253  {
254  isFastMathEnabled = modelOptions->IsFastMathEnabled();
255  }
256  }
257  }
258  return std::make_unique<NeonConvolution3dWorkload>(*convolution3dQueueDescriptor,
259  info,
260  m_MemoryManager->GetIntraLayerManager(),
261  isFastMathEnabled);
262  }
263  case LayerType::Debug :
264  {
265  auto debugQueueDescriptor = PolymorphicDowncast<const DebugQueueDescriptor*>(&descriptor);
266  return MakeWorkloadHelper<NullWorkload, NullWorkload>(*debugQueueDescriptor, info);
267  }
269  {
270  auto depthToSpaceQueueDescriptor = PolymorphicDowncast<const DepthToSpaceQueueDescriptor*>(&descriptor);
271  return std::make_unique<NeonDepthToSpaceWorkload>(*depthToSpaceQueueDescriptor, info);
272  }
274  {
275  auto depthwiseConvolution2dQueueDescriptor
276  = PolymorphicDowncast<const DepthwiseConvolution2dQueueDescriptor*>(&descriptor);
277  return std::make_unique<NeonDepthwiseConvolutionWorkload>(*depthwiseConvolution2dQueueDescriptor, info);
278  }
279  case LayerType::Dequantize :
280  {
281  auto dequantizeQueueDescriptor = PolymorphicDowncast<const DequantizeQueueDescriptor*>(&descriptor);
282  return std::make_unique<NeonDequantizeWorkload>(*dequantizeQueueDescriptor, info);
283  }
285  {
286  auto detectionPostProcessQueueDescriptor
287  = PolymorphicDowncast<const DetectionPostProcessQueueDescriptor*>(&descriptor);
288  return MakeWorkloadHelper<NullWorkload, NullWorkload>(*detectionPostProcessQueueDescriptor, info);
289  }
290  case LayerType::Division :
291  {
292  auto divisionQueueDescriptor = PolymorphicDowncast<const DivisionQueueDescriptor*>(&descriptor);
293  return std::make_unique<NeonDivisionWorkload>(*divisionQueueDescriptor, info);
294  }
296  {
297  auto elementwiseBinaryQueueDescriptor
298  = PolymorphicDowncast<const ElementwiseBinaryQueueDescriptor*>(&descriptor);
299  switch (elementwiseBinaryQueueDescriptor->m_Parameters.m_Operation)
300  {
302  {
303  AdditionQueueDescriptor additionQueueDescriptor;
304  additionQueueDescriptor.m_Inputs = descriptor.m_Inputs;
305  additionQueueDescriptor.m_Outputs = descriptor.m_Outputs;
306  return std::make_unique<NeonAdditionWorkload>(additionQueueDescriptor, info);
307  }
309  {
310  DivisionQueueDescriptor divisionQueueDescriptor;
311  divisionQueueDescriptor.m_Inputs = descriptor.m_Inputs;
312  divisionQueueDescriptor.m_Outputs = descriptor.m_Outputs;
313  return std::make_unique<NeonDivisionWorkload>(divisionQueueDescriptor, info);
314  }
316  {
317  DivisionQueueDescriptor floorDivQueueDescriptor;
318  floorDivQueueDescriptor.m_Inputs = descriptor.m_Inputs;
319  floorDivQueueDescriptor.m_Outputs = descriptor.m_Outputs;
320  return std::make_unique<NeonFloorDivWorkload>(floorDivQueueDescriptor, info);
321  }
323  {
324  MaximumQueueDescriptor maximumQueueDescriptor;
325  maximumQueueDescriptor.m_Inputs = descriptor.m_Inputs;
326  maximumQueueDescriptor.m_Outputs = descriptor.m_Outputs;
327  return std::make_unique<NeonMaximumWorkload>(maximumQueueDescriptor, info);
328  }
330  {
331  MinimumQueueDescriptor minimumQueueDescriptor;
332  minimumQueueDescriptor.m_Inputs = descriptor.m_Inputs;
333  minimumQueueDescriptor.m_Outputs = descriptor.m_Outputs;
334  return std::make_unique<NeonMinimumWorkload>(minimumQueueDescriptor, info);
335  }
337  {
338  MultiplicationQueueDescriptor multiplicationQueueDescriptor;
339  multiplicationQueueDescriptor.m_Inputs = descriptor.m_Inputs;
340  multiplicationQueueDescriptor.m_Outputs = descriptor.m_Outputs;
341  return std::make_unique<NeonMultiplicationWorkload>(multiplicationQueueDescriptor, info);
342  }
345  {
346  return std::make_unique<NeonElementwiseBinaryWorkload>(*elementwiseBinaryQueueDescriptor, info);
347  }
349  {
350  SubtractionQueueDescriptor subtractionQueueDescriptor;
351  subtractionQueueDescriptor.m_Inputs = descriptor.m_Inputs;
352  subtractionQueueDescriptor.m_Outputs = descriptor.m_Outputs;
353  return std::make_unique<NeonSubtractionWorkload>(subtractionQueueDescriptor, info);
354  }
355  default:
356  return nullptr;
357  }
358  }
360  {
361  auto elementwiseUnaryQueueDescriptor
362  = PolymorphicDowncast<const ElementwiseUnaryQueueDescriptor*>(&descriptor);
363  switch(elementwiseUnaryQueueDescriptor->m_Parameters.m_Operation)
364  {
365  case UnaryOperation::Abs:
366  {
367  AbsQueueDescriptor absQueueDescriptor;
368  absQueueDescriptor.m_Inputs = elementwiseUnaryQueueDescriptor->m_Inputs;
369  absQueueDescriptor.m_Outputs = elementwiseUnaryQueueDescriptor->m_Outputs;
370  return std::make_unique<NeonAbsWorkload>(absQueueDescriptor, info);
371  }
372  case UnaryOperation::Exp:
373  return std::make_unique<NeonExpWorkload>(*elementwiseUnaryQueueDescriptor, info);
375  return std::make_unique<NeonLogicalNotWorkload>(*elementwiseUnaryQueueDescriptor, info);
376  case UnaryOperation::Log:
377  return std::make_unique<NeonLogWorkload>(*elementwiseUnaryQueueDescriptor, info);
378  case UnaryOperation::Neg:
379  return std::make_unique<NeonNegWorkload>(*elementwiseUnaryQueueDescriptor, info);
381  {
382  RsqrtQueueDescriptor rsqrtQueueDescriptor;
383  rsqrtQueueDescriptor.m_Inputs = elementwiseUnaryQueueDescriptor->m_Inputs;
384  rsqrtQueueDescriptor.m_Outputs = elementwiseUnaryQueueDescriptor->m_Outputs;
385  return std::make_unique<NeonRsqrtWorkload>(rsqrtQueueDescriptor, info);
386  }
387  case UnaryOperation::Sin:
388  return std::make_unique<NeonSinWorkload>(*elementwiseUnaryQueueDescriptor, info);
390  return std::make_unique<NeonSqrtWorkload>(*elementwiseUnaryQueueDescriptor, info);
391  default:
392  return nullptr;
393  }
394  }
395  case LayerType::Fill :
396  {
397  auto fillQueueDescriptor = PolymorphicDowncast<const FillQueueDescriptor*>(&descriptor);
398  return std::make_unique<NeonFillWorkload>(*fillQueueDescriptor, info);
399  }
400  case LayerType::Floor :
401  {
402  auto floorQueueDescriptor = PolymorphicDowncast<const FloorQueueDescriptor*>(&descriptor);
403  return MakeWorkloadHelper<NeonFloorFloatWorkload, NullWorkload>(*floorQueueDescriptor, info);
404  }
406  {
407  auto fullyConnectedQueueDescriptor = PolymorphicDowncast<const FullyConnectedQueueDescriptor*>(&descriptor);
408  return std::make_unique<NeonFullyConnectedWorkload>(*fullyConnectedQueueDescriptor,
409  info,
410  m_MemoryManager->GetIntraLayerManager());
411  }
412  case LayerType::Fused :
413  {
414  auto fusedQueueDescriptor = PolymorphicDowncast<const FusedQueueDescriptor*>(&descriptor);
415  return std::make_unique<NeonFusedWorkload>(*fusedQueueDescriptor, info);
416  }
417  case LayerType::Gather :
418  {
419  auto gatherQueueDescriptor = PolymorphicDowncast<const GatherQueueDescriptor*>(&descriptor);
420  return std::make_unique<NeonGatherWorkload>(*gatherQueueDescriptor, info);
421  }
422  case LayerType::GatherNd :
423  {
424  auto gatherNdQueueDescriptor = PolymorphicDowncast<const GatherNdQueueDescriptor*>(&descriptor);
425  return std::make_unique<NeonGatherNdWorkload>(*gatherNdQueueDescriptor, info);
426  }
427  case LayerType::Input :
428  {
429  auto inputQueueDescriptor = PolymorphicDowncast<const InputQueueDescriptor*>(&descriptor);
430  return std::make_unique<CopyMemGenericWorkload>(*inputQueueDescriptor, info);
431  }
433  {
434  auto instanceNormalizationQueueDescriptor
435  = PolymorphicDowncast<const InstanceNormalizationQueueDescriptor*>(&descriptor);
436  return std::make_unique<NeonInstanceNormalizationWorkload>(*instanceNormalizationQueueDescriptor, info);
437  }
439  {
440  auto l2NormalizationQueueDescriptor
441  = PolymorphicDowncast<const L2NormalizationQueueDescriptor*>(&descriptor);
442  return MakeWorkloadHelper<NeonL2NormalizationFloatWorkload, NullWorkload>
443  (*l2NormalizationQueueDescriptor, info, m_MemoryManager->GetIntraLayerManager());
444  }
445  case LayerType::LogSoftmax :
446  {
447  auto logSoftmaxQueueDescriptor = PolymorphicDowncast<const LogSoftmaxQueueDescriptor*>(&descriptor);
448  return std::make_unique<NeonLogSoftmaxWorkload>(*logSoftmaxQueueDescriptor,
449  info,
450  m_MemoryManager->GetIntraLayerManager());
451  }
453  {
454  auto logicalBinaryQueueDescriptor = PolymorphicDowncast<const LogicalBinaryQueueDescriptor*>(&descriptor);
455  switch(logicalBinaryQueueDescriptor->m_Parameters.m_Operation)
456  {
458  return std::make_unique<NeonLogicalAndWorkload>(*logicalBinaryQueueDescriptor, info);
460  return std::make_unique<NeonLogicalOrWorkload>(*logicalBinaryQueueDescriptor, info);
461  default:
462  return nullptr;
463  }
464  }
465  case LayerType::Lstm :
466  {
467  auto lstmQueueDescriptor = PolymorphicDowncast<const LstmQueueDescriptor*>(&descriptor);
468  return MakeWorkloadHelper<NeonLstmFloatWorkload, NullWorkload>(*lstmQueueDescriptor, info);
469  }
470  case LayerType::Maximum :
471  {
472  auto maximumQueueDescriptor = PolymorphicDowncast<const MaximumQueueDescriptor*>(&descriptor);
473  return std::make_unique<NeonMaximumWorkload>(*maximumQueueDescriptor, info);
474  }
475  case LayerType::Mean :
476  {
477  auto meanQueueDescriptor = PolymorphicDowncast<const MeanQueueDescriptor*>(&descriptor);
478  return std::make_unique<NeonMeanWorkload>(*meanQueueDescriptor, info);
479  }
480  case LayerType::MemCopy :
481  {
482  auto memCopyQueueDescriptor = PolymorphicDowncast<const MemCopyQueueDescriptor*>(&descriptor);
483  if (memCopyQueueDescriptor->m_Inputs.empty() || !memCopyQueueDescriptor->m_Inputs[0])
484  {
485  throw InvalidArgumentException("NeonWorkloadFactory: Invalid null input for MemCopy workload");
486  }
487  return MakeWorkloadHelper<CopyMemGenericWorkload, CopyMemGenericWorkload>(*memCopyQueueDescriptor, info);
488  }
489  case LayerType::MemImport :
490  {
491  auto memImportQueueDescriptor = PolymorphicDowncast<const MemImportQueueDescriptor*>(&descriptor);
492  if (memImportQueueDescriptor->m_Inputs.empty() || !memImportQueueDescriptor->m_Inputs[0])
493  {
494  throw InvalidArgumentException("NeonWorkloadFactory: Invalid null input for MemImport workload");
495  }
496  return std::make_unique<ImportMemGenericWorkload>(*memImportQueueDescriptor, info);
497  }
498  case LayerType::Minimum :
499  {
500  auto minimumQueueDescriptor = PolymorphicDowncast<const MinimumQueueDescriptor*>(&descriptor);
501  return std::make_unique<NeonMinimumWorkload>(*minimumQueueDescriptor, info);
502  }
504  {
505  auto multiplicationQueueDescriptor = PolymorphicDowncast<const MultiplicationQueueDescriptor*>(&descriptor);
506  return std::make_unique<NeonMultiplicationWorkload>(*multiplicationQueueDescriptor, info);
507  }
509  {
510  auto normalizationQueueDescriptor = PolymorphicDowncast<const NormalizationQueueDescriptor*>(&descriptor);
511  return MakeWorkloadHelper<NeonNormalizationFloatWorkload, NullWorkload>
512  (*normalizationQueueDescriptor, info, m_MemoryManager->GetIntraLayerManager());
513  }
514  case LayerType::Output :
515  {
516  auto outputQueueDescriptor = PolymorphicDowncast<const OutputQueueDescriptor*>(&descriptor);
517  return std::make_unique<CopyMemGenericWorkload>(*outputQueueDescriptor, info);
518  }
519  case LayerType::Pad :
520  {
521  auto padQueueDescriptor = PolymorphicDowncast<const PadQueueDescriptor*>(&descriptor);
522  return std::make_unique<NeonPadWorkload>(*padQueueDescriptor, info);
523  }
524  case LayerType::Permute :
525  {
526  auto permuteQueueDescriptor = PolymorphicDowncast<const PermuteQueueDescriptor*>(&descriptor);
527  return std::make_unique<NeonPermuteWorkload>(*permuteQueueDescriptor, info);
528  }
529  case LayerType::Pooling2d :
530  {
531  auto pooling2dQueueDescriptor = PolymorphicDowncast<const Pooling2dQueueDescriptor*>(&descriptor);
532  return std::make_unique<NeonPooling2dWorkload>(*pooling2dQueueDescriptor, info);
533  }
534  case LayerType::Pooling3d :
535  {
536  auto pooling3dQueueDescriptor = PolymorphicDowncast<const Pooling3dQueueDescriptor*>(&descriptor);
537  return std::make_unique<NeonPooling3dWorkload>(*pooling3dQueueDescriptor, info);
538  }
540  {
541  auto preCompiledQueueDescriptor = PolymorphicDowncast<const PreCompiledQueueDescriptor*>(&descriptor);
542  return MakeWorkloadHelper<NullWorkload, NullWorkload>(*preCompiledQueueDescriptor, info);
543  }
544  case LayerType::Prelu :
545  {
546  auto preluQueueDescriptor = PolymorphicDowncast<const PreluQueueDescriptor*>(&descriptor);
547  return std::make_unique<NeonPreluWorkload>(*preluQueueDescriptor, info);
548  }
549  case LayerType::QLstm :
550  {
551  auto qLstmQueueDescriptor = PolymorphicDowncast<const QLstmQueueDescriptor*>(&descriptor);
552  return std::make_unique<NeonQLstmWorkload>(*qLstmQueueDescriptor, info);
553  }
554  case LayerType::Quantize :
555  {
556  auto quantizeQueueDescriptor = PolymorphicDowncast<const QuantizeQueueDescriptor*>(&descriptor);
557  return std::make_unique<NeonQuantizeWorkload>(*quantizeQueueDescriptor, info);
558  }
560  {
561  auto quantizedLstmQueueDescriptor = PolymorphicDowncast<const QuantizedLstmQueueDescriptor*>(&descriptor);
562  return std::make_unique<NeonQuantizedLstmWorkload>(*quantizedLstmQueueDescriptor, info);
563  }
564  case LayerType::Rank :
565  {
566  auto rankQueueDescriptor = PolymorphicDowncast<const RankQueueDescriptor*>(&descriptor);
567  return std::make_unique<NeonRankWorkload>(*rankQueueDescriptor, info);
568  }
569  case LayerType::Reduce :
570  {
571  auto reduceQueueDescriptor = PolymorphicDowncast<const ReduceQueueDescriptor*>(&descriptor);
572  return std::make_unique<NeonReduceWorkload>(*reduceQueueDescriptor, info);
573  }
574  case LayerType::Reshape :
575  {
576  auto reshapeQueueDescriptor = PolymorphicDowncast<const ReshapeQueueDescriptor*>(&descriptor);
577  return std::make_unique<NeonReshapeWorkload>(*reshapeQueueDescriptor, info);
578  }
579  case LayerType::Resize :
580  {
581  auto resizeQueueDescriptor = PolymorphicDowncast<const ResizeQueueDescriptor*>(&descriptor);
582  return std::make_unique<NeonResizeWorkload>(*resizeQueueDescriptor, info);
583  }
584  case LayerType::ReverseV2 :
585  {
586  auto reverseV2QueueDescriptor = PolymorphicDowncast<const ReverseV2QueueDescriptor*>(&descriptor);
587  return std::make_unique<NeonReverseV2Workload>(*reverseV2QueueDescriptor, info);
588  }
589  case LayerType::Slice :
590  {
591  auto sliceQueueDescriptor = PolymorphicDowncast<const SliceQueueDescriptor*>(&descriptor);
592  return std::make_unique<NeonSliceWorkload>(*sliceQueueDescriptor, info);
593  }
594  case LayerType::Softmax :
595  {
596  auto softmaxQueueDescriptor = PolymorphicDowncast<const SoftmaxQueueDescriptor*>(&descriptor);
597  return std::make_unique<NeonSoftmaxWorkload>(*softmaxQueueDescriptor,
598  info,
599  m_MemoryManager->GetIntraLayerManager());
600  }
602  {
603  auto spaceToBatchNdQueueDescriptor
604  = PolymorphicDowncast<const SpaceToBatchNdQueueDescriptor*>(&descriptor);
605  return std::make_unique<NeonSpaceToBatchNdWorkload>(*spaceToBatchNdQueueDescriptor, info);
606  }
608  {
609  auto spaceToDepthQueueDescriptor = PolymorphicDowncast<const SpaceToDepthQueueDescriptor*>(&descriptor);
610  return std::make_unique<NeonSpaceToDepthWorkload>(*spaceToDepthQueueDescriptor, info);
611  }
612  case LayerType::Splitter :
613  {
614  auto splitterQueueDescriptor = PolymorphicDowncast<const SplitterQueueDescriptor*>(&descriptor);
615  return std::make_unique<NeonSplitterWorkload>(*splitterQueueDescriptor, info);
616  }
617  case LayerType::Stack :
618  {
619  auto stackQueueDescriptor = PolymorphicDowncast<const StackQueueDescriptor*>(&descriptor);
620  return std::make_unique<NeonStackWorkload>(*stackQueueDescriptor, info);
621  }
623  {
624  auto stridedSliceQueueDescriptor = PolymorphicDowncast<const StridedSliceQueueDescriptor*>(&descriptor);
625  return std::make_unique<NeonStridedSliceWorkload>(*stridedSliceQueueDescriptor, info);
626  }
628  {
629  auto subtractionQueueDescriptor = PolymorphicDowncast<const SubtractionQueueDescriptor*>(&descriptor);
630  return std::make_unique<NeonSubtractionWorkload>(*subtractionQueueDescriptor, info);
631  }
632  case LayerType::Tile:
633  {
634  auto tileQueueDescriptor = PolymorphicDowncast<const TileQueueDescriptor*>(&descriptor);
635  return std::make_unique<NeonTileWorkload>(*tileQueueDescriptor, info);
636  }
637  case LayerType::Transpose :
638  {
639  auto transposeQueueDescriptor = PolymorphicDowncast<const TransposeQueueDescriptor*>(&descriptor);
640  return std::make_unique<NeonTransposeWorkload>(*transposeQueueDescriptor, info);
641  }
643  {
644  auto transposeConvolution2dQueueDescriptor
645  = PolymorphicDowncast<const TransposeConvolution2dQueueDescriptor*>(&descriptor);
646  return std::make_unique<NeonTransposeConvolution2dWorkload>(*transposeConvolution2dQueueDescriptor,
647  info,
648  m_MemoryManager->GetIntraLayerManager());
649  }
651  {
652  auto desc = PolymorphicDowncast<const UnidirectionalSequenceLstmQueueDescriptor*>(&descriptor);
653  if ((info.m_InputTensorInfos[0].GetDataType() == armnn::DataType::Float32) &&
654  (info.m_InputTensorInfos[1].GetDataType() == armnn::DataType::Float32) &&
655  (info.m_InputTensorInfos[2].GetDataType() == armnn::DataType::Float32) &&
656  (info.m_OutputTensorInfos[0].GetDataType() == armnn::DataType::Float32) &&
657  (info.m_OutputTensorInfos[1].GetDataType() == armnn::DataType::Float32) &&
658  (info.m_OutputTensorInfos[2].GetDataType() == armnn::DataType::Float32))
659  {
660  return std::make_unique<NeonUnidirectionalSequenceLstmFloatWorkload>(*desc, info);
661  }
662  else
663  {
664  return std::make_unique<NeonUnidirectionalSequenceLstmWorkload>(*desc, info);
665  }
666  }
667  default:
668  return nullptr;
669  }
670 }
671 
672 } // namespace armnn
std::shared_ptr< IBackendModelContext > IBackendSpecificModelContextPtr
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
Definition: INetwork.hpp:81
virtual TensorShape GetShape() const =0
Get the number of elements for each dimension ordered from slowest iterating dimension to fastest ite...
static bool IsLayerSupported(const BackendId &backendId, const IConnectableLayer &layer, Optional< DataType > dataType, std::string &outReasonIfUnsupported)
The NeonBackendModelContext is used to pass in Neon specific backend ModelOptions.
NeonWorkloadFactory(const std::shared_ptr< NeonMemoryManager > &memoryManager)
std::unique_ptr< ITensorHandle > CreateTensorHandle(const TensorInfo &tensorInfo, const bool IsMemoryManaged=true) const override
std::unique_ptr< IWorkload > CreateWorkload(LayerType type, const QueueDescriptor &descriptor, const WorkloadInfo &info) const override
Backends should implement their own CreateWorkload function with a switch statement.
static bool IsLayerSupported(const Layer &layer, Optional< DataType > dataType, std::string &outReasonIfUnsupported)
std::unique_ptr< ITensorHandle > CreateSubTensorHandle(ITensorHandle &parent, TensorShape const &subTensorShape, unsigned int const *subTensorOrigin) const override
const BackendId & GetBackendId() const override
unsigned int GetNumDimensions() const
Function that returns the tensor rank.
Definition: Tensor.cpp:174
Copyright (c) 2021 ARM Limited and Contributors.
constexpr const char * NeonBackendId()
LayerType
When adding a new layer, adapt also the LastLayer enum value in the enum class LayerType below.
Definition: Types.hpp:494
std::vector< BackendOptions > ModelOptions
std::array< unsigned int, MaxNumOfTensorDimensions > Coordinates
DataLayout
Definition: Types.hpp:63
std::vector< ITensorHandle * > m_Inputs
std::vector< ITensorHandle * > m_Outputs
Contains information about TensorInfos of a layer.