blob: 63c70c7092cc447938d14c4113ef17dbcac26e53 [file] [log] [blame]
Laurent Carlier749294b2020-06-01 09:03:17 +01001//
Teresa Charlin21bda142024-03-13 16:10:32 +00002// Copyright © 2017-2024 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//
5#pragma once
6
7#include <armnn/Tensor.hpp>
8#include <armnn/DescriptorsFwd.hpp>
9
Matthew Sloyan171214c2020-09-09 09:07:37 +010010#include <armnn/utility/NumericCast.hpp>
11
telsoa014fcda012018-03-09 14:13:49 +000012#include <arm_compute/core/ITensor.h>
13#include <arm_compute/core/TensorInfo.h>
surmeh013537c2c2018-05-18 16:31:43 +010014#include <arm_compute/core/Types.h>
Teresa Charlin21bda142024-03-13 16:10:32 +000015#include <arm_compute/function_info/ScatterInfo.h>
telsoa014fcda012018-03-09 14:13:49 +000016
Mike Kelly0a08ec62019-07-25 08:39:31 +010017#include <Half.hpp>
18
telsoa014fcda012018-03-09 14:13:49 +000019namespace armnn
20{
21class ITensorHandle;
22
23namespace armcomputetensorutils
24{
25
telsoa01c577f2c2018-08-31 09:22:23 +010026/// Utility function to map an armnn::DataType to corresponding arm_compute::DataType.
Derek Lambertid466a542020-01-22 15:37:29 +000027arm_compute::DataType GetArmComputeDataType(armnn::DataType dataType, bool multiScales);
telsoa014fcda012018-03-09 14:13:49 +000028
Cathal Corbettfd5bec42022-03-03 15:13:23 +000029/// Utility function to map an arm_compute::DataType to corresponding armnn::DataType.
30armnn::DataType GetArmNNDataType(arm_compute::DataType datatype);
31
Matthew Benthamfd899962018-12-31 15:49:42 +000032/// Utility function used to set up an arm_compute::Coordinates from a vector of ArmNN Axes for reduction functions
33arm_compute::Coordinates BuildArmComputeReductionCoordinates(size_t inputDimensions,
34 unsigned int originalInputRank,
35 const std::vector<unsigned int>& armnnAxes);
36
telsoa01c577f2c2018-08-31 09:22:23 +010037/// Utility function used to setup an arm_compute::TensorShape object from an armnn::TensorShape.
telsoa014fcda012018-03-09 14:13:49 +000038arm_compute::TensorShape BuildArmComputeTensorShape(const armnn::TensorShape& tensorShape);
39
Mike Kelly0e3fe102023-01-23 19:32:06 +000040/// Utility function used to setup an arm_compute::TensorShape object from an armnn::TensorShape. This will
41/// attempt to reduce the number of leading 1s until the dimension length is equal to the dimensions passed in.
42arm_compute::TensorShape BuildArmComputeTensorShape(const armnn::TensorShape& tensorShape, unsigned int dimensions);
43
telsoa014fcda012018-03-09 14:13:49 +000044/// Utility function used to setup an arm_compute::ITensorInfo object whose dimensions are based on the given
telsoa01c577f2c2018-08-31 09:22:23 +010045/// armnn::ITensorInfo.
telsoa014fcda012018-03-09 14:13:49 +000046arm_compute::TensorInfo BuildArmComputeTensorInfo(const armnn::TensorInfo& tensorInfo);
47
Francis Murtagh351d13d2018-09-24 15:01:18 +010048/// Utility function used to setup an arm_compute::ITensorInfo object whose dimensions are based on the given
Mike Kelly0e3fe102023-01-23 19:32:06 +000049/// armnn::ITensorInfo. This will attempt to reduce the number of leading 1s until the dimension length is equal
50/// to the dimensions passed in.
51arm_compute::TensorInfo BuildArmComputeTensorInfo(const armnn::TensorInfo& tensorInfo, unsigned int dimensions);
52
53/// Utility function used to setup an arm_compute::ITensorInfo object whose dimensions are based on the given
54/// armnn::ITensorInfo. This will attempt to reduce the number of leading 1s until the dimension length is equal
55/// to the dimensions passed in.
56arm_compute::TensorInfo BuildArmComputeTensorInfo(const armnn::TensorInfo& tensorInfo,
57 armnn::DataLayout dataLayout,
58 unsigned int dimensions);
59
60/// Utility function used to setup an arm_compute::ITensorInfo object whose dimensions are based on the given
Francis Murtagh351d13d2018-09-24 15:01:18 +010061/// armnn::ITensorInfo.
62/// armnn::DataLayout.
63arm_compute::TensorInfo BuildArmComputeTensorInfo(const armnn::TensorInfo& tensorInfo,
64 armnn::DataLayout dataLayout);
65
Mike Kelly0e3fe102023-01-23 19:32:06 +000066/// Utility function used to setup an arm_compute::ITensorInfo object whose dimensions are based on the given
67/// armnn::ITensorInfo. This will attempt to reduce the number of leading 1s until the dimension length is equal
68/// to the dimensions passed in.
69arm_compute::TensorInfo BuildArmComputeTensorInfo(const armnn::TensorInfo& tensorInfo,
70 armnn::DataLayout dataLayout, unsigned int dimensions);
71
Matteo Martincigh747ef822018-12-18 09:26:39 +000072/// Utility function used to convert armnn::DataLayout to arm_compute::DataLayout
73/// armnn::DataLayout.
74arm_compute::DataLayout ConvertDataLayout(armnn::DataLayout dataLayout);
75
Sadik Armagana3600ba2019-10-10 10:43:20 +010076/// Utility function used to setup an arm_compute::PoolingLayerInfo object from given
77/// armnn::Pooling2dDescriptor
78/// bool fpMixedPrecision
79arm_compute::PoolingLayerInfo BuildArmComputePoolingLayerInfo(const Pooling2dDescriptor& descriptor,
80 bool fpMixedPrecision = false);
telsoa014fcda012018-03-09 14:13:49 +000081
Ryan OSheabab8fa92022-03-09 10:29:02 +000082/// Utility function used to setup an arm_compute::Pooling3dLayerInfo object from given
83/// armnn::Pooling3dDescriptor
84/// bool fpMixedPrecision
85arm_compute::Pooling3dLayerInfo BuildArmComputePooling3dLayerInfo(const Pooling3dDescriptor& descriptor,
86 bool fpMixedPrecision = false);
87
telsoa01c577f2c2018-08-31 09:22:23 +010088/// Utility function to setup an arm_compute::NormalizationLayerInfo object from an armnn::NormalizationDescriptor.
telsoa014fcda012018-03-09 14:13:49 +000089arm_compute::NormalizationLayerInfo BuildArmComputeNormalizationLayerInfo(const NormalizationDescriptor& desc);
90
telsoa01c577f2c2018-08-31 09:22:23 +010091/// Utility function used to setup an arm_compute::PermutationVector object from an armnn::PermutationVector.
Teresa Charlin6bc85252022-12-06 20:43:06 +000092/// \param perm PermutationVector used in Arm NN Permute layer
93/// \return PermutationVector used in ACL Transpose layer
94arm_compute::PermutationVector BuildArmComputePermutationVector(const armnn::PermutationVector& perm);
telsoa014fcda012018-03-09 14:13:49 +000095
Mike Kellyc9ea45a2020-02-28 18:11:58 +000096/// Utility function used to setup an arm_compute::PermutationVector object from an armnn::PermutationVector.
Teresa Charlin6bc85252022-12-06 20:43:06 +000097/// \param perm PermutationVector used in Arm NN Transpose layer
98/// \return PermutationVector used in ACL Transpose layer
99arm_compute::PermutationVector BuildArmComputeTransposeVector(const armnn::PermutationVector& perm);
Mike Kellyc9ea45a2020-02-28 18:11:58 +0000100
Sadik Armaganf4464322018-12-20 16:19:12 +0000101/// Utility function used to setup an arm_compute::Size2D object from width and height values.
102arm_compute::Size2D BuildArmComputeSize2D(const unsigned int width, const unsigned int height);
103
Matthew Sloyan2e5d0b22021-10-21 14:05:31 +0100104/// Gets the appropriate PixelValue for the TensorInfo DataType
Kevin May263d7092022-11-29 14:34:48 +0000105arm_compute::PixelValue GetPixelValue(const arm_compute::ITensorInfo* tensorInfo, float value);
Mike Kelly0a08ec62019-07-25 08:39:31 +0100106
Cathal Corbett4b19d222022-05-11 20:12:17 +0100107/// Computes the depth multiplier parameter for the Depthwise Conv2d ACL workload.
108unsigned int ComputeDepthwiseConv2dDepthMultiplier(armnn::DataLayout layout,
109 const arm_compute::TensorShape& weightsShape,
110 const arm_compute::TensorShape& inputShape);
111
Teresa Charlin21bda142024-03-13 16:10:32 +0000112/// Utility function used to setup an arm_compute::ScatterInfo from ArmNN ScatterNd descriptor
113arm_compute::ScatterInfo BuildArmComputeScatterInfo(const ScatterNdDescriptor& descriptor);
114
Teresa Charlinca5c82a2023-03-28 11:00:36 +0100115/// Utility function used to setup an arm_compute::PadStrideInfo object from an ArmNN layer descriptor.
surmeh013537c2c2018-05-18 16:31:43 +0100116template <typename Descriptor>
Teresa Charlin5b701842023-05-16 12:27:28 +0100117arm_compute::PadStrideInfo BuildArmComputePadStrideInfo(const Descriptor& descriptor)
surmeh013537c2c2018-05-18 16:31:43 +0100118{
119 return arm_compute::PadStrideInfo(descriptor.m_StrideX,
120 descriptor.m_StrideY,
121 descriptor.m_PadLeft,
122 descriptor.m_PadRight,
123 descriptor.m_PadTop,
124 descriptor.m_PadBottom,
125 arm_compute::DimensionRoundingType::FLOOR);
126}
127
David Monahan8a570462023-11-22 13:24:25 +0000128/// Utility function used to setup an arm_compute::Padding2D object from an armnn layer descriptor.
129template <typename Descriptor>
130arm_compute::Padding2D BuildArmComputePaddingInfo(const Descriptor &descriptor)
131{
132 return arm_compute::Padding2D(descriptor.m_PadLeft,
133 descriptor.m_PadRight,
134 descriptor.m_PadTop,
135 descriptor.m_PadBottom);
136}
137
Teresa Charlinca5c82a2023-03-28 11:00:36 +0100138/// Utility function used to setup an arm_compute::CropInfo object from an ArmNN layer descriptor.
139template <typename Descriptor>
Teresa Charlin2ea403d2023-06-19 12:06:19 +0100140arm_compute::CropInfo BuildArmComputeCropInfo(const Descriptor& descriptor, const unsigned int rank = 4)
Teresa Charlinca5c82a2023-03-28 11:00:36 +0100141{
Teresa Charlin2ea403d2023-06-19 12:06:19 +0100142 if (rank == 3)
143 {
144 return arm_compute::CropInfo(0, 0,
145 descriptor.m_Crops[0].first, descriptor.m_Crops[0].second);
146 }
147 else if (rank == 4)
148 {
149 return arm_compute::CropInfo(descriptor.m_Crops[1].first, descriptor.m_Crops[1].second,
150 descriptor.m_Crops[0].first, descriptor.m_Crops[0].second);
151 }
152 else
153 {
154 throw InvalidArgumentException("Tensor rank must be either 3 or 4", CHECK_LOCATION());
155 }
Teresa Charlinca5c82a2023-03-28 11:00:36 +0100156}
157
telsoa014fcda012018-03-09 14:13:49 +0000158/// Sets up the given ArmCompute tensor's dimensions based on the given ArmNN tensor.
159template <typename Tensor>
160void BuildArmComputeTensor(Tensor& tensor, const armnn::TensorInfo& tensorInfo)
161{
162 tensor.allocator()->init(BuildArmComputeTensorInfo(tensorInfo));
163}
164
Francis Murtagh351d13d2018-09-24 15:01:18 +0100165/// Sets up the given ArmCompute tensor's dimensions based on the given ArmNN tensor.
166template <typename Tensor>
167void BuildArmComputeTensor(Tensor& tensor, const armnn::TensorInfo& tensorInfo, DataLayout dataLayout)
168{
169 tensor.allocator()->init(BuildArmComputeTensorInfo(tensorInfo, dataLayout));
170}
171
telsoa014fcda012018-03-09 14:13:49 +0000172template <typename Tensor>
173void InitialiseArmComputeTensorEmpty(Tensor& tensor)
174{
175 tensor.allocator()->allocate();
176}
177
telsoa01c577f2c2018-08-31 09:22:23 +0100178/// Utility function to free unused tensors after a workload is configured and prepared
179template <typename Tensor>
180void FreeTensorIfUnused(std::unique_ptr<Tensor>& tensor)
181{
182 if (tensor && !tensor->is_used())
183 {
184 tensor.reset(nullptr);
185 }
186}
187
telsoa014fcda012018-03-09 14:13:49 +0000188// Helper function to obtain byte offset into tensor data
189inline size_t GetTensorOffset(const arm_compute::ITensorInfo& info,
Matthew Jacksondba634f2019-08-15 15:14:18 +0100190 uint32_t depthIndex,
telsoa014fcda012018-03-09 14:13:49 +0000191 uint32_t batchIndex,
192 uint32_t channelIndex,
193 uint32_t y,
194 uint32_t x)
195{
196 arm_compute::Coordinates coords;
Matthew Jacksondba634f2019-08-15 15:14:18 +0100197 coords.set(4, static_cast<int>(depthIndex));
telsoa01c577f2c2018-08-31 09:22:23 +0100198 coords.set(3, static_cast<int>(batchIndex));
199 coords.set(2, static_cast<int>(channelIndex));
200 coords.set(1, static_cast<int>(y));
201 coords.set(0, static_cast<int>(x));
Matthew Sloyan171214c2020-09-09 09:07:37 +0100202 return armnn::numeric_cast<size_t>(info.offset_element_in_bytes(coords));
telsoa014fcda012018-03-09 14:13:49 +0000203}
204
telsoa01c577f2c2018-08-31 09:22:23 +0100205// Helper function to obtain element offset into data buffer representing tensor data (assuming no strides).
telsoa014fcda012018-03-09 14:13:49 +0000206inline size_t GetLinearBufferOffset(const arm_compute::ITensorInfo& info,
Matthew Jacksondba634f2019-08-15 15:14:18 +0100207 uint32_t depthIndex,
telsoa014fcda012018-03-09 14:13:49 +0000208 uint32_t batchIndex,
209 uint32_t channelIndex,
210 uint32_t y,
211 uint32_t x)
212{
213 const arm_compute::TensorShape& shape = info.tensor_shape();
telsoa01c577f2c2018-08-31 09:22:23 +0100214 uint32_t width = static_cast<uint32_t>(shape[0]);
215 uint32_t height = static_cast<uint32_t>(shape[1]);
216 uint32_t numChannels = static_cast<uint32_t>(shape[2]);
Matthew Jacksondba634f2019-08-15 15:14:18 +0100217 uint32_t numBatches = static_cast<uint32_t>(shape[3]);
218 return (((depthIndex * numBatches + batchIndex) * numChannels + channelIndex) * height + y) * width + x;
telsoa014fcda012018-03-09 14:13:49 +0000219}
220
221template <typename T>
222void CopyArmComputeITensorData(const arm_compute::ITensor& srcTensor, T* dstData)
223{
telsoa01c577f2c2018-08-31 09:22:23 +0100224 // If MaxNumOfTensorDimensions is increased, this loop will need fixing.
Matthew Jacksondba634f2019-08-15 15:14:18 +0100225 static_assert(MaxNumOfTensorDimensions == 5, "Please update CopyArmComputeITensorData");
telsoa014fcda012018-03-09 14:13:49 +0000226 {
227 const arm_compute::ITensorInfo& info = *srcTensor.info();
228 const arm_compute::TensorShape& shape = info.tensor_shape();
229 const uint8_t* const bufferPtr = srcTensor.buffer();
telsoa01c577f2c2018-08-31 09:22:23 +0100230 uint32_t width = static_cast<uint32_t>(shape[0]);
231 uint32_t height = static_cast<uint32_t>(shape[1]);
232 uint32_t numChannels = static_cast<uint32_t>(shape[2]);
233 uint32_t numBatches = static_cast<uint32_t>(shape[3]);
Matthew Jacksondba634f2019-08-15 15:14:18 +0100234 uint32_t depth = static_cast<uint32_t>(shape[4]);
telsoa014fcda012018-03-09 14:13:49 +0000235
Matthew Jacksondba634f2019-08-15 15:14:18 +0100236 for (unsigned int depthIndex = 0; depthIndex < depth; ++depthIndex)
telsoa014fcda012018-03-09 14:13:49 +0000237 {
Matthew Jacksondba634f2019-08-15 15:14:18 +0100238 for (unsigned int batchIndex = 0; batchIndex < numBatches; ++batchIndex)
telsoa014fcda012018-03-09 14:13:49 +0000239 {
Matthew Jacksondba634f2019-08-15 15:14:18 +0100240 for (unsigned int channelIndex = 0; channelIndex < numChannels; ++channelIndex)
telsoa014fcda012018-03-09 14:13:49 +0000241 {
Matthew Jacksondba634f2019-08-15 15:14:18 +0100242 for (unsigned int y = 0; y < height; ++y)
243 {
244 // Copies one row from arm_compute tensor buffer to linear memory buffer.
245 // A row is the largest contiguous region we can copy, as the tensor data may be using strides.
246 memcpy(
247 dstData + GetLinearBufferOffset(info, depthIndex, batchIndex, channelIndex, y, 0),
248 bufferPtr + GetTensorOffset(info, depthIndex, batchIndex, channelIndex, y, 0),
249 width * sizeof(T));
250 }
telsoa014fcda012018-03-09 14:13:49 +0000251 }
252 }
253 }
254 }
255}
256
257template <typename T>
258void CopyArmComputeITensorData(const T* srcData, arm_compute::ITensor& dstTensor)
259{
telsoa01c577f2c2018-08-31 09:22:23 +0100260 // If MaxNumOfTensorDimensions is increased, this loop will need fixing.
Matthew Jacksondba634f2019-08-15 15:14:18 +0100261 static_assert(MaxNumOfTensorDimensions == 5, "Please update CopyArmComputeITensorData");
telsoa014fcda012018-03-09 14:13:49 +0000262 {
263 const arm_compute::ITensorInfo& info = *dstTensor.info();
264 const arm_compute::TensorShape& shape = info.tensor_shape();
265 uint8_t* const bufferPtr = dstTensor.buffer();
telsoa01c577f2c2018-08-31 09:22:23 +0100266 uint32_t width = static_cast<uint32_t>(shape[0]);
267 uint32_t height = static_cast<uint32_t>(shape[1]);
268 uint32_t numChannels = static_cast<uint32_t>(shape[2]);
269 uint32_t numBatches = static_cast<uint32_t>(shape[3]);
Matthew Jacksondba634f2019-08-15 15:14:18 +0100270 uint32_t depth = static_cast<uint32_t>(shape[4]);
telsoa014fcda012018-03-09 14:13:49 +0000271
Matthew Jacksondba634f2019-08-15 15:14:18 +0100272 for (unsigned int depthIndex = 0; depthIndex < depth; ++depthIndex)
telsoa014fcda012018-03-09 14:13:49 +0000273 {
Matthew Jacksondba634f2019-08-15 15:14:18 +0100274 for (unsigned int batchIndex = 0; batchIndex < numBatches; ++batchIndex)
telsoa014fcda012018-03-09 14:13:49 +0000275 {
Matthew Jacksondba634f2019-08-15 15:14:18 +0100276 for (unsigned int channelIndex = 0; channelIndex < numChannels; ++channelIndex)
telsoa014fcda012018-03-09 14:13:49 +0000277 {
Matthew Jacksondba634f2019-08-15 15:14:18 +0100278 for (unsigned int y = 0; y < height; ++y)
279 {
280 // Copies one row from linear memory buffer to arm_compute tensor buffer.
281 // A row is the largest contiguous region we can copy, as the tensor data may be using strides.
282 memcpy(
283 bufferPtr + GetTensorOffset(info, depthIndex, batchIndex, channelIndex, y, 0),
284 srcData + GetLinearBufferOffset(info, depthIndex, batchIndex, channelIndex, y, 0),
285 width * sizeof(T));
286 }
telsoa014fcda012018-03-09 14:13:49 +0000287 }
288 }
289 }
290 }
291}
292
telsoa01c577f2c2018-08-31 09:22:23 +0100293/// Construct a TensorShape object from an ArmCompute object based on arm_compute::Dimensions.
294/// \tparam ArmComputeType Any type that implements the Dimensions interface
295/// \tparam T Shape value type
296/// \param shapelike An ArmCompute object that implements the Dimensions interface
297/// \param initial A default value to initialise the shape with
298/// \return A TensorShape object filled from the Acl shapelike object.
299template<typename ArmComputeType, typename T>
300TensorShape GetTensorShape(const ArmComputeType& shapelike, T initial)
301{
302 std::vector<unsigned int> s(MaxNumOfTensorDimensions, initial);
303 for (unsigned int i=0; i < shapelike.num_dimensions(); ++i)
304 {
Matthew Sloyan171214c2020-09-09 09:07:37 +0100305 s[(shapelike.num_dimensions()-1)-i] = armnn::numeric_cast<unsigned int>(shapelike[i]);
telsoa01c577f2c2018-08-31 09:22:23 +0100306 }
Matthew Sloyan171214c2020-09-09 09:07:37 +0100307 return TensorShape(armnn::numeric_cast<unsigned int>(shapelike.num_dimensions()), s.data());
telsoa01c577f2c2018-08-31 09:22:23 +0100308};
309
310/// Get the strides from an ACL strides object
311inline TensorShape GetStrides(const arm_compute::Strides& strides)
312{
313 return GetTensorShape(strides, 0U);
314}
315
316/// Get the shape from an ACL shape object
317inline TensorShape GetShape(const arm_compute::TensorShape& shape)
318{
319 return GetTensorShape(shape, 1U);
320}
321
telsoa014fcda012018-03-09 14:13:49 +0000322} // namespace armcomputetensorutils
323} // namespace armnn