From 37e68686a4889b6e79b035356202903647671f13 Mon Sep 17 00:00:00 2001 From: Ellen Norris-Thompson Date: Mon, 15 Jul 2019 14:23:30 +0100 Subject: IVGCVSW-3297 Add Neon backend support for ResizeNearestNeighbour * Renamed NeonResizeBilinearWorkload.* to NeonResizeWorkload.* and added support for ResizeNearestNeighbour * Added CreateWorkload and LayerTests for Neon backend Signed-off-by: Ellen Norris-Thompson Change-Id: I72f5340608a0928f8b32a41d1915ee2c35849f18 --- src/backends/neon/NeonLayerSupport.cpp | 29 ++++----- src/backends/neon/NeonWorkloadFactory.cpp | 25 +++----- src/backends/neon/backend.mk | 2 +- src/backends/neon/test/NeonCreateWorkloadTests.cpp | 52 ++++++++++++++++ src/backends/neon/test/NeonLayerTests.cpp | 66 ++++++++++++++++++++ src/backends/neon/workloads/CMakeLists.txt | 4 +- .../neon/workloads/NeonResizeBilinearWorkload.cpp | 59 ------------------ .../neon/workloads/NeonResizeBilinearWorkload.hpp | 29 --------- src/backends/neon/workloads/NeonResizeWorkload.cpp | 72 ++++++++++++++++++++++ src/backends/neon/workloads/NeonResizeWorkload.hpp | 29 +++++++++ src/backends/neon/workloads/NeonWorkloads.hpp | 2 +- 11 files changed, 248 insertions(+), 121 deletions(-) delete mode 100644 src/backends/neon/workloads/NeonResizeBilinearWorkload.cpp delete mode 100644 src/backends/neon/workloads/NeonResizeBilinearWorkload.hpp create mode 100644 src/backends/neon/workloads/NeonResizeWorkload.cpp create mode 100644 src/backends/neon/workloads/NeonResizeWorkload.hpp diff --git a/src/backends/neon/NeonLayerSupport.cpp b/src/backends/neon/NeonLayerSupport.cpp index ea875f6926..cb709c315a 100644 --- a/src/backends/neon/NeonLayerSupport.cpp +++ b/src/backends/neon/NeonLayerSupport.cpp @@ -39,7 +39,7 @@ #include "workloads/NeonPooling2dWorkload.hpp" #include "workloads/NeonPreluWorkload.hpp" #include "workloads/NeonQuantizeWorkload.hpp" -#include "workloads/NeonResizeBilinearWorkload.hpp" +#include "workloads/NeonResizeWorkload.hpp" #include "workloads/NeonSoftmaxBaseWorkload.hpp" #include "workloads/NeonSpaceToDepthWorkload.hpp" #include "workloads/NeonSplitterWorkload.hpp" @@ -511,25 +511,26 @@ bool NeonLayerSupport::IsResizeSupported(const TensorInfo& input, const ResizeDescriptor& descriptor, Optional reasonIfUnsupported) const { - if (descriptor.m_Method == ResizeMethod::Bilinear) - { - FORWARD_WORKLOAD_VALIDATE_FUNC(NeonResizeBilinearWorkloadValidate, - reasonIfUnsupported, - input, - output); - } - - return false; + FORWARD_WORKLOAD_VALIDATE_FUNC(NeonResizeWorkloadValidate, + reasonIfUnsupported, + input, + output, + descriptor); } bool NeonLayerSupport::IsResizeBilinearSupported(const TensorInfo& input, const TensorInfo& output, Optional reasonIfUnsupported) const { - FORWARD_WORKLOAD_VALIDATE_FUNC(NeonResizeBilinearWorkloadValidate, - reasonIfUnsupported, - input, - output); + ResizeDescriptor descriptor; + descriptor.m_Method = ResizeMethod::Bilinear; + descriptor.m_DataLayout = DataLayout::NCHW; + + const TensorShape& outputShape = output.GetShape(); + descriptor.m_TargetHeight = outputShape[2]; + descriptor.m_TargetWidth = outputShape[3]; + + return IsResizeSupported(input, output, descriptor, reasonIfUnsupported); } bool NeonLayerSupport::IsSoftmaxSupported(const TensorInfo& input, diff --git a/src/backends/neon/NeonWorkloadFactory.cpp b/src/backends/neon/NeonWorkloadFactory.cpp index eadd636dd1..c50eaece1a 100644 --- a/src/backends/neon/NeonWorkloadFactory.cpp +++ b/src/backends/neon/NeonWorkloadFactory.cpp @@ -227,27 +227,22 @@ std::unique_ptr NeonWorkloadFactory::CreateMemCopy(const MemCo std::unique_ptr NeonWorkloadFactory::CreateResize(const ResizeQueueDescriptor& descriptor, const WorkloadInfo& info) const { - if (descriptor.m_Parameters.m_Method == ResizeMethod::Bilinear) - { - ResizeBilinearQueueDescriptor resizeBilinearDescriptor; - resizeBilinearDescriptor.m_Inputs = descriptor.m_Inputs; - resizeBilinearDescriptor.m_Outputs = descriptor.m_Outputs; - - resizeBilinearDescriptor.m_Parameters.m_DataLayout = descriptor.m_Parameters.m_DataLayout; - resizeBilinearDescriptor.m_Parameters.m_TargetWidth = descriptor.m_Parameters.m_TargetWidth; - resizeBilinearDescriptor.m_Parameters.m_TargetHeight = descriptor.m_Parameters.m_TargetHeight; - - return std::make_unique(resizeBilinearDescriptor, info); - } - - return MakeWorkloadHelper(descriptor, info); + return std::make_unique(descriptor, info); } std::unique_ptr NeonWorkloadFactory::CreateResizeBilinear( const ResizeBilinearQueueDescriptor& descriptor, const WorkloadInfo& info) const { - return std::make_unique(descriptor, info); + ResizeQueueDescriptor resizeDescriptor; + resizeDescriptor.m_Inputs = descriptor.m_Inputs; + resizeDescriptor.m_Outputs = descriptor.m_Outputs; + + resizeDescriptor.m_Parameters.m_DataLayout = descriptor.m_Parameters.m_DataLayout; + resizeDescriptor.m_Parameters.m_TargetWidth = descriptor.m_Parameters.m_TargetWidth; + resizeDescriptor.m_Parameters.m_TargetHeight = descriptor.m_Parameters.m_TargetHeight; + + return CreateResize(resizeDescriptor, info); } std::unique_ptr NeonWorkloadFactory::CreateFakeQuantization( diff --git a/src/backends/neon/backend.mk b/src/backends/neon/backend.mk index 9b0c188ea1..305abfcb49 100644 --- a/src/backends/neon/backend.mk +++ b/src/backends/neon/backend.mk @@ -45,7 +45,7 @@ BACKEND_SOURCES := \ workloads/NeonPreluWorkload.cpp \ workloads/NeonQuantizeWorkload.cpp \ workloads/NeonReshapeWorkload.cpp \ - workloads/NeonResizeBilinearWorkload.cpp \ + workloads/NeonResizeWorkload.cpp \ workloads/NeonSoftmaxBaseWorkload.cpp \ workloads/NeonSoftmaxFloatWorkload.cpp \ workloads/NeonSoftmaxUint8Workload.cpp \ diff --git a/src/backends/neon/test/NeonCreateWorkloadTests.cpp b/src/backends/neon/test/NeonCreateWorkloadTests.cpp index 49c5a72a90..ac7eb253c2 100644 --- a/src/backends/neon/test/NeonCreateWorkloadTests.cpp +++ b/src/backends/neon/test/NeonCreateWorkloadTests.cpp @@ -19,6 +19,12 @@ BOOST_AUTO_TEST_SUITE(CreateWorkloadNeon) namespace { +boost::test_tools::predicate_result CompareIAclTensorHandleShape(IAclTensorHandle* tensorHandle, + std::initializer_list expectedDimensions) +{ + return CompareTensorHandleShape(tensorHandle, expectedDimensions); +} + bool TestNeonTensorHandleInfo(armnn::IAclTensorHandle* handle, const armnn::TensorInfo& expectedInfo) { using namespace armnn::armcomputetensorutils; @@ -493,6 +499,52 @@ BOOST_AUTO_TEST_CASE(CreateReshapeUint8Workload) NeonCreateReshapeWorkloadTest(); } +template +static void NeonCreateResizeWorkloadTest(DataLayout dataLayout) +{ + Graph graph; + NeonWorkloadFactory factory = + NeonWorkloadFactoryHelper::GetFactory(NeonWorkloadFactoryHelper::GetMemoryManager()); + auto workload = CreateResizeBilinearWorkloadTest(factory, graph, dataLayout); + + auto queueDescriptor = workload->GetData(); + + auto inputHandle = boost::polymorphic_downcast(queueDescriptor.m_Inputs[0]); + auto outputHandle = boost::polymorphic_downcast(queueDescriptor.m_Outputs[0]); + + switch (dataLayout) + { + case DataLayout::NHWC: + BOOST_TEST(CompareIAclTensorHandleShape(inputHandle, { 2, 4, 4, 3 })); + BOOST_TEST(CompareIAclTensorHandleShape(outputHandle, { 2, 2, 2, 3 })); + break; + case DataLayout::NCHW: + default: + BOOST_TEST(CompareIAclTensorHandleShape(inputHandle, { 2, 3, 4, 4 })); + BOOST_TEST(CompareIAclTensorHandleShape(outputHandle, { 2, 3, 2, 2 })); + } +} + +BOOST_AUTO_TEST_CASE(CreateResizeFloat32NchwWorkload) +{ + NeonCreateResizeWorkloadTest(DataLayout::NCHW); +} + +BOOST_AUTO_TEST_CASE(CreateResizeUint8NchwWorkload) +{ + NeonCreateResizeWorkloadTest(DataLayout::NCHW); +} + +BOOST_AUTO_TEST_CASE(CreateResizeFloat32NhwcWorkload) +{ + NeonCreateResizeWorkloadTest(DataLayout::NHWC); +} + +BOOST_AUTO_TEST_CASE(CreateResizeUint8NhwcWorkload) +{ + NeonCreateResizeWorkloadTest(DataLayout::NHWC); +} + template static void NeonCreateSoftmaxWorkloadTest() { diff --git a/src/backends/neon/test/NeonLayerTests.cpp b/src/backends/neon/test/NeonLayerTests.cpp index 586e994db5..aeebd4fd9e 100644 --- a/src/backends/neon/test/NeonLayerTests.cpp +++ b/src/backends/neon/test/NeonLayerTests.cpp @@ -616,6 +616,72 @@ ARMNN_AUTO_TEST_CASE(ResizeBilinearMagUint8Nhwc, ResizeBilinearMagTest, armnn::DataLayout::NHWC) +// Resize NearestNeighbor - NCHW +ARMNN_AUTO_TEST_CASE(SimpleResizeNearestNeighbor, + SimpleResizeNearestNeighborTest, + armnn::DataLayout::NCHW) +ARMNN_AUTO_TEST_CASE(ResizeNearestNeighborNop, + ResizeNearestNeighborNopTest, + armnn::DataLayout::NCHW) +ARMNN_AUTO_TEST_CASE(ResizeNearestNeighborSqMin, + ResizeNearestNeighborSqMinTest, + armnn::DataLayout::NCHW) +ARMNN_AUTO_TEST_CASE(ResizeNearestNeighborMin, + ResizeNearestNeighborMinTest, + armnn::DataLayout::NCHW) +ARMNN_AUTO_TEST_CASE(ResizeNearestNeighborMag, + ResizeNearestNeighborMagTest, + armnn::DataLayout::NCHW, 0.1f, 50, 0.1f, 50) + +ARMNN_AUTO_TEST_CASE(SimpleResizeNearestNeighborUint8, + SimpleResizeNearestNeighborTest, + armnn::DataLayout::NCHW) +ARMNN_AUTO_TEST_CASE(ResizeNearestNeighborNopUint8, + ResizeNearestNeighborNopTest, + armnn::DataLayout::NCHW) +ARMNN_AUTO_TEST_CASE(ResizeNearestNeighborSqMinUint8, + ResizeNearestNeighborSqMinTest, + armnn::DataLayout::NCHW) +ARMNN_AUTO_TEST_CASE(ResizeNearestNeighborMinUint8, + ResizeNearestNeighborMinTest, + armnn::DataLayout::NCHW) +ARMNN_AUTO_TEST_CASE(ResizeNearestNeighborMagUint8, + ResizeNearestNeighborMagTest, + armnn::DataLayout::NCHW, 0.1f, 50, 0.1f, 50) + +// Resize NearestNeighbor - NHWC +ARMNN_AUTO_TEST_CASE(ResizeNearestNeighborNopNhwc, + ResizeNearestNeighborNopTest, + armnn::DataLayout::NHWC) +ARMNN_AUTO_TEST_CASE(SimpleResizeNearestNeighborNhwc, + SimpleResizeNearestNeighborTest, + armnn::DataLayout::NHWC) +ARMNN_AUTO_TEST_CASE(ResizeNearestNeighborSqMinNhwc, + ResizeNearestNeighborSqMinTest, + armnn::DataLayout::NHWC) +ARMNN_AUTO_TEST_CASE(ResizeNearestNeighborMinNhwc, + ResizeNearestNeighborMinTest, + armnn::DataLayout::NHWC) +ARMNN_AUTO_TEST_CASE(ResizeNearestNeighborMagNhwc, + ResizeNearestNeighborMagTest, + armnn::DataLayout::NHWC, 0.1f, 50, 0.1f, 50) + +ARMNN_AUTO_TEST_CASE(ResizeNearestNeighborNopUint8Nhwc, + ResizeNearestNeighborNopTest, + armnn::DataLayout::NHWC) +ARMNN_AUTO_TEST_CASE(SimpleResizeNearestNeighborUint8Nhwc, + SimpleResizeNearestNeighborTest, + armnn::DataLayout::NHWC) +ARMNN_AUTO_TEST_CASE(ResizeNearestNeighborSqMinUint8Nhwc, + ResizeNearestNeighborSqMinTest, + armnn::DataLayout::NHWC) +ARMNN_AUTO_TEST_CASE(ResizeNearestNeighborMinUint8Nhwc, + ResizeNearestNeighborMinTest, + armnn::DataLayout::NHWC) +ARMNN_AUTO_TEST_CASE(ResizeNearestNeighborMagUint8Nhwc, + ResizeNearestNeighborMagTest, + armnn::DataLayout::NHWC, 0.1f, 50, 0.1f, 50) + // Quantize ARMNN_AUTO_TEST_CASE(QuantizeSimpleUint8, QuantizeSimpleUint8Test) ARMNN_AUTO_TEST_CASE(QuantizeClampUint8, QuantizeClampUint8Test) diff --git a/src/backends/neon/workloads/CMakeLists.txt b/src/backends/neon/workloads/CMakeLists.txt index 0ad961aa86..7bde80859e 100644 --- a/src/backends/neon/workloads/CMakeLists.txt +++ b/src/backends/neon/workloads/CMakeLists.txt @@ -56,8 +56,8 @@ list(APPEND armnnNeonBackendWorkloads_sources NeonQuantizeWorkload.hpp NeonReshapeWorkload.cpp NeonReshapeWorkload.hpp - NeonResizeBilinearWorkload.cpp - NeonResizeBilinearWorkload.hpp + NeonResizeWorkload.cpp + NeonResizeWorkload.hpp NeonSoftmaxBaseWorkload.cpp NeonSoftmaxBaseWorkload.hpp NeonSoftmaxFloatWorkload.cpp diff --git a/src/backends/neon/workloads/NeonResizeBilinearWorkload.cpp b/src/backends/neon/workloads/NeonResizeBilinearWorkload.cpp deleted file mode 100644 index 6943d872e4..0000000000 --- a/src/backends/neon/workloads/NeonResizeBilinearWorkload.cpp +++ /dev/null @@ -1,59 +0,0 @@ -// -// Copyright © 2017 Arm Ltd. All rights reserved. -// SPDX-License-Identifier: MIT -// - -#include "NeonResizeBilinearWorkload.hpp" - -#include -#include -#include -#include -#include - -using namespace armnn::armcomputetensorutils; - -namespace armnn -{ - -arm_compute::Status NeonResizeBilinearWorkloadValidate(const TensorInfo& input, const TensorInfo& output) -{ - const arm_compute::TensorInfo aclInputInfo = armcomputetensorutils::BuildArmComputeTensorInfo(input); - const arm_compute::TensorInfo aclOutputInfo = armcomputetensorutils::BuildArmComputeTensorInfo(output); - - return arm_compute::NEScale::validate(&aclInputInfo, - &aclOutputInfo, - arm_compute::InterpolationPolicy::BILINEAR, - arm_compute::BorderMode::REPLICATE, - arm_compute::PixelValue(0.f), - arm_compute::SamplingPolicy::TOP_LEFT); -} - -NeonResizeBilinearWorkload::NeonResizeBilinearWorkload(const ResizeBilinearQueueDescriptor& descriptor, - const WorkloadInfo& info) - : BaseWorkload(descriptor, info) -{ - m_Data.ValidateInputsOutputs("NeonResizeBilinearWorkload", 1, 1); - - arm_compute::ITensor& input = boost::polymorphic_downcast(m_Data.m_Inputs[0])->GetTensor(); - arm_compute::ITensor& output = boost::polymorphic_downcast(m_Data.m_Outputs[0])->GetTensor(); - - arm_compute::DataLayout aclDataLayout = ConvertDataLayout(m_Data.m_Parameters.m_DataLayout); - input.info()->set_data_layout(aclDataLayout); - output.info()->set_data_layout(aclDataLayout); - - m_ResizeBilinearLayer.configure(&input, - &output, - arm_compute::InterpolationPolicy::BILINEAR, - arm_compute::BorderMode::REPLICATE, - arm_compute::PixelValue(0.f), - arm_compute::SamplingPolicy::TOP_LEFT); -}; - -void NeonResizeBilinearWorkload::Execute() const -{ - ARMNN_SCOPED_PROFILING_EVENT_NEON("NeonResizeBilinearWorkload_Execute"); - m_ResizeBilinearLayer.run(); -} - -} //namespace armnn diff --git a/src/backends/neon/workloads/NeonResizeBilinearWorkload.hpp b/src/backends/neon/workloads/NeonResizeBilinearWorkload.hpp deleted file mode 100644 index 21753b3127..0000000000 --- a/src/backends/neon/workloads/NeonResizeBilinearWorkload.hpp +++ /dev/null @@ -1,29 +0,0 @@ -// -// Copyright © 2017 Arm Ltd. All rights reserved. -// SPDX-License-Identifier: MIT -// - -#pragma once - -#include - -#include - -#include - -namespace armnn -{ - -arm_compute::Status NeonResizeBilinearWorkloadValidate(const TensorInfo& input, const TensorInfo& output); - -class NeonResizeBilinearWorkload : public BaseWorkload -{ -public: - NeonResizeBilinearWorkload(const ResizeBilinearQueueDescriptor& descriptor, const WorkloadInfo& info); - void Execute() const override; - -private: - mutable arm_compute::NEScale m_ResizeBilinearLayer; -}; - -} //namespace armnn diff --git a/src/backends/neon/workloads/NeonResizeWorkload.cpp b/src/backends/neon/workloads/NeonResizeWorkload.cpp new file mode 100644 index 0000000000..a4e4a4a511 --- /dev/null +++ b/src/backends/neon/workloads/NeonResizeWorkload.cpp @@ -0,0 +1,72 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "NeonResizeWorkload.hpp" + +#include "NeonWorkloadUtils.hpp" + +#include +#include +#include +#include + +using namespace armnn::armcomputetensorutils; + +namespace armnn +{ + +arm_compute::Status NeonResizeWorkloadValidate(const TensorInfo& input, + const TensorInfo& output, + const ResizeDescriptor& descriptor) +{ + arm_compute::TensorInfo aclInputInfo = BuildArmComputeTensorInfo(input); + arm_compute::TensorInfo aclOutputInfo = BuildArmComputeTensorInfo(output); + + arm_compute::DataLayout aclDataLayout = ConvertDataLayout(descriptor.m_DataLayout); + aclInputInfo.set_data_layout(aclDataLayout); + aclOutputInfo.set_data_layout(aclDataLayout); + + arm_compute::InterpolationPolicy aclInterpolationPolicy = + ConvertResizeMethodToAclInterpolationPolicy(descriptor.m_Method); + + return arm_compute::NEScale::validate(&aclInputInfo, + &aclOutputInfo, + aclInterpolationPolicy, + arm_compute::BorderMode::REPLICATE, + arm_compute::PixelValue(0.f), + arm_compute::SamplingPolicy::TOP_LEFT); +} + +NeonResizeWorkload::NeonResizeWorkload(const ResizeQueueDescriptor& descriptor, + const WorkloadInfo& info) + : BaseWorkload(descriptor, info) +{ + m_Data.ValidateInputsOutputs("NeonResizeWorkload", 1, 1); + + arm_compute::ITensor& input = boost::polymorphic_downcast(m_Data.m_Inputs[0])->GetTensor(); + arm_compute::ITensor& output = boost::polymorphic_downcast(m_Data.m_Outputs[0])->GetTensor(); + + arm_compute::DataLayout aclDataLayout = ConvertDataLayout(m_Data.m_Parameters.m_DataLayout); + input.info()->set_data_layout(aclDataLayout); + output.info()->set_data_layout(aclDataLayout); + + arm_compute::InterpolationPolicy aclInterpolationPolicy = + ConvertResizeMethodToAclInterpolationPolicy(descriptor.m_Parameters.m_Method); + + m_ResizeLayer.configure(&input, + &output, + aclInterpolationPolicy, + arm_compute::BorderMode::REPLICATE, + arm_compute::PixelValue(0.f), + arm_compute::SamplingPolicy::TOP_LEFT); +}; + +void NeonResizeWorkload::Execute() const +{ + ARMNN_SCOPED_PROFILING_EVENT_NEON("NeonResizeWorkload_Execute"); + m_ResizeLayer.run(); +} + +} //namespace armnn diff --git a/src/backends/neon/workloads/NeonResizeWorkload.hpp b/src/backends/neon/workloads/NeonResizeWorkload.hpp new file mode 100644 index 0000000000..69995c6311 --- /dev/null +++ b/src/backends/neon/workloads/NeonResizeWorkload.hpp @@ -0,0 +1,29 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include + +#include + +namespace armnn +{ + +arm_compute::Status NeonResizeWorkloadValidate(const TensorInfo& input, + const TensorInfo& output, + const ResizeDescriptor& descriptor); + +class NeonResizeWorkload : public BaseWorkload +{ +public: + NeonResizeWorkload(const ResizeQueueDescriptor& descriptor, const WorkloadInfo& info); + void Execute() const override; + +private: + mutable arm_compute::NEScale m_ResizeLayer; +}; + +} //namespace armnn diff --git a/src/backends/neon/workloads/NeonWorkloads.hpp b/src/backends/neon/workloads/NeonWorkloads.hpp index a9604a160c..c5f4a54b77 100644 --- a/src/backends/neon/workloads/NeonWorkloads.hpp +++ b/src/backends/neon/workloads/NeonWorkloads.hpp @@ -30,7 +30,7 @@ #include "NeonPreluWorkload.hpp" #include "NeonQuantizeWorkload.hpp" #include "NeonReshapeWorkload.hpp" -#include "NeonResizeBilinearWorkload.hpp" +#include "NeonResizeWorkload.hpp" #include "NeonSoftmaxFloatWorkload.hpp" #include "NeonSoftmaxUint8Workload.hpp" #include "NeonSpaceToDepthWorkload.hpp" -- cgit v1.2.1