ArmNN
 25.11
Loading...
Searching...
No Matches
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
11
12namespace armnn
13{
14arm_compute::Status NeonGatherNdWorkloadValidate(const TensorInfo& paramsInfo,
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.
NeonBaseWorkload(const GatherNdQueueDescriptor &descriptor, const WorkloadInfo &info)
virtual void Execute() const override
NeonGatherNdWorkload(const GatherNdQueueDescriptor &descriptor, const WorkloadInfo &info)
const TensorShape & GetShape() const
Definition Tensor.hpp:193
unsigned int GetNumDimensions() const
Definition Tensor.hpp:197
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,...
DestType PolymorphicDowncast(SourceType *value)
Polymorphic downcast for build in pointers only.
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)
arm_compute::Status NeonGatherNdWorkloadValidate(const TensorInfo &paramsInfo, const TensorInfo &indicesInfo, const TensorInfo &outputInfo)
Contains information about TensorInfos of a layer.