diff options
author | Tamás Nyíri <tamas.nyiri@arm.com> | 2021-10-26 14:47:57 +0100 |
---|---|---|
committer | Tamas Nyiri <tamas.nyiri@arm.com> | 2021-11-17 11:31:44 +0000 |
commit | 7b885b3cce70154596b1994b013ea91527117c26 (patch) | |
tree | cdc2ee30a6dc03a4e26e6783a84ccd9be867242a /src/backends/reference | |
parent | 888a363115e0bf47f227c9db6fc1dbfe0418f69c (diff) | |
download | armnn-7b885b3cce70154596b1994b013ea91527117c26.tar.gz |
IVGCVSW-6509 Front End + Reference Workload implementation
Subtask of story: IVGCVSW-6164 Add a Pooling3d FrontEnd and Ref Implementation
* Add front end
* Add reference workload
* Add corresponding unit tests
Change-Id: Icce4146dd0a06a1da46a2def00a82d343e171750
Signed-off-by: Tamas Nyiri <tamas.nyiri@arm.com>
Diffstat (limited to 'src/backends/reference')
-rw-r--r-- | src/backends/reference/RefLayerSupport.cpp | 32 | ||||
-rw-r--r-- | src/backends/reference/RefLayerSupport.hpp | 5 | ||||
-rw-r--r-- | src/backends/reference/RefWorkloadFactory.cpp | 6 | ||||
-rw-r--r-- | src/backends/reference/RefWorkloadFactory.hpp | 3 | ||||
-rw-r--r-- | src/backends/reference/backend.mk | 2 | ||||
-rw-r--r-- | src/backends/reference/test/RefLayerTests.cpp | 64 | ||||
-rw-r--r-- | src/backends/reference/workloads/CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/backends/reference/workloads/Pooling3d.cpp | 328 | ||||
-rw-r--r-- | src/backends/reference/workloads/Pooling3d.hpp | 21 | ||||
-rw-r--r-- | src/backends/reference/workloads/RefPooling3dWorkload.cpp | 42 | ||||
-rw-r--r-- | src/backends/reference/workloads/RefPooling3dWorkload.hpp | 26 | ||||
-rw-r--r-- | src/backends/reference/workloads/RefWorkloads.hpp | 2 |
12 files changed, 534 insertions, 1 deletions
diff --git a/src/backends/reference/RefLayerSupport.cpp b/src/backends/reference/RefLayerSupport.cpp index b80aa9992f..0ac2ddc2a9 100644 --- a/src/backends/reference/RefLayerSupport.cpp +++ b/src/backends/reference/RefLayerSupport.cpp @@ -1721,6 +1721,38 @@ bool RefLayerSupport::IsPooling2dSupported(const TensorInfo& input, return supported; } +bool RefLayerSupport::IsPooling3dSupported(const TensorInfo& input, + const TensorInfo& output, + const Pooling3dDescriptor& descriptor, + Optional<std::string&> reasonIfUnsupported) const +{ + IgnoreUnused(descriptor); + bool supported = true; + + // Define supported output and inputs types. + std::array<DataType,6> supportedTypes = + { + DataType::BFloat16, + DataType::Float32, + DataType::Float16, + DataType::QAsymmS8, + DataType::QAsymmU8, + DataType::QSymmS16 + }; + + supported &= CheckSupportRule(TypeAnyOf(input, supportedTypes), reasonIfUnsupported, + "Reference poolind3d: input is not a supported type."); + + supported &= CheckSupportRule(TypeAnyOf(output, supportedTypes), reasonIfUnsupported, + "Reference poolind3d: output is not a supported type."); + + supported &= CheckSupportRule(TypesAreEqual(input, output), reasonIfUnsupported, + "Reference poolind3d: input and output types are mismatched."); + + return supported; +} + + bool RefLayerSupport::IsQLstmSupported(const TensorInfo& input, const TensorInfo& previousOutputIn, const TensorInfo& previousCellStateIn, diff --git a/src/backends/reference/RefLayerSupport.hpp b/src/backends/reference/RefLayerSupport.hpp index 53d7907204..61d0556746 100644 --- a/src/backends/reference/RefLayerSupport.hpp +++ b/src/backends/reference/RefLayerSupport.hpp @@ -250,6 +250,11 @@ public: const Pooling2dDescriptor& descriptor, Optional<std::string&> reasonIfUnsupported = EmptyOptional()) const override; + bool IsPooling3dSupported(const TensorInfo& input, + const TensorInfo& output, + const Pooling3dDescriptor& descriptor, + Optional<std::string&> reasonIfUnsupported = EmptyOptional()) const override; + bool IsQuantizeSupported(const TensorInfo& input, const TensorInfo& output, Optional<std::string&> reasonIfUnsupported = EmptyOptional()) const override; diff --git a/src/backends/reference/RefWorkloadFactory.cpp b/src/backends/reference/RefWorkloadFactory.cpp index 36dcd21d32..eff301c89f 100644 --- a/src/backends/reference/RefWorkloadFactory.cpp +++ b/src/backends/reference/RefWorkloadFactory.cpp @@ -543,6 +543,12 @@ std::unique_ptr<IWorkload> RefWorkloadFactory::CreatePooling2d(const Pooling2dQu return std::make_unique<RefPooling2dWorkload>(descriptor, info); } +std::unique_ptr<IWorkload> RefWorkloadFactory::CreatePooling3d(const Pooling3dQueueDescriptor& descriptor, + const WorkloadInfo& info) const +{ + return std::make_unique<RefPooling3dWorkload>(descriptor, info); +} + std::unique_ptr<IWorkload> RefWorkloadFactory::CreatePreCompiled(const PreCompiledQueueDescriptor& /*descriptor*/, const WorkloadInfo& /*info*/) const { diff --git a/src/backends/reference/RefWorkloadFactory.hpp b/src/backends/reference/RefWorkloadFactory.hpp index a85e8dda3e..21dfed92e5 100644 --- a/src/backends/reference/RefWorkloadFactory.hpp +++ b/src/backends/reference/RefWorkloadFactory.hpp @@ -201,6 +201,9 @@ public: std::unique_ptr<IWorkload> CreatePooling2d(const Pooling2dQueueDescriptor& descriptor, const WorkloadInfo& info) const override; + std::unique_ptr<IWorkload> CreatePooling3d(const Pooling3dQueueDescriptor& descriptor, + const WorkloadInfo& info) const override; + std::unique_ptr<IWorkload> CreatePreCompiled(const PreCompiledQueueDescriptor& descriptor, const WorkloadInfo& info) const override; diff --git a/src/backends/reference/backend.mk b/src/backends/reference/backend.mk index 7049279557..0ddb16a23b 100644 --- a/src/backends/reference/backend.mk +++ b/src/backends/reference/backend.mk @@ -44,6 +44,7 @@ BACKEND_SOURCES := \ workloads/MirrorPad.cpp \ workloads/Pad.cpp \ workloads/Pooling2d.cpp \ + workloads/Pooling3d.cpp \ workloads/PreluImpl.cpp \ workloads/Reduce.cpp \ workloads/RefActivationWorkload.cpp \ @@ -84,6 +85,7 @@ BACKEND_SOURCES := \ workloads/RefPadWorkload.cpp \ workloads/RefPermuteWorkload.cpp \ workloads/RefPooling2dWorkload.cpp \ + workloads/RefPooling3dWorkload.cpp \ workloads/RefPreluWorkload.cpp \ workloads/RefQLstmWorkload.cpp \ workloads/RefQuantizeWorkload.cpp \ diff --git a/src/backends/reference/test/RefLayerTests.cpp b/src/backends/reference/test/RefLayerTests.cpp index 5993270173..13487dd53f 100644 --- a/src/backends/reference/test/RefLayerTests.cpp +++ b/src/backends/reference/test/RefLayerTests.cpp @@ -482,7 +482,7 @@ ARMNN_AUTO_TEST_CASE_WITH_THF(DepthwiseConvolution2dPerAxisQuantTestNchw, Depthw ARMNN_AUTO_TEST_CASE_WITH_THF(DepthwiseConvolution2dPerAxisQuantTestNhwc, DepthwiseConvolution2dPerAxisQuantTest, DataLayout::NHWC); -// Pooling +// [ Pooling 2D //MaxPooling ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleMaxPooling2dSize2x2Stride2x2, SimpleMaxPooling2dSize2x2Stride2x2Test, false) ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleMaxPooling2dSize2x2Stride2x2Uint8, @@ -564,6 +564,68 @@ ARMNN_AUTO_TEST_CASE_WITH_THF(L2Pooling2dSize7Int16, L2Pooling2dSize7Int16Test) ARMNN_AUTO_TEST_CASE_WITH_THF(AsymmNonSquarePooling2d, AsymmetricNonSquarePooling2dTest) ARMNN_AUTO_TEST_CASE_WITH_THF(AsymmNonSquarePooling2dUint8, AsymmetricNonSquarePooling2dUint8Test) ARMNN_AUTO_TEST_CASE_WITH_THF(AsymmNonSquarePooling2dInt16, AsymmetricNonSquarePooling2dInt16Test) +// Pooling 2D ] + +// [ Pooling 3D +//MaxPooling +ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleMaxPooling3dSize2x2x2Stride1x1x1, SimpleMaxPooling3dSize2x2x2Stride1x1x1Test) +ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleMaxPooling3dSize2x2x2Stride1x1x1Uint8, + SimpleMaxPooling3dSize2x2x2Stride1x1x1Uint8Test) +ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleMaxPooling3dSize2x2x2Stride1x1x1Int16, + SimpleMaxPooling3dSize2x2x2Stride1x1x1Int16Test) + +ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleMaxPooling3d, SimpleMaxPooling3dTest, DataLayout::NDHWC) +ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleMaxPooling3dNCDHW, SimpleMaxPooling3dTest, DataLayout::NCDHW) +ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleMaxPooling3dUint8, SimpleMaxPooling3dUint8Test, DataLayout::NDHWC) +ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleMaxPooling3dInt16, SimpleMaxPooling3dInt16Test, DataLayout::NDHWC) +ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleMaxPooling3dUint8NCDHW, SimpleMaxPooling3dUint8Test, DataLayout::NCDHW) +ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleMaxPooling3dInt16NCDHW, SimpleMaxPooling3dInt16Test, DataLayout::NCDHW) + +ARMNN_AUTO_TEST_CASE_WITH_THF(IgnorePaddingSimpleMaxPooling3d, IgnorePaddingSimpleMaxPooling3dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(IgnorePaddingSimpleMaxPooling3dUint8, IgnorePaddingSimpleMaxPooling3dUint8Test) +ARMNN_AUTO_TEST_CASE_WITH_THF(IgnorePaddingSimpleMaxPooling3dInt16, IgnorePaddingSimpleMaxPooling3dInt16Test) + +//AveragePooling +ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleAveragePooling3d, SimpleAveragePooling3dTest, DataLayout::NDHWC) +ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleAveragePooling3dNCDHW, SimpleAveragePooling3dTest, DataLayout::NCDHW) +ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleAveragePooling3dUint8, SimpleAveragePooling3dUint8Test, DataLayout::NDHWC) +ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleAveragePooling3dInt16, SimpleAveragePooling3dInt16Test, DataLayout::NDHWC) +ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleAveragePooling3dUint8NCDHW, SimpleAveragePooling3dUint8Test, DataLayout::NCDHW) +ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleAveragePooling3dInt16NCDHW, SimpleAveragePooling3dInt16Test, DataLayout::NCDHW) + +ARMNN_AUTO_TEST_CASE_WITH_THF(LargeTensorsAveragePooling3d, LargeTensorsAveragePooling3dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(LargeTensorsAveragePooling3dUint8, LargeTensorsAveragePooling3dUint8Test) +ARMNN_AUTO_TEST_CASE_WITH_THF(LargeTensorsAveragePooling3dInt16, LargeTensorsAveragePooling3dInt16Test) + +ARMNN_AUTO_TEST_CASE_WITH_THF(IgnorePaddingSimpleAveragePooling3d, IgnorePaddingSimpleAveragePooling3dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(IgnorePaddingSimpleAveragePooling3dUint8, IgnorePaddingSimpleAveragePooling3dUint8Test) +ARMNN_AUTO_TEST_CASE_WITH_THF(IgnorePaddingSimpleAveragePooling3dInt16, IgnorePaddingSimpleAveragePooling3dInt16Test) + +//L2Pooling +ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleL2Pooling3d, SimpleL2Pooling3dTest, DataLayout::NDHWC) +ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleL2Pooling3dNCDHW, SimpleL2Pooling3dTest, DataLayout::NCDHW) +ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleL2Pooling3dUint8, SimpleL2Pooling3dUint8Test, DataLayout::NDHWC) +ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleL2Pooling3dInt16, SimpleL2Pooling3dInt16Test, DataLayout::NDHWC) +ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleL2Pooling3dUint8NCDHW, SimpleL2Pooling3dUint8Test, DataLayout::NCDHW) +ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleL2Pooling3dInt16NCDHW, SimpleL2Pooling3dInt16Test, DataLayout::NCDHW) + +ARMNN_AUTO_TEST_CASE_WITH_THF(IgnorePaddingSimpleL2Pooling3d, IgnorePaddingSimpleL2Pooling3dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(IgnorePaddingSimpleL2Pooling3dUint8, IgnorePaddingSimpleL2Pooling3dUint8Test) +ARMNN_AUTO_TEST_CASE_WITH_THF(IgnorePaddingSimpleL2Pooling3dInt16, IgnorePaddingSimpleL2Pooling3dInt16Test) + +//NonSquarePooling +ARMNN_AUTO_TEST_CASE_WITH_THF(AsymmNonSquareMaxPooling3d, AsymmetricNonSquareMaxPooling3dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(AsymmNonSquareMaxPooling3dUint8, AsymmetricNonSquareMaxPooling3dUint8Test) +ARMNN_AUTO_TEST_CASE_WITH_THF(AsymmNonSquareMaxPooling3dInt16, AsymmetricNonSquareMaxPooling3dInt16Test) + +ARMNN_AUTO_TEST_CASE_WITH_THF(AsymmNonSquareAveragePooling3d, AsymmetricNonSquareAveragePooling3dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(AsymmNonSquareAveragePooling3dUint8, AsymmetricNonSquareAveragePooling3dUint8Test) +ARMNN_AUTO_TEST_CASE_WITH_THF(AsymmNonSquareAveragePooling3dInt16, AsymmetricNonSquareAveragePooling3dInt16Test) + +ARMNN_AUTO_TEST_CASE_WITH_THF(AsymmNonSquareL2Pooling3d, AsymmetricNonSquareL2Pooling3dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(AsymmNonSquareL2Pooling3dUint8, AsymmetricNonSquareL2Pooling3dUint8Test) +ARMNN_AUTO_TEST_CASE_WITH_THF(AsymmNonSquareL2Pooling3dInt16, AsymmetricNonSquareL2Pooling3dInt16Test) +// Pooling 3D ] // Linear Activation diff --git a/src/backends/reference/workloads/CMakeLists.txt b/src/backends/reference/workloads/CMakeLists.txt index f212522895..60d8255454 100644 --- a/src/backends/reference/workloads/CMakeLists.txt +++ b/src/backends/reference/workloads/CMakeLists.txt @@ -58,6 +58,8 @@ list(APPEND armnnRefBackendWorkloads_sources Pad.hpp Pooling2d.cpp Pooling2d.hpp + Pooling3d.cpp + Pooling3d.hpp PreluImpl.cpp PreluImpl.hpp Reduce.cpp @@ -139,6 +141,8 @@ list(APPEND armnnRefBackendWorkloads_sources RefPermuteWorkload.hpp RefPooling2dWorkload.cpp RefPooling2dWorkload.hpp + RefPooling3dWorkload.cpp + RefPooling3dWorkload.hpp RefPreluWorkload.cpp RefPreluWorkload.hpp RefQuantizeWorkload.cpp diff --git a/src/backends/reference/workloads/Pooling3d.cpp b/src/backends/reference/workloads/Pooling3d.cpp new file mode 100644 index 0000000000..3cae2a94b9 --- /dev/null +++ b/src/backends/reference/workloads/Pooling3d.cpp @@ -0,0 +1,328 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "Pooling3d.hpp" + +#include <armnn/Exceptions.hpp> +#include <armnn/Types.hpp> + +#include <armnnUtils/DataLayoutIndexed.hpp> +#include <armnn/utility/NumericCast.hpp> + +#include <limits> +#include <algorithm> +#include <functional> + +namespace +{ + using PoolingAlgorithm = armnn::PoolingAlgorithm; + + float DefaultInitializer(PoolingAlgorithm algorithm) + { + switch (algorithm) + { + case PoolingAlgorithm::Max: + { + return std::numeric_limits<float>::lowest(); + } + case PoolingAlgorithm::Average: + case PoolingAlgorithm::L2: + { + return 0.0f; + } + default: + { + throw armnn::InvalidArgumentException("Unsupported pooling algorithm"); + } + } + } + + using Accumulator = std::function<void(float & accu, float value)>; + + Accumulator GetAccumulator(PoolingAlgorithm algorithm) + { + switch (algorithm) + { + case PoolingAlgorithm::Max: + { + return [](float & accu, float value) { + if (value > accu) { + accu = value; + } + }; + } + + case PoolingAlgorithm::Average: + { + return [](float & accu, float value) { + accu += value; + }; + } + + case PoolingAlgorithm::L2: + { + return [](float & accu, float value) { + accu += (value*value); + }; + } + + default: + { + throw armnn::InvalidArgumentException("Unsupported pooling algorithm"); + } + } + } + + using Executor = std::function<void(float & accumulated, float kernelSize)>; + + Executor GetExecutor(PoolingAlgorithm algorithm) + { + switch (algorithm) + { + case PoolingAlgorithm::Max: + { + return [](float & /*accumulated*/, float /*kernelSize*/) {}; + } + + case PoolingAlgorithm::Average: + { + return [](float & accumulated, float kernelSize) { + accumulated /= kernelSize; + }; + } + + case PoolingAlgorithm::L2: + { + return [](float & accumulated, float kernelSize) { + accumulated = sqrtf(accumulated / kernelSize); + }; + } + + default: + { + throw armnn::InvalidArgumentException("Unsupported pooling algorithm"); + } + } + } + + bool OnPaddingOnly(int start, int end, int maxRange) + { + if (end <= 0 || start > maxRange) + { + return true; + } + else + { + return false; + } + } + + + bool ClampRange(int & start, int & end, int maxRange) + { + if (start < 0 || end > maxRange) + { + start = std::min(std::max(start, 0), maxRange); + end = std::min(std::max(end, 0), maxRange); + return true; + } + else + { + return false; + } + } + + int CalculateIndex(int channels, int depth, int height, int width, + int n, int c, int z, int y, int x, + armnnUtils::DataLayoutIndexed dataLayout) { + switch (dataLayout.GetDataLayout()) + { + case armnn::DataLayout::NDHWC: + { + int outputIndex = n * depth * height * width * channels + + z * height * width * channels + + y * width * channels + + x * channels + + c; + return outputIndex; + } + case armnn::DataLayout::NCDHW: + { + int outputIndex = n * channels * depth * height * width + + c * depth * height * width + + z * height * width + + y * width + + x; + return outputIndex; + } + default: + { + throw armnn::InvalidArgumentException("Unsupported data layout."); + } + } + } +} + +using namespace armnnUtils; + +namespace armnn +{ +void Pooling3d(Decoder<float>& rInputDecoder, + Encoder<float>& rOutputEncoder, + const TensorInfo& inputInfo, + const TensorInfo& outputInfo, + const Pooling3dDescriptor& params) +{ + const DataLayoutIndexed dataLayout(params.m_DataLayout); + + auto channelsIndex = dataLayout.GetChannelsIndex(); + + auto depthIndex = dataLayout.GetDepthIndex(); + auto heightIndex = dataLayout.GetHeightIndex(); + auto widthIndex = dataLayout.GetWidthIndex(); + + const int batchSize = armnn::numeric_cast<int>(outputInfo.GetShape()[0]); + const int channels = armnn::numeric_cast<int>(outputInfo.GetShape()[channelsIndex]); + + const int depthOutput = armnn::numeric_cast<int>(outputInfo.GetShape()[depthIndex]); + const int heightOutput = armnn::numeric_cast<int>(outputInfo.GetShape()[heightIndex]); + const int widthOutput = armnn::numeric_cast<int>(outputInfo.GetShape()[widthIndex]); + + const int depthInput = armnn::numeric_cast<int>(inputInfo.GetShape()[depthIndex]); + const int heightInput = armnn::numeric_cast<int>(inputInfo.GetShape()[heightIndex]); + const int widthInput = armnn::numeric_cast<int>(inputInfo.GetShape()[widthIndex]); + + const int padLeft = armnn::numeric_cast<int>(params.m_PadLeft); + const int padRight = armnn::numeric_cast<int>(params.m_PadRight); + const int padTop = armnn::numeric_cast<int>(params.m_PadTop); + const int padBottom = armnn::numeric_cast<int>(params.m_PadBottom); + const int padFront = armnn::numeric_cast<int>(params.m_PadFront); + const int padBack = armnn::numeric_cast<int>(params.m_PadBack); + + const int strideX = armnn::numeric_cast<int>(params.m_StrideX); + const int strideY = armnn::numeric_cast<int>(params.m_StrideY); + const int strideZ = armnn::numeric_cast<int>(params.m_StrideZ); + + const int poolHeight = armnn::numeric_cast<int>(params.m_PoolHeight); + const int poolWidth = armnn::numeric_cast<int>(params.m_PoolWidth); + const int poolDepth = armnn::numeric_cast<int>(params.m_PoolDepth); + + float defaultInitializer = DefaultInitializer(params.m_PoolType); + Accumulator accumulate = GetAccumulator(params.m_PoolType); + Executor execute = GetExecutor(params.m_PoolType); + + // Check supported padding methods outside the loop to simplify + // the inner loop. + if (params.m_PaddingMethod != PaddingMethod::Exclude && + params.m_PaddingMethod != PaddingMethod::IgnoreValue) + { + throw armnn::InvalidArgumentException("Unsupported padding type"); + } + + const std::vector<float> decodedInputVec = rInputDecoder.DecodeTensor(inputInfo.GetShape()); + + for (int n = 0; n < batchSize; n++) + { + for (int c = 0; c < channels; c++) + { + for (int zOutput = 0; zOutput < depthOutput; zOutput++) + { + // Calculate values independent of the x and y axis + int dstart = (zOutput * strideZ) - padFront; + int dend = dstart + poolDepth; + // Clamp the pooling region inside the valid input area (which includes the padding). + // This is necessary because the final pooling in a row may overlap beyond the padding. + dend = std::min(dend, depthInput + padBack); + + int depth = dend - dstart; + bool dclamped = ClampRange(dstart, dend, depthInput); + int depthClamped = dend - dstart; + + for (int yOutput = 0; yOutput < heightOutput; yOutput++) + { + int hstart = (yOutput * strideY) - padTop; + int hend = hstart + poolHeight; + // Clamp the pooling region inside the valid input area (which includes the padding). + // This is necessary because the final pooling in a row may overlap beyond the padding. + hend = std::min(hend, heightInput + padBottom); + + int height = hend - hstart; + bool hclamped = ClampRange(hstart, hend, heightInput); + int heightClamped = hend - hstart; + + for (int xOutput = 0; xOutput < widthOutput; xOutput++) + { + int wstart = (xOutput * strideX) - padLeft; + int wend = wstart + poolWidth; + // Clamp the pooling region inside the valid input area (which includes the padding). + // This is necessary because the final pooling in a row may overlap beyond the padding. + wend = std::min(wend, widthInput + padRight); + + int width = wend - wstart; + bool wclamped = ClampRange(wstart, wend, widthInput); + int widthClamped = wend - wstart; + + float result = defaultInitializer; + float poolAreaSize = armnn::numeric_cast<float>(depth * height * width); + + // Special case: when the pooling kernel is over a padding region and the padding + // size is larger or equal to the kernel and the kernel only covers + // padding and no real values, then we initialize the result as zero + // by convention. This is because we need to choose a value here and + // all values we have are padding, which we ignore. + if (OnPaddingOnly(dstart, dend, depthInput) || + OnPaddingOnly(hstart, hend, heightInput) || + OnPaddingOnly(wstart, wend, widthInput)) + { + result = 0.0f; + + int outputIndex = CalculateIndex(channels, depthOutput, heightOutput, widthOutput, + n, c, zOutput, yOutput, xOutput, dataLayout); + + rOutputEncoder[static_cast<unsigned int>(outputIndex)]; + rOutputEncoder.Set(result); + + continue; + } + + bool clamped = (dclamped | hclamped | wclamped); + + if (clamped && params.m_PaddingMethod == PaddingMethod::Exclude) + { + // When we exclude the padding, it means we calculate with a smaller + // kernel size, so I changed the divisor here. + poolAreaSize = armnn::numeric_cast<float>(depthClamped * heightClamped * widthClamped); + } + + for (auto zInput = dstart; zInput < dend; zInput++) + { + for (auto yInput = hstart; yInput < hend; yInput++) + { + for (auto xInput = wstart; xInput < wend; xInput++) + { + + int inputIndex = CalculateIndex(channels, depthInput, heightInput, widthInput, + n, c, zInput, yInput, xInput, dataLayout); + + accumulate(result, decodedInputVec[static_cast<unsigned int>(inputIndex)]); + } + } + } + + execute(result, poolAreaSize); + + int outputIndex = CalculateIndex(channels, depthOutput, heightOutput, widthOutput, + n, c, zOutput, yOutput, xOutput, dataLayout); + + rOutputEncoder[static_cast<unsigned int>(outputIndex)]; + rOutputEncoder.Set(result); + } + } + } + } + } +} + +} //namespace armnn diff --git a/src/backends/reference/workloads/Pooling3d.hpp b/src/backends/reference/workloads/Pooling3d.hpp new file mode 100644 index 0000000000..dd3c919975 --- /dev/null +++ b/src/backends/reference/workloads/Pooling3d.hpp @@ -0,0 +1,21 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include <armnn/Descriptors.hpp> +#include <armnn/Tensor.hpp> + +#include "BaseIterator.hpp" + +namespace armnn +{ +/// Computes the Pooling3d operation. +void Pooling3d(Decoder<float>& rInputDecoder, + Encoder<float>& rOutputEncoder, + const TensorInfo& inputInfo, + const TensorInfo& outputInfo, + const Pooling3dDescriptor& params); +} //namespace armnn diff --git a/src/backends/reference/workloads/RefPooling3dWorkload.cpp b/src/backends/reference/workloads/RefPooling3dWorkload.cpp new file mode 100644 index 0000000000..d1e00aa5f7 --- /dev/null +++ b/src/backends/reference/workloads/RefPooling3dWorkload.cpp @@ -0,0 +1,42 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "RefPooling3dWorkload.hpp" + +#include "Pooling3d.hpp" +#include "RefWorkloadUtils.hpp" + +#include "Profiling.hpp" +#include "BaseIterator.hpp" + +namespace armnn +{ +void RefPooling3dWorkload::Execute() const +{ + Execute(m_Data.m_Inputs, m_Data.m_Outputs); +} + +void RefPooling3dWorkload::ExecuteAsync(WorkingMemDescriptor &workingMemDescriptor) +{ + Execute(workingMemDescriptor.m_Inputs, workingMemDescriptor.m_Outputs); +} + +void RefPooling3dWorkload::Execute(std::vector<ITensorHandle*> inputs, std::vector<ITensorHandle*> outputs) const +{ + ARMNN_SCOPED_PROFILING_EVENT(Compute::CpuRef, "RefPooling3dWorkload_Execute"); + + const TensorInfo& inputInfo = GetTensorInfo(inputs[0]); + const TensorInfo& outputInfo = GetTensorInfo(outputs[0]); + + auto inputDecoder = MakeDecoder<float>(inputInfo, inputs[0] ->Map()); + auto outputEncoder = MakeEncoder<float>(outputInfo, outputs[0]->Map()); + + Pooling3d(*inputDecoder, + *outputEncoder, + inputInfo, + outputInfo, + m_Data.m_Parameters); +} +} //namespace armnn diff --git a/src/backends/reference/workloads/RefPooling3dWorkload.hpp b/src/backends/reference/workloads/RefPooling3dWorkload.hpp new file mode 100644 index 0000000000..1188af23ca --- /dev/null +++ b/src/backends/reference/workloads/RefPooling3dWorkload.hpp @@ -0,0 +1,26 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include <backendsCommon/Workload.hpp> +#include <backendsCommon/WorkloadData.hpp> + +#include "Decoders.hpp" +#include "Encoders.hpp" + +namespace armnn +{ +class RefPooling3dWorkload : public BaseWorkload<Pooling3dQueueDescriptor> +{ +public: + using BaseWorkload<Pooling3dQueueDescriptor>::BaseWorkload; + + void Execute() const override; + void ExecuteAsync(WorkingMemDescriptor& workingMemDescriptor) override; +private: + void Execute(std::vector<ITensorHandle*> inputs, std::vector<ITensorHandle*> outputs) const; +}; +} //namespace armnn diff --git a/src/backends/reference/workloads/RefWorkloads.hpp b/src/backends/reference/workloads/RefWorkloads.hpp index 914137c23d..700a1d6184 100644 --- a/src/backends/reference/workloads/RefWorkloads.hpp +++ b/src/backends/reference/workloads/RefWorkloads.hpp @@ -14,6 +14,7 @@ #include "FullyConnected.hpp" #include "Gather.hpp" #include "Pooling2d.hpp" +#include "Pooling3d.hpp" #include "RefActivationWorkload.hpp" #include "RefArgMinMaxWorkload.hpp" #include "RefBatchNormalizationWorkload.hpp" @@ -51,6 +52,7 @@ #include "RefMeanWorkload.hpp" #include "RefNormalizationWorkload.hpp" #include "RefPooling2dWorkload.hpp" +#include "RefPooling3dWorkload.hpp" #include "RefPermuteWorkload.hpp" #include "RefPadWorkload.hpp" #include "RefPreluWorkload.hpp" |