ArmNN
 25.02
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
NeonGatherNdWorkload.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2022-2024 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
7 #include "NeonWorkloadUtils.hpp"
11 
12 namespace armnn
13 {
15  const TensorInfo& indicesInfo,
16  const TensorInfo& outputInfo)
17 {
18  // Calculate ND, K, W, C.
19  std::map<std::string, unsigned int> keyIndices = CalculateGatherNdKeyIndices(paramsInfo, indicesInfo);
20 
21  /// Validate Mul
22  // Indices with shape { W, ND }
23  armnn::TensorInfo indices_W_ND_Info = indicesInfo;
24  indices_W_ND_Info.SetShape({ keyIndices["W"], keyIndices["ND"] });
25  const arm_compute::TensorInfo aclIndicesInfo = BuildArmComputeTensorInfo(indices_W_ND_Info);
26 
27  // Flattened coefficients with shape { ND }
28  armnn::TensorInfo flattenedCoeff_Info = indicesInfo;
29  flattenedCoeff_Info.SetShape({ keyIndices["ND"] });
30  const arm_compute::TensorInfo aclFlattenedCoeffInfo = BuildArmComputeTensorInfo(flattenedCoeff_Info);
31 
32  // Output of Mul with shape { W, ND }
33  const arm_compute::TensorInfo aclOutputMulInfo = BuildArmComputeTensorInfo(indices_W_ND_Info);
34 
35  auto statusMul = arm_compute::NEPixelWiseMultiplication::validate(&aclIndicesInfo,
36  &aclFlattenedCoeffInfo,
37  &aclOutputMulInfo,
38  1.0f,
39  arm_compute::ConvertPolicy::WRAP,
40  arm_compute::RoundingPolicy::TO_ZERO,
41  arm_compute::ActivationLayerInfo());
42 
43  /// Validate ReduceSum
44  // Flattened indices with shape { W }
45  armnn::TensorInfo flattenedIndices_Info = indicesInfo;
46  flattenedIndices_Info.SetShape({ keyIndices["W"] });
47  const arm_compute::TensorInfo aclFlattenedIndicesInfo = BuildArmComputeTensorInfo(flattenedIndices_Info);
48 
49  const std::vector<unsigned int> armnnReduceAxes(1, 1);
50  arm_compute::Coordinates coords = BuildArmComputeReductionCoordinates(aclOutputMulInfo.num_dimensions(),
51  indices_W_ND_Info.GetNumDimensions(),
52  armnnReduceAxes);
53 
54  auto statusReduceSum = arm_compute::NEReductionOperation::validate(&aclOutputMulInfo,
55  &aclFlattenedIndicesInfo,
56  static_cast<unsigned int>(coords[0]),
57  arm_compute::ReductionOperation::SUM,
58  false);
59 
60  /// Validate Gather
61  // Params with shape { K, C }
62  armnn::TensorInfo params_K_C_Info = paramsInfo;
63  params_K_C_Info.SetShape({ keyIndices["K"], keyIndices["C"] });
64  const arm_compute::TensorInfo aclParamsInfo = BuildArmComputeTensorInfo(params_K_C_Info);
65 
66  // Output of gather with shape { W, C }
67  armnn::TensorInfo outputGather_Info = outputInfo;
68  outputGather_Info.SetShape({ keyIndices["W"], keyIndices["C"] });
69  const arm_compute::TensorInfo aclOutputGatherInfo = BuildArmComputeTensorInfo(outputGather_Info);
70 
71  auto aclAxis = ComputeAclAxis(0, params_K_C_Info);
72  auto statusGather =
73  arm_compute::NEGather::validate(&aclParamsInfo, &aclFlattenedIndicesInfo, &aclOutputGatherInfo, aclAxis);
74 
75  /// Validate Reshape
76  const arm_compute::TensorInfo aclOutputInfo = BuildArmComputeTensorInfo(outputInfo);
77  const arm_compute::TensorInfo aclParamsOriginalShapeInfo = BuildArmComputeTensorInfo(paramsInfo);
78  const arm_compute::TensorInfo aclIndicesOriginalShapeInfo = BuildArmComputeTensorInfo(indicesInfo);
79  const arm_compute::TensorInfo aclParamsReshapeInfo = BuildArmComputeTensorInfo(paramsInfo);
80  const arm_compute::TensorInfo aclIndicesReshapeInfo = BuildArmComputeTensorInfo(indicesInfo);
81 
82  auto statusOutputReshape = arm_compute::NEReshapeLayer::validate(&aclOutputGatherInfo, &aclOutputInfo);
83  auto statusParamsReshape = arm_compute::NEReshapeLayer::validate(&aclParamsOriginalShapeInfo,
84  &aclParamsReshapeInfo);
85  auto statusIndicesReshape = arm_compute::NEReshapeLayer::validate(&aclIndicesOriginalShapeInfo,
86  &aclIndicesReshapeInfo);
87 
88  /// Return OK if all the layers are valid
89  auto okCode = arm_compute::ErrorCode::OK;
90  if (statusMul.error_code() == okCode &&
91  statusReduceSum.error_code() == okCode &&
92  statusGather.error_code() == okCode &&
93  statusParamsReshape.error_code() == okCode &&
94  statusIndicesReshape.error_code() == okCode &&
95  statusOutputReshape.error_code() == okCode)
96  {
97  return arm_compute::Status(arm_compute::ErrorCode::OK,
98  "All GatherND layers validate status OK.");
99  }
100  else
101  {
102  return arm_compute::Status(arm_compute::ErrorCode::RUNTIME_ERROR,
103  "GatherND layer validate status failed.");
104  }
105 }
106 
108  const WorkloadInfo& info)
110 {
111  m_Data.ValidateInputsOutputs("NeonGatherNdWorkload", 2, 1);
112 
113  TensorInfo paramsInfo = info.m_InputTensorInfos[0];
114  TensorInfo indicesInfo = info.m_InputTensorInfos[1];
115  TensorInfo outputInfo = info.m_OutputTensorInfos[0];
116 
117  arm_compute::ITensor& input = PolymorphicDowncast<IAclTensorHandle*>(m_Data.m_Inputs[0])->GetTensor();
118  arm_compute::ITensor& indices = PolymorphicDowncast<IAclTensorHandle*>(m_Data.m_Inputs[1])->GetTensor();
119  arm_compute::ITensor& output = PolymorphicDowncast<IAclTensorHandle*>(m_Data.m_Outputs[0])->GetTensor();
120 
121  // Calculate ND, K, W, C.
122  std::map<std::string, unsigned int> keyIndices = CalculateGatherNdKeyIndices(paramsInfo, indicesInfo);
123 
124  /// Calculate flattened indices: m_FlattenedIndices = indices * m_FlattenedCoeff.
125  /// This could be done using MatMul instead of multiplication followed by reduce sum operation,
126  /// but GeMM does not support s32 at the moment.
127 
128  // Prepare the tensor to store the output of the reduce_sum operation
129  armnn::TensorInfo flattenedIndices_Info = indicesInfo;
130  flattenedIndices_Info.SetShape({ keyIndices["W"] });
131  BuildArmComputeTensor(m_FlattenedIndices, flattenedIndices_Info);
132  armcomputetensorutils::InitialiseArmComputeTensorEmpty(m_FlattenedIndices);
133 
134  // Reshape indices into { W, ND }
135  armnn::TensorInfo indicesInfoReshape = indicesInfo;
136  indicesInfoReshape.SetShape({ keyIndices["W"], keyIndices["ND"] });
137  BuildArmComputeTensor(m_IndicesReshaped, indicesInfoReshape);
138  armcomputetensorutils::InitialiseArmComputeTensorEmpty(m_IndicesReshaped);
139 
140  // Calculate the m_FlattenedCoeff
141  TensorShape paramsShape = paramsInfo.GetShape();
142  std::vector<int32_t> flattenedCoeff(keyIndices["ND"], 1);
143  for (unsigned int i = 1; i < keyIndices["ND"]; ++i)
144  {
145  flattenedCoeff[i - 1] = static_cast<int32_t>(paramsShape[i]);
146  }
147  for (unsigned int i = keyIndices["ND"] - 1; i > 0; --i)
148  {
149  flattenedCoeff[i - 1] *= flattenedCoeff[i];
150  }
151  armnn::TensorInfo flattenedCoeff_Info = indicesInfo;
152  flattenedCoeff_Info.SetShape({ keyIndices["ND"] });
153  BuildArmComputeTensor(m_FlattenedCoeff, flattenedCoeff_Info);
154  armcomputetensorutils::InitialiseArmComputeTensorEmpty(m_FlattenedCoeff);
155  CopyArmComputeITensorData<int32_t>(flattenedCoeff.data(), m_FlattenedCoeff);
156 
157  // Prepare the tensor to store the output of the multiplication
158  armnn::TensorInfo outputMul_Info = indicesInfo;
159  outputMul_Info.SetShape({ keyIndices["W"], keyIndices["ND"] });
160  BuildArmComputeTensor(m_OutputMul, outputMul_Info);
161  armcomputetensorutils::InitialiseArmComputeTensorEmpty(m_OutputMul);
162 
163  // Reshape indices to the mul layer input shape
164  m_ReshapeIndicesLayer.configure(&indices, &m_IndicesReshaped);
165 
166  // Multiply
167  m_MulLayer.configure(&m_IndicesReshaped,
168  &m_FlattenedCoeff,
169  &m_OutputMul,
170  1.0f,
171  arm_compute::ConvertPolicy::WRAP,
172  arm_compute::RoundingPolicy::TO_ZERO,
173  arm_compute::ActivationLayerInfo());
174 
175  // Reduce Sum
176  const std::vector<unsigned int> armnnReduceAxes(1, 1);
177  arm_compute::Coordinates coords = BuildArmComputeReductionCoordinates(m_OutputMul.info()->num_dimensions(),
178  outputMul_Info.GetNumDimensions(),
179  armnnReduceAxes);
180  m_ReduceSumLayer.configure(&m_OutputMul,
181  &m_FlattenedIndices,
182  static_cast<unsigned int>(coords[0]),
183  arm_compute::ReductionOperation::SUM,
184  false);
185 
186  /// Call Gather with adequate shapes
187  // Reshape params into { K, C }
188  armnn::TensorInfo paramsInfoReshape = paramsInfo;
189  paramsInfoReshape.SetShape({ keyIndices["K"], keyIndices["C"] });
190  BuildArmComputeTensor(m_InputGather, paramsInfoReshape);
191  armcomputetensorutils::InitialiseArmComputeTensorEmpty(m_InputGather);
192 
193  // Reshape input to the gather params input shape
194  m_ReshapeInputLayer.configure(&input, &m_InputGather);
195 
196  // Reshape output to have the shape given by gather { W, C }
197  // (the original outputInfo has the shape given by gatherNd)
198  armnn::TensorInfo outputGather_Info = outputInfo;
199  outputGather_Info.SetShape({ keyIndices["W"], keyIndices["C"] });
200  BuildArmComputeTensor(m_OutputGather, outputGather_Info);
201  armcomputetensorutils::InitialiseArmComputeTensorEmpty(m_OutputGather);
202 
203  m_GatherLayer.configure(&m_InputGather,
204  &m_FlattenedIndices,
205  &m_OutputGather,
206  ComputeAclAxis(0, paramsInfoReshape));
207 
208  // Reshape output to the original output shape
209  m_ReshapeOutputLayer.configure(&m_OutputGather, &output);
210 }
211 
213 {
214  ARMNN_SCOPED_PROFILING_EVENT_NEON_NAME_GUID("NeonGatherNdWorkload_Execute");
215  m_ReshapeInputLayer.run();
216  m_ReshapeIndicesLayer.run();
217  m_MulLayer.run();
218  m_ReduceSumLayer.run();
219  m_GatherLayer.run();
220  m_ReshapeOutputLayer.run();
221 }
222 } //namespace armnn
#define ARMNN_SCOPED_PROFILING_EVENT_NEON_NAME_GUID(label)
Creates a profiling event that uses GetGuid() and GetName() from the calling class.
QueueDescriptor m_Data
Definition: Workload.hpp:74
virtual void Execute() const override
NeonGatherNdWorkload(const GatherNdQueueDescriptor &descriptor, const WorkloadInfo &info)
unsigned int GetNumDimensions() const
Definition: Tensor.hpp:197
const TensorShape & GetShape() const
Definition: Tensor.hpp:193
void SetShape(const TensorShape &newShape)
Definition: Tensor.hpp:195
Copyright (c) 2021 ARM Limited and Contributors.
int ComputeAclAxis(const int &armnnAxis, const armnn::TensorInfo &tensor)
Function to convert ArmNN axis (left to right) to ACL axis (right to left) ranging from [-rank,...
Status
enumeration
Definition: Types.hpp:43
std::map< std::string, unsigned int > CalculateGatherNdKeyIndices(TensorInfo inputInfo0, TensorInfo inputInfo1)
Calculates the key index values needed for GatherNd: N, ND, K, W, C (N is always 1)
std::array< unsigned int, MaxNumOfTensorDimensions > Coordinates
arm_compute::Status NeonGatherNdWorkloadValidate(const TensorInfo &paramsInfo, const TensorInfo &indicesInfo, const TensorInfo &outputInfo)
std::vector< ITensorHandle * > m_Inputs
std::vector< ITensorHandle * > m_Outputs
void ValidateInputsOutputs(const std::string &descName, unsigned int numExpectedIn, unsigned int numExpectedOut) const
Contains information about TensorInfos of a layer.