ArmNN
 25.11
Loading...
Searching...
No Matches
ClGatherNdWorkload.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 "ClWorkloadUtils.hpp"
10#include <cl/ClTensorHandle.hpp>
11
12using namespace armnn::armcomputetensorutils;
13
14namespace armnn
15{
16arm_compute::Status ClGatherNdWorkloadValidate(const TensorInfo& paramsInfo,
17 const TensorInfo& indicesInfo,
18 const TensorInfo& outputInfo)
19{
20 // Calculate ND, K, W, C.
21 std::map<std::string, unsigned int> keyIndices = CalculateGatherNdKeyIndices(paramsInfo, indicesInfo);
22
23 /// Validate Mul
24 // Indices with shape { W, ND }
25 armnn::TensorInfo indices_W_ND_Info = indicesInfo;
26 indices_W_ND_Info.SetShape({ keyIndices["W"], keyIndices["ND"] });
27 const arm_compute::TensorInfo aclIndicesInfo = BuildArmComputeTensorInfo(indices_W_ND_Info);
28
29 // Flattened coefficients with shape { ND }
30 armnn::TensorInfo flattenedCoeff_Info = indicesInfo;
31 flattenedCoeff_Info.SetShape({ keyIndices["ND"] });
32 const arm_compute::TensorInfo aclFlattenedCoeffInfo = BuildArmComputeTensorInfo(flattenedCoeff_Info);
33
34 // Output of Mul with shape { W, ND }
35 const arm_compute::TensorInfo aclOutputMulInfo = BuildArmComputeTensorInfo(indices_W_ND_Info);
36
37 auto statusMul = arm_compute::CLPixelWiseMultiplication::validate(&aclIndicesInfo,
38 &aclFlattenedCoeffInfo,
39 &aclOutputMulInfo,
40 1.0f,
41 arm_compute::ConvertPolicy::WRAP,
42 arm_compute::RoundingPolicy::TO_ZERO,
43 arm_compute::ActivationLayerInfo());
44
45 /// Validate ReduceSum
46 // Flattened indices with shape { W }
47 armnn::TensorInfo flattenedIndices_Info = indicesInfo;
48 flattenedIndices_Info.SetShape({ keyIndices["W"] });
49 const arm_compute::TensorInfo aclFlattenedIndicesInfo = BuildArmComputeTensorInfo(flattenedIndices_Info);
50
51 const std::vector<unsigned int> armnnReduceAxes(1, 1);
52 arm_compute::Coordinates coords = BuildArmComputeReductionCoordinates(aclOutputMulInfo.num_dimensions(),
53 indices_W_ND_Info.GetNumDimensions(),
54 armnnReduceAxes);
55
56 auto statusReduceSum = arm_compute::CLReductionOperation::validate(&aclOutputMulInfo,
57 &aclFlattenedIndicesInfo,
58 static_cast<unsigned int>(coords[0]),
59 arm_compute::ReductionOperation::SUM,
60 false);
61
62 /// Validate Gather
63 // Params with shape { K, C }
64 armnn::TensorInfo params_K_C_Info = paramsInfo;
65 params_K_C_Info.SetShape({ keyIndices["K"], keyIndices["C"] });
66 const arm_compute::TensorInfo aclParamsInfo = BuildArmComputeTensorInfo(params_K_C_Info);
67
68 // Output of gather with shape { W, C }
69 armnn::TensorInfo outputGather_Info = outputInfo;
70 outputGather_Info.SetShape({ keyIndices["W"], keyIndices["C"] });
71 const arm_compute::TensorInfo aclOutputGatherInfo = BuildArmComputeTensorInfo(outputGather_Info);
72
73 auto aclAxis = ComputeAclAxis(0, params_K_C_Info);
74 auto statusGather =
75 arm_compute::CLGather::validate(&aclParamsInfo, &aclFlattenedIndicesInfo, &aclOutputGatherInfo, aclAxis);
76
77 /// Validate Reshape
78 const arm_compute::TensorInfo aclOutputInfo = BuildArmComputeTensorInfo(outputInfo);
79 const arm_compute::TensorInfo aclParamsOriginalShapeInfo = BuildArmComputeTensorInfo(paramsInfo);
80 const arm_compute::TensorInfo aclIndicesOriginalShapeInfo = BuildArmComputeTensorInfo(indicesInfo);
81 const arm_compute::TensorInfo aclParamsReshapeInfo = BuildArmComputeTensorInfo(paramsInfo);
82 const arm_compute::TensorInfo aclIndicesReshapeInfo = BuildArmComputeTensorInfo(indicesInfo);
83
84 auto statusOutputReshape = arm_compute::CLReshapeLayer::validate(&aclOutputGatherInfo, &aclOutputInfo);
85 auto statusParamsReshape = arm_compute::CLReshapeLayer::validate(&aclParamsOriginalShapeInfo,
86 &aclParamsReshapeInfo);
87 auto statusIndicesReshape = arm_compute::CLReshapeLayer::validate(&aclIndicesOriginalShapeInfo,
88 &aclIndicesReshapeInfo);
89
90 /// Return OK if all the layers are valid
91 auto okCode = arm_compute::ErrorCode::OK;
92 if (statusMul.error_code() == okCode &&
93 statusReduceSum.error_code() == okCode &&
94 statusGather.error_code() == okCode &&
95 statusParamsReshape.error_code() == okCode &&
96 statusIndicesReshape.error_code() == okCode &&
97 statusOutputReshape.error_code() == okCode)
98 {
99 return arm_compute::Status(arm_compute::ErrorCode::OK,
100 "All GatherND layers validate status OK.");
101 }
102 else
103 {
104 return arm_compute::Status(arm_compute::ErrorCode::RUNTIME_ERROR,
105 "GatherND layer validate status failed.");
106 }
107}
108
110 const WorkloadInfo& info,
111 const arm_compute::CLCompileContext& clCompileContext)
113{
114 m_Data.ValidateInputsOutputs("ClGatherNdWorkload", 2, 1);
115
116 TensorInfo paramsInfo = info.m_InputTensorInfos[0];
117 TensorInfo indicesInfo = info.m_InputTensorInfos[1];
118 TensorInfo outputInfo = info.m_OutputTensorInfos[0];
119
120 arm_compute::ICLTensor& input = static_cast<IClTensorHandle*>(m_Data.m_Inputs[0])->GetTensor();
121 arm_compute::ICLTensor& indices = static_cast<IClTensorHandle*>(m_Data.m_Inputs[1])->GetTensor();
122 arm_compute::ICLTensor& output = static_cast<IClTensorHandle*>(m_Data.m_Outputs[0])->GetTensor();
123
124 // Calculate ND, K, W, C.
125 std::map<std::string, unsigned int> keyIndices = CalculateGatherNdKeyIndices(paramsInfo, indicesInfo);
126
127 /// Calculate flattened indices: m_FlattenedIndices = indices * m_FlattenedCoeff.
128 /// This could be done using MatMul instead of multiplication followed by reduce sum operation,
129 /// but GeMM does not support s32 at the moment.
130
131 // Prepare the tensor to store the output of the reduce_sum operation
132 armnn::TensorInfo flattenedIndices_Info = indicesInfo;
133 flattenedIndices_Info.SetShape({ keyIndices["W"] });
134 BuildArmComputeTensor(m_FlattenedIndices, flattenedIndices_Info);
135 armcomputetensorutils::InitialiseArmComputeTensorEmpty(m_FlattenedIndices);
136
137 // Reshape indices into { W, ND }
138 armnn::TensorInfo indicesInfoReshape = indicesInfo;
139 indicesInfoReshape.SetShape({ keyIndices["W"], keyIndices["ND"] });
140 BuildArmComputeTensor(m_IndicesReshaped, indicesInfoReshape);
141 armcomputetensorutils::InitialiseArmComputeTensorEmpty(m_IndicesReshaped);
142
143 // Calculate the m_FlattenedCoeff
144 TensorShape paramsShape = paramsInfo.GetShape();
145 std::vector<int32_t> flattenedCoeff(keyIndices["ND"], 1);
146 for (unsigned int i = 1; i < keyIndices["ND"]; ++i)
147 {
148 flattenedCoeff[i - 1] = static_cast<int32_t>(paramsShape[i]);
149 }
150 for (unsigned int i = keyIndices["ND"] - 1; i > 0; --i)
151 {
152 flattenedCoeff[i - 1] *= flattenedCoeff[i];
153 }
154 armnn::TensorInfo flattenedCoeff_Info = indicesInfo;
155 flattenedCoeff_Info.SetShape({ keyIndices["ND"] });
156 BuildArmComputeTensor(m_FlattenedCoeff, flattenedCoeff_Info);
157 armcomputetensorutils::InitialiseArmComputeTensorEmpty(m_FlattenedCoeff);
158 CopyArmComputeClTensorData<int32_t>(m_FlattenedCoeff, flattenedCoeff.data());
159
160 // Prepare the tensor to store the output of the multiplication
161 armnn::TensorInfo outputMul_Info = indicesInfo;
162 outputMul_Info.SetShape({ keyIndices["W"], keyIndices["ND"] });
163 BuildArmComputeTensor(m_OutputMul, outputMul_Info);
164 armcomputetensorutils::InitialiseArmComputeTensorEmpty(m_OutputMul);
165
166 // Reshape indices to the mul layer input shape
167 m_ReshapeIndicesLayer.configure(&indices, &m_IndicesReshaped);
168
169 // Multiply
170 m_MulLayer.configure(clCompileContext,
171 &m_IndicesReshaped,
172 &m_FlattenedCoeff,
173 &m_OutputMul,
174 1.0f,
175 arm_compute::ConvertPolicy::WRAP,
176 arm_compute::RoundingPolicy::TO_ZERO,
177 arm_compute::ActivationLayerInfo());
178
179 // Reduce Sum
180 const std::vector<unsigned int> armnnReduceAxes(1, 1);
181 arm_compute::Coordinates coords = BuildArmComputeReductionCoordinates(m_OutputMul.info()->num_dimensions(),
182 outputMul_Info.GetNumDimensions(),
183 armnnReduceAxes);
184 m_ReduceSumLayer.configure(clCompileContext,
185 &m_OutputMul,
186 &m_FlattenedIndices,
187 static_cast<unsigned int>(coords[0]),
188 arm_compute::ReductionOperation::SUM,
189 false);
190
191 /// Call Gather with adequate shapes
192 // Reshape params into { K, C }
193 armnn::TensorInfo paramsInfoReshape = paramsInfo;
194 paramsInfoReshape.SetShape({ keyIndices["K"], keyIndices["C"] });
195 BuildArmComputeTensor(m_InputGather, paramsInfoReshape);
196 armcomputetensorutils::InitialiseArmComputeTensorEmpty(m_InputGather);
197
198 // Reshape input to the gather params input shape
199 m_ReshapeInputLayer.configure(&input, &m_InputGather);
200
201 // Reshape output to have the shape given by gather { W, C }
202 // (the original outputInfo has the shape given by gatherNd)
203 armnn::TensorInfo outputGather_Info = outputInfo;
204 outputGather_Info.SetShape({ keyIndices["W"], keyIndices["C"] });
205 BuildArmComputeTensor(m_OutputGather, outputGather_Info);
206 armcomputetensorutils::InitialiseArmComputeTensorEmpty(m_OutputGather);
207 {
208 ARMNN_SCOPED_PROFILING_EVENT_CL_NAME_GUID("ClGatherNdWorkload_configure");
209 auto aclAxis = ComputeAclAxis(0, paramsInfoReshape);
210 m_GatherLayer.configure(clCompileContext, &m_InputGather, &m_FlattenedIndices, &m_OutputGather, aclAxis);
211 }
212
213 // Reshape output to the original output shape
214 m_ReshapeOutputLayer.configure(clCompileContext, &m_OutputGather, &output);
215};
216
218{
219 ARMNN_SCOPED_PROFILING_EVENT_CL_NAME_GUID("ClGatherNdWorkload_Execute");
220 RunClFunction(m_ReshapeInputLayer, CHECK_LOCATION());
221 RunClFunction(m_ReshapeIndicesLayer, CHECK_LOCATION());
222 RunClFunction(m_MulLayer, CHECK_LOCATION());
223 RunClFunction(m_ReduceSumLayer, CHECK_LOCATION());
224 RunClFunction(m_GatherLayer, CHECK_LOCATION());
225 RunClFunction(m_ReshapeOutputLayer, CHECK_LOCATION());
226}
227} // namespace armnn
#define ARMNN_SCOPED_PROFILING_EVENT_CL_NAME_GUID(label)
Creates a profiling event that uses GetGuid() and GetName() from the calling class.
#define CHECK_LOCATION()
ClBaseWorkload(const GatherNdQueueDescriptor &descriptor, const WorkloadInfo &info)
ClGatherNdWorkload(const GatherNdQueueDescriptor &descriptor, const WorkloadInfo &info, const arm_compute::CLCompileContext &clCompileContext)
virtual void Execute() const override
virtual arm_compute::ICLTensor & GetTensor()=0
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,...
void RunClFunction(arm_compute::IFunction &function, const CheckLocation &location)
void CopyArmComputeClTensorData(arm_compute::CLTensor &dstTensor, const T *srcData)
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 ClGatherNdWorkloadValidate(const TensorInfo &paramsInfo, const TensorInfo &indicesInfo, const TensorInfo &outputInfo)
Contains information about TensorInfos of a layer.