blob: 2a0707872e393dafb41253615d843ae2b6b73e99 [file] [log] [blame]
telsoa014fcda012018-03-09 14:13:49 +00001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
David Beckecb56cd2018-09-05 12:52:57 +01003// SPDX-License-Identifier: MIT
telsoa014fcda012018-03-09 14:13:49 +00004//
5#pragma once
6
telsoa014fcda012018-03-09 14:13:49 +00007#include <armnn/Descriptors.hpp>
Aron Virginas-Tar5c3e9232018-11-16 11:00:48 +00008#include <armnn/Tensor.hpp>
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01009#include <armnn/utility/Assert.hpp>
Mike Kelly0d4ed392020-11-13 15:26:41 +000010#include <backendsCommon/WorkloadData.hpp>
telsoa014fcda012018-03-09 14:13:49 +000011
12#include <arm_compute/core/Types.h>
13
14namespace armnn
15{
16
17inline arm_compute::NormalizationLayerInfo
Matteo Martincigh539b44d2018-10-01 09:26:39 +010018CreateAclNormalizationLayerInfoForL2Normalization(const armnn::TensorInfo& tensorInfo,
19 armnn::DataLayout dataLayout)
telsoa014fcda012018-03-09 14:13:49 +000020{
Matteo Martincigh539b44d2018-10-01 09:26:39 +010021 unsigned int depthDimension = dataLayout == armnn::DataLayout::NCHW ? 1 : 3;
22 const unsigned int depth = tensorInfo.GetShape()[depthDimension];
telsoa014fcda012018-03-09 14:13:49 +000023
24 // At the time of writing, {CL|Neon}L2Normalization performs the reduction only along dimension 0. This version of
25 // L2 Normalization always performs the reduction along the depth axis, though. Thus, we repurpose
26 // {CL|Neon}NormalizationLayers to act as depthwise L2 normalizations by carefully chosing the normalization
27 // parameters.
28 //
29 // Please refer to both the reference implementation of the normalization layer and the implementation of
30 // {CL|Neon}NormalizationLayer when checking the derivations for the parameter values below.
31
32 // Make sure normalization covers the entire depth range. ACL requires the normalization size to be odd.
33 // CL: This does not result in extra kernel threads not doing any work: See usage of the RADIUS parameter in
34 // ACL's normalization_layer_cross_map() CL function.
35 const uint32_t normSize = depth * 2u + 1u;
36
37 // See ACL's NormalizationLayerInfo::scale_coeff() definition.
38 // For the reference implementation, to make alpha_ become 1, we'd have to use alpha = normSize instead.
39 const float alpha = 1.0f;
40
telsoa01c577f2c2018-08-31 09:22:23 +010041 // Don't offset the reduction.
telsoa014fcda012018-03-09 14:13:49 +000042 const float kappa = 0.0f;
43
44 // pow(reduction, -0.5) = 1 / sqrt(reduction)
45 const float beta = 0.5f;
46
47 return arm_compute::NormalizationLayerInfo(arm_compute::NormType::CROSS_MAP, normSize, alpha, beta, kappa, false);
48}
49
50inline arm_compute::ActivationLayerInfo::ActivationFunction
51ConvertActivationFunctionToAclActivationFunction(ActivationFunction armnnFunction)
52{
53 using AclActivationFunction = arm_compute::ActivationLayerInfo::ActivationFunction;
54
55 switch (armnnFunction)
56 {
57 case ActivationFunction::Linear: return AclActivationFunction::LINEAR;
telsoa01c577f2c2018-08-31 09:22:23 +010058 // Arm compute's 'logistic' function is non-parameterized, so it is exactly a sigmoid function.
telsoa014fcda012018-03-09 14:13:49 +000059 case ActivationFunction::Sigmoid: return AclActivationFunction::LOGISTIC;
60 case ActivationFunction::ReLu: return AclActivationFunction::RELU;
61 case ActivationFunction::BoundedReLu: return AclActivationFunction::LU_BOUNDED_RELU;
62 case ActivationFunction::SoftReLu: return AclActivationFunction::SOFT_RELU;
63 case ActivationFunction::LeakyReLu: return AclActivationFunction::LEAKY_RELU;
64 case ActivationFunction::Abs: return AclActivationFunction::ABS;
65 case ActivationFunction::Sqrt: return AclActivationFunction::SQRT;
66 case ActivationFunction::Square: return AclActivationFunction::SQUARE;
67 case ActivationFunction::TanH: return AclActivationFunction::TANH;
David Monahan3b3c3812020-02-25 09:03:29 +000068 case ActivationFunction::Elu: return AclActivationFunction::ELU;
Jan Eilersa83af7b2020-03-18 15:58:11 +000069 case ActivationFunction::HardSwish: return AclActivationFunction::HARD_SWISH;
telsoa014fcda012018-03-09 14:13:49 +000070 default: throw InvalidArgumentException("Unsupported activation function");
71 }
72}
73
74inline arm_compute::ActivationLayerInfo
75ConvertActivationDescriptorToAclActivationLayerInfo(const ActivationDescriptor& actDesc)
76{
77 return arm_compute::ActivationLayerInfo(ConvertActivationFunctionToAclActivationFunction(actDesc.m_Function),
78 actDesc.m_A, actDesc.m_B);
79}
80
Mike Kelly07810fc2020-11-12 10:58:48 +000081inline arm_compute::ActivationLayerInfo
82ConvertActivationDescriptorToAclActivationLayerInfo(const ActivationDescriptor* activationDescPtr)
83{
84 if (activationDescPtr != nullptr)
85 {
86 return ConvertActivationDescriptorToAclActivationLayerInfo(static_cast<ActivationDescriptor>(
87 *activationDescPtr));
88 }
89 return arm_compute::ActivationLayerInfo();
90}
91
92inline arm_compute::ActivationLayerInfo
93ConvertAdditionalInfoToAclActivationLayerInfo(const QueueDescriptor& queueDescriptor)
94{
95 const ActivationDescriptor* activationDescPtr = queueDescriptor.GetAdditionalInformation<ActivationDescriptor>();
96
97 if (activationDescPtr != nullptr)
98 {
99 return ConvertActivationDescriptorToAclActivationLayerInfo(static_cast<ActivationDescriptor>(
100 *activationDescPtr));
101 }
102 return arm_compute::ActivationLayerInfo();
103}
104
Teresa Charlin2b030d92020-03-27 16:40:56 +0000105inline arm_compute::ComparisonOperation ConvertComparisonOperationToAcl(const ComparisonDescriptor& descriptor)
106{
107 switch (descriptor.m_Operation)
108 {
109 case ComparisonOperation::Greater: return arm_compute::ComparisonOperation::Greater;
110 case ComparisonOperation::GreaterOrEqual: return arm_compute::ComparisonOperation::GreaterEqual;
111 case ComparisonOperation::Less: return arm_compute::ComparisonOperation::Less;
112 case ComparisonOperation::LessOrEqual: return arm_compute::ComparisonOperation::LessEqual;
113 case ComparisonOperation::Equal: return arm_compute::ComparisonOperation::Equal;
114 case ComparisonOperation::NotEqual: return arm_compute::ComparisonOperation::NotEqual;
115 default: throw InvalidArgumentException("Unsupported comparison function");
116 }
117}
118
telsoa014fcda012018-03-09 14:13:49 +0000119inline arm_compute::PoolingType ConvertPoolingAlgorithmToAclPoolingType(PoolingAlgorithm poolingAlgorithm)
120{
121 using arm_compute::PoolingType;
122
123 switch (poolingAlgorithm)
124 {
125 case PoolingAlgorithm::Max: return PoolingType::MAX;
126 case PoolingAlgorithm::Average: return PoolingType::AVG;
127 case PoolingAlgorithm::L2: return PoolingType::L2;
128 default: throw InvalidArgumentException("Unsupported pooling algorithm");
129 }
130}
131
132inline arm_compute::DimensionRoundingType ConvertOutputShapeRoundingToAclDimensionRoundingType(OutputShapeRounding
133 rounding)
134{
135 using arm_compute::DimensionRoundingType;
136
137 switch (rounding)
138 {
139 case OutputShapeRounding::Ceiling: return DimensionRoundingType::CEIL;
140 case OutputShapeRounding::Floor: return DimensionRoundingType::FLOOR;
141 default: throw InvalidArgumentException("Unsupported Output Shape Rounding type");
142 }
143}
144
145inline arm_compute::NormType
146ConvertNormalizationAlgorithmChannelToAclNormType(NormalizationAlgorithmChannel channelType)
147{
148 using arm_compute::NormType;
149 switch (channelType)
150 {
151 case NormalizationAlgorithmChannel::Across: return NormType::CROSS_MAP;
152 case NormalizationAlgorithmChannel::Within: return NormType::IN_MAP_2D;
153 default: throw InvalidArgumentException("Unsupported normalization algorithm channel type");
154 }
155}
156
telsoa01c577f2c2018-08-31 09:22:23 +0100157inline arm_compute::FullyConnectedLayerInfo
Mike Kelly07810fc2020-11-12 10:58:48 +0000158ConvertFullyConnectedDescriptorToAclFullyConnectedLayerInfo(const FullyConnectedDescriptor& fullyConnectedDesc,
159 const ActivationDescriptor* activationDesc)
telsoa01c577f2c2018-08-31 09:22:23 +0100160{
161 arm_compute::FullyConnectedLayerInfo fc_info;
162 fc_info.transpose_weights = fullyConnectedDesc.m_TransposeWeightMatrix;
Mike Kelly07810fc2020-11-12 10:58:48 +0000163 fc_info.activation_info = ConvertActivationDescriptorToAclActivationLayerInfo(activationDesc);
164 return fc_info;
165}
166
167inline arm_compute::FullyConnectedLayerInfo
168ConvertFullyConnectedDescriptorToAclFullyConnectedLayerInfo(const FullyConnectedDescriptor& fullyConnectedDesc,
169 arm_compute::ActivationLayerInfo activationLayerInfo)
170{
171 arm_compute::FullyConnectedLayerInfo fc_info;
172 fc_info.transpose_weights = fullyConnectedDesc.m_TransposeWeightMatrix;
173 fc_info.activation_info = activationLayerInfo;
telsoa01c577f2c2018-08-31 09:22:23 +0100174 return fc_info;
175}
176
Aron Virginas-Tarcc0cefb2019-07-02 17:25:47 +0100177inline arm_compute::InterpolationPolicy ConvertResizeMethodToAclInterpolationPolicy(ResizeMethod resizeMethod)
178{
179 switch (resizeMethod)
180 {
181 case ResizeMethod::Bilinear:
182 return arm_compute::InterpolationPolicy::BILINEAR;
183 case ResizeMethod::NearestNeighbor:
184 return arm_compute::InterpolationPolicy::NEAREST_NEIGHBOR;
185 default:
186 throw InvalidArgumentException("Unsupported resize method");
187 }
188}
189
Teresa Charlinc1f6b092020-05-11 16:10:38 +0100190template<typename T>
191inline T ComputeSoftmaxAclAxis(const SoftmaxDescriptor& softmaxDesc, const armnn::TensorInfo& tensor)
Narumol Prangnawarat65d30962019-03-14 11:55:03 +0000192{
David Monahan9b14bfc2020-06-30 15:57:56 +0100193 // Detect the Android default value of -1 and return the ACL default value of 0.
Colm Donelanc3c5fc22019-08-15 16:03:17 +0100194 if (softmaxDesc.m_Axis == -1)
195 {
David Monahan9b14bfc2020-06-30 15:57:56 +0100196 return 0;
Colm Donelanc3c5fc22019-08-15 16:03:17 +0100197 }
198
David Monahan9b14bfc2020-06-30 15:57:56 +0100199 unsigned int dim = tensor.GetNumDimensions();
Narumol Prangnawarat65d30962019-03-14 11:55:03 +0000200
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100201 ARMNN_ASSERT(dim != 0);
Narumol Prangnawarat65d30962019-03-14 11:55:03 +0000202
203 // Currently ArmNN support axis 1.
David Monahan9b14bfc2020-06-30 15:57:56 +0100204 auto aclAxis = (static_cast<T>(dim) - 1);
205 aclAxis = aclAxis > 0 ? aclAxis -1 : aclAxis;
206
207 return aclAxis;
Narumol Prangnawarat65d30962019-03-14 11:55:03 +0000208}
209
Narumol Prangnawarat15eb5832019-05-20 15:31:05 +0100210inline std::set<unsigned int> ComputeSplitAxis(const armnn::SplitterDescriptor& desc, const TensorShape& input)
211{
212 unsigned int numSplit = desc.GetNumViews();
213 unsigned int numDimensions = desc.GetNumDimensions();
214 std::set<unsigned int> splitAxis;
215
216 for (unsigned int i = 0; i < numSplit; ++i)
217 {
218 for (unsigned int dimIdx = 0; dimIdx < numDimensions; ++dimIdx)
219 {
220 if (desc.GetViewSizes(i)[dimIdx] != input[dimIdx])
221 {
222 splitAxis.insert(dimIdx);
223 }
224 }
225 }
226 return splitAxis;
227}
228
Teresa Charlin7ac3ca62020-07-28 15:17:12 +0100229/// Function to convert ArmNN axis (left to right) to ACL axis (right to left) ranging from [-rank, rank)
Teresa Charlinf540eb82020-04-10 19:24:55 +0100230inline int ComputeAclAxis(const int& armnnAxis, const armnn::TensorInfo& tensor)
231{
Teresa Charlin7ac3ca62020-07-28 15:17:12 +0100232 int rank = static_cast<int>(tensor.GetNumDimensions());
Teresa Charlinf540eb82020-04-10 19:24:55 +0100233
Teresa Charlin7ac3ca62020-07-28 15:17:12 +0100234 ARMNN_ASSERT(rank != 0);
235 ARMNN_ASSERT((-1 * rank) <= armnnAxis);
236 ARMNN_ASSERT(armnnAxis < rank);
Teresa Charlinf540eb82020-04-10 19:24:55 +0100237
238 int sign = (armnnAxis < 0) ? -1 : 1;
Teresa Charlin7ac3ca62020-07-28 15:17:12 +0100239 int aclAxis = sign * rank - 1 - armnnAxis;
Teresa Charlinf540eb82020-04-10 19:24:55 +0100240
241 return aclAxis;
242}
243
Teresa Charlin7ac3ca62020-07-28 15:17:12 +0100244/// Function to convert axis to its positive equivalent value.
245/// [-rank, rank) --> [0, rank)
246inline unsigned int ComputePositiveAxis(const int& axis, const armnn::TensorInfo& tensor)
247{
248 int rank = static_cast<int>(tensor.GetNumDimensions());
249
250 ARMNN_ASSERT(rank != 0);
251 ARMNN_ASSERT((-1 * rank) <= axis);
252 ARMNN_ASSERT(axis < rank);
253
254 int positiveAxis = (axis < 0) ? rank + axis : axis;
255 return static_cast<unsigned int>(positiveAxis);
256}
257
Aron Virginas-Tar5c3e9232018-11-16 11:00:48 +0000258} // namespace armnn