From 1e4c31dafb1c8984a126fa1d211ed8f9eedaf7cc Mon Sep 17 00:00:00 2001 From: narpra01 Date: Fri, 28 Sep 2018 11:07:51 +0100 Subject: IVGCVSW-1812 Adding Ref implementation and tests of MeanWorkloads Change-Id: I6fb15c407024e3b91d5abf4513f8090be5821760 --- src/backends/reference/workloads/Mean.cpp | 136 ++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 src/backends/reference/workloads/Mean.cpp (limited to 'src/backends/reference/workloads/Mean.cpp') diff --git a/src/backends/reference/workloads/Mean.cpp b/src/backends/reference/workloads/Mean.cpp new file mode 100644 index 0000000000..0db67a0eed --- /dev/null +++ b/src/backends/reference/workloads/Mean.cpp @@ -0,0 +1,136 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "Mean.hpp" +#include "backends/WorkloadData.hpp" + +#include + +#include +#include +#include +#include + +namespace armnn +{ +bool NextIndex(const unsigned int numDims, const armnn::TensorShape& dims, std::vector& current) +{ + unsigned int carry = 1; + + for (unsigned int idx = numDims; idx-- > 0; ) + { + unsigned int current_val = current[idx] + carry; + if (dims[idx] == current_val) + { + current[idx] = 0; + } + else + { + current[idx] = current_val; + carry = 0; + break; + } + } + return (carry == 0); +} + +std::size_t ReducedOutputOffset(const unsigned int numDims, const armnn::TensorShape& dims, + std::vector& index, const unsigned int numAxis, + const std::vector& axis) { + std::size_t offset = 0; + for (unsigned int idx = 0; idx < numDims; ++idx) + { + bool isAxis = false; + if (!axis.empty()) + { + for (unsigned int axisIdx = 0; axisIdx < numAxis; ++axisIdx) + { + if (idx == axis[axisIdx]) + { + isAxis = true; + break; + } + } + } + if (!isAxis) + { + offset = offset * boost::numeric_cast(dims[idx]) + boost::numeric_cast(index[idx]); + } + } + return offset; +} +} // namespace + +namespace armnn +{ +void Mean(const armnn::TensorInfo& inputInfo, + const armnn::TensorInfo& outputInfo, + const std::vector& axis, + const float* inputData, + float* outputData) { + + unsigned int inputNumDims = inputInfo.GetNumDimensions(); + unsigned int outputNumDims = outputInfo.GetNumDimensions(); + + armnn::TensorShape outputDims = outputInfo.GetShape(); + armnn::TensorShape inputDims = inputInfo.GetShape(); + + // Initialise output data. + size_t numOutputs = 1; + for (unsigned int idx = 0; idx < outputNumDims; ++idx) + { + numOutputs *= boost::numeric_cast(outputDims[idx]); + } + + std::vector tempSum(numOutputs); + for (size_t idx = 0; idx < numOutputs; ++idx) + { + outputData[idx] = 0.0f; + tempSum[idx] = 0.0f; + } + + // Initialise temp index. + std::vector tempIndex(inputNumDims); + for (unsigned int idx = 0; idx < inputNumDims; ++idx) + { + tempIndex[idx] = 0; + } + + std::vector resolvedAxis = axis; + if (resolvedAxis.empty()) + { + for (unsigned int idx = 0; idx < inputNumDims; ++idx) + { + resolvedAxis.push_back(idx); + } + } + unsigned int numResolvedAxis = boost::numeric_cast(resolvedAxis.size()); + + // Iterates through input_data and sum up the reduced axis. + for (bool hasNext = true; hasNext; hasNext = NextIndex(inputNumDims, inputDims, tempIndex)) + { + size_t inputOffset = ReducedOutputOffset(inputNumDims, inputDims, tempIndex, 0, {}); + size_t outputOffset = ReducedOutputOffset(inputNumDims, inputDims, tempIndex, + numResolvedAxis, resolvedAxis); + tempSum[outputOffset] += inputData[inputOffset]; + } + + // Takes average by num of elements added to get mean. + size_t numElementsInAxis = 1; + for (unsigned int idx = 0; idx < numResolvedAxis; ++idx) + { + size_t current = boost::numeric_cast(inputDims[resolvedAxis[idx]]); + BOOST_ASSERT(boost::numeric_cast(current) < + (std::numeric_limits::max() / boost::numeric_cast(numElementsInAxis))); + numElementsInAxis *= current; + } + if (numElementsInAxis > 0) { + for (size_t idx = 0; idx < numOutputs; ++idx) + { + outputData[idx] = tempSum[idx] / boost::numeric_cast(numElementsInAxis); + } + } +} +} //namespace armnn -- cgit v1.2.1