2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
8 #include <TensorUtils.hpp>
16 /// Computes the softmax function on some inputs, into outputs, with a shape given by tensorInfo.
17 void Softmax(Decoder<float>& in, Encoder<float>& out, const TensorInfo& inputTensorInfo, float beta, int axis)
19 BOOST_ASSERT_MSG(axis < static_cast<int>(inputTensorInfo.GetNumDimensions()),
20 "Required axis index greater than number of dimensions.");
21 BOOST_ASSERT_MSG(axis >= -static_cast<int>(inputTensorInfo.GetNumDimensions()),
22 "Required axis index lower than negative of the number of dimensions");
24 unsigned int uAxis = axis < 0 ?
25 inputTensorInfo.GetNumDimensions() - static_cast<unsigned int>(abs(axis))
26 : static_cast<unsigned int>(axis);
28 const TensorShape& inputShape = inputTensorInfo.GetShape();
29 const unsigned int outerSize = armnnUtils::GetNumElementsBetween(inputShape, 0, uAxis);
30 const unsigned int axisSize = inputShape[uAxis];
31 const unsigned int innerSize = armnnUtils::GetNumElementsBetween(inputShape,
33 inputShape.GetNumDimensions());
35 for (unsigned int outer = 0; outer < outerSize; ++outer)
37 unsigned int inputBeginIdx = outer * axisSize * innerSize;
38 unsigned int inputEndIdx = inputBeginIdx + axisSize * innerSize;
39 unsigned int outputBeginIdx = outer * axisSize * innerSize;
41 for (unsigned int inner = 0; inner < innerSize; ++inner, ++inputBeginIdx, ++inputEndIdx, ++outputBeginIdx)
44 float maxValue = std::numeric_limits<float>::lowest();
45 for (unsigned int iter = inputBeginIdx; iter < inputEndIdx; iter += innerSize)
48 maxValue = std::max(maxValue, in.Get());
53 for (unsigned int iter = inputBeginIdx; iter < inputEndIdx; iter += innerSize)
56 sum += std::exp((in.Get() - maxValue) * beta);
60 unsigned int outputIter = outputBeginIdx;
62 for (unsigned int iter = inputBeginIdx; iter < inputEndIdx; iter += innerSize, outputIter += innerSize)
66 out.Set(std::exp((in.Get() - maxValue) * beta) / sum);