From 9b3983299f882c8d84c5abd0d40ca75a801ea7f2 Mon Sep 17 00:00:00 2001 From: Mike Kelly Date: Wed, 22 May 2019 17:21:49 +0100 Subject: IVGCVSW-3025: Refactor reference Convolution2d workload * Refactored RefConvolution2dWorkload to support all DataTypes through Encoders and Decoders. * Added Convolute function to ConvImpl that uses Encoders and Decoders to support all DataTypes. * Deleted RefConvolution2dFloat32Workload and RefConvolution2dUint8Workload. Signed-off-by: Mike Kelly Signed-off-by: Teresa Charlin Change-Id: Ic5ef0f499d08b948fa65fdee54b5f681fd0b1c05 --- src/backends/reference/workloads/BaseIterator.hpp | 15 ++ src/backends/reference/workloads/CMakeLists.txt | 6 +- src/backends/reference/workloads/ConvImpl.cpp | 173 +++++++++++++++++++++ src/backends/reference/workloads/ConvImpl.hpp | 19 +++ src/backends/reference/workloads/Decoders.hpp | 6 + .../workloads/RefConvolution2dFloat32Workload.cpp | 35 ----- .../workloads/RefConvolution2dFloat32Workload.hpp | 27 ---- .../workloads/RefConvolution2dUint8Workload.cpp | 42 ----- .../workloads/RefConvolution2dUint8Workload.hpp | 28 ---- .../workloads/RefConvolution2dWorkload.cpp | 53 +++++++ .../workloads/RefConvolution2dWorkload.hpp | 41 +++++ src/backends/reference/workloads/RefWorkloads.hpp | 3 +- 12 files changed, 310 insertions(+), 138 deletions(-) delete mode 100644 src/backends/reference/workloads/RefConvolution2dFloat32Workload.cpp delete mode 100644 src/backends/reference/workloads/RefConvolution2dFloat32Workload.hpp delete mode 100644 src/backends/reference/workloads/RefConvolution2dUint8Workload.cpp delete mode 100644 src/backends/reference/workloads/RefConvolution2dUint8Workload.hpp create mode 100644 src/backends/reference/workloads/RefConvolution2dWorkload.cpp create mode 100644 src/backends/reference/workloads/RefConvolution2dWorkload.hpp (limited to 'src/backends/reference/workloads') diff --git a/src/backends/reference/workloads/BaseIterator.hpp b/src/backends/reference/workloads/BaseIterator.hpp index 97af95a0eb..ab6de2b37f 100644 --- a/src/backends/reference/workloads/BaseIterator.hpp +++ b/src/backends/reference/workloads/BaseIterator.hpp @@ -123,6 +123,21 @@ public: } }; +class ScaledInt32Decoder : public TypedIterator> +{ +public: + ScaledInt32Decoder(const int32_t* data, const float scale) + : TypedIterator(data), m_Scale(scale) {} + + float Get() const override + { + return static_cast(*m_Iterator) * m_Scale; + } + +private: + const float m_Scale; +}; + class QASymm8Encoder : public TypedIterator> { public: diff --git a/src/backends/reference/workloads/CMakeLists.txt b/src/backends/reference/workloads/CMakeLists.txt index 6e4d7637bd..ab4fea619a 100644 --- a/src/backends/reference/workloads/CMakeLists.txt +++ b/src/backends/reference/workloads/CMakeLists.txt @@ -51,10 +51,8 @@ list(APPEND armnnRefBackendWorkloads_sources RefConvertFp16ToFp32Workload.hpp RefConvertFp32ToFp16Workload.cpp RefConvertFp32ToFp16Workload.hpp - RefConvolution2dFloat32Workload.cpp - RefConvolution2dFloat32Workload.hpp - RefConvolution2dUint8Workload.cpp - RefConvolution2dUint8Workload.hpp + RefConvolution2dWorkload.cpp + RefConvolution2dWorkload.hpp RefElementwiseWorkload.cpp RefElementwiseWorkload.hpp RefDebugWorkload.cpp diff --git a/src/backends/reference/workloads/ConvImpl.cpp b/src/backends/reference/workloads/ConvImpl.cpp index 8743a2bd0d..6a5ac535e4 100644 --- a/src/backends/reference/workloads/ConvImpl.cpp +++ b/src/backends/reference/workloads/ConvImpl.cpp @@ -68,4 +68,177 @@ int32_t QuantizedMultiplierSmallerThanOne::RoundingDivideByPOT(int32_t x, int ex return (x >> exponent) + (remainder > threshold ? 1 : 0); } +inline unsigned int GetOffset(DataLayout& dataLayout, const TensorShape& shape, unsigned int b, unsigned int c, + unsigned int h, unsigned int w) +{ + switch (dataLayout) + { + case DataLayout::NHWC: + b *= shape[1] * shape[2] * shape[3]; + h *= shape[2] * shape[3]; + w *= shape[3]; + break; + case DataLayout::NCHW: + default: + b *= shape[1] * shape[2] * shape[3]; + c *= shape[2] * shape[3]; + h *= shape[3]; + break; + } + return b + c + h + w; +} + +void Convolve(const TensorShape& rInputShape, + Decoder& rInputDecoder, + const TensorShape& rOutputShape, + Encoder& rOutputEncoder, + const TensorShape& rFilterShape, + Decoder& rFilterDecoder, + bool biasEnabled, + Decoder* pBiasDecoder, + DataLayout dataLayout, + unsigned int paddingTop, + unsigned int paddingLeft, + unsigned int xStride, + unsigned int yStride, + unsigned int xDilation, + unsigned int yDilation, + bool depthwise) +{ + if (biasEnabled && !pBiasDecoder) + { + throw InvalidArgumentException("Bias is enabled but the bias data is invalid"); + } + const armnnUtils::DataLayoutIndexed dataLayoutIndexed(dataLayout); + + const unsigned int channelsIndex = dataLayoutIndexed.GetChannelsIndex(); + const unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex(); + const unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex(); + + unsigned int depthMultiplier = depthwise ? rFilterShape[0] : 1; + unsigned int inputChannels = depthwise ? rFilterShape[1] : rFilterShape[channelsIndex]; + unsigned int outputChannels = depthwise ? inputChannels * depthMultiplier : rFilterShape[0]; + + unsigned int batchSize = rOutputShape[0]; + unsigned int outputHeight = rOutputShape[heightIndex]; + unsigned int outputWidth = rOutputShape[widthIndex]; + unsigned int inputHeight = rInputShape[heightIndex]; + unsigned int inputWidth = rInputShape[widthIndex]; + + unsigned int filterHeight = depthwise ? rFilterShape[2] : rFilterShape[heightIndex]; + unsigned int filterWidth = depthwise ? rFilterShape[3] : rFilterShape[widthIndex]; + + for (unsigned int batchIdx = 0; batchIdx < batchSize; batchIdx++) + { + for (unsigned int cOutput = 0; cOutput < outputChannels; cOutput++) + { + for (unsigned int yOutput = 0; yOutput < outputHeight; yOutput++) + { + for (unsigned int xOutput = 0; xOutput < outputWidth; xOutput++) + { + // This loop goes over each output element. + float sum = 0.0f; + + // For depthwise, each output channel corresponds to exactly one input channel. + // For normal, must loop over each input channel. + for (unsigned int cInput = 0; cInput < (depthwise ? 1 : inputChannels); cInput++) + { + unsigned int depthwiseMultiplierIdx = 0; + if (depthwise) + { + cInput = cOutput / depthMultiplier; + depthwiseMultiplierIdx = cOutput % depthMultiplier; + } + + for (unsigned int yFilter = 0; yFilter < filterHeight; yFilter++) + { + for (unsigned int xFilter = 0; xFilter < filterWidth; xFilter++) + { + // This loop goes over each input element for each output element. + unsigned int filterIndex = 0; + + // Since dimensionality of kernel depends on depthwiseness, so does index. + if (depthwise) + { + filterIndex = depthwiseMultiplierIdx * filterWidth * filterHeight * inputChannels + + cInput * filterWidth * filterHeight + + yFilter * filterWidth + + xFilter; + } + else + { + if (dataLayout == DataLayout::NHWC) + { + filterIndex = cOutput * filterHeight * filterWidth * inputChannels + + yFilter * filterWidth * inputChannels + + xFilter * inputChannels + + cInput; + } + else + { + filterIndex = cOutput * filterWidth * filterHeight * inputChannels + + cInput * filterWidth * filterHeight + + yFilter * filterWidth + + xFilter; + } + } + rFilterDecoder += filterIndex; + float filterValue = rFilterDecoder.Get(); + rFilterDecoder -= filterIndex; + + unsigned int yInput = yOutput * yStride + yFilter * yDilation; + unsigned int xInput = xOutput * xStride + xFilter * xDilation; + + float inputValue; + + // Check if we're in the padding. + if (yInput < paddingTop || yInput >= inputHeight + paddingTop || + xInput < paddingLeft || xInput >= inputWidth + paddingLeft ) + { + inputValue = 0.0f; + } + else + { + unsigned int inputIndex; + + if (dataLayout == DataLayout::NHWC) + { + inputIndex = batchIdx * inputHeight * inputWidth * inputChannels + + (yInput - paddingTop) * inputWidth * inputChannels + + (xInput - paddingLeft) * inputChannels + + cInput; + } + else + { + inputIndex = batchIdx * inputWidth * inputHeight * inputChannels + + inputWidth * inputHeight * cInput + + inputWidth * (yInput - paddingTop) + + xInput - paddingLeft; + } + rInputDecoder += inputIndex; + inputValue = rInputDecoder.Get(); + rInputDecoder -= inputIndex; + } + sum += filterValue * inputValue; + } + } + } + + if (biasEnabled) + { + *pBiasDecoder += cOutput; + sum += pBiasDecoder->Get(); + *pBiasDecoder -= cOutput; + } + unsigned int outIdx = GetOffset(dataLayout, rOutputShape, batchIdx, cOutput, yOutput, xOutput); + + rOutputEncoder += outIdx; + rOutputEncoder.Set(sum); + rOutputEncoder -= outIdx; + } + } + } + } +} + } //namespace armnn diff --git a/src/backends/reference/workloads/ConvImpl.hpp b/src/backends/reference/workloads/ConvImpl.hpp index 23b402aa77..3551ba8f90 100644 --- a/src/backends/reference/workloads/ConvImpl.hpp +++ b/src/backends/reference/workloads/ConvImpl.hpp @@ -7,6 +7,9 @@ #include "RefWorkloadUtils.hpp" #include "TensorBufferArrayView.hpp" +#include "BaseIterator.hpp" +#include "Decoders.hpp" +#include "Encoders.hpp" #include @@ -224,4 +227,20 @@ static void ConvImpl(ConvData data, } } +void Convolve(const TensorShape& rInputShape, + Decoder& rInputDecoder, + const TensorShape& rOutputShape, + Encoder& rOutputEncoder, + const TensorShape& rFilterShape, + Decoder& rFilterDecoder, + bool biasEnabled, + Decoder* pBiasDecoder, + DataLayout dataLayout, + unsigned int paddingTop, + unsigned int paddingLeft, + unsigned int xStride, + unsigned int yStride, + unsigned int xDilation, + unsigned int yDilation, + bool depthwise = false); } //namespace armnn diff --git a/src/backends/reference/workloads/Decoders.hpp b/src/backends/reference/workloads/Decoders.hpp index acf20c4b69..57c19a2a58 100644 --- a/src/backends/reference/workloads/Decoders.hpp +++ b/src/backends/reference/workloads/Decoders.hpp @@ -36,6 +36,12 @@ inline std::unique_ptr> MakeDecoder(const TensorInfo& info, const { return std::make_unique(static_cast(data)); } + case armnn::DataType::Signed32: + { + return std::make_unique( + static_cast(data), + info.GetQuantizationScale()); + } default: { BOOST_ASSERT_MSG(false, "Not supported Data Type!"); diff --git a/src/backends/reference/workloads/RefConvolution2dFloat32Workload.cpp b/src/backends/reference/workloads/RefConvolution2dFloat32Workload.cpp deleted file mode 100644 index 7b298df967..0000000000 --- a/src/backends/reference/workloads/RefConvolution2dFloat32Workload.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright © 2017 Arm Ltd. All rights reserved. -// SPDX-License-Identifier: MIT -// - -#include "RefConvolution2dFloat32Workload.hpp" - -#include "ConvImpl.hpp" -#include "RefWorkloadUtils.hpp" - -#include "Profiling.hpp" - -namespace armnn -{ -RefConvolution2dFloat32Workload::RefConvolution2dFloat32Workload( - const Convolution2dQueueDescriptor& descriptor, const WorkloadInfo& info) - : Float32Workload(descriptor, info), - m_Weight(std::make_unique(*(descriptor.m_Weight))), - m_Bias(descriptor.m_Parameters.m_BiasEnabled - ? std::make_unique(*(descriptor.m_Bias)) : nullptr) {} - -void RefConvolution2dFloat32Workload::Execute() const -{ - ARMNN_SCOPED_PROFILING_EVENT(Compute::CpuRef, "RefConvolution2dFloat32Workload_Execute"); - - const float* inputData = GetInputTensorDataFloat(0, m_Data); - const float* filterData = m_Weight->template GetConstTensor(); - const float* biasData = m_Data.m_Parameters.m_BiasEnabled ? m_Bias->template GetConstTensor() : nullptr; - const TensorInfo& filterInfo = m_Weight->GetTensorInfo(); - - ConvImpl( - m_Data, inputData, 0.0f, 0, filterData, 0.0f, 0, biasData, 0.0f, 0, filterInfo); -} - -} //namespace armnn diff --git a/src/backends/reference/workloads/RefConvolution2dFloat32Workload.hpp b/src/backends/reference/workloads/RefConvolution2dFloat32Workload.hpp deleted file mode 100644 index 5ff743d511..0000000000 --- a/src/backends/reference/workloads/RefConvolution2dFloat32Workload.hpp +++ /dev/null @@ -1,27 +0,0 @@ -// -// Copyright © 2017 Arm Ltd. All rights reserved. -// SPDX-License-Identifier: MIT -// - -#pragma once - -#include -#include - -namespace armnn -{ - -class RefConvolution2dFloat32Workload : public Float32Workload -{ -public: - explicit RefConvolution2dFloat32Workload(const Convolution2dQueueDescriptor& descriptor, - const WorkloadInfo& info); - virtual void Execute() const override; - -private: - std::unique_ptr m_Weight; - std::unique_ptr m_Bias; - -}; - -} //namespace armnn diff --git a/src/backends/reference/workloads/RefConvolution2dUint8Workload.cpp b/src/backends/reference/workloads/RefConvolution2dUint8Workload.cpp deleted file mode 100644 index af2c7ad0d6..0000000000 --- a/src/backends/reference/workloads/RefConvolution2dUint8Workload.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// -// Copyright © 2017 Arm Ltd. All rights reserved. -// SPDX-License-Identifier: MIT -// - -#include "RefConvolution2dUint8Workload.hpp" - -#include "ConvImpl.hpp" -#include "RefWorkloadUtils.hpp" - -#include "Profiling.hpp" - -namespace armnn -{ -RefConvolution2dUint8Workload::RefConvolution2dUint8Workload( - const Convolution2dQueueDescriptor& descriptor, const WorkloadInfo& info) - : Uint8Workload(descriptor, info), - m_Weight(std::make_unique(*(descriptor.m_Weight))), - m_Bias(descriptor.m_Parameters.m_BiasEnabled - ? std::make_unique(*(descriptor.m_Bias)) : nullptr) {} - -void RefConvolution2dUint8Workload::Execute() const -{ - ARMNN_SCOPED_PROFILING_EVENT(Compute::CpuRef, "RefConvolution2dUint8Workload_Execute"); - - const uint8_t* inputData = GetInputTensorDataU8(0, m_Data); - const TensorInfo& inputInfo = GetTensorInfo(m_Data.m_Inputs[0]); - const uint8_t* weightsData = m_Weight->template GetConstTensor(); - const TensorInfo& weightsInfo = GetTensorInfo(m_Weight.get()); - const int32_t* biasData = m_Data.m_Parameters.m_BiasEnabled ? m_Bias->template GetConstTensor() : nullptr; - const TensorInfo& outputInfo = GetTensorInfo(m_Data.m_Outputs[0]); - const TensorInfo& filterInfo = m_Weight->GetTensorInfo(); - - ConvImpl( - m_Data, - inputData, inputInfo.GetQuantizationScale(), inputInfo.GetQuantizationOffset(), - weightsData, weightsInfo.GetQuantizationScale(), weightsInfo.GetQuantizationOffset(), - biasData, - outputInfo.GetQuantizationScale(), outputInfo.GetQuantizationOffset(), filterInfo); -} - -} //namespace armnn diff --git a/src/backends/reference/workloads/RefConvolution2dUint8Workload.hpp b/src/backends/reference/workloads/RefConvolution2dUint8Workload.hpp deleted file mode 100644 index a58f23a2a0..0000000000 --- a/src/backends/reference/workloads/RefConvolution2dUint8Workload.hpp +++ /dev/null @@ -1,28 +0,0 @@ -// -// Copyright © 2017 Arm Ltd. All rights reserved. -// SPDX-License-Identifier: MIT -// - -#pragma once - -#include -#include - -namespace armnn -{ - -class RefConvolution2dUint8Workload : public Uint8Workload -{ -public: - explicit RefConvolution2dUint8Workload(const Convolution2dQueueDescriptor& descriptor, - const WorkloadInfo& info); - - virtual void Execute() const override; - -private: - std::unique_ptr m_Weight; - std::unique_ptr m_Bias; - -}; - -} //namespace armnn diff --git a/src/backends/reference/workloads/RefConvolution2dWorkload.cpp b/src/backends/reference/workloads/RefConvolution2dWorkload.cpp new file mode 100644 index 0000000000..0824d5cf1c --- /dev/null +++ b/src/backends/reference/workloads/RefConvolution2dWorkload.cpp @@ -0,0 +1,53 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "RefConvolution2dWorkload.hpp" + +#include "ConvImpl.hpp" +#include "RefWorkloadUtils.hpp" + +#include "Profiling.hpp" + +namespace armnn +{ +RefConvolution2dWorkload::RefConvolution2dWorkload( + const Convolution2dQueueDescriptor& descriptor, const WorkloadInfo& info) + : BaseWorkload(descriptor, info) +{ + m_Weight = std::make_unique(*(descriptor.m_Weight)); + const TensorInfo& rFilterInfo = GetTensorInfo(m_Weight.get()); + m_FilterShape = rFilterInfo.GetShape(); + m_FilterDecoder = MakeDecoder(rFilterInfo, m_Weight.get()->Map(true)); + + if (descriptor.m_Parameters.m_BiasEnabled) + { + m_Bias = std::make_unique(*(descriptor.m_Bias)); + const TensorInfo& biasInfo = GetTensorInfo(m_Bias.get()); + m_BiasDecoder = MakeDecoder(biasInfo, m_Bias.get()->Map(true)); + } +} + +void RefConvolution2dWorkload::PostAllocationConfigure() +{ + const TensorInfo& inputInfo = GetTensorInfo(m_Data.m_Inputs[0]); + m_InputShape = inputInfo.GetShape(); + m_InputDecoder = MakeDecoder(inputInfo, m_Data.m_Inputs[0]->Map()); + + const TensorInfo& outputInfo = GetTensorInfo(m_Data.m_Outputs[0]); + m_OutputShape = outputInfo.GetShape(); + m_OutputEncoder = MakeEncoder(outputInfo, m_Data.m_Outputs[0]->Map()); +} + +void RefConvolution2dWorkload::Execute() const { + ARMNN_SCOPED_PROFILING_EVENT(Compute::CpuRef, "RefConvolution2dWorkload_Execute"); + + Convolve(m_InputShape, *m_InputDecoder, m_OutputShape, *m_OutputEncoder, m_FilterShape, + *m_FilterDecoder, m_Data.m_Parameters.m_BiasEnabled, m_BiasDecoder.get(), + m_Data.m_Parameters.m_DataLayout, m_Data.m_Parameters.m_PadTop, m_Data.m_Parameters.m_PadLeft, + m_Data.m_Parameters.m_StrideX, m_Data.m_Parameters.m_StrideY, + m_Data.m_Parameters.m_DilationX, m_Data.m_Parameters.m_DilationY); +} + +} //namespace armnn diff --git a/src/backends/reference/workloads/RefConvolution2dWorkload.hpp b/src/backends/reference/workloads/RefConvolution2dWorkload.hpp new file mode 100644 index 0000000000..b6bdf23ffa --- /dev/null +++ b/src/backends/reference/workloads/RefConvolution2dWorkload.hpp @@ -0,0 +1,41 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include +#include +#include "Decoders.hpp" +#include "Encoders.hpp" + +namespace armnn +{ + +class RefConvolution2dWorkload : public BaseWorkload +{ +public: + explicit RefConvolution2dWorkload(const Convolution2dQueueDescriptor& descriptor, + const WorkloadInfo& info); + + void PostAllocationConfigure() override; + + virtual void Execute() const override; + +private: + std::unique_ptr m_Weight; + std::unique_ptr m_Bias; + + std::unique_ptr> m_InputDecoder; + std::unique_ptr> m_OutputEncoder; + std::unique_ptr> m_FilterDecoder; + std::unique_ptr> m_BiasDecoder; + + TensorShape m_InputShape; + TensorShape m_OutputShape; + TensorShape m_FilterShape; +}; + +} //namespace armnn + diff --git a/src/backends/reference/workloads/RefWorkloads.hpp b/src/backends/reference/workloads/RefWorkloads.hpp index 314e65beeb..5a65f60c40 100644 --- a/src/backends/reference/workloads/RefWorkloads.hpp +++ b/src/backends/reference/workloads/RefWorkloads.hpp @@ -9,7 +9,7 @@ #include "RefElementwiseWorkload.hpp" #include "ConvImpl.hpp" #include "RefConstantWorkload.hpp" -#include "RefConvolution2dUint8Workload.hpp" +#include "RefConvolution2dWorkload.hpp" #include "RefSplitterUint8Workload.hpp" #include "RefResizeBilinearUint8Workload.hpp" #include "RefL2NormalizationFloat32Workload.hpp" @@ -46,7 +46,6 @@ #include "RefSpaceToBatchNdWorkload.hpp" #include "RefSplitterFloat32Workload.hpp" #include "RefStridedSliceWorkload.hpp" -#include "RefConvolution2dFloat32Workload.hpp" #include "Pooling2d.hpp" #include "RefFakeQuantizationFloat32Workload.hpp" #include "RefPermuteWorkload.hpp" -- cgit v1.2.1