ArmNN  NotReleased
TensorUtils.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
7 
9 
10 #include <boost/assert.hpp>
11 #include <boost/format.hpp>
12 #include <boost/numeric/conversion/cast.hpp>
13 
14 using namespace armnn;
15 
16 namespace armnnUtils
17 {
18 
19 TensorShape GetTensorShape(unsigned int numberOfBatches,
20  unsigned int numberOfChannels,
21  unsigned int height,
22  unsigned int width,
23  const DataLayout dataLayout)
24 {
25  switch (dataLayout)
26  {
27  case DataLayout::NCHW:
28  return TensorShape({numberOfBatches, numberOfChannels, height, width});
29  case DataLayout::NHWC:
30  return TensorShape({numberOfBatches, height, width, numberOfChannels});
31  default:
32  throw InvalidArgumentException("Unknown data layout ["
33  + std::to_string(static_cast<int>(dataLayout)) +
34  "]", CHECK_LOCATION());
35  }
36 }
37 
38 TensorInfo GetTensorInfo(unsigned int numberOfBatches,
39  unsigned int numberOfChannels,
40  unsigned int height,
41  unsigned int width,
42  const DataLayout dataLayout,
43  const DataType dataType)
44 {
45  switch (dataLayout)
46  {
47  case DataLayout::NCHW:
48  return TensorInfo({numberOfBatches, numberOfChannels, height, width}, dataType);
49  case DataLayout::NHWC:
50  return TensorInfo({numberOfBatches, height, width, numberOfChannels}, dataType);
51  default:
52  throw InvalidArgumentException("Unknown data layout ["
53  + std::to_string(static_cast<int>(dataLayout)) +
54  "]", CHECK_LOCATION());
55  }
56 }
57 
58 std::pair<float, float> FindMinMax(ITensorHandle* tensorHandle)
59 {
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 
85 TensorShape ExpandDims(const TensorShape& tensorShape, int axis)
86 {
87  unsigned int outputDim = tensorShape.GetNumDimensions() + 1;
88 
89  if (axis < -boost::numeric_cast<int>(outputDim) || axis > boost::numeric_cast<int>(tensorShape.GetNumDimensions()))
90  {
92  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 
110  return TensorShape(outputDim, outputShape.data());
111 }
112 
113 unsigned int GetNumElementsBetween(const TensorShape& shape,
114  const unsigned int firstAxisInclusive,
115  const unsigned int lastAxisExclusive)
116 {
117  BOOST_ASSERT(firstAxisInclusive <= lastAxisExclusive);
118  BOOST_ASSERT(lastAxisExclusive <= shape.GetNumDimensions());
119  unsigned int count = 1;
120  for (unsigned int i = firstAxisInclusive; i < lastAxisExclusive; i++)
121  {
122  count *= shape[i];
123  }
124  return count;
125 }
126 
127 unsigned int GetUnsignedAxis(const unsigned int inputDimension, const int axis)
128 {
129  BOOST_ASSERT_MSG(axis < boost::numeric_cast<int>(inputDimension),
130  "Required axis index greater than number of dimensions.");
131  BOOST_ASSERT_MSG(axis >= -boost::numeric_cast<int>(inputDimension),
132  "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 
140 unsigned int GetNumElementsAfter(const armnn::TensorShape& shape, unsigned int axis)
141 {
142  unsigned int numDim = shape.GetNumDimensions();
143  BOOST_ASSERT(axis <= numDim - 1);
144  unsigned int count = 1;
145  for (unsigned int i = axis; i < numDim; i++)
146  {
147  count *= shape[i];
148  }
149  return count;
150 }
151 
152 std::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();
156  if (!info.HasPerAxisQuantization())
157  {
159  std::string("Per-axis quantization params not set for tensor of type ") +
161  }
162  unsigned int axisFactor = GetNumElementsAfter(info.GetShape(), quantizationDim.value());
163 
164  return { axisFactor, scales };
165 }
166 
167 } // namespace armnnUtils
armnn::TensorShape GetTensorShape(unsigned int numberOfBatches, unsigned int numberOfChannels, unsigned int height, unsigned int width, const armnn::DataLayout dataLayout)
Definition: TensorUtils.cpp:19
bool HasPerAxisQuantization() const
Definition: Tensor.cpp:232
unsigned int GetNumDimensions() const
Definition: Tensor.hpp:43
std::pair< float, float > FindMinMax(armnn::ITensorHandle *tensorHandle)
Definition: TensorUtils.cpp:58
unsigned int GetUnsignedAxis(const unsigned int inputDimension, const int axis)
virtual const void * Map(bool blocking=true) const =0
#define CHECK_LOCATION()
Definition: Exceptions.hpp:169
virtual TensorShape GetShape() const =0
Optional< unsigned int > GetQuantizationDim() const
Definition: Tensor.cpp:280
std::pair< unsigned int, std::vector< float > > GetPerAxisParams(const armnn::TensorInfo &info)
armnn::TensorShape ExpandDims(const armnn::TensorShape &tensorShape, int axis)
Definition: TensorUtils.cpp:85
unsigned int GetNumElements() const
Definition: Tensor.cpp:106
std::vector< float > GetQuantizationScales() const
Definition: Tensor.cpp:237
virtual void Unmap() const =0
Unmap the tensor data.
DataLayout
Definition: Types.hpp:48
DataType
Definition: Types.hpp:32
DataType GetDataType() const
Definition: Tensor.hpp:95
unsigned int GetNumElementsBetween(const armnn::TensorShape &shape, unsigned int firstAxisInclusive, unsigned int lastAxisExclusive)
const TensorShape & GetShape() const
Definition: Tensor.hpp:88
constexpr const char * GetDataTypeName(DataType dataType)
Definition: TypesUtils.hpp:165
const TensorInfo & GetTensorInfo(const ITensorHandle *tensorHandle)
float32 helpers
unsigned int GetNumElementsAfter(const armnn::TensorShape &shape, unsigned int axis)