blob: 18f41ee173eec55a011df51aa0b915aabb038166 [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
7#include <armnn/Tensor.hpp>
8#include <armnn/DescriptorsFwd.hpp>
9
10#include <arm_compute/core/ITensor.h>
11#include <arm_compute/core/TensorInfo.h>
surmeh013537c2c2018-05-18 16:31:43 +010012#include <arm_compute/core/Types.h>
telsoa014fcda012018-03-09 14:13:49 +000013
14#include <boost/cast.hpp>
15
16namespace armnn
17{
18class ITensorHandle;
19
20namespace armcomputetensorutils
21{
22
telsoa01c577f2c2018-08-31 09:22:23 +010023/// Utility function to map an armnn::DataType to corresponding arm_compute::DataType.
telsoa014fcda012018-03-09 14:13:49 +000024arm_compute::DataType GetArmComputeDataType(armnn::DataType dataType);
25
telsoa01c577f2c2018-08-31 09:22:23 +010026/// Utility function used to setup an arm_compute::TensorShape object from an armnn::TensorShape.
telsoa014fcda012018-03-09 14:13:49 +000027arm_compute::TensorShape BuildArmComputeTensorShape(const armnn::TensorShape& tensorShape);
28
29/// Utility function used to setup an arm_compute::ITensorInfo object whose dimensions are based on the given
telsoa01c577f2c2018-08-31 09:22:23 +010030/// armnn::ITensorInfo.
telsoa014fcda012018-03-09 14:13:49 +000031arm_compute::TensorInfo BuildArmComputeTensorInfo(const armnn::TensorInfo& tensorInfo);
32
Francis Murtagh351d13d2018-09-24 15:01:18 +010033/// Utility function used to convert armnn::DataLayout to arm_compute::DataLayout
34/// armnn::DataLayout.
35arm_compute::DataLayout ConvertDataLayout(armnn::DataLayout dataLayout);
36
37/// Utility function used to setup an arm_compute::ITensorInfo object whose dimensions are based on the given
38/// armnn::ITensorInfo.
39/// armnn::DataLayout.
40arm_compute::TensorInfo BuildArmComputeTensorInfo(const armnn::TensorInfo& tensorInfo,
41 armnn::DataLayout dataLayout);
42
telsoa01c577f2c2018-08-31 09:22:23 +010043/// Utility function used to setup an arm_compute::PoolingLayerInfo object from an armnn::Pooling2dDescriptor.
telsoa014fcda012018-03-09 14:13:49 +000044arm_compute::PoolingLayerInfo BuildArmComputePoolingLayerInfo(const Pooling2dDescriptor& descriptor);
45
telsoa01c577f2c2018-08-31 09:22:23 +010046/// Utility function to setup an arm_compute::NormalizationLayerInfo object from an armnn::NormalizationDescriptor.
telsoa014fcda012018-03-09 14:13:49 +000047arm_compute::NormalizationLayerInfo BuildArmComputeNormalizationLayerInfo(const NormalizationDescriptor& desc);
48
telsoa01c577f2c2018-08-31 09:22:23 +010049/// Utility function used to setup an arm_compute::PermutationVector object from an armnn::PermutationVector.
telsoa014fcda012018-03-09 14:13:49 +000050arm_compute::PermutationVector BuildArmComputePermutationVector(const armnn::PermutationVector& vector);
51
telsoa01c577f2c2018-08-31 09:22:23 +010052/// Utility function used to setup an arm_compute::PadStrideInfo object from an armnn layer descriptor.
surmeh013537c2c2018-05-18 16:31:43 +010053template <typename Descriptor>
54arm_compute::PadStrideInfo BuildArmComputePadStrideInfo(const Descriptor &descriptor)
55{
56 return arm_compute::PadStrideInfo(descriptor.m_StrideX,
57 descriptor.m_StrideY,
58 descriptor.m_PadLeft,
59 descriptor.m_PadRight,
60 descriptor.m_PadTop,
61 descriptor.m_PadBottom,
62 arm_compute::DimensionRoundingType::FLOOR);
63}
64
telsoa014fcda012018-03-09 14:13:49 +000065/// Sets up the given ArmCompute tensor's dimensions based on the given ArmNN tensor.
66template <typename Tensor>
67void BuildArmComputeTensor(Tensor& tensor, const armnn::TensorInfo& tensorInfo)
68{
69 tensor.allocator()->init(BuildArmComputeTensorInfo(tensorInfo));
70}
71
Francis Murtagh351d13d2018-09-24 15:01:18 +010072/// Sets up the given ArmCompute tensor's dimensions based on the given ArmNN tensor.
73template <typename Tensor>
74void BuildArmComputeTensor(Tensor& tensor, const armnn::TensorInfo& tensorInfo, DataLayout dataLayout)
75{
76 tensor.allocator()->init(BuildArmComputeTensorInfo(tensorInfo, dataLayout));
77}
78
telsoa014fcda012018-03-09 14:13:49 +000079template <typename Tensor>
80void InitialiseArmComputeTensorEmpty(Tensor& tensor)
81{
82 tensor.allocator()->allocate();
83}
84
telsoa01c577f2c2018-08-31 09:22:23 +010085/// Utility function to free unused tensors after a workload is configured and prepared
86template <typename Tensor>
87void FreeTensorIfUnused(std::unique_ptr<Tensor>& tensor)
88{
89 if (tensor && !tensor->is_used())
90 {
91 tensor.reset(nullptr);
92 }
93}
94
telsoa014fcda012018-03-09 14:13:49 +000095// Helper function to obtain byte offset into tensor data
96inline size_t GetTensorOffset(const arm_compute::ITensorInfo& info,
97 uint32_t batchIndex,
98 uint32_t channelIndex,
99 uint32_t y,
100 uint32_t x)
101{
102 arm_compute::Coordinates coords;
telsoa01c577f2c2018-08-31 09:22:23 +0100103 coords.set(3, static_cast<int>(batchIndex));
104 coords.set(2, static_cast<int>(channelIndex));
105 coords.set(1, static_cast<int>(y));
106 coords.set(0, static_cast<int>(x));
telsoa014fcda012018-03-09 14:13:49 +0000107 return info.offset_element_in_bytes(coords);
108}
109
telsoa01c577f2c2018-08-31 09:22:23 +0100110// Helper function to obtain element offset into data buffer representing tensor data (assuming no strides).
telsoa014fcda012018-03-09 14:13:49 +0000111inline size_t GetLinearBufferOffset(const arm_compute::ITensorInfo& info,
112 uint32_t batchIndex,
113 uint32_t channelIndex,
114 uint32_t y,
115 uint32_t x)
116{
117 const arm_compute::TensorShape& shape = info.tensor_shape();
telsoa01c577f2c2018-08-31 09:22:23 +0100118 uint32_t width = static_cast<uint32_t>(shape[0]);
119 uint32_t height = static_cast<uint32_t>(shape[1]);
120 uint32_t numChannels = static_cast<uint32_t>(shape[2]);
telsoa014fcda012018-03-09 14:13:49 +0000121 return ((batchIndex * numChannels + channelIndex) * height + y) * width + x;
122}
123
124template <typename T>
125void CopyArmComputeITensorData(const arm_compute::ITensor& srcTensor, T* dstData)
126{
telsoa01c577f2c2018-08-31 09:22:23 +0100127 // If MaxNumOfTensorDimensions is increased, this loop will need fixing.
telsoa014fcda012018-03-09 14:13:49 +0000128 static_assert(MaxNumOfTensorDimensions == 4, "Please update CopyArmComputeITensorData");
129 {
130 const arm_compute::ITensorInfo& info = *srcTensor.info();
131 const arm_compute::TensorShape& shape = info.tensor_shape();
132 const uint8_t* const bufferPtr = srcTensor.buffer();
telsoa01c577f2c2018-08-31 09:22:23 +0100133 uint32_t width = static_cast<uint32_t>(shape[0]);
134 uint32_t height = static_cast<uint32_t>(shape[1]);
135 uint32_t numChannels = static_cast<uint32_t>(shape[2]);
136 uint32_t numBatches = static_cast<uint32_t>(shape[3]);
telsoa014fcda012018-03-09 14:13:49 +0000137
138 for (unsigned int batchIndex = 0; batchIndex < numBatches; ++batchIndex)
139 {
140 for (unsigned int channelIndex = 0; channelIndex < numChannels; ++channelIndex)
141 {
142 for (unsigned int y = 0; y < height; ++y)
143 {
telsoa01c577f2c2018-08-31 09:22:23 +0100144 // Copies one row from arm_compute tensor buffer to linear memory buffer.
145 // A row is the largest contiguous region we can copy, as the tensor data may be using strides.
telsoa014fcda012018-03-09 14:13:49 +0000146 memcpy(dstData + GetLinearBufferOffset(info, batchIndex, channelIndex, y, 0),
147 bufferPtr + GetTensorOffset(info, batchIndex, channelIndex, y, 0),
148 width * sizeof(T));
149 }
150 }
151 }
152 }
153}
154
155template <typename T>
156void CopyArmComputeITensorData(const T* srcData, arm_compute::ITensor& dstTensor)
157{
telsoa01c577f2c2018-08-31 09:22:23 +0100158 // If MaxNumOfTensorDimensions is increased, this loop will need fixing.
telsoa014fcda012018-03-09 14:13:49 +0000159 static_assert(MaxNumOfTensorDimensions == 4, "Please update CopyArmComputeITensorData");
160 {
161 const arm_compute::ITensorInfo& info = *dstTensor.info();
162 const arm_compute::TensorShape& shape = info.tensor_shape();
163 uint8_t* const bufferPtr = dstTensor.buffer();
telsoa01c577f2c2018-08-31 09:22:23 +0100164 uint32_t width = static_cast<uint32_t>(shape[0]);
165 uint32_t height = static_cast<uint32_t>(shape[1]);
166 uint32_t numChannels = static_cast<uint32_t>(shape[2]);
167 uint32_t numBatches = static_cast<uint32_t>(shape[3]);
telsoa014fcda012018-03-09 14:13:49 +0000168
169 for (unsigned int batchIndex = 0; batchIndex < numBatches; ++batchIndex)
170 {
171 for (unsigned int channelIndex = 0; channelIndex < numChannels; ++channelIndex)
172 {
173 for (unsigned int y = 0; y < height; ++y)
174 {
telsoa01c577f2c2018-08-31 09:22:23 +0100175 // Copies one row from linear memory buffer to arm_compute tensor buffer.
176 // A row is the largest contiguous region we can copy, as the tensor data may be using strides.
telsoa014fcda012018-03-09 14:13:49 +0000177 memcpy(bufferPtr + GetTensorOffset(info, batchIndex, channelIndex, y, 0),
178 srcData + GetLinearBufferOffset(info, batchIndex, channelIndex, y, 0),
179 width * sizeof(T));
180 }
181 }
182 }
183 }
184}
185
telsoa01c577f2c2018-08-31 09:22:23 +0100186/// Construct a TensorShape object from an ArmCompute object based on arm_compute::Dimensions.
187/// \tparam ArmComputeType Any type that implements the Dimensions interface
188/// \tparam T Shape value type
189/// \param shapelike An ArmCompute object that implements the Dimensions interface
190/// \param initial A default value to initialise the shape with
191/// \return A TensorShape object filled from the Acl shapelike object.
192template<typename ArmComputeType, typename T>
193TensorShape GetTensorShape(const ArmComputeType& shapelike, T initial)
194{
195 std::vector<unsigned int> s(MaxNumOfTensorDimensions, initial);
196 for (unsigned int i=0; i < shapelike.num_dimensions(); ++i)
197 {
198 s[(shapelike.num_dimensions()-1)-i] = boost::numeric_cast<unsigned int>(shapelike[i]);
199 }
200 return TensorShape(boost::numeric_cast<unsigned int>(shapelike.num_dimensions()), s.data());
201};
202
203/// Get the strides from an ACL strides object
204inline TensorShape GetStrides(const arm_compute::Strides& strides)
205{
206 return GetTensorShape(strides, 0U);
207}
208
209/// Get the shape from an ACL shape object
210inline TensorShape GetShape(const arm_compute::TensorShape& shape)
211{
212 return GetTensorShape(shape, 1U);
213}
214
telsoa014fcda012018-03-09 14:13:49 +0000215} // namespace armcomputetensorutils
216} // namespace armnn