From 0c3ea5b8ac5ad8ca516930a0491afb1d1074e45b Mon Sep 17 00:00:00 2001 From: Sadik Armagan Date: Wed, 3 Feb 2021 09:29:30 +0000 Subject: 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 Signed-off-by: Sadik Armagan --- src/backends/reference/workloads/CMakeLists.txt | 6 +- src/backends/reference/workloads/Mean.cpp | 143 ------------------- src/backends/reference/workloads/Mean.hpp | 22 --- src/backends/reference/workloads/Reduce.cpp | 151 +++++++++++++++++++++ src/backends/reference/workloads/Reduce.hpp | 24 ++++ .../reference/workloads/RefMeanWorkload.cpp | 9 +- .../reference/workloads/RefReduceWorkload.cpp | 42 ++++++ .../reference/workloads/RefReduceWorkload.hpp | 23 ++++ src/backends/reference/workloads/RefWorkloads.hpp | 1 + 9 files changed, 252 insertions(+), 169 deletions(-) delete mode 100644 src/backends/reference/workloads/Mean.cpp delete mode 100644 src/backends/reference/workloads/Mean.hpp create mode 100644 src/backends/reference/workloads/Reduce.cpp create mode 100644 src/backends/reference/workloads/Reduce.hpp create mode 100644 src/backends/reference/workloads/RefReduceWorkload.cpp create mode 100644 src/backends/reference/workloads/RefReduceWorkload.hpp (limited to 'src/backends/reference/workloads') diff --git a/src/backends/reference/workloads/CMakeLists.txt b/src/backends/reference/workloads/CMakeLists.txt index 1b20e5bf2d..1f4298be5d 100644 --- a/src/backends/reference/workloads/CMakeLists.txt +++ b/src/backends/reference/workloads/CMakeLists.txt @@ -44,8 +44,6 @@ list(APPEND armnnRefBackendWorkloads_sources LstmUtils.hpp LstmUtils.cpp Maximum.hpp - Mean.cpp - Mean.hpp Concatenate.hpp Concatenate.cpp Minimum.hpp @@ -55,6 +53,8 @@ list(APPEND armnnRefBackendWorkloads_sources Pooling2d.hpp PreluImpl.cpp PreluImpl.hpp + Reduce.cpp + Reduce.hpp RefActivationWorkload.cpp RefActivationWorkload.hpp RefArgMinMaxWorkload.cpp @@ -132,6 +132,8 @@ list(APPEND armnnRefBackendWorkloads_sources RefQLstmWorkload.cpp RefQLstmWorkload.hpp RefRankWorkload.hpp + RefReduceWorkload.cpp + RefReduceWorkload.hpp RefReshapeWorkload.cpp RefReshapeWorkload.hpp RefResizeBilinearWorkload.cpp diff --git a/src/backends/reference/workloads/Mean.cpp b/src/backends/reference/workloads/Mean.cpp deleted file mode 100644 index fe34efe0c7..0000000000 --- a/src/backends/reference/workloads/Mean.cpp +++ /dev/null @@ -1,143 +0,0 @@ -// -// Copyright © 2017 Arm Ltd. All rights reserved. -// SPDX-License-Identifier: MIT -// - -#include "Mean.hpp" -#include - -#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); -} - -unsigned int ReducedOutputOffset(const unsigned int numDims, - const armnn::TensorShape& dims, - std::vector& index, - const unsigned int numAxis, - const std::vector& 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; -} -} // namespace - -namespace armnn -{ -void Mean(const armnn::TensorInfo& inputInfo, - const armnn::TensorInfo& outputInfo, - const std::vector& axis, - Decoder& input, - Encoder& output) -{ - - 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 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 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); - } - } - auto numResolvedAxis = armnn::numeric_cast(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(current) < - (std::numeric_limits::max() / armnn::numeric_cast(numElementsInAxis))); - numElementsInAxis *= current; - } - if (numElementsInAxis > 0) { - for (unsigned int idx = 0; idx < numOutputs; ++idx) - { - output[idx]; - output.Set(tempSum[idx] / armnn::numeric_cast(numElementsInAxis)); - } - } -} -} //namespace armnn diff --git a/src/backends/reference/workloads/Mean.hpp b/src/backends/reference/workloads/Mean.hpp deleted file mode 100644 index dfb0302bf9..0000000000 --- a/src/backends/reference/workloads/Mean.hpp +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright © 2017 Arm Ltd. All rights reserved. -// SPDX-License-Identifier: MIT -// - -#pragma once - -#include "armnn/DescriptorsFwd.hpp" -#include "armnn/Tensor.hpp" -#include "BaseIterator.hpp" - -#include - -namespace armnn -{ -void Mean(const TensorInfo& inputInfo, - const TensorInfo& outputInfo, - const std::vector& axis, - Decoder& input, - Encoder& output); -} //namespace armnn - 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 + +#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); +} + +unsigned int ReducedOutputOffset(const unsigned int numDims, + const armnn::TensorShape& dims, + std::vector& index, + const unsigned int numAxis, + const std::vector& 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& input, + Encoder& output, + const std::vector 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 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 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); + } + } + auto numResolvedAxis = armnn::numeric_cast(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(current) < + (std::numeric_limits::max() / armnn::numeric_cast(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(numElementsInAxis)); + } + } + } +} + +} //namespace armnn \ No newline at end of file diff --git a/src/backends/reference/workloads/Reduce.hpp b/src/backends/reference/workloads/Reduce.hpp new file mode 100644 index 0000000000..ad777adcf5 --- /dev/null +++ b/src/backends/reference/workloads/Reduce.hpp @@ -0,0 +1,24 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include "BaseIterator.hpp" +#include "Decoders.hpp" +#include "Encoders.hpp" + +#include + +namespace armnn +{ + +void Reduce(const TensorInfo& inputInfo, + const TensorInfo& outputInfo, + Decoder& input, + Encoder& output, + const std::vector axis, + const ReduceOperation reduceOperation); + +} //namespace armnn diff --git a/src/backends/reference/workloads/RefMeanWorkload.cpp b/src/backends/reference/workloads/RefMeanWorkload.cpp index 375ab395be..00e59bca4c 100644 --- a/src/backends/reference/workloads/RefMeanWorkload.cpp +++ b/src/backends/reference/workloads/RefMeanWorkload.cpp @@ -5,7 +5,7 @@ #include "RefMeanWorkload.hpp" -#include "Mean.hpp" +#include "Reduce.hpp" #include "RefWorkloadUtils.hpp" #include "Profiling.hpp" @@ -28,7 +28,12 @@ void RefMeanWorkload::Execute() const auto inputDecoder = MakeDecoder(inputInfo, m_Data.m_Inputs[0]->Map()); auto outputEncoder = MakeEncoder(outputInfo, m_Data.m_Outputs[0]->Map()); - Mean(inputInfo, outputInfo, m_Data.m_Parameters.m_Axis, *inputDecoder, *outputEncoder); + Reduce(inputInfo, + outputInfo, + *inputDecoder, + *outputEncoder, + m_Data.m_Parameters.m_Axis, + armnn::ReduceOperation::Mean); } } //namespace armnn diff --git a/src/backends/reference/workloads/RefReduceWorkload.cpp b/src/backends/reference/workloads/RefReduceWorkload.cpp new file mode 100644 index 0000000000..7a46ff9ffc --- /dev/null +++ b/src/backends/reference/workloads/RefReduceWorkload.cpp @@ -0,0 +1,42 @@ +// +// Copyright © 2020 Samsung Electronics Co Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "RefReduceWorkload.hpp" + +#include "Reduce.hpp" +#include "RefWorkloadUtils.hpp" +#include "BaseIterator.hpp" +#include "Profiling.hpp" + +namespace armnn +{ + +RefReduceWorkload::RefReduceWorkload( + const ReduceQueueDescriptor& descriptor, + const WorkloadInfo& info) + : BaseWorkload(descriptor, info) {} + +void RefReduceWorkload::Execute() const +{ + ARMNN_SCOPED_PROFILING_EVENT(Compute::CpuRef, "RefReduceWorkload_Execute"); + + const TensorInfo& inputInfo = GetTensorInfo(m_Data.m_Inputs[0]); + const TensorInfo& outputInfo = GetTensorInfo(m_Data.m_Outputs[0]); + + std::unique_ptr> decoderPtr = MakeDecoder(inputInfo, m_Data.m_Inputs[0]->Map()); + Decoder& decoder = *decoderPtr; + + std::unique_ptr> encoderPtr = MakeEncoder(outputInfo, m_Data.m_Outputs[0]->Map()); + Encoder& encoder = *encoderPtr; + + Reduce(inputInfo, + outputInfo, + decoder, + encoder, + m_Data.m_Parameters.m_vAxis, + m_Data.m_Parameters.m_ReduceOperation); +} + +} //namespace armnn diff --git a/src/backends/reference/workloads/RefReduceWorkload.hpp b/src/backends/reference/workloads/RefReduceWorkload.hpp new file mode 100644 index 0000000000..1d551acb4a --- /dev/null +++ b/src/backends/reference/workloads/RefReduceWorkload.hpp @@ -0,0 +1,23 @@ +// +// Copyright © 2020 Samsung Electronics Co Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include +#include + +namespace armnn +{ + +class RefReduceWorkload : public BaseWorkload +{ +public: + explicit RefReduceWorkload(const ReduceQueueDescriptor& descriptor, + const WorkloadInfo& info); + + virtual void Execute() const override; +}; + +} //namespace armnn diff --git a/src/backends/reference/workloads/RefWorkloads.hpp b/src/backends/reference/workloads/RefWorkloads.hpp index 390b2a8d55..989644f633 100644 --- a/src/backends/reference/workloads/RefWorkloads.hpp +++ b/src/backends/reference/workloads/RefWorkloads.hpp @@ -54,6 +54,7 @@ #include "RefQLstmWorkload.hpp" #include "RefQuantizeWorkload.hpp" #include "RefRankWorkload.hpp" +#include "RefReduceWorkload.hpp" #include "RefReshapeWorkload.hpp" #include "RefResizeBilinearWorkload.hpp" #include "RefResizeWorkload.hpp" -- cgit v1.2.1