diff options
author | Sadik Armagan <sadik.armagan@arm.com> | 2021-02-03 09:29:30 +0000 |
---|---|---|
committer | Sadik Armagan <sadik.armagan@arm.com> | 2021-02-03 09:29:47 +0000 |
commit | 0c3ea5b8ac5ad8ca516930a0491afb1d1074e45b (patch) | |
tree | 47ff1e9c1c70a3b134c1e9063dada66d70a7c963 /src/backends/reference/workloads/Reduce.cpp | |
parent | 84f41eb74765bd93307f3c6b334354c486dc746d (diff) | |
download | armnn-0c3ea5b8ac5ad8ca516930a0491afb1d1074e45b.tar.gz |
backends/reference: Add ReduceSum operation support
This patch addes ReduceSum operation support for reference backend,
which computes the sum of elements across dimensions of a tensor.
Changelog v1:
- Fix file header descriptions.
Chagelog v2:
- Fix line limit issue.
- Fix type conversion issue.
Changelog v3:
- Remove tabs.
- Modify newly added file headers.
Changelog v4:
- Symbol on header isn't allowed so drop it from newly added file headers.
Changelog v5:
- Remove tabs, fix the use of brackets and align lines correctly.
Changelog v6:
- Add serializer and deserializer support.
Changelog v7:
- Fix build error add missed code.
Changelog v8:
- Rename ReduceSumDecriptor to ReduceDescriptor
- Update m_KeepDims field data type to bool on ReduceDescriptor
- Add ReduceOperation field to ReduceDescriptor
- Rename ReduceSumLayer to ReduceLayer
- Update ReduceLayer to use ReduceDescriptor
- Update ReduceLayer::ValidateTensorShapesFromInputs() function
- Rename RefReduceSumWokload to RefReduceWorkload
- Update workload to use ReduceDescriptor
- Update workload to use Decoders and Encoders
- Remove ReduceSum.hpp and ReduceSum.cpp
- Added Reduce.hpp and Reduce.cpp
- Move Mean.cpp (which is implementing REDUCE_MEAN) functionality to Reduce.cpp
- Update RefMeanWorkload to call Reduce function with ReduceOperation::Mean argument
- Remove Mean.hpp and Mean.cpp
- Update the Serializer/Deserializer ArmnnSchema.fbs for ReduceLayer, ReduceDescriptor, and ReduceOperation
- Update Serializer and Deserializer for serializing/parsing ReduceLayer
- Added TfLiter parser Sum test for REDUCE_SUM operator
- Make corresponding changes on front-end and Ref backend to support REDUCE_SUM operator
Changelog v9:
- Fixed build errors.
Change-Id: I8c8e034f3df73f9565b3c18eff51ecca6c542195
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Sadik Armagan <sadik.armagan@arm.com>
Diffstat (limited to 'src/backends/reference/workloads/Reduce.cpp')
-rw-r--r-- | src/backends/reference/workloads/Reduce.cpp | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/src/backends/reference/workloads/Reduce.cpp b/src/backends/reference/workloads/Reduce.cpp new file mode 100644 index 0000000000..5375c7163a --- /dev/null +++ b/src/backends/reference/workloads/Reduce.cpp @@ -0,0 +1,151 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "Reduce.hpp" + +#include <armnn/utility/NumericCast.hpp> + +#include <backendsCommon/WorkloadData.hpp> + +#include <cmath> +#include <cstddef> +#include <functional> +#include <limits> + +namespace armnn +{ + +bool NextIndex(const unsigned int numDims, const armnn::TensorShape& dims, std::vector<unsigned int>& 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); +} + +unsigned int ReducedOutputOffset(const unsigned int numDims, + const armnn::TensorShape& dims, + std::vector<unsigned int>& index, + const unsigned int numAxis, + const std::vector<unsigned int>& axis) +{ + unsigned int 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 * dims[idx] + index[idx]; + } + } + return offset; +} + + +void Reduce(const TensorInfo& inputInfo, + const TensorInfo& outputInfo, + Decoder<float>& input, + Encoder<float>& output, + const std::vector<uint32_t> axis, + const ReduceOperation reduceOperation) +{ + unsigned int inputNumDims = inputInfo.GetNumDimensions(); + unsigned int outputNumDims = outputInfo.GetNumDimensions(); + + armnn::TensorShape outputDims = outputInfo.GetShape(); + armnn::TensorShape inputDims = inputInfo.GetShape(); + + // Initialise output data. + unsigned int numOutputs = 1; + for (unsigned int idx = 0; idx < outputNumDims; ++idx) + { + numOutputs *= outputDims[idx]; + } + + std::vector<float> tempSum(numOutputs); + for (unsigned int idx = 0; idx < numOutputs; ++idx) + { + output[idx]; + output.Set(0.0f); + tempSum[idx] = 0.0f; + } + + // Initialise temp index. + std::vector<unsigned int> tempIndex(inputNumDims); + for (unsigned int idx = 0; idx < inputNumDims; ++idx) + { + tempIndex[idx] = 0; + } + + std::vector<unsigned int> resolvedAxis = axis; + if (resolvedAxis.empty()) + { + for (unsigned int idx = 0; idx < inputNumDims; ++idx) + { + resolvedAxis.push_back(idx); + } + } + auto numResolvedAxis = armnn::numeric_cast<unsigned int>(resolvedAxis.size()); + + // Iterates through input_data and sum up the reduced axis. + for (bool hasNext = true; hasNext; hasNext = NextIndex(inputNumDims, inputDims, tempIndex)) + { + unsigned int inputOffset = ReducedOutputOffset(inputNumDims, inputDims, tempIndex, 0, {}); + unsigned int outputOffset = ReducedOutputOffset(inputNumDims, inputDims, tempIndex, + numResolvedAxis, resolvedAxis); + input[inputOffset]; + tempSum[outputOffset] += input.Get(); + } + + // Takes average by num of elements added to get mean. + size_t numElementsInAxis = 1; + for (unsigned int idx = 0; idx < numResolvedAxis; ++idx) + { + unsigned int current = inputDims[resolvedAxis[idx]]; + ARMNN_ASSERT(armnn::numeric_cast<float>(current) < + (std::numeric_limits<float>::max() / armnn::numeric_cast<float>(numElementsInAxis))); + numElementsInAxis *= current; + } + if (numElementsInAxis > 0) { + for (unsigned int idx = 0; idx < numOutputs; ++idx) + { + output[idx]; + if (reduceOperation == ReduceOperation::Sum) + { + output.Set(tempSum[idx]); + } + else if (reduceOperation == ReduceOperation::Mean) + { + output.Set(tempSum[idx] / armnn::numeric_cast<float>(numElementsInAxis)); + } + } + } +} + +} //namespace armnn
\ No newline at end of file |