diff options
Diffstat (limited to 'src/backends/reference')
-rw-r--r-- | src/backends/reference/backend.mk | 1 | ||||
-rw-r--r-- | src/backends/reference/test/RefLayerTests.cpp | 1 | ||||
-rw-r--r-- | src/backends/reference/workloads/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/backends/reference/workloads/Merger.cpp | 110 | ||||
-rw-r--r-- | src/backends/reference/workloads/Merger.hpp | 67 |
5 files changed, 116 insertions, 64 deletions
diff --git a/src/backends/reference/backend.mk b/src/backends/reference/backend.mk index acaedc9688..a75146b946 100644 --- a/src/backends/reference/backend.mk +++ b/src/backends/reference/backend.mk @@ -21,6 +21,7 @@ BACKEND_SOURCES := \ workloads/FullyConnected.cpp \ workloads/Gather.cpp \ workloads/Mean.cpp \ + workloads/Merger.cpp \ workloads/Pad.cpp \ workloads/Pooling2d.cpp \ workloads/RefActivationFloat32Workload.cpp \ diff --git a/src/backends/reference/test/RefLayerTests.cpp b/src/backends/reference/test/RefLayerTests.cpp index b4ef85a1dd..cf8e6a2e25 100644 --- a/src/backends/reference/test/RefLayerTests.cpp +++ b/src/backends/reference/test/RefLayerTests.cpp @@ -209,6 +209,7 @@ ARMNN_AUTO_TEST_CASE(CopyViaSplitterUint8, CopyViaSplitterUint8Test) // Merger ARMNN_AUTO_TEST_CASE(SimpleMerger, MergerTest) ARMNN_AUTO_TEST_CASE(MergerUint8, MergerUint8Test) +ARMNN_AUTO_TEST_CASE(MergerUint8DifferentQParams, MergerUint8DifferentQParamsTest) // Add ARMNN_AUTO_TEST_CASE(SimpleAdd, AdditionTest) diff --git a/src/backends/reference/workloads/CMakeLists.txt b/src/backends/reference/workloads/CMakeLists.txt index 47e42f7fcc..89aed9194b 100644 --- a/src/backends/reference/workloads/CMakeLists.txt +++ b/src/backends/reference/workloads/CMakeLists.txt @@ -25,6 +25,7 @@ list(APPEND armnnRefBackendWorkloads_sources Gather.hpp Maximum.hpp Merger.hpp + Merger.cpp Minimum.hpp Pad.cpp Pad.hpp diff --git a/src/backends/reference/workloads/Merger.cpp b/src/backends/reference/workloads/Merger.cpp new file mode 100644 index 0000000000..10cc2494c4 --- /dev/null +++ b/src/backends/reference/workloads/Merger.cpp @@ -0,0 +1,110 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "Merger.hpp" +#include "RefWorkloadUtils.hpp" + +namespace armnn +{ + +template <> +void CopyValue<float>(const float& source, const TensorInfo& sourceInfo, float& dest, const TensorInfo& destInfo) +{ + dest = source; +} + +template <> +void CopyValue<uint8_t>(const uint8_t& source, const TensorInfo& sourceInfo, uint8_t& dest, const TensorInfo& destInfo) +{ + if (sourceInfo.GetQuantizationScale() != destInfo.GetQuantizationScale() || + sourceInfo.GetQuantizationOffset() != destInfo.GetQuantizationOffset()) + { + // Dequantize value acording to sourceInfo params + float dequantizedValue = armnn::Dequantize<uint8_t>(source, + sourceInfo.GetQuantizationScale(), + sourceInfo.GetQuantizationOffset()); + + // Quantize again according to destInfo paramns + dest = armnn::Quantize<uint8_t>(dequantizedValue, + destInfo.GetQuantizationScale(), + destInfo.GetQuantizationOffset()); + } + else + { + dest = source; + } +} + +template <typename DataType> +void Merger(const MergerQueueDescriptor& data) +{ + const TensorInfo& outputInfo0 = GetTensorInfo(data.m_Outputs[0]); + + for (unsigned int index = 0 ; index < outputInfo0.GetNumElements(); ++index) + { + unsigned int indices[MaxNumOfTensorDimensions] = { 0 }; + + unsigned int indexRemainder = index; + unsigned int dimensionStride = outputInfo0.GetNumElements(); + + for (unsigned int i = 0; i < outputInfo0.GetNumDimensions(); i++) + { + dimensionStride /= outputInfo0.GetShape()[i]; + indices[i] = indexRemainder / dimensionStride; // Use integer division to round down. + indexRemainder -= indices[i] * dimensionStride; + } + + for (unsigned int viewIdx = 0; viewIdx < data.m_ViewOrigins.size(); ++viewIdx) + { + MergerQueueDescriptor::ViewOrigin const& view = data.m_ViewOrigins[viewIdx]; + + //Split view extents are defined by the size of (the corresponding) input tensor. + const TensorInfo& inputInfo = GetTensorInfo(data.m_Inputs[viewIdx]); + BOOST_ASSERT(inputInfo.GetNumDimensions() == outputInfo0.GetNumDimensions()); + + // Check all dimensions to see if this element is inside the given input view. + bool insideView = true; + for (unsigned int i = 0; i < inputInfo.GetNumDimensions(); i++) + { + if (indices[i] < view.m_Origin[i]) + { + insideView = false; + } + if (indices[i] >= view.m_Origin[i] + inputInfo.GetShape()[i]) + { + insideView = false; + } + } + + if (insideView) + { + unsigned int inIndex = 0; + unsigned int dimensionStride = 1; + + for (unsigned int i = inputInfo.GetNumDimensions(); i-- > 0;) + { + inIndex += dimensionStride * (indices[i] - view.m_Origin[i]); + dimensionStride *= inputInfo.GetShape()[i]; + } + + CopyValue<DataType>((GetInputTensorData<DataType>(viewIdx, data))[inIndex], + GetTensorInfo(data.m_Inputs[viewIdx]), + (GetOutputTensorData<DataType>(0, data))[index], + outputInfo0); + + //What should we do if input views overlap on the output tensor? + //We could error, take the average, or shm else... + //For now just stop after finding first view (input) that matches. + break; + } + } + } +} + +template void Merger<float>(const MergerQueueDescriptor& data); + +template void Merger<uint8_t>(const MergerQueueDescriptor& data); + +} //namespace armnn diff --git a/src/backends/reference/workloads/Merger.hpp b/src/backends/reference/workloads/Merger.hpp index 76d807cb2c..ba3b99b6e2 100644 --- a/src/backends/reference/workloads/Merger.hpp +++ b/src/backends/reference/workloads/Merger.hpp @@ -5,8 +5,6 @@ #pragma once -#include "RefWorkloadUtils.hpp" - #include <backendsCommon/WorkloadData.hpp> #include <armnn/Tensor.hpp> @@ -14,68 +12,9 @@ namespace armnn { template <typename DataType> -void Merger(const MergerQueueDescriptor& data) -{ - const TensorInfo& outputInfo0 = GetTensorInfo(data.m_Outputs[0]); - - for (unsigned int index = 0 ; index < outputInfo0.GetNumElements(); ++index) - { - unsigned int indices[MaxNumOfTensorDimensions] = { 0 }; - - unsigned int indexRemainder = index; - unsigned int dimensionStride = outputInfo0.GetNumElements(); - - for (unsigned int i=0; i<outputInfo0.GetNumDimensions(); i++) - { - dimensionStride /= outputInfo0.GetShape()[i]; - indices[i] = indexRemainder / dimensionStride; // Use integer division to round down. - indexRemainder -= indices[i] * dimensionStride; - } - - for (unsigned int viewIdx = 0; viewIdx < data.m_ViewOrigins.size(); ++viewIdx) - { - MergerQueueDescriptor::ViewOrigin const& view = data.m_ViewOrigins[viewIdx]; +void CopyValue(const DataType& source, const TensorInfo& sourceInfo, DataType& dest, const TensorInfo& destInfo); - //Split view extents are defined by the size of (the corresponding) input tensor. - const TensorInfo& inputInfo = GetTensorInfo(data.m_Inputs[viewIdx]); - BOOST_ASSERT(inputInfo.GetNumDimensions() == outputInfo0.GetNumDimensions()); - - // Check all dimensions to see if this element is inside the given input view. - bool insideView = true; - for (unsigned int i=0; i<inputInfo.GetNumDimensions(); i++) - { - if (indices[i] < view.m_Origin[i]) - { - insideView = false; - } - if (indices[i] >= view.m_Origin[i] + inputInfo.GetShape()[i]) - { - insideView = false; - } - } - - if (insideView) - { - unsigned int inIndex = 0; - unsigned int dimensionStride = 1; - - for (unsigned int i = inputInfo.GetNumDimensions(); i-- > 0;) - { - inIndex += dimensionStride * (indices[i] - view.m_Origin[i]); - dimensionStride *= inputInfo.GetShape()[i]; - } - - //We are within the view, copy input data to the output corresponding to this view. - (GetOutputTensorData<DataType>(0, data))[index] = - (GetInputTensorData<DataType>(viewIdx, data))[inIndex]; - - //What should we do if input views overlap on the output tensor? - //We could error, take the average, or shm else... - //For now just stop after finding first view (input) that matches. - break; - } - } - } -} +template <typename DataType> +void Merger(const MergerQueueDescriptor& data); } //namespace armnn |