ArmNN
 25.02
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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 
6 #include "ClGatherNdWorkload.hpp"
7 #include "ClWorkloadUtils.hpp"
10 #include <cl/ClTensorHandle.hpp>
11 
12 using namespace armnn::armcomputetensorutils;
13 
14 namespace armnn
15 {
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()
Definition: Exceptions.hpp:203
QueueDescriptor m_Data
Definition: Workload.hpp:74
ClGatherNdWorkload(const GatherNdQueueDescriptor &descriptor, const WorkloadInfo &info, const arm_compute::CLCompileContext &clCompileContext)
virtual void Execute() const override
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 ClGatherNdWorkloadValidate(const TensorInfo &paramsInfo, const TensorInfo &indicesInfo, const TensorInfo &outputInfo)
void RunClFunction(arm_compute::IFunction &function, const CheckLocation &location)
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.