ArmNN
 21.05
ArmComputeTensorUtils.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
7 
8 #include "armnn/Exceptions.hpp"
9 #include <armnn/Descriptors.hpp>
10 
11 namespace armnn
12 {
13 namespace armcomputetensorutils
14 {
15 
16 arm_compute::DataType GetArmComputeDataType(armnn::DataType dataType, bool multiScales)
17 {
18  switch(dataType)
19  {
21  return arm_compute::DataType::BFLOAT16;
23  return arm_compute::DataType::U8;
25  return arm_compute::DataType::F16;
27  return arm_compute::DataType::F32;
29  return arm_compute::DataType::QASYMM8_SIGNED;
31  return arm_compute::DataType::QASYMM8;
33  return arm_compute::DataType::QSYMM16;
35  return arm_compute::DataType::S64;
37  {
38  return multiScales ? arm_compute::DataType::QSYMM8_PER_CHANNEL : arm_compute::DataType::QSYMM8;
39  }
42  return arm_compute::DataType::QSYMM8_PER_CHANNEL;
45  return arm_compute::DataType::S32;
46  default:
47  ARMNN_ASSERT_MSG(false, "Unknown data type");
48  return arm_compute::DataType::UNKNOWN;
49  }
50 }
51 
52 arm_compute::Coordinates BuildArmComputeReductionCoordinates(size_t inputDimensions,
53  unsigned int originalInputRank,
54  const std::vector<unsigned int>& armnnAxes)
55 {
56  arm_compute::Coordinates outAclCoords;
57 
58  if (armnnAxes.empty())
59  {
60  // If no reduction axes were provided, then the input must be reduced along all dimensions.
61  // Since Compute Library does not accept an empty vector as the reduction dimensions, we then
62  // manually create a vector including all the input dimensions (in reversed order) as:
63  //
64  // { inputDimensions - 1, inputDimensions - 2, ..., 1, 0 }
65  //
66  outAclCoords.set_num_dimensions(inputDimensions);
67  std::generate(outAclCoords.begin(), outAclCoords.end(), [d = inputDimensions - 1] () mutable { return d--; });
68  }
69  else
70  {
71  // Create a vector of reduction dimensions (in reversed order) with the given reduction axes.
72  //
73  // Adjust the given reduction axes according to the original rank of the input tensor (before ACL applied any
74  // dimension correction).
75  // For example, if the input tensor originally had 4 dimensions, and one of the reduction axes was 2, then the
76  // new value for that reduction axis should be 1.
77  //
78  // Example:
79  // ArmNN input shape = { 1, 1, 3, 2 } -> ACL input shape = { 2, 3 }
80  // ArmNN reduction axis = { 2 } -> ACL reduction axis = { 1 }
81  // ArmNN reduction axis = { 3 } -> ACL reduction axis = { 0 }
82  //
83  // The transformation: ACL reduction axis index = original rank - ArmNN reduction axis index - 1
84  //
85  outAclCoords.set_num_dimensions(armnnAxes.size());
86  std::transform(armnnAxes.begin(), armnnAxes.end(),
87  outAclCoords.begin(),
88  [originalInputRank](unsigned int i){ return originalInputRank - i - 1; });
89  }
90 
91  return outAclCoords;
92 }
93 
94 arm_compute::TensorShape BuildArmComputeTensorShape(const armnn::TensorShape& tensorShape)
95 {
96  arm_compute::TensorShape shape;
97 
98  // armnn tensors are (batch, channels, height, width).
99  // arm_compute tensors are (width, height, channels, batch).
100  for (unsigned int i = 0; i < tensorShape.GetNumDimensions(); i++)
101  {
102  // Note that our dimensions are stored in the opposite order to ACL's.
103  shape.set(tensorShape.GetNumDimensions() - i - 1, tensorShape[i], false);
104 
105  // TensorShape::set() flattens leading ones, so that batch size 1 cannot happen.
106  // arm_compute tensors expect this.
107  }
108 
109  // prevent arm_compute issue where tensor is flattened to nothing
110  if (shape.num_dimensions() == 0)
111  {
112  shape.set_num_dimensions(1);
113  }
114 
115  return shape;
116 }
117 
118 // Utility function used to build a TensorInfo object, that can be used to initialise
119 // ARM Compute Tensor and CLTensor allocators.
120 arm_compute::TensorInfo BuildArmComputeTensorInfo(const armnn::TensorInfo& tensorInfo)
121 {
122  bool multiScales = tensorInfo.HasMultipleQuantizationScales();
123  const arm_compute::TensorShape aclTensorShape = BuildArmComputeTensorShape(tensorInfo.GetShape());
124  const arm_compute::DataType aclDataType = GetArmComputeDataType(tensorInfo.GetDataType(), multiScales);
125 
126  const arm_compute::QuantizationInfo aclQuantizationInfo = multiScales ?
127  arm_compute::QuantizationInfo(tensorInfo.GetQuantizationScales()) :
128  arm_compute::QuantizationInfo(tensorInfo.GetQuantizationScale(), tensorInfo.GetQuantizationOffset());
129 
130  return arm_compute::TensorInfo(aclTensorShape, 1, aclDataType, aclQuantizationInfo);
131 }
132 
133 arm_compute::TensorInfo BuildArmComputeTensorInfo(const armnn::TensorInfo& tensorInfo,
134  armnn::DataLayout dataLayout)
135 {
136  arm_compute::TensorInfo aclTensorInfo = BuildArmComputeTensorInfo(tensorInfo);
137  aclTensorInfo.set_data_layout(ConvertDataLayout(dataLayout));
138 
139  return aclTensorInfo;
140 }
141 
142 arm_compute::DataLayout ConvertDataLayout(armnn::DataLayout dataLayout)
143 {
144  switch(dataLayout)
145  {
146  case armnn::DataLayout::NHWC : return arm_compute::DataLayout::NHWC;
147 
148  case armnn::DataLayout::NCHW : return arm_compute::DataLayout::NCHW;
149 
150  default: throw InvalidArgumentException("Unknown armnn::DataLayout: [" +
151  std::to_string(static_cast<int>(dataLayout)) + "]");
152  }
153 }
154 
155 arm_compute::PoolingLayerInfo BuildArmComputePoolingLayerInfo(const Pooling2dDescriptor& descriptor,
156  bool fpMixedPrecision)
157 {
158  using arm_compute::PoolingType;
159  using arm_compute::DimensionRoundingType;
160  using arm_compute::PadStrideInfo;
161  using arm_compute::PoolingLayerInfo;
162  using arm_compute::Size2D;
164 
165  // Resolve ARM Compute layer parameters.
166  const PoolingType poolingType = ConvertPoolingAlgorithmToAclPoolingType(descriptor.m_PoolType);
167 
168  const DataLayout dataLayout = ConvertDataLayout(descriptor.m_DataLayout);
169 
170  bool isGlobalPooling = (descriptor.m_StrideX==0 && descriptor.m_StrideY==0);
171  //use specific constructor if global pooling
172  if(isGlobalPooling)
173  {
174  return arm_compute::PoolingLayerInfo(poolingType, dataLayout);
175  }
176 
177  const DimensionRoundingType rounding = ConvertOutputShapeRoundingToAclDimensionRoundingType(
178  descriptor.m_OutputShapeRounding);
179  const PadStrideInfo padStrideInfo(descriptor.m_StrideX,
180  descriptor.m_StrideY,
181  descriptor.m_PadLeft,
182  descriptor.m_PadRight,
183  descriptor.m_PadTop,
184  descriptor.m_PadBottom,
185  rounding);
186 
187  const bool excludePadding = (descriptor.m_PaddingMethod == PaddingMethod::Exclude);
188 
189  const Size2D poolSize(descriptor.m_PoolWidth, descriptor.m_PoolHeight);
190 
191  return arm_compute::PoolingLayerInfo(poolingType, poolSize, dataLayout, padStrideInfo, excludePadding,
192  fpMixedPrecision);
193 }
194 
195 arm_compute::NormalizationLayerInfo BuildArmComputeNormalizationLayerInfo(const NormalizationDescriptor& descriptor)
196 {
197  const arm_compute::NormType normType =
198  ConvertNormalizationAlgorithmChannelToAclNormType(descriptor.m_NormChannelType);
199  return arm_compute::NormalizationLayerInfo(normType,
200  descriptor.m_NormSize,
201  descriptor.m_Alpha,
202  descriptor.m_Beta,
203  descriptor.m_K,
204  false);
205 }
206 
207 arm_compute::PermutationVector BuildArmComputePermutationVector(const armnn::PermutationVector& perm)
208 {
209  arm_compute::PermutationVector aclPerm;
210 
211  unsigned int start = 0;
212  while ((start < perm.GetSize()) && (start == perm[start]))
213  {
214  ++start;
215  }
216 
217  for (unsigned int i = start; i < perm.GetSize(); ++i)
218  {
219  aclPerm.set(i - start, perm[i] - start);
220  }
221  return aclPerm;
222 }
223 
224 arm_compute::PermutationVector BuildArmComputeTransposeVector(const armnn::PermutationVector& perm)
225 {
226  arm_compute::PermutationVector aclPerm;
227  std::map<unsigned int, unsigned int> permuteMappings;
228  for (unsigned int i = 0; i < perm.GetSize(); ++i)
229  {
230  permuteMappings[perm[i]] = i;
231  }
232 
233  std::vector<unsigned int> permuteVector;
234  for (unsigned int i = 0; i < perm.GetSize(); ++i)
235  {
236  permuteVector.push_back(permuteMappings.at(i));
237  }
238 
239  unsigned int start = 0;
240  while ((start < perm.GetSize()) && (start == permuteVector[start]))
241  {
242  ++start;
243  }
244 
245  for (unsigned int i = start; i < perm.GetSize(); ++i)
246  {
247  aclPerm.set(i - start, permuteVector[i] - start);
248  }
249  return aclPerm;
250 }
251 
252 arm_compute::Size2D BuildArmComputeSize2D(const unsigned int width, const unsigned int height)
253 {
254  return arm_compute::Size2D(width, height);
255 }
256 
257 arm_compute::PixelValue GetPixelValue(arm_compute::ITensor& input, float pixelValue)
258 {
259  switch (input.info()->data_type())
260  {
261  case arm_compute::DataType::F16:
262  return arm_compute::PixelValue(static_cast<Half>(pixelValue));
263  case arm_compute::DataType::F32:
264  return arm_compute::PixelValue(pixelValue);
265  case arm_compute::DataType::QASYMM8:
266  return arm_compute::PixelValue(static_cast<uint8_t>(pixelValue));
267  case arm_compute::DataType::QSYMM16:
268  return arm_compute::PixelValue(static_cast<int16_t>(pixelValue));
269  case arm_compute::DataType::QASYMM8_SIGNED:
270  case arm_compute::DataType::QSYMM8_PER_CHANNEL:
271  return arm_compute::PixelValue(static_cast<int8_t>(pixelValue));
272  case arm_compute::DataType::S32:
273  return arm_compute::PixelValue(static_cast<int32_t>(pixelValue));
274  default:
275  throw InvalidArgumentException("Unsupported DataType: [" +
276  std::to_string(static_cast<int>(input.info()->data_type())) + "]");
277  }
278 }
279 
280 } // namespace armcomputetensorutils
281 } // namespace armnn
DataLayout
Definition: Types.hpp:54
const TensorShape & GetShape() const
Definition: Tensor.hpp:187
arm_compute::PoolingType ConvertPoolingAlgorithmToAclPoolingType(PoolingAlgorithm poolingAlgorithm)
#define ARMNN_NO_DEPRECATE_WARN_BEGIN
Definition: Deprecated.hpp:33
std::array< unsigned int, MaxNumOfTensorDimensions > Coordinates
The padding fields don&#39;t count and are ignored.
arm_compute::NormType ConvertNormalizationAlgorithmChannelToAclNormType(NormalizationAlgorithmChannel channelType)
Copyright (c) 2021 ARM Limited and Contributors.
SizeType GetSize() const
Definition: Types.hpp:274
std::vector< float > GetQuantizationScales() const
Definition: Tensor.cpp:442
bool HasMultipleQuantizationScales() const
Definition: Tensor.hpp:197
DataType
Definition: Types.hpp:36
#define ARMNN_NO_DEPRECATE_WARN_END
Definition: Deprecated.hpp:34
#define ARMNN_ASSERT_MSG(COND, MSG)
Definition: Assert.hpp:15
arm_compute::DimensionRoundingType ConvertOutputShapeRoundingToAclDimensionRoundingType(OutputShapeRounding rounding)
int32_t GetQuantizationOffset() const
Definition: Tensor.cpp:469
float GetQuantizationScale() const
Definition: Tensor.cpp:452
DataType GetDataType() const
Definition: Tensor.hpp:194
unsigned int GetNumDimensions() const
Function that returns the tensor rank.
Definition: Tensor.cpp:174