blob: e43a4d5312a69f0cb6c300c23ba701e34d13a598 [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
Matthew Sloyan171214c2020-09-09 09:07:37 +01009#include <armnn/utility/NumericCast.hpp>
10
narpra011e4c31d2018-09-28 11:07:51 +010011#include <boost/numeric/conversion/cast.hpp>
12
13#include <cmath>
14#include <cstddef>
15#include <functional>
16#include <limits>
17
18namespace armnn
19{
20bool NextIndex(const unsigned int numDims, const armnn::TensorShape& dims, std::vector<unsigned int>& current)
21{
22 unsigned int carry = 1;
23
24 for (unsigned int idx = numDims; idx-- > 0; )
25 {
26 unsigned int current_val = current[idx] + carry;
27 if (dims[idx] == current_val)
28 {
29 current[idx] = 0;
30 }
31 else
32 {
33 current[idx] = current_val;
34 carry = 0;
35 break;
36 }
37 }
38 return (carry == 0);
39}
40
James Conroy4d1ff582019-06-10 17:06:39 +010041unsigned int ReducedOutputOffset(const unsigned int numDims,
42 const armnn::TensorShape& dims,
43 std::vector<unsigned int>& index,
44 const unsigned int numAxis,
45 const std::vector<unsigned int>& axis)
46{
47 unsigned int offset = 0;
narpra011e4c31d2018-09-28 11:07:51 +010048 for (unsigned int idx = 0; idx < numDims; ++idx)
49 {
50 bool isAxis = false;
51 if (!axis.empty())
52 {
53 for (unsigned int axisIdx = 0; axisIdx < numAxis; ++axisIdx)
54 {
55 if (idx == axis[axisIdx])
56 {
57 isAxis = true;
58 break;
59 }
60 }
61 }
62 if (!isAxis)
63 {
James Conroy4d1ff582019-06-10 17:06:39 +010064 offset = offset * dims[idx] + index[idx];
narpra011e4c31d2018-09-28 11:07:51 +010065 }
66 }
67 return offset;
68}
69} // namespace
70
71namespace armnn
72{
73void Mean(const armnn::TensorInfo& inputInfo,
74 const armnn::TensorInfo& outputInfo,
75 const std::vector<unsigned int>& axis,
James Conroy4d1ff582019-06-10 17:06:39 +010076 Decoder<float>& input,
77 Encoder<float>& output)
78{
narpra011e4c31d2018-09-28 11:07:51 +010079
80 unsigned int inputNumDims = inputInfo.GetNumDimensions();
81 unsigned int outputNumDims = outputInfo.GetNumDimensions();
82
83 armnn::TensorShape outputDims = outputInfo.GetShape();
84 armnn::TensorShape inputDims = inputInfo.GetShape();
85
86 // Initialise output data.
James Conroy4d1ff582019-06-10 17:06:39 +010087 unsigned int numOutputs = 1;
narpra011e4c31d2018-09-28 11:07:51 +010088 for (unsigned int idx = 0; idx < outputNumDims; ++idx)
89 {
James Conroy4d1ff582019-06-10 17:06:39 +010090 numOutputs *= outputDims[idx];
narpra011e4c31d2018-09-28 11:07:51 +010091 }
92
93 std::vector<float> tempSum(numOutputs);
James Conroy4d1ff582019-06-10 17:06:39 +010094 for (unsigned int idx = 0; idx < numOutputs; ++idx)
narpra011e4c31d2018-09-28 11:07:51 +010095 {
James Conroy4d1ff582019-06-10 17:06:39 +010096 output[idx];
97 output.Set(0.0f);
narpra011e4c31d2018-09-28 11:07:51 +010098 tempSum[idx] = 0.0f;
99 }
100
101 // Initialise temp index.
102 std::vector<unsigned int> tempIndex(inputNumDims);
103 for (unsigned int idx = 0; idx < inputNumDims; ++idx)
104 {
105 tempIndex[idx] = 0;
106 }
107
108 std::vector<unsigned int> resolvedAxis = axis;
109 if (resolvedAxis.empty())
110 {
111 for (unsigned int idx = 0; idx < inputNumDims; ++idx)
112 {
113 resolvedAxis.push_back(idx);
114 }
115 }
Matthew Sloyan171214c2020-09-09 09:07:37 +0100116 auto numResolvedAxis = armnn::numeric_cast<unsigned int>(resolvedAxis.size());
narpra011e4c31d2018-09-28 11:07:51 +0100117
118 // Iterates through input_data and sum up the reduced axis.
119 for (bool hasNext = true; hasNext; hasNext = NextIndex(inputNumDims, inputDims, tempIndex))
120 {
James Conroy4d1ff582019-06-10 17:06:39 +0100121 unsigned int inputOffset = ReducedOutputOffset(inputNumDims, inputDims, tempIndex, 0, {});
122 unsigned int outputOffset = ReducedOutputOffset(inputNumDims, inputDims, tempIndex,
123 numResolvedAxis, resolvedAxis);
124 input[inputOffset];
125 tempSum[outputOffset] += input.Get();
narpra011e4c31d2018-09-28 11:07:51 +0100126 }
127
128 // Takes average by num of elements added to get mean.
129 size_t numElementsInAxis = 1;
130 for (unsigned int idx = 0; idx < numResolvedAxis; ++idx)
131 {
James Conroy4d1ff582019-06-10 17:06:39 +0100132 unsigned int current = inputDims[resolvedAxis[idx]];
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100133 ARMNN_ASSERT(boost::numeric_cast<float>(current) <
narpra011e4c31d2018-09-28 11:07:51 +0100134 (std::numeric_limits<float>::max() / boost::numeric_cast<float>(numElementsInAxis)));
135 numElementsInAxis *= current;
136 }
137 if (numElementsInAxis > 0) {
James Conroy4d1ff582019-06-10 17:06:39 +0100138 for (unsigned int idx = 0; idx < numOutputs; ++idx)
narpra011e4c31d2018-09-28 11:07:51 +0100139 {
James Conroy4d1ff582019-06-10 17:06:39 +0100140 output[idx];
141 output.Set(tempSum[idx] / boost::numeric_cast<float>(numElementsInAxis));
narpra011e4c31d2018-09-28 11:07:51 +0100142 }
143 }
144}
145} //namespace armnn