blob: f2c0a4fc3f25ac5034c79d5ffdd68b0e5fcaa348 [file] [log] [blame]
narpra011e4c31d2018-09-28 11:07:51 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "Mean.hpp"
Matteo Martincighe5b8eb92019-11-28 15:45:42 +00007#include <backendsCommon/WorkloadData.hpp>
narpra011e4c31d2018-09-28 11:07:51 +01008
9#include <boost/numeric/conversion/cast.hpp>
10
11#include <cmath>
12#include <cstddef>
13#include <functional>
14#include <limits>
15
16namespace armnn
17{
18bool NextIndex(const unsigned int numDims, const armnn::TensorShape& dims, std::vector<unsigned int>& current)
19{
20 unsigned int carry = 1;
21
22 for (unsigned int idx = numDims; idx-- > 0; )
23 {
24 unsigned int current_val = current[idx] + carry;
25 if (dims[idx] == current_val)
26 {
27 current[idx] = 0;
28 }
29 else
30 {
31 current[idx] = current_val;
32 carry = 0;
33 break;
34 }
35 }
36 return (carry == 0);
37}
38
James Conroy4d1ff582019-06-10 17:06:39 +010039unsigned int ReducedOutputOffset(const unsigned int numDims,
40 const armnn::TensorShape& dims,
41 std::vector<unsigned int>& index,
42 const unsigned int numAxis,
43 const std::vector<unsigned int>& axis)
44{
45 unsigned int offset = 0;
narpra011e4c31d2018-09-28 11:07:51 +010046 for (unsigned int idx = 0; idx < numDims; ++idx)
47 {
48 bool isAxis = false;
49 if (!axis.empty())
50 {
51 for (unsigned int axisIdx = 0; axisIdx < numAxis; ++axisIdx)
52 {
53 if (idx == axis[axisIdx])
54 {
55 isAxis = true;
56 break;
57 }
58 }
59 }
60 if (!isAxis)
61 {
James Conroy4d1ff582019-06-10 17:06:39 +010062 offset = offset * dims[idx] + index[idx];
narpra011e4c31d2018-09-28 11:07:51 +010063 }
64 }
65 return offset;
66}
67} // namespace
68
69namespace armnn
70{
71void Mean(const armnn::TensorInfo& inputInfo,
72 const armnn::TensorInfo& outputInfo,
73 const std::vector<unsigned int>& axis,
James Conroy4d1ff582019-06-10 17:06:39 +010074 Decoder<float>& input,
75 Encoder<float>& output)
76{
narpra011e4c31d2018-09-28 11:07:51 +010077
78 unsigned int inputNumDims = inputInfo.GetNumDimensions();
79 unsigned int outputNumDims = outputInfo.GetNumDimensions();
80
81 armnn::TensorShape outputDims = outputInfo.GetShape();
82 armnn::TensorShape inputDims = inputInfo.GetShape();
83
84 // Initialise output data.
James Conroy4d1ff582019-06-10 17:06:39 +010085 unsigned int numOutputs = 1;
narpra011e4c31d2018-09-28 11:07:51 +010086 for (unsigned int idx = 0; idx < outputNumDims; ++idx)
87 {
James Conroy4d1ff582019-06-10 17:06:39 +010088 numOutputs *= outputDims[idx];
narpra011e4c31d2018-09-28 11:07:51 +010089 }
90
91 std::vector<float> tempSum(numOutputs);
James Conroy4d1ff582019-06-10 17:06:39 +010092 for (unsigned int idx = 0; idx < numOutputs; ++idx)
narpra011e4c31d2018-09-28 11:07:51 +010093 {
James Conroy4d1ff582019-06-10 17:06:39 +010094 output[idx];
95 output.Set(0.0f);
narpra011e4c31d2018-09-28 11:07:51 +010096 tempSum[idx] = 0.0f;
97 }
98
99 // Initialise temp index.
100 std::vector<unsigned int> tempIndex(inputNumDims);
101 for (unsigned int idx = 0; idx < inputNumDims; ++idx)
102 {
103 tempIndex[idx] = 0;
104 }
105
106 std::vector<unsigned int> resolvedAxis = axis;
107 if (resolvedAxis.empty())
108 {
109 for (unsigned int idx = 0; idx < inputNumDims; ++idx)
110 {
111 resolvedAxis.push_back(idx);
112 }
113 }
James Conroy4d1ff582019-06-10 17:06:39 +0100114 auto numResolvedAxis = boost::numeric_cast<unsigned int>(resolvedAxis.size());
narpra011e4c31d2018-09-28 11:07:51 +0100115
116 // Iterates through input_data and sum up the reduced axis.
117 for (bool hasNext = true; hasNext; hasNext = NextIndex(inputNumDims, inputDims, tempIndex))
118 {
James Conroy4d1ff582019-06-10 17:06:39 +0100119 unsigned int inputOffset = ReducedOutputOffset(inputNumDims, inputDims, tempIndex, 0, {});
120 unsigned int outputOffset = ReducedOutputOffset(inputNumDims, inputDims, tempIndex,
121 numResolvedAxis, resolvedAxis);
122 input[inputOffset];
123 tempSum[outputOffset] += input.Get();
narpra011e4c31d2018-09-28 11:07:51 +0100124 }
125
126 // Takes average by num of elements added to get mean.
127 size_t numElementsInAxis = 1;
128 for (unsigned int idx = 0; idx < numResolvedAxis; ++idx)
129 {
James Conroy4d1ff582019-06-10 17:06:39 +0100130 unsigned int current = inputDims[resolvedAxis[idx]];
narpra011e4c31d2018-09-28 11:07:51 +0100131 BOOST_ASSERT(boost::numeric_cast<float>(current) <
132 (std::numeric_limits<float>::max() / boost::numeric_cast<float>(numElementsInAxis)));
133 numElementsInAxis *= current;
134 }
135 if (numElementsInAxis > 0) {
James Conroy4d1ff582019-06-10 17:06:39 +0100136 for (unsigned int idx = 0; idx < numOutputs; ++idx)
narpra011e4c31d2018-09-28 11:07:51 +0100137 {
James Conroy4d1ff582019-06-10 17:06:39 +0100138 output[idx];
139 output.Set(tempSum[idx] / boost::numeric_cast<float>(numElementsInAxis));
narpra011e4c31d2018-09-28 11:07:51 +0100140 }
141 }
142}
143} //namespace armnn