ArmNN
 24.08
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 
78  auto statusReshape = arm_compute::NEReshapeLayer::validate(&aclOutputGatherInfo, &aclOutputInfo);
79 
80  /// Return OK if all the layers are valid
81  auto okCode = arm_compute::ErrorCode::OK;
82  if (statusMul.error_code() == okCode &&
83  statusReduceSum.error_code() == okCode &&
84  statusGather.error_code() == okCode &&
85  statusReshape.error_code() == okCode)
86  {
87  return arm_compute::Status(arm_compute::ErrorCode::OK,
88  "All GatherND layers validate status OK.");
89  }
90  else
91  {
92  return arm_compute::Status(arm_compute::ErrorCode::RUNTIME_ERROR,
93  "GatherND layer validate status failed.");
94  }
95 }
96 
98  const WorkloadInfo& info)
100 {
101  m_Data.ValidateInputsOutputs("NeonGatherNdWorkload", 2, 1);
102 
103  TensorInfo paramsInfo = info.m_InputTensorInfos[0];
104  TensorInfo indicesInfo = info.m_InputTensorInfos[1];
105  TensorInfo outputInfo = info.m_OutputTensorInfos[0];
106 
107  arm_compute::ITensor& input = PolymorphicDowncast<IAclTensorHandle*>(m_Data.m_Inputs[0])->GetTensor();
108  arm_compute::ITensor& indices = PolymorphicDowncast<IAclTensorHandle*>(m_Data.m_Inputs[1])->GetTensor();
109  arm_compute::ITensor& output = PolymorphicDowncast<IAclTensorHandle*>(m_Data.m_Outputs[0])->GetTensor();
110 
111  // Calculate ND, K, W, C.
112  std::map<std::string, unsigned int> keyIndices = CalculateGatherNdKeyIndices(paramsInfo, indicesInfo);
113 
114  /// Calculate flattened indices: m_FlattenedIndices = indices * m_FlattenedCoeff.
115  /// This could be done using MatMul instead of multiplication followed by reduce sum operation,
116  /// but GeMM does not support s32 at the moment.
117 
118  // Prepare the tensor to store the output of the reduce_sum operation
119  armnn::TensorInfo flattenedIndices_Info = indicesInfo;
120  flattenedIndices_Info.SetShape({ keyIndices["W"] });
121  BuildArmComputeTensor(m_FlattenedIndices, flattenedIndices_Info);
122  armcomputetensorutils::InitialiseArmComputeTensorEmpty(m_FlattenedIndices);
123 
124  // Reshape indices into { W, ND }
125  indices.info()->set_tensor_shape(BuildArmComputeTensorShape({ keyIndices["W"], keyIndices["ND"] }));
126 
127  // Calculate the m_FlattenedCoeff
128  TensorShape paramsShape = paramsInfo.GetShape();
129  std::vector<int32_t> flattenedCoeff(keyIndices["ND"], 1);
130  for (unsigned int i = 1; i < keyIndices["ND"]; ++i)
131  {
132  flattenedCoeff[i - 1] = static_cast<int32_t>(paramsShape[i]);
133  }
134  for (unsigned int i = keyIndices["ND"] - 1; i > 0; --i)
135  {
136  flattenedCoeff[i - 1] *= flattenedCoeff[i];
137  }
138  armnn::TensorInfo flattenedCoeff_Info = indicesInfo;
139  flattenedCoeff_Info.SetShape({ keyIndices["ND"] });
140  BuildArmComputeTensor(m_FlattenedCoeff, flattenedCoeff_Info);
141  armcomputetensorutils::InitialiseArmComputeTensorEmpty(m_FlattenedCoeff);
142  CopyArmComputeITensorData<int32_t>(flattenedCoeff.data(), m_FlattenedCoeff);
143 
144  // Prepare the tensor to store the output of the multiplication
145  armnn::TensorInfo outputMul_Info = indicesInfo;
146  outputMul_Info.SetShape({ keyIndices["W"], keyIndices["ND"] });
147  BuildArmComputeTensor(m_OutputMul, outputMul_Info);
148  armcomputetensorutils::InitialiseArmComputeTensorEmpty(m_OutputMul);
149 
150  // Multiply
151  m_MulLayer.configure(&indices,
152  &m_FlattenedCoeff,
153  &m_OutputMul,
154  1.0f,
155  arm_compute::ConvertPolicy::WRAP,
156  arm_compute::RoundingPolicy::TO_ZERO,
157  arm_compute::ActivationLayerInfo());
158 
159  // Reduce Sum
160  const std::vector<unsigned int> armnnReduceAxes(1, 1);
161  arm_compute::Coordinates coords = BuildArmComputeReductionCoordinates(m_OutputMul.info()->num_dimensions(),
162  outputMul_Info.GetNumDimensions(),
163  armnnReduceAxes);
164  m_ReduceSumLayer.configure(&m_OutputMul,
165  &m_FlattenedIndices,
166  static_cast<unsigned int>(coords[0]),
167  arm_compute::ReductionOperation::SUM,
168  false);
169 
170  /// Call Gather with adequate shapes
171  // Reshape params into { K, C }
172  paramsInfo.SetShape({ keyIndices["K"], keyIndices["C"] });
173  input.info()->set_tensor_shape(BuildArmComputeTensorShape(paramsInfo.GetShape()));
174 
175  // Reshape output to have the shape given by gather { W, C }
176  // (the original outputInfo has the shape given by gatherNd)
177  armnn::TensorInfo outputGather_Info = outputInfo;
178  outputGather_Info.SetShape({ keyIndices["W"], keyIndices["C"] });
179  BuildArmComputeTensor(m_OutputGather, outputGather_Info);
180  armcomputetensorutils::InitialiseArmComputeTensorEmpty(m_OutputGather);
181 
182  m_GatherLayer.configure(&input, &m_FlattenedIndices, &m_OutputGather, ComputeAclAxis(0, paramsInfo));
183 
184  // Reshape output to the original output shape
185  m_ReshapeLayer.configure(&m_OutputGather, &output);
186 }
187 
189 {
190  ARMNN_SCOPED_PROFILING_EVENT_NEON_NAME_GUID("NeonGatherNdWorkload_Execute");
191  m_MulLayer.run();
192  m_ReduceSumLayer.run();
193  m_GatherLayer.run();
194  m_ReshapeLayer.run();
195 }
196 } //namespace armnn
armnn::GatherNdQueueDescriptor
Definition: WorkloadData.hpp:502
WorkloadUtils.hpp
armnn::QueueDescriptor::ValidateInputsOutputs
void ValidateInputsOutputs(const std::string &descName, unsigned int numExpectedIn, unsigned int numExpectedOut) const
Definition: WorkloadData.cpp:447
armnn::TensorInfo
Definition: Tensor.hpp:152
armnn::TensorInfo::GetNumDimensions
unsigned int GetNumDimensions() const
Definition: Tensor.hpp:197
armnn::NeonGatherNdWorkload::NeonGatherNdWorkload
NeonGatherNdWorkload(const GatherNdQueueDescriptor &descriptor, const WorkloadInfo &info)
Definition: NeonGatherNdWorkload.cpp:97
armnn::Coordinates
std::array< unsigned int, MaxNumOfTensorDimensions > Coordinates
Definition: InternalTypes.hpp:15
armnn::TensorShape
Definition: Tensor.hpp:20
armnn::NeonGatherNdWorkloadValidate
arm_compute::Status NeonGatherNdWorkloadValidate(const TensorInfo &paramsInfo, const TensorInfo &indicesInfo, const TensorInfo &outputInfo)
Definition: NeonGatherNdWorkload.cpp:14
armnn::WorkloadInfo
Contains information about TensorInfos of a layer.
Definition: WorkloadInfo.hpp:16
PolymorphicDowncast.hpp
armnn::CalculateGatherNdKeyIndices
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)
Definition: WorkloadUtils.cpp:313
armnn::NeonGatherNdWorkload::Execute
virtual void Execute() const override
Definition: NeonGatherNdWorkload.cpp:188
ArmComputeUtils.hpp
armnn::BoostLogSeverityMapping::info
@ info
armnn::QueueDescriptor::m_Outputs
std::vector< ITensorHandle * > m_Outputs
Definition: WorkloadData.hpp:27
armnn::Status
Status
Definition: Types.hpp:42
armnn::BaseWorkload< GatherNdQueueDescriptor >::m_Data
GatherNdQueueDescriptor m_Data
Definition: Workload.hpp:89
armnn::TensorInfo::GetShape
const TensorShape & GetShape() const
Definition: Tensor.hpp:193
NeonWorkloadUtils.hpp
armnn::TensorInfo::SetShape
void SetShape(const TensorShape &newShape)
Definition: Tensor.hpp:195
armnn
Copyright (c) 2021 ARM Limited and Contributors.
Definition: 01_00_quick_start.dox:6
NeonGatherNdWorkload.hpp
ARMNN_SCOPED_PROFILING_EVENT_NEON_NAME_GUID
#define ARMNN_SCOPED_PROFILING_EVENT_NEON_NAME_GUID(label)
Creates a profiling event that uses GetGuid() and GetName() from the calling class.
Definition: NeonWorkloadUtils.hpp:33
armnn::NeonBaseWorkload
Definition: NeonBaseWorkload.hpp:13
armnn::ComputeAclAxis
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,...
Definition: ArmComputeUtils.hpp:246
armnn::QueueDescriptor::m_Inputs
std::vector< ITensorHandle * > m_Inputs
Definition: WorkloadData.hpp:26