blob: 952c76885a5db6f9a5539b248fb5ba2011ced288 [file] [log] [blame]
Nina Drozdd41b2592018-11-19 13:03:36 +00001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
Matteo Martincighe011d202019-11-28 11:35:47 +00006#include <armnnUtils/TensorUtils.hpp>
Matteo Martincigh9a5f9f22019-10-31 11:02:47 +00007
Matteo Martincighe5b8eb92019-11-28 15:45:42 +00008#include <armnn/backends/ITensorHandle.hpp>
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +01009#include <armnn/utility/Assert.hpp>
Nina Drozdd41b2592018-11-19 13:03:36 +000010
Narumol Prangnawarat02807852019-09-11 16:43:09 +010011#include <boost/format.hpp>
12#include <boost/numeric/conversion/cast.hpp>
13
Matteo Martincigh9a5f9f22019-10-31 11:02:47 +000014using namespace armnn;
15
Nina Drozdd41b2592018-11-19 13:03:36 +000016namespace armnnUtils
17{
18
Matteo Martincigh9a5f9f22019-10-31 11:02:47 +000019TensorShape GetTensorShape(unsigned int numberOfBatches,
Nina Drozdd41b2592018-11-19 13:03:36 +000020 unsigned int numberOfChannels,
21 unsigned int height,
22 unsigned int width,
Matteo Martincigh9a5f9f22019-10-31 11:02:47 +000023 const DataLayout dataLayout)
Nina Drozdd41b2592018-11-19 13:03:36 +000024{
25 switch (dataLayout)
26 {
Matteo Martincigh9a5f9f22019-10-31 11:02:47 +000027 case DataLayout::NCHW:
28 return TensorShape({numberOfBatches, numberOfChannels, height, width});
29 case DataLayout::NHWC:
30 return TensorShape({numberOfBatches, height, width, numberOfChannels});
Nina Drozdd41b2592018-11-19 13:03:36 +000031 default:
Matteo Martincigh9a5f9f22019-10-31 11:02:47 +000032 throw InvalidArgumentException("Unknown data layout ["
Nina Drozdd41b2592018-11-19 13:03:36 +000033 + std::to_string(static_cast<int>(dataLayout)) +
34 "]", CHECK_LOCATION());
35 }
36}
37
Matteo Martincigh9a5f9f22019-10-31 11:02:47 +000038TensorInfo GetTensorInfo(unsigned int numberOfBatches,
Nattapat Chaimanowong649dd952019-01-22 16:10:44 +000039 unsigned int numberOfChannels,
40 unsigned int height,
41 unsigned int width,
Matteo Martincigh9a5f9f22019-10-31 11:02:47 +000042 const DataLayout dataLayout,
43 const DataType dataType)
Nattapat Chaimanowong649dd952019-01-22 16:10:44 +000044{
45 switch (dataLayout)
46 {
Matteo Martincigh9a5f9f22019-10-31 11:02:47 +000047 case DataLayout::NCHW:
48 return TensorInfo({numberOfBatches, numberOfChannels, height, width}, dataType);
49 case DataLayout::NHWC:
50 return TensorInfo({numberOfBatches, height, width, numberOfChannels}, dataType);
Nattapat Chaimanowong649dd952019-01-22 16:10:44 +000051 default:
Matteo Martincigh9a5f9f22019-10-31 11:02:47 +000052 throw InvalidArgumentException("Unknown data layout ["
Nattapat Chaimanowong649dd952019-01-22 16:10:44 +000053 + std::to_string(static_cast<int>(dataLayout)) +
54 "]", CHECK_LOCATION());
55 }
Nina Drozdd41b2592018-11-19 13:03:36 +000056}
57
Matteo Martincigh9a5f9f22019-10-31 11:02:47 +000058std::pair<float, float> FindMinMax(ITensorHandle* tensorHandle)
Jim Flynnf92dfce2019-05-02 11:33:25 +010059{
60 auto tensor_data = static_cast<const float *>(tensorHandle->Map(true));
61 auto tensor_size = tensorHandle->GetShape().GetNumElements();
62
63 // Set min/max initially to first value in tensor
64 float min = tensor_data[0];
65 float max = tensor_data[0];
66
67 // Loop over rest of tensor and update min/max if necessary
68 for (unsigned int val = 1; val < tensor_size; val++)
69 {
70 if (tensor_data[val] < min)
71 {
72 min = tensor_data[val];
73 }
74 else if (tensor_data[val] > max)
75 {
76 max = tensor_data[val];
77 }
78 }
79
80 tensorHandle->Unmap();
81
82 return std::make_pair(min, max);
83}
84
Matteo Martincigh9a5f9f22019-10-31 11:02:47 +000085TensorShape ExpandDims(const TensorShape& tensorShape, int axis)
Narumol Prangnawarat02807852019-09-11 16:43:09 +010086{
87 unsigned int outputDim = tensorShape.GetNumDimensions() + 1;
88
89 if (axis < -boost::numeric_cast<int>(outputDim) || axis > boost::numeric_cast<int>(tensorShape.GetNumDimensions()))
90 {
Matteo Martincigh9a5f9f22019-10-31 11:02:47 +000091 throw InvalidArgumentException(
Narumol Prangnawarat02807852019-09-11 16:43:09 +010092 boost::str(boost::format("Invalid expansion axis %1% for %2%D input tensor. %3%") %
93 axis %
94 tensorShape.GetNumDimensions() %
95 CHECK_LOCATION().AsString()));
96 }
97
98 if (axis < 0)
99 {
100 axis = boost::numeric_cast<int>(outputDim) + axis;
101 }
102
103 std::vector<unsigned int> outputShape;
104 for (unsigned int i = 0; i < tensorShape.GetNumDimensions(); ++i)
105 {
106 outputShape.push_back(tensorShape[i]);
107 }
108 outputShape.insert(outputShape.begin() + axis, 1);
109
Matteo Martincigh9a5f9f22019-10-31 11:02:47 +0000110 return TensorShape(outputDim, outputShape.data());
Narumol Prangnawarat02807852019-09-11 16:43:09 +0100111}
112
Matteo Martincigh9a5f9f22019-10-31 11:02:47 +0000113unsigned int GetNumElementsBetween(const TensorShape& shape,
Narumol Prangnawarat4dc64a62019-09-16 17:00:22 +0100114 const unsigned int firstAxisInclusive,
115 const unsigned int lastAxisExclusive)
116{
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100117 ARMNN_ASSERT(firstAxisInclusive <= lastAxisExclusive);
118 ARMNN_ASSERT(lastAxisExclusive <= shape.GetNumDimensions());
Narumol Prangnawarat4dc64a62019-09-16 17:00:22 +0100119 unsigned int count = 1;
120 for (unsigned int i = firstAxisInclusive; i < lastAxisExclusive; i++)
121 {
122 count *= shape[i];
123 }
124 return count;
125}
126
127unsigned int GetUnsignedAxis(const unsigned int inputDimension, const int axis)
128{
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100129 ARMNN_ASSERT_MSG(axis < boost::numeric_cast<int>(inputDimension),
Narumol Prangnawarat4dc64a62019-09-16 17:00:22 +0100130 "Required axis index greater than number of dimensions.");
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100131 ARMNN_ASSERT_MSG(axis >= -boost::numeric_cast<int>(inputDimension),
Narumol Prangnawarat4dc64a62019-09-16 17:00:22 +0100132 "Required axis index lower than negative of the number of dimensions");
133
134 unsigned int uAxis = axis < 0 ?
135 inputDimension - boost::numeric_cast<unsigned int>(abs(axis))
136 : boost::numeric_cast<unsigned int>(axis);
137 return uAxis;
138}
139
Aron Virginas-Tarb67f9572019-11-04 15:00:19 +0000140unsigned int GetNumElementsAfter(const armnn::TensorShape& shape, unsigned int axis)
141{
142 unsigned int numDim = shape.GetNumDimensions();
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100143 ARMNN_ASSERT(axis <= numDim - 1);
Aron Virginas-Tarb67f9572019-11-04 15:00:19 +0000144 unsigned int count = 1;
145 for (unsigned int i = axis; i < numDim; i++)
146 {
147 count *= shape[i];
148 }
149 return count;
150}
151
152std::pair<unsigned int, std::vector<float>> GetPerAxisParams(const armnn::TensorInfo& info)
153{
154 const std::vector<float>& scales = info.GetQuantizationScales();
155 armnn::Optional<unsigned int> quantizationDim = info.GetQuantizationDim();
Aron Virginas-Tar5edc8812019-11-05 18:00:21 +0000156 if (!info.HasPerAxisQuantization())
Aron Virginas-Tarb67f9572019-11-04 15:00:19 +0000157 {
158 throw armnn::InvalidArgumentException(
159 std::string("Per-axis quantization params not set for tensor of type ") +
160 armnn::GetDataTypeName(info.GetDataType()), CHECK_LOCATION());
161 }
162 unsigned int axisFactor = GetNumElementsAfter(info.GetShape(), quantizationDim.value());
163
164 return { axisFactor, scales };
165}
166
Matteo Martincigh9a5f9f22019-10-31 11:02:47 +0000167} // namespace armnnUtils