blob: 2dc6d2a2b2b300b7656092c6d4e9e555df72677b [file] [log] [blame]
Laurent Carlier749294b2020-06-01 09:03:17 +01001//
Teresa Charlinec5f7d12021-10-22 17:15:00 +01002// Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
David Beckecb56cd2018-09-05 12:52:57 +01003// SPDX-License-Identifier: MIT
telsoa014fcda012018-03-09 14:13:49 +00004//
Aron Virginas-Tarc9cc8042018-11-01 16:15:57 +00005#include <aclCommon/ArmComputeTensorUtils.hpp>
6#include <aclCommon/ArmComputeUtils.hpp>
telsoa014fcda012018-03-09 14:13:49 +00007
Francis Murtagh351d13d2018-09-24 15:01:18 +01008#include "armnn/Exceptions.hpp"
telsoa014fcda012018-03-09 14:13:49 +00009#include <armnn/Descriptors.hpp>
10
11namespace armnn
12{
13namespace armcomputetensorutils
14{
15
Derek Lambertid466a542020-01-22 15:37:29 +000016arm_compute::DataType GetArmComputeDataType(armnn::DataType dataType, bool multiScales)
telsoa014fcda012018-03-09 14:13:49 +000017{
18 switch(dataType)
19 {
Narumol Prangnawarat250d3922020-03-30 16:11:04 +010020 case armnn::DataType::BFloat16:
21 return arm_compute::DataType::BFLOAT16;
Mike Kelly130ec602019-11-08 12:08:35 +000022 case armnn::DataType::Boolean:
23 return arm_compute::DataType::U8;
telsoa01c577f2c2018-08-31 09:22:23 +010024 case armnn::DataType::Float16:
25 return arm_compute::DataType::F16;
telsoa014fcda012018-03-09 14:13:49 +000026 case armnn::DataType::Float32:
telsoa014fcda012018-03-09 14:13:49 +000027 return arm_compute::DataType::F32;
Ryan OShea9add1202020-02-07 10:06:33 +000028 case armnn::DataType::QAsymmS8:
29 return arm_compute::DataType::QASYMM8_SIGNED;
Derek Lambertif90c56d2020-01-10 17:14:08 +000030 case armnn::DataType::QAsymmU8:
telsoa014fcda012018-03-09 14:13:49 +000031 return arm_compute::DataType::QASYMM8;
Derek Lambertif90c56d2020-01-10 17:14:08 +000032 case armnn::DataType::QSymmS16:
Aron Virginas-Tar7a3e2fe2019-06-27 18:54:47 +010033 return arm_compute::DataType::QSYMM16;
Inki Daed4619e22020-09-10 15:33:54 +090034 case armnn::DataType::Signed64:
35 return arm_compute::DataType::S64;
Finn Williamsfd271062019-12-04 14:27:27 +000036 case armnn::DataType::QSymmS8:
Derek Lambertid466a542020-01-22 15:37:29 +000037 {
38 return multiScales ? arm_compute::DataType::QSYMM8_PER_CHANNEL : arm_compute::DataType::QSYMM8;
39 }
telsoa014fcda012018-03-09 14:13:49 +000040 case armnn::DataType::Signed32:
telsoa014fcda012018-03-09 14:13:49 +000041 return arm_compute::DataType::S32;
telsoa014fcda012018-03-09 14:13:49 +000042 default:
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +010043 ARMNN_ASSERT_MSG(false, "Unknown data type");
telsoa014fcda012018-03-09 14:13:49 +000044 return arm_compute::DataType::UNKNOWN;
telsoa014fcda012018-03-09 14:13:49 +000045 }
46}
47
Cathal Corbettfd5bec42022-03-03 15:13:23 +000048armnn::DataType GetArmNNDataType(arm_compute::DataType dataType)
49{
50 switch(dataType)
51 {
52 case arm_compute::DataType::BFLOAT16:
53 return armnn::DataType::BFloat16;
54 case arm_compute::DataType::U8:
55 return armnn::DataType::Boolean;
56 case arm_compute::DataType::F16:
57 return armnn::DataType::Float16;
58 case arm_compute::DataType::F32:
59 return armnn::DataType::Float32;
60 case arm_compute::DataType::QASYMM8_SIGNED:
61 return armnn::DataType::QAsymmS8;
62 case arm_compute::DataType::QASYMM8:
63 return armnn::DataType::QAsymmU8;
64 case arm_compute::DataType::QSYMM16:
65 return armnn::DataType::QSymmS16;
66 case arm_compute::DataType::S64:
67 return armnn::DataType::Signed64;
68 case arm_compute::DataType::QSYMM8_PER_CHANNEL:
69 return armnn::DataType::QSymmS8;
70 case arm_compute::DataType::QSYMM8:
71 return armnn::DataType::QSymmS8;
72 case arm_compute::DataType::S32:
73 return armnn::DataType::Signed32;
74 default:
75 ARMNN_ASSERT_MSG(false, "Unknown data type");
76 return armnn::DataType::Float32;
77 }
78}
79
Matthew Benthamfd899962018-12-31 15:49:42 +000080arm_compute::Coordinates BuildArmComputeReductionCoordinates(size_t inputDimensions,
81 unsigned int originalInputRank,
82 const std::vector<unsigned int>& armnnAxes)
83{
84 arm_compute::Coordinates outAclCoords;
85
86 if (armnnAxes.empty())
87 {
88 // If no reduction axes were provided, then the input must be reduced along all dimensions.
89 // Since Compute Library does not accept an empty vector as the reduction dimensions, we then
90 // manually create a vector including all the input dimensions (in reversed order) as:
91 //
92 // { inputDimensions - 1, inputDimensions - 2, ..., 1, 0 }
93 //
94 outAclCoords.set_num_dimensions(inputDimensions);
95 std::generate(outAclCoords.begin(), outAclCoords.end(), [d = inputDimensions - 1] () mutable { return d--; });
96 }
97 else
98 {
99 // Create a vector of reduction dimensions (in reversed order) with the given reduction axes.
100 //
101 // Adjust the given reduction axes according to the original rank of the input tensor (before ACL applied any
102 // dimension correction).
103 // For example, if the input tensor originally had 4 dimensions, and one of the reduction axes was 2, then the
104 // new value for that reduction axis should be 1.
105 //
106 // Example:
107 // ArmNN input shape = { 1, 1, 3, 2 } -> ACL input shape = { 2, 3 }
108 // ArmNN reduction axis = { 2 } -> ACL reduction axis = { 1 }
109 // ArmNN reduction axis = { 3 } -> ACL reduction axis = { 0 }
110 //
111 // The transformation: ACL reduction axis index = original rank - ArmNN reduction axis index - 1
112 //
113 outAclCoords.set_num_dimensions(armnnAxes.size());
114 std::transform(armnnAxes.begin(), armnnAxes.end(),
115 outAclCoords.begin(),
116 [originalInputRank](unsigned int i){ return originalInputRank - i - 1; });
117 }
118
119 return outAclCoords;
120}
121
telsoa014fcda012018-03-09 14:13:49 +0000122arm_compute::TensorShape BuildArmComputeTensorShape(const armnn::TensorShape& tensorShape)
123{
124 arm_compute::TensorShape shape;
125
telsoa01c577f2c2018-08-31 09:22:23 +0100126 // armnn tensors are (batch, channels, height, width).
127 // arm_compute tensors are (width, height, channels, batch).
telsoa014fcda012018-03-09 14:13:49 +0000128 for (unsigned int i = 0; i < tensorShape.GetNumDimensions(); i++)
129 {
telsoa01c577f2c2018-08-31 09:22:23 +0100130 // Note that our dimensions are stored in the opposite order to ACL's.
Matthew Bentham89105282018-11-20 14:33:33 +0000131 shape.set(tensorShape.GetNumDimensions() - i - 1, tensorShape[i], false);
telsoa014fcda012018-03-09 14:13:49 +0000132
133 // TensorShape::set() flattens leading ones, so that batch size 1 cannot happen.
telsoa01c577f2c2018-08-31 09:22:23 +0100134 // arm_compute tensors expect this.
telsoa014fcda012018-03-09 14:13:49 +0000135 }
136
137 // prevent arm_compute issue where tensor is flattened to nothing
138 if (shape.num_dimensions() == 0)
139 {
140 shape.set_num_dimensions(1);
141 }
142
143 return shape;
144}
145
146// Utility function used to build a TensorInfo object, that can be used to initialise
147// ARM Compute Tensor and CLTensor allocators.
148arm_compute::TensorInfo BuildArmComputeTensorInfo(const armnn::TensorInfo& tensorInfo)
149{
Derek Lambertid466a542020-01-22 15:37:29 +0000150 bool multiScales = tensorInfo.HasMultipleQuantizationScales();
telsoa014fcda012018-03-09 14:13:49 +0000151 const arm_compute::TensorShape aclTensorShape = BuildArmComputeTensorShape(tensorInfo.GetShape());
Derek Lambertid466a542020-01-22 15:37:29 +0000152 const arm_compute::DataType aclDataType = GetArmComputeDataType(tensorInfo.GetDataType(), multiScales);
Aron Virginas-Tar13b653f2019-11-01 11:40:39 +0000153
Derek Lambertid466a542020-01-22 15:37:29 +0000154 const arm_compute::QuantizationInfo aclQuantizationInfo = multiScales ?
Aron Virginas-Tar13b653f2019-11-01 11:40:39 +0000155 arm_compute::QuantizationInfo(tensorInfo.GetQuantizationScales()) :
156 arm_compute::QuantizationInfo(tensorInfo.GetQuantizationScale(), tensorInfo.GetQuantizationOffset());
telsoa014fcda012018-03-09 14:13:49 +0000157
158 return arm_compute::TensorInfo(aclTensorShape, 1, aclDataType, aclQuantizationInfo);
159}
160
Francis Murtagh351d13d2018-09-24 15:01:18 +0100161arm_compute::TensorInfo BuildArmComputeTensorInfo(const armnn::TensorInfo& tensorInfo,
162 armnn::DataLayout dataLayout)
163{
Aron Virginas-Tar13b653f2019-11-01 11:40:39 +0000164 arm_compute::TensorInfo aclTensorInfo = BuildArmComputeTensorInfo(tensorInfo);
165 aclTensorInfo.set_data_layout(ConvertDataLayout(dataLayout));
Francis Murtagh351d13d2018-09-24 15:01:18 +0100166
Aron Virginas-Tar13b653f2019-11-01 11:40:39 +0000167 return aclTensorInfo;
Francis Murtagh351d13d2018-09-24 15:01:18 +0100168}
169
Matteo Martincigh747ef822018-12-18 09:26:39 +0000170arm_compute::DataLayout ConvertDataLayout(armnn::DataLayout dataLayout)
171{
172 switch(dataLayout)
173 {
174 case armnn::DataLayout::NHWC : return arm_compute::DataLayout::NHWC;
175
176 case armnn::DataLayout::NCHW : return arm_compute::DataLayout::NCHW;
177
Teresa Charlinec5f7d12021-10-22 17:15:00 +0100178 case armnn::DataLayout::NDHWC : return arm_compute::DataLayout::NDHWC;
179
180 case armnn::DataLayout::NCDHW : return arm_compute::DataLayout::NCDHW;
181
Matteo Martincigh747ef822018-12-18 09:26:39 +0000182 default: throw InvalidArgumentException("Unknown armnn::DataLayout: [" +
183 std::to_string(static_cast<int>(dataLayout)) + "]");
184 }
185}
186
Sadik Armagana3600ba2019-10-10 10:43:20 +0100187arm_compute::PoolingLayerInfo BuildArmComputePoolingLayerInfo(const Pooling2dDescriptor& descriptor,
188 bool fpMixedPrecision)
telsoa014fcda012018-03-09 14:13:49 +0000189{
190 using arm_compute::PoolingType;
191 using arm_compute::DimensionRoundingType;
192 using arm_compute::PadStrideInfo;
193 using arm_compute::PoolingLayerInfo;
surmeh01bceff2f2018-03-29 16:29:27 +0100194 using arm_compute::Size2D;
Teresa Charlinc809a292020-01-31 10:21:44 +0000195 using arm_compute::DataLayout;
telsoa014fcda012018-03-09 14:13:49 +0000196
telsoa01c577f2c2018-08-31 09:22:23 +0100197 // Resolve ARM Compute layer parameters.
telsoa014fcda012018-03-09 14:13:49 +0000198 const PoolingType poolingType = ConvertPoolingAlgorithmToAclPoolingType(descriptor.m_PoolType);
telsoa01c577f2c2018-08-31 09:22:23 +0100199
Teresa Charlinc809a292020-01-31 10:21:44 +0000200 const DataLayout dataLayout = ConvertDataLayout(descriptor.m_DataLayout);
201
telsoa01c577f2c2018-08-31 09:22:23 +0100202 bool isGlobalPooling = (descriptor.m_StrideX==0 && descriptor.m_StrideY==0);
203 //use specific constructor if global pooling
204 if(isGlobalPooling)
205 {
Teresa Charlinc809a292020-01-31 10:21:44 +0000206 return arm_compute::PoolingLayerInfo(poolingType, dataLayout);
telsoa01c577f2c2018-08-31 09:22:23 +0100207 }
208
telsoa014fcda012018-03-09 14:13:49 +0000209 const DimensionRoundingType rounding = ConvertOutputShapeRoundingToAclDimensionRoundingType(
210 descriptor.m_OutputShapeRounding);
telsoa014fcda012018-03-09 14:13:49 +0000211 const PadStrideInfo padStrideInfo(descriptor.m_StrideX,
212 descriptor.m_StrideY,
213 descriptor.m_PadLeft,
214 descriptor.m_PadRight,
215 descriptor.m_PadTop,
216 descriptor.m_PadBottom,
217 rounding);
218
219 const bool excludePadding = (descriptor.m_PaddingMethod == PaddingMethod::Exclude);
220
surmeh01bceff2f2018-03-29 16:29:27 +0100221 const Size2D poolSize(descriptor.m_PoolWidth, descriptor.m_PoolHeight);
222
Teresa Charlinc809a292020-01-31 10:21:44 +0000223 return arm_compute::PoolingLayerInfo(poolingType, poolSize, dataLayout, padStrideInfo, excludePadding,
224 fpMixedPrecision);
telsoa014fcda012018-03-09 14:13:49 +0000225}
226
227arm_compute::NormalizationLayerInfo BuildArmComputeNormalizationLayerInfo(const NormalizationDescriptor& descriptor)
228{
229 const arm_compute::NormType normType =
230 ConvertNormalizationAlgorithmChannelToAclNormType(descriptor.m_NormChannelType);
231 return arm_compute::NormalizationLayerInfo(normType,
232 descriptor.m_NormSize,
233 descriptor.m_Alpha,
234 descriptor.m_Beta,
235 descriptor.m_K,
236 false);
237}
238
239arm_compute::PermutationVector BuildArmComputePermutationVector(const armnn::PermutationVector& perm)
240{
241 arm_compute::PermutationVector aclPerm;
242
243 unsigned int start = 0;
surmeh01bceff2f2018-03-29 16:29:27 +0100244 while ((start < perm.GetSize()) && (start == perm[start]))
telsoa014fcda012018-03-09 14:13:49 +0000245 {
246 ++start;
247 }
248
249 for (unsigned int i = start; i < perm.GetSize(); ++i)
250 {
251 aclPerm.set(i - start, perm[i] - start);
252 }
Mike Kellyc9ea45a2020-02-28 18:11:58 +0000253 return aclPerm;
254}
telsoa014fcda012018-03-09 14:13:49 +0000255
Mike Kellyc9ea45a2020-02-28 18:11:58 +0000256arm_compute::PermutationVector BuildArmComputeTransposeVector(const armnn::PermutationVector& perm)
257{
258 arm_compute::PermutationVector aclPerm;
259 std::map<unsigned int, unsigned int> permuteMappings;
260 for (unsigned int i = 0; i < perm.GetSize(); ++i)
261 {
262 permuteMappings[perm[i]] = i;
263 }
264
265 std::vector<unsigned int> permuteVector;
266 for (unsigned int i = 0; i < perm.GetSize(); ++i)
267 {
268 permuteVector.push_back(permuteMappings.at(i));
269 }
270
271 unsigned int start = 0;
272 while ((start < perm.GetSize()) && (start == permuteVector[start]))
273 {
274 ++start;
275 }
276
277 for (unsigned int i = start; i < perm.GetSize(); ++i)
278 {
279 aclPerm.set(i - start, permuteVector[i] - start);
280 }
telsoa014fcda012018-03-09 14:13:49 +0000281 return aclPerm;
282}
283
Sadik Armaganf4464322018-12-20 16:19:12 +0000284arm_compute::Size2D BuildArmComputeSize2D(const unsigned int width, const unsigned int height)
285{
286 return arm_compute::Size2D(width, height);
287}
288
Matthew Sloyan2e5d0b22021-10-21 14:05:31 +0100289arm_compute::PixelValue GetPixelValue(const arm_compute::ITensorInfo* tensorInfo, float pixelValue)
Mike Kelly0a08ec62019-07-25 08:39:31 +0100290{
Matthew Sloyan2e5d0b22021-10-21 14:05:31 +0100291 switch (tensorInfo->data_type())
Mike Kelly0a08ec62019-07-25 08:39:31 +0100292 {
Mike Kelly0a08ec62019-07-25 08:39:31 +0100293 case arm_compute::DataType::F16:
294 return arm_compute::PixelValue(static_cast<Half>(pixelValue));
295 case arm_compute::DataType::F32:
296 return arm_compute::PixelValue(pixelValue);
Mike Kelly130ec602019-11-08 12:08:35 +0000297 case arm_compute::DataType::QASYMM8:
298 return arm_compute::PixelValue(static_cast<uint8_t>(pixelValue));
299 case arm_compute::DataType::QSYMM16:
300 return arm_compute::PixelValue(static_cast<int16_t>(pixelValue));
Tamas Nyirid3065d72021-11-12 11:22:50 +0000301 case arm_compute::DataType::QSYMM8:
Sadik Armagane5d0b932020-04-09 15:48:44 +0100302 case arm_compute::DataType::QASYMM8_SIGNED:
Mike Kelly130ec602019-11-08 12:08:35 +0000303 case arm_compute::DataType::QSYMM8_PER_CHANNEL:
304 return arm_compute::PixelValue(static_cast<int8_t>(pixelValue));
Sadik Armagana792a052020-06-23 16:22:23 +0100305 case arm_compute::DataType::S32:
306 return arm_compute::PixelValue(static_cast<int32_t>(pixelValue));
Mike Kelly0a08ec62019-07-25 08:39:31 +0100307 default:
308 throw InvalidArgumentException("Unsupported DataType: [" +
Matthew Sloyan2e5d0b22021-10-21 14:05:31 +0100309 std::to_string(static_cast<int>(tensorInfo->data_type())) + "]");
Mike Kelly0a08ec62019-07-25 08:39:31 +0100310 }
311}
312
telsoa014fcda012018-03-09 14:13:49 +0000313} // namespace armcomputetensorutils
314} // namespace armnn