ArmNN
 25.11
Loading...
Searching...
No Matches
ArmComputeUtils.hpp
Go to the documentation of this file.
1//
2// Copyright © 2017-2024 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5#pragma once
6
9#include <armnn/Tensor.hpp>
13
14#include <arm_compute/runtime/FunctionDescriptors.h>
15#include <arm_compute/function_info/FullyConnectedLayerInfo.h>
16
17#if defined(ARMCOMPUTENEON_ENABLED)
19#endif
20
21#if defined(ARMCOMPUTECL_ENABLED)
23#endif
24
25namespace armnn
26{
27
28inline arm_compute::NormalizationLayerInfo
30 armnn::DataLayout dataLayout)
31{
32 unsigned int depthDimension = dataLayout == armnn::DataLayout::NCHW ? 1 : 3;
33 const unsigned int depth = tensorInfo.GetShape()[depthDimension];
34
35 // At the time of writing, {CL|Neon}L2Normalization performs the reduction only along dimension 0. This version of
36 // L2 Normalization always performs the reduction along the depth axis, though. Thus, we repurpose
37 // {CL|Neon}NormalizationLayers to act as depthwise L2 normalizations by carefully chosing the normalization
38 // parameters.
39 //
40 // Please refer to both the reference implementation of the normalization layer and the implementation of
41 // {CL|Neon}NormalizationLayer when checking the derivations for the parameter values below.
42
43 // Make sure normalization covers the entire depth range. ACL requires the normalization size to be odd.
44 // CL: This does not result in extra kernel threads not doing any work: See usage of the RADIUS parameter in
45 // ACL's normalization_layer_cross_map() CL function.
46 const uint32_t normSize = depth * 2u + 1u;
47
48 // See ACL's NormalizationLayerInfo::scale_coeff() definition.
49 // For the reference implementation, to make alpha_ become 1, we'd have to use alpha = normSize instead.
50 const float alpha = 1.0f;
51
52 // Don't offset the reduction.
53 const float kappa = 0.0f;
54
55 // pow(reduction, -0.5) = 1 / sqrt(reduction)
56 const float beta = 0.5f;
57
58 return arm_compute::NormalizationLayerInfo(arm_compute::NormType::CROSS_MAP, normSize, alpha, beta, kappa, false);
59}
60
61inline arm_compute::ActivationLayerInfo::ActivationFunction
63{
64 using AclActivationFunction = arm_compute::ActivationLayerInfo::ActivationFunction;
65
66 switch (armnnFunction)
67 {
68 case ActivationFunction::Linear: return AclActivationFunction::LINEAR;
69 // Arm compute's 'logistic' function is non-parameterized, so it is exactly a sigmoid function.
70 case ActivationFunction::Sigmoid: return AclActivationFunction::LOGISTIC;
71 case ActivationFunction::ReLu: return AclActivationFunction::RELU;
72 case ActivationFunction::BoundedReLu: return AclActivationFunction::LU_BOUNDED_RELU;
73 case ActivationFunction::SoftReLu: return AclActivationFunction::SOFT_RELU;
74 case ActivationFunction::LeakyReLu: return AclActivationFunction::LEAKY_RELU;
75 case ActivationFunction::Abs: return AclActivationFunction::ABS;
76 case ActivationFunction::Sqrt: return AclActivationFunction::SQRT;
77 case ActivationFunction::Square: return AclActivationFunction::SQUARE;
78 case ActivationFunction::TanH: return AclActivationFunction::TANH;
79 case ActivationFunction::Elu: return AclActivationFunction::ELU;
80 case ActivationFunction::HardSwish: return AclActivationFunction::HARD_SWISH;
81 case ActivationFunction::Gelu: return AclActivationFunction::GELU;
82 default: throw InvalidArgumentException("Unsupported activation function");
83 }
84}
85
86inline arm_compute::ActivationLayerInfo
88{
89 return arm_compute::ActivationLayerInfo(ConvertActivationFunctionToAclActivationFunction(actDesc.m_Function),
90 actDesc.m_A, actDesc.m_B);
91}
92
93inline arm_compute::ActivationLayerInfo
95{
96 if (activationDescPtr != nullptr)
97 {
99 *activationDescPtr));
100 }
101 return arm_compute::ActivationLayerInfo();
102}
103
104inline arm_compute::ActivationLayerInfo
106{
107 const ActivationDescriptor* activationDescPtr = queueDescriptor.GetAdditionalInformation<ActivationDescriptor>();
108
109 if (activationDescPtr != nullptr)
110 {
112 *activationDescPtr));
113 }
114 return arm_compute::ActivationLayerInfo();
115}
116
117inline arm_compute::ActivationLayerInfo
118ConvertLstmActivationFuncToAclLayerInfo(uint32_t activationFunction)
119{
120 // For preparing the object for the class ActivationLayerInfo, we need to consider 5 situations.
121 switch (activationFunction)
122 {
123 case 0:
124 return arm_compute::ActivationLayerInfo(); // no activation, do nothing
125 case 1:
126 return arm_compute::ActivationLayerInfo(arm_compute::ActivationLayerInfo::ActivationFunction::RELU);
127 case 3:
128 return arm_compute::ActivationLayerInfo(
129 arm_compute::ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 6.0);
130 case 4:
131 return arm_compute::ActivationLayerInfo(
132 arm_compute::ActivationLayerInfo::ActivationFunction::TANH, 1.0, 1.0);
133 case 6:
134 return arm_compute::ActivationLayerInfo(
135 arm_compute::ActivationLayerInfo::ActivationFunction::LOGISTIC);
136 default:
137 throw armnn::Exception("Wrong Type of Activation Function!");
138 }
139}
140
141inline arm_compute::ComparisonOperation ConvertComparisonOperationToAcl(const ComparisonDescriptor& descriptor)
142{
143 switch (descriptor.m_Operation)
144 {
145 case ComparisonOperation::Greater: return arm_compute::ComparisonOperation::Greater;
146 case ComparisonOperation::GreaterOrEqual: return arm_compute::ComparisonOperation::GreaterEqual;
147 case ComparisonOperation::Less: return arm_compute::ComparisonOperation::Less;
148 case ComparisonOperation::LessOrEqual: return arm_compute::ComparisonOperation::LessEqual;
149 case ComparisonOperation::Equal: return arm_compute::ComparisonOperation::Equal;
150 case ComparisonOperation::NotEqual: return arm_compute::ComparisonOperation::NotEqual;
151 default: throw InvalidArgumentException("Unsupported comparison function");
152 }
153}
154
155inline arm_compute::PoolingType ConvertPoolingAlgorithmToAclPoolingType(PoolingAlgorithm poolingAlgorithm)
156{
157 using arm_compute::PoolingType;
158
159 switch (poolingAlgorithm)
160 {
161 case PoolingAlgorithm::Max: return PoolingType::MAX;
162 case PoolingAlgorithm::Average: return PoolingType::AVG;
163 case PoolingAlgorithm::L2: return PoolingType::L2;
164 default: throw InvalidArgumentException("Unsupported pooling algorithm");
165 }
166}
167
169 rounding)
170{
171 using arm_compute::DimensionRoundingType;
172
173 switch (rounding)
174 {
175 case OutputShapeRounding::Ceiling: return DimensionRoundingType::CEIL;
176 case OutputShapeRounding::Floor: return DimensionRoundingType::FLOOR;
177 default: throw InvalidArgumentException("Unsupported Output Shape Rounding type");
178 }
179}
180
181inline arm_compute::NormType
183{
184 using arm_compute::NormType;
185 switch (channelType)
186 {
187 case NormalizationAlgorithmChannel::Across: return NormType::CROSS_MAP;
188 case NormalizationAlgorithmChannel::Within: return NormType::IN_MAP_2D;
189 default: throw InvalidArgumentException("Unsupported normalization algorithm channel type");
190 }
191}
192
193inline arm_compute::FullyConnectedLayerInfo
195 const ActivationDescriptor* activationDesc)
196{
197 arm_compute::FullyConnectedLayerInfo fc_info;
198 fc_info.transpose_weights = fullyConnectedDesc.m_TransposeWeightMatrix;
199 fc_info.activation_info = ConvertActivationDescriptorToAclActivationLayerInfo(activationDesc);
200 return fc_info;
201}
202
203inline arm_compute::FullyConnectedLayerInfo
205 arm_compute::ActivationLayerInfo activationLayerInfo)
206{
207 arm_compute::FullyConnectedLayerInfo fc_info;
208 fc_info.transpose_weights = fullyConnectedDesc.m_TransposeWeightMatrix;
209 fc_info.activation_info = activationLayerInfo;
210 return fc_info;
211}
212
213inline arm_compute::InterpolationPolicy ConvertResizeMethodToAclInterpolationPolicy(ResizeMethod resizeMethod)
214{
215 switch (resizeMethod)
216 {
218 return arm_compute::InterpolationPolicy::BILINEAR;
220 return arm_compute::InterpolationPolicy::NEAREST_NEIGHBOR;
221 default:
222 throw InvalidArgumentException("Unsupported resize method");
223 }
224}
225
226template<typename T>
227inline T ComputeSoftmaxAclAxis(const SoftmaxDescriptor& softmaxDesc, const armnn::TensorInfo& tensor)
228{
229 // Detect the Android default value of -1 and return the ACL default value of 0.
230 if (softmaxDesc.m_Axis == -1)
231 {
232 return 0;
233 }
234
235 unsigned int dim = tensor.GetNumDimensions();
236 ARMNN_THROW_INVALIDARG_MSG_IF_FALSE(dim != 0, "The number of dimensions in this tensor cannot be zero.");
237
238 // Currently ArmNN support axis 1.
239 auto aclAxis = (static_cast<T>(dim) - 1);
240 aclAxis = aclAxis > 0 ? aclAxis -1 : aclAxis;
241
242 return aclAxis;
243}
244
245/// Function to convert ArmNN axis (left to right) to ACL axis (right to left) ranging from [-rank, rank)
246inline int ComputeAclAxis(const int& armnnAxis, const armnn::TensorInfo& tensor)
247{
248 int rank = static_cast<int>(tensor.GetNumDimensions());
249
250 ARMNN_THROW_INVALIDARG_MSG_IF_FALSE(rank != 0, "The number of dimensions in this tensor cannot be zero.");
251 ARMNN_THROW_INVALIDARG_MSG_IF_FALSE(armnnAxis < rank, "Incompatible value of armnnAxis.");
252 ARMNN_THROW_INVALIDARG_MSG_IF_FALSE((-1 * rank) <= armnnAxis, "Incompatible value of armnnAxis.");
253
254 int sign = (armnnAxis < 0) ? -1 : 1;
255 int aclAxis = sign * rank - 1 - armnnAxis;
256
257 return aclAxis;
258}
259
260/// Utility function used to setup an arm_compute::Conv3dInfo object from convolution3d descriptor.
261inline arm_compute::Conv3dInfo ComputeConv3DInfo(const armnn::Convolution3dDescriptor descriptor,
262 bool isFastMathEnabled,
263 const ActivationDescriptor* activationDescriptor)
264{
265 const arm_compute::Size3D stride{descriptor.m_StrideX, descriptor.m_StrideY, descriptor.m_StrideZ};
266 const arm_compute::Padding3D padding{descriptor.m_PadLeft, descriptor.m_PadRight,
267 descriptor.m_PadTop, descriptor.m_PadBottom,
268 descriptor.m_PadFront, descriptor.m_PadBack};
269 const arm_compute::Size3D dilation{descriptor.m_DilationX, descriptor.m_DilationY, descriptor.m_DilationZ};
270
271 const arm_compute::ActivationLayerInfo activationInfo =
273 const auto roundType = arm_compute::DimensionRoundingType::FLOOR;
274
275 return arm_compute::Conv3dInfo{stride, padding, activationInfo, dilation, roundType, isFastMathEnabled};
276}
277
278inline arm_compute::Conv3dInfo ComputeConv3DInfo(const armnn::Convolution3dQueueDescriptor queueDescriptor,
279 bool isFastMathEnabled)
280{
281 auto descriptor = queueDescriptor.m_Parameters;
282 const arm_compute::Size3D stride{descriptor.m_StrideX, descriptor.m_StrideY, descriptor.m_StrideZ};
283 const arm_compute::Padding3D padding{descriptor.m_PadLeft, descriptor.m_PadRight,
284 descriptor.m_PadTop, descriptor.m_PadBottom,
285 descriptor.m_PadFront, descriptor.m_PadBack};
286 const arm_compute::Size3D dilation{descriptor.m_DilationX, descriptor.m_DilationY, descriptor.m_DilationZ};
287
288 const arm_compute::ActivationLayerInfo activationInfo =
290 const auto roundType = arm_compute::DimensionRoundingType::FLOOR;
291
292 return arm_compute::Conv3dInfo{stride, padding, activationInfo, dilation, roundType, isFastMathEnabled};
293}
294
295inline arm_compute::PaddingMode ConvertPaddingModeToAcl(const PaddingMode& paddingMode)
296{
297 switch (paddingMode)
298 {
299 case PaddingMode::Constant: return arm_compute::PaddingMode::CONSTANT;
300 case PaddingMode::Reflect: return arm_compute::PaddingMode::REFLECT;
301 case PaddingMode::Symmetric: return arm_compute::PaddingMode::SYMMETRIC;
302 default: throw InvalidArgumentException("Unsupported Padding Mode");
303 }
304}
305
306inline arm_compute::ReductionOperation ConvertReductionOperationToAcl(const ReduceDescriptor& descriptor)
307{
308 switch (descriptor.m_ReduceOperation)
309 {
310 case ReduceOperation::Sum: return arm_compute::ReductionOperation::SUM;
311 case ReduceOperation::Mean: return arm_compute::ReductionOperation::MEAN_SUM;
312 case ReduceOperation::Max: return arm_compute::ReductionOperation::MAX;
313 case ReduceOperation::Min: return arm_compute::ReductionOperation::MIN;
314 case ReduceOperation::Prod: return arm_compute::ReductionOperation::PROD;
315 default: throw InvalidArgumentException("Unsupported Reduction operation");
316 }
317}
318
319/// Function to compute the output tensor shape based on the axes and if keepDims is set.
321 const std::vector<uint32_t>& vAxis,
322 const bool keepDims)
323{
324 auto reducedTensorInfo = input;
325 unsigned int rank = reducedTensorInfo.GetNumDimensions();
326 unsigned int outputRank = 0;
327 // Calculate output dimension
328 if (keepDims)
329 {
330 outputRank = rank;
331 }
332 else if (vAxis.empty())
333 {
334 outputRank = 1;
335 }
336 else if (vAxis.size() > reducedTensorInfo.GetNumDimensions())
337 {
338 throw LayerValidationException("ReduceLayer: Dimensions to reduce can not be bigger than input dimensions");
339 }
340 else
341 {
342 outputRank = reducedTensorInfo.GetNumDimensions() - armnn::numeric_cast<unsigned int>(vAxis.size());
343 if (outputRank == 0)
344 {
345 outputRank = 1;
346 }
347 }
348 std::vector<unsigned int> dimSizes(outputRank, 1);
349 if (!vAxis.empty())
350 {
351 // Skip the dimension that has been reduced unless keepDims is true.
352 unsigned int outputIndex = 0;
353 for (unsigned int i = 0; i < reducedTensorInfo.GetNumDimensions(); ++i)
354 {
355 if (std::find(vAxis.begin(), vAxis.end(), i) == vAxis.end())
356 {
357 dimSizes[outputIndex] = armnn::numeric_cast<unsigned int>(reducedTensorInfo.GetShape()[i]);
358 ++outputIndex;
359 }
360 else if (keepDims)
361 {
362 dimSizes[outputIndex] = 1;
363 ++outputIndex;
364 }
365 }
366 }
367 const TensorShape inferredShape = TensorShape(outputRank, dimSizes.data());
368 reducedTensorInfo.SetShape(inferredShape);
369 return reducedTensorInfo;
370}
371
372/// Function pointer type used in IsMultiAxesReduceSupported for readability
373using reduceValidateFunction = arm_compute::Status (*)(const armnn::TensorInfo&,
374 const armnn::TensorInfo&,
376
377/// Function to check if layer with multiple axes is supported on each backend
379 const armnn::TensorInfo& input,
380 const armnn::TensorInfo& output,
381 const armnn::ReduceDescriptor& desc,
382 arm_compute::Status& status)
383{
384 armnn::TensorInfo inputTensorInfo = input;
385 unsigned int recalulatedAxis = 0;
386 std::vector<uint32_t> axes;
387 axes.reserve(desc.m_vAxis.size());
388
389 for (unsigned int i = 0; i != desc.m_vAxis.size(); ++i)
390 {
391 axes.emplace_back(desc.m_vAxis[i]);
392
393 // Getting next reduced tensor shape
394 armnn::TensorInfo reducedTensorInfo =
395 ComputeReductionTensorShape(input, axes, desc.m_KeepDims);
396
397 // If the next reduced tensor shape is the output, set the corresponding quantization
398 if(reducedTensorInfo.GetShape() == output.GetShape())
399 {
401 {
402 reducedTensorInfo.SetQuantizationScales(output.GetQuantizationScales());
403 }
404 else
405 {
406 reducedTensorInfo.SetQuantizationScale(output.GetQuantizationScale());
407 }
408 reducedTensorInfo.SetQuantizationOffset(output.GetQuantizationOffset());
409 }
410
411 std::vector<uint32_t> singleAxis(1, desc.m_vAxis[i] - recalulatedAxis);
412
413 armnn::ReduceDescriptor newReduceDescriptor = desc;
414 newReduceDescriptor.m_vAxis.assign(singleAxis.begin(), singleAxis.end());
415
416 status = func(inputTensorInfo, reducedTensorInfo, newReduceDescriptor);
417 if (!status)
418 {
419 break;
420 }
421
422 if (!desc.m_KeepDims)
423 {
424 recalulatedAxis++;
425 }
426
427 inputTensorInfo = reducedTensorInfo;
428 }
429}
430
431} // namespace armnn
#define ARMNN_THROW_INVALIDARG_MSG_IF_FALSE(_cond, _str)
Base class for all ArmNN exceptions so that users can filter to just those.
float GetQuantizationScale() const
Definition Tensor.cpp:461
const TensorShape & GetShape() const
Definition Tensor.hpp:193
unsigned int GetNumDimensions() const
Definition Tensor.hpp:197
void SetQuantizationScales(const std::vector< float > &scales)
Definition Tensor.cpp:456
void SetQuantizationOffset(int32_t offset)
Definition Tensor.cpp:493
void SetQuantizationScale(float scale)
Definition Tensor.cpp:477
int32_t GetQuantizationOffset() const
Definition Tensor.cpp:482
std::vector< float > GetQuantizationScales() const
Definition Tensor.cpp:451
bool HasMultipleQuantizationScales() const
Definition Tensor.hpp:203
Copyright (c) 2021 ARM Limited and Contributors.
const TensorInfo ComputeReductionTensorShape(const armnn::TensorInfo &input, const std::vector< uint32_t > &vAxis, const bool keepDims)
Function to compute the output tensor shape based on the axes and if keepDims is set.
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,...
PaddingMode
The padding mode controls whether the padding should be filled with constant values (Constant),...
Definition Types.hpp:202
arm_compute::PoolingType ConvertPoolingAlgorithmToAclPoolingType(PoolingAlgorithm poolingAlgorithm)
arm_compute::NormalizationLayerInfo CreateAclNormalizationLayerInfoForL2Normalization(const armnn::TensorInfo &tensorInfo, armnn::DataLayout dataLayout)
arm_compute::Conv3dInfo ComputeConv3DInfo(const armnn::Convolution3dDescriptor descriptor, bool isFastMathEnabled, const ActivationDescriptor *activationDescriptor)
Utility function used to setup an arm_compute::Conv3dInfo object from convolution3d descriptor.
T ComputeSoftmaxAclAxis(const SoftmaxDescriptor &softmaxDesc, const armnn::TensorInfo &tensor)
ActivationFunction
Definition Types.hpp:87
@ BoundedReLu
min(a, max(b, input)) ReLu1 & ReLu6.
Definition Types.hpp:92
arm_compute::DimensionRoundingType ConvertOutputShapeRoundingToAclDimensionRoundingType(OutputShapeRounding rounding)
arm_compute::ActivationLayerInfo ConvertAdditionalInfoToAclActivationLayerInfo(const QueueDescriptor &queueDescriptor)
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
arm_compute::NormType ConvertNormalizationAlgorithmChannelToAclNormType(NormalizationAlgorithmChannel channelType)
arm_compute::InterpolationPolicy ConvertResizeMethodToAclInterpolationPolicy(ResizeMethod resizeMethod)
PoolingAlgorithm
Definition Types.hpp:152
ResizeMethod
Definition Types.hpp:168
arm_compute::ComparisonOperation ConvertComparisonOperationToAcl(const ComparisonDescriptor &descriptor)
arm_compute::ActivationLayerInfo ConvertLstmActivationFuncToAclLayerInfo(uint32_t activationFunction)
void IsMultiAxesReduceSupported(reduceValidateFunction func, const armnn::TensorInfo &input, const armnn::TensorInfo &output, const armnn::ReduceDescriptor &desc, arm_compute::Status &status)
Function to check if layer with multiple axes is supported on each backend.
arm_compute::PaddingMode ConvertPaddingModeToAcl(const PaddingMode &paddingMode)
NormalizationAlgorithmChannel
Definition Types.hpp:209
arm_compute::ActivationLayerInfo::ActivationFunction ConvertActivationFunctionToAclActivationFunction(ActivationFunction armnnFunction)
arm_compute::ActivationLayerInfo ConvertActivationDescriptorToAclActivationLayerInfo(const ActivationDescriptor &actDesc)
DataLayout
Definition Types.hpp:63
arm_compute::ReductionOperation ConvertReductionOperationToAcl(const ReduceDescriptor &descriptor)
arm_compute::FullyConnectedLayerInfo ConvertFullyConnectedDescriptorToAclFullyConnectedLayerInfo(const FullyConnectedDescriptor &fullyConnectedDesc, const ActivationDescriptor *activationDesc)
OutputShapeRounding
Definition Types.hpp:223
arm_compute::Status(*)(const armnn::TensorInfo &, const armnn::TensorInfo &, const armnn::ReduceDescriptor &) reduceValidateFunction
Function pointer type used in IsMultiAxesReduceSupported for readability.
An ActivationDescriptor for the ActivationLayer.
float m_A
Alpha upper bound value used by the activation functions. (BoundedReLu, Linear, TanH,...
float m_B
Beta lower bound value used by the activation functions. (BoundedReLu, Linear, TanH).
ActivationFunction m_Function
The activation function to use (Sigmoid, TanH, Linear, ReLu, BoundedReLu, SoftReLu,...
A ComparisonDescriptor for the ComparisonLayer.
ComparisonOperation m_Operation
Specifies the comparison operation to execute.
A Convolution3dDescriptor for the Convolution3dLayer.
uint32_t m_PadRight
Padding right value in the width dimension.
uint32_t m_PadBack
Padding back value in the depth dimension.
uint32_t m_DilationZ
Dilation along z axis.
uint32_t m_DilationY
Dilation along y axis.
uint32_t m_StrideZ
Stride value when proceeding through input for the depth dimension.
uint32_t m_PadTop
Padding top value in the height dimension.
uint32_t m_PadFront
Padding front value in the depth dimension.
uint32_t m_DilationX
Dilation along x axis.
uint32_t m_PadBottom
Padding bottom value in the height dimension.
uint32_t m_PadLeft
Padding left value in the width dimension.
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
A FullyConnectedDescriptor for the FullyConnectedLayer.
bool m_TransposeWeightMatrix
Enable/disable transpose weight matrix.
const T * GetAdditionalInformation() const
A ReduceDescriptor for the REDUCE operators.
bool m_KeepDims
if true then output shape has no change.
std::vector< uint32_t > m_vAxis
The indices of the dimensions to reduce.
ReduceOperation m_ReduceOperation
Specifies the reduction operation to execute.
A SoftmaxDescriptor for the SoftmaxLayer.
int m_Axis
Scalar, defaulted to the last index (-1), specifying the dimension the activation will be performed o...