• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include <armnnUtils/TensorUtils.hpp>
7 
8 #include <armnn/backends/ITensorHandle.hpp>
9 #include <armnn/utility/Assert.hpp>
10 #include <armnn/utility/NumericCast.hpp>
11 
12 #include <fmt/format.h>
13 
14 using namespace armnn;
15 
16 namespace armnnUtils
17 {
18 
GetTensorShape(unsigned int numberOfBatches,unsigned int numberOfChannels,unsigned int height,unsigned int width,const DataLayout dataLayout)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 
GetTensorInfo(unsigned int numberOfBatches,unsigned int numberOfChannels,unsigned int height,unsigned int width,const DataLayout dataLayout,const DataType dataType)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 
FindMinMax(ITensorHandle * tensorHandle)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 
ExpandDims(const TensorShape & tensorShape,int axis)85 TensorShape ExpandDims(const TensorShape& tensorShape, int axis)
86 {
87     unsigned int outputDim = tensorShape.GetNumDimensions() + 1;
88 
89     if (axis < -armnn::numeric_cast<int>(outputDim) || axis > armnn::numeric_cast<int>(tensorShape.GetNumDimensions()))
90     {
91         throw InvalidArgumentException(fmt::format("Invalid expansion axis {} for {}D input tensor. {}",
92                                                    axis,
93                                                    tensorShape.GetNumDimensions(),
94                                                    CHECK_LOCATION().AsString()));
95     }
96 
97     if (axis < 0)
98     {
99         axis = armnn::numeric_cast<int>(outputDim) + axis;
100     }
101 
102     std::vector<unsigned int> outputShape;
103     outputShape.reserve(tensorShape.GetNumDimensions());
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 
GetNumElementsBetween(const TensorShape & shape,const unsigned int firstAxisInclusive,const unsigned int lastAxisExclusive)113 unsigned int GetNumElementsBetween(const TensorShape& shape,
114                                    const unsigned int firstAxisInclusive,
115                                    const unsigned int lastAxisExclusive)
116 {
117     ARMNN_ASSERT(firstAxisInclusive <= lastAxisExclusive);
118     ARMNN_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 
GetUnsignedAxis(const unsigned int inputDimension,const int axis)127 unsigned int GetUnsignedAxis(const unsigned int inputDimension, const int axis)
128 {
129     ARMNN_ASSERT_MSG(axis < armnn::numeric_cast<int>(inputDimension),
130                      "Required axis index greater than number of dimensions.");
131     ARMNN_ASSERT_MSG(axis >= -armnn::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 - armnn::numeric_cast<unsigned int>(abs(axis))
136                          : armnn::numeric_cast<unsigned int>(axis);
137     return uAxis;
138 }
139 
GetNumElementsAfter(const armnn::TensorShape & shape,unsigned int axis)140 unsigned int GetNumElementsAfter(const armnn::TensorShape& shape, unsigned int axis)
141 {
142     unsigned int numDim = shape.GetNumDimensions();
143     ARMNN_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 
GetPerAxisParams(const armnn::TensorInfo & info)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     {
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 
167 } // namespace armnnUtils
168