diff options
author | Francis Murtagh <francis.murtagh@arm.com> | 2018-10-05 14:08:48 +0100 |
---|---|---|
committer | Matthew Bentham <matthew.bentham@arm.com> | 2018-10-10 16:16:58 +0100 |
commit | 043d0d0e07e0a29648894cb9ba68993e540bb94d (patch) | |
tree | 8f757c83d11ba0472f6b636f8ce8fa5b2f3e620e /src/backends | |
parent | 7c22c70418192cf5803ae60dd2da041b0a6aafe5 (diff) | |
download | armnn-043d0d0e07e0a29648894cb9ba68993e540bb94d.tar.gz |
IVGCVSW-1860 Support NHWC for Pooling2D
Change-Id: I9059a292e47867df82a5efbba5808fd264949ec9
Diffstat (limited to 'src/backends')
-rw-r--r-- | src/backends/cl/workloads/ClPooling2dBaseWorkload.cpp | 8 | ||||
-rw-r--r-- | src/backends/neon/workloads/NeonPooling2dBaseWorkload.cpp | 8 | ||||
-rw-r--r-- | src/backends/test/ArmComputeCl.cpp | 1 | ||||
-rw-r--r-- | src/backends/test/ArmComputeNeon.cpp | 1 | ||||
-rw-r--r-- | src/backends/test/LayerTests.cpp | 5 | ||||
-rw-r--r-- | src/backends/test/LayerTests.hpp | 1 | ||||
-rw-r--r-- | src/backends/test/Pooling2dTestImpl.hpp | 135 |
7 files changed, 146 insertions, 13 deletions
diff --git a/src/backends/cl/workloads/ClPooling2dBaseWorkload.cpp b/src/backends/cl/workloads/ClPooling2dBaseWorkload.cpp index 98911856fe..e61ad4f28e 100644 --- a/src/backends/cl/workloads/ClPooling2dBaseWorkload.cpp +++ b/src/backends/cl/workloads/ClPooling2dBaseWorkload.cpp @@ -17,8 +17,8 @@ arm_compute::Status ClPooling2dWorkloadValidate(const TensorInfo& input, const TensorInfo& output, const Pooling2dDescriptor& descriptor) { - const arm_compute::TensorInfo aclInputInfo = BuildArmComputeTensorInfo(input); - const arm_compute::TensorInfo aclOutputInfo = BuildArmComputeTensorInfo(output); + const arm_compute::TensorInfo aclInputInfo = BuildArmComputeTensorInfo(input, descriptor.m_DataLayout); + const arm_compute::TensorInfo aclOutputInfo = BuildArmComputeTensorInfo(output, descriptor.m_DataLayout); arm_compute::PoolingLayerInfo layerInfo = BuildArmComputePoolingLayerInfo(descriptor); @@ -35,6 +35,10 @@ ClPooling2dBaseWorkload<dataTypes...>::ClPooling2dBaseWorkload( arm_compute::ICLTensor& input = static_cast<IClTensorHandle*>(m_Data.m_Inputs[0])->GetTensor(); arm_compute::ICLTensor& output = static_cast<IClTensorHandle*>(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::PoolingLayerInfo layerInfo = BuildArmComputePoolingLayerInfo(m_Data.m_Parameters); // Run the layer. diff --git a/src/backends/neon/workloads/NeonPooling2dBaseWorkload.cpp b/src/backends/neon/workloads/NeonPooling2dBaseWorkload.cpp index 109e856506..054f9c5f75 100644 --- a/src/backends/neon/workloads/NeonPooling2dBaseWorkload.cpp +++ b/src/backends/neon/workloads/NeonPooling2dBaseWorkload.cpp @@ -17,8 +17,8 @@ arm_compute::Status NeonPooling2dWorkloadValidate(const TensorInfo& input, const TensorInfo& output, const Pooling2dDescriptor& descriptor) { - const arm_compute::TensorInfo aclInputInfo = BuildArmComputeTensorInfo(input); - const arm_compute::TensorInfo aclOutputInfo = BuildArmComputeTensorInfo(output); + const arm_compute::TensorInfo aclInputInfo = BuildArmComputeTensorInfo(input, descriptor.m_DataLayout); + const arm_compute::TensorInfo aclOutputInfo = BuildArmComputeTensorInfo(output, descriptor.m_DataLayout); arm_compute::PoolingLayerInfo layerInfo = BuildArmComputePoolingLayerInfo(descriptor); @@ -35,6 +35,10 @@ NeonPooling2dBaseWorkload<dataTypes...>::NeonPooling2dBaseWorkload( arm_compute::ITensor& input = boost::polymorphic_downcast<INeonTensorHandle*>(m_Data.m_Inputs[0])->GetTensor(); arm_compute::ITensor& output = boost::polymorphic_downcast<INeonTensorHandle*>(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::PoolingLayerInfo layerInfo = BuildArmComputePoolingLayerInfo(m_Data.m_Parameters); m_PoolingLayer.configure(&input, &output, layerInfo); diff --git a/src/backends/test/ArmComputeCl.cpp b/src/backends/test/ArmComputeCl.cpp index faa3d4f37b..f4ead34c58 100644 --- a/src/backends/test/ArmComputeCl.cpp +++ b/src/backends/test/ArmComputeCl.cpp @@ -122,6 +122,7 @@ ARMNN_AUTO_TEST_CASE(IgnorePaddingL2Pooling2dSize3, IgnorePaddingL2Pooling2dSize ARMNN_AUTO_TEST_CASE(UNSUPPORTED_IgnorePaddingL2Pooling2dSize3Uint8, IgnorePaddingL2Pooling2dSize3Uint8Test) ARMNN_AUTO_TEST_CASE(SimpleAveragePooling2d, SimpleAveragePooling2dTest) +ARMNN_AUTO_TEST_CASE(SimpleAveragePooling2dNhwc, SimpleAveragePooling2dNhwcTest) ARMNN_AUTO_TEST_CASE(SimpleAveragePooling2dUint8, SimpleAveragePooling2dUint8Test) ARMNN_AUTO_TEST_CASE(IgnorePaddingAveragePooling2dSize3x2Stride2x2, IgnorePaddingAveragePooling2dSize3x2Stride2x2Test, diff --git a/src/backends/test/ArmComputeNeon.cpp b/src/backends/test/ArmComputeNeon.cpp index 7a60c31f73..045aa30889 100644 --- a/src/backends/test/ArmComputeNeon.cpp +++ b/src/backends/test/ArmComputeNeon.cpp @@ -232,6 +232,7 @@ BOOST_AUTO_TEST_CASE(DepthwiseConv2dUtils) ARMNN_AUTO_TEST_CASE(SimpleMaxPooling2dSize3x3Stride2x4, SimpleMaxPooling2dSize3x3Stride2x4Test, true) ARMNN_AUTO_TEST_CASE(SimpleMaxPooling2dSize3x3Stride2x4Uint8, SimpleMaxPooling2dSize3x3Stride2x4Uint8Test, true) ARMNN_AUTO_TEST_CASE(SimpleAveragePooling2d, SimpleAveragePooling2dTest) +ARMNN_AUTO_TEST_CASE(SimpleAveragePooling2dNhwc, SimpleAveragePooling2dNhwcTest) ARMNN_AUTO_TEST_CASE(SimpleAveragePooling2dUint8, SimpleAveragePooling2dUint8Test) ARMNN_AUTO_TEST_CASE(LargeTensorsAveragePooling2d, LargeTensorsAveragePooling2dTest) diff --git a/src/backends/test/LayerTests.cpp b/src/backends/test/LayerTests.cpp index a7fb6a824e..17f3ae12e1 100644 --- a/src/backends/test/LayerTests.cpp +++ b/src/backends/test/LayerTests.cpp @@ -4929,6 +4929,11 @@ LayerTestResult<float, 4> SimpleAveragePooling2dTest(armnn::IWorkloadFactory& wo return SimpleAveragePooling2dTestCommon<float>(workloadFactory); } +LayerTestResult<float, 4> SimpleAveragePooling2dNhwcTest(armnn::IWorkloadFactory& workloadFactory) +{ + return SimpleAveragePooling2dNhwcTestCommon<float>(workloadFactory); +} + LayerTestResult<uint8_t, 4> SimpleAveragePooling2dUint8Test(armnn::IWorkloadFactory& workloadFactory) { return SimpleAveragePooling2dTestCommon<uint8_t>(workloadFactory, 0.5, -1); diff --git a/src/backends/test/LayerTests.hpp b/src/backends/test/LayerTests.hpp index 71a468b36b..f5abd985c8 100644 --- a/src/backends/test/LayerTests.hpp +++ b/src/backends/test/LayerTests.hpp @@ -88,6 +88,7 @@ LayerTestResult<float, 4> IgnorePaddingMaxPooling2dSize3Test(armnn::IWorkloadF LayerTestResult<uint8_t, 4> IgnorePaddingMaxPooling2dSize3Uint8Test(armnn::IWorkloadFactory& workloadFactory); LayerTestResult<float, 4> SimpleAveragePooling2dTest(armnn::IWorkloadFactory& workloadFactory); +LayerTestResult<float, 4> SimpleAveragePooling2dNhwcTest(armnn::IWorkloadFactory& workloadFactory); LayerTestResult<uint8_t, 4> SimpleAveragePooling2dUint8Test(armnn::IWorkloadFactory& workloadFactory); LayerTestResult<float, 4> IgnorePaddingAveragePooling2dSize3x2Stride2x2Test(armnn::IWorkloadFactory& workloadFactory, bool forceNoPadding); diff --git a/src/backends/test/Pooling2dTestImpl.hpp b/src/backends/test/Pooling2dTestImpl.hpp index c87548cd5b..7366bcaf44 100644 --- a/src/backends/test/Pooling2dTestImpl.hpp +++ b/src/backends/test/Pooling2dTestImpl.hpp @@ -5,25 +5,23 @@ #pragma once #include <armnn/ArmNN.hpp> -#include <armnn/Tensor.hpp> -#include <armnn/TypesUtils.hpp> #include <test/TensorHelpers.hpp> #include "QuantizeHelper.hpp" #include <backends/CpuTensorHandle.hpp> #include <backends/WorkloadFactory.hpp> - +#include <backends/WorkloadInfo.hpp> #include <algorithm> template<typename T> LayerTestResult<T, 4> SimplePooling2dTestImpl( - armnn::IWorkloadFactory& workloadFactory, - armnn::Pooling2dDescriptor descriptor, - float qScale, - int32_t qOffset, - const boost::multi_array<T, 4>& input, - const boost::multi_array<T, 4>& outputExpected) + armnn::IWorkloadFactory& workloadFactory, + armnn::Pooling2dDescriptor descriptor, + float qScale, + int32_t qOffset, + const boost::multi_array<T, 4>& input, + const boost::multi_array<T, 4>& outputExpected) { unsigned int inputHeight = boost::numeric_cast<unsigned int>(input.shape()[2]); unsigned int inputWidth = boost::numeric_cast<unsigned int>(input.shape()[3]); @@ -88,6 +86,80 @@ LayerTestResult<T, 4> SimplePooling2dTestImpl( return result; } +template<typename T> +LayerTestResult<T, 4> SimplePooling2dNhwcTestImpl( + armnn::IWorkloadFactory& workloadFactory, + armnn::Pooling2dDescriptor descriptor, + float qScale, + int32_t qOffset, + const boost::multi_array<T, 4>& input, + const boost::multi_array<T, 4>& outputExpected) +{ + unsigned int inputHeight = boost::numeric_cast<unsigned int>(input.shape()[1]); + unsigned int inputWidth = boost::numeric_cast<unsigned int>(input.shape()[2]); + unsigned int inputChannels = boost::numeric_cast<unsigned int>(input.shape()[3]); + unsigned int inputBatchSize = boost::numeric_cast<unsigned int>(input.shape()[0]); + + unsigned int outputHeight = boost::numeric_cast<unsigned int>(outputExpected.shape()[1]); + unsigned int outputWidth = boost::numeric_cast<unsigned int>(outputExpected.shape()[2]); + unsigned int outputChannels = boost::numeric_cast<unsigned int>(outputExpected.shape()[3]); + unsigned int outputBatchSize = boost::numeric_cast<unsigned int>(outputExpected.shape()[0]); + + armnn::TensorInfo inputTensorInfo({ inputBatchSize, inputHeight, inputWidth, inputChannels }, + armnn::GetDataType<T>()); + armnn::TensorInfo outputTensorInfo({ outputBatchSize, outputHeight, outputWidth, outputChannels }, + armnn::GetDataType<T>()); + + // Set quantization parameters if the requested type is a quantized type. + if(armnn::IsQuantizedType<T>()) + { + inputTensorInfo.SetQuantizationScale(qScale); + inputTensorInfo.SetQuantizationOffset(qOffset); + outputTensorInfo.SetQuantizationScale(qScale); + outputTensorInfo.SetQuantizationOffset(qOffset); + } + + LayerTestResult<T, 4> result(outputTensorInfo); + + std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo); + std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo); + + armnn::Pooling2dQueueDescriptor queueDescriptor; + queueDescriptor.m_Parameters = descriptor; + queueDescriptor.m_Parameters.m_DataLayout = armnn::DataLayout::NHWC; + + armnn::WorkloadInfo workloadInfo; + AddInputToWorkload(queueDescriptor, workloadInfo, inputTensorInfo, inputHandle.get()); + AddOutputToWorkload(queueDescriptor, workloadInfo, outputTensorInfo, outputHandle.get()); + + // Don't execute if Pooling is not supported, as an exception will be raised. + armnn::Compute compute = workloadFactory.GetCompute(); + const size_t reasonIfUnsupportedMaxLen = 255; + char reasonIfUnsupported[reasonIfUnsupportedMaxLen+1]; + result.supported = armnn::IsPooling2dSupported(compute, inputTensorInfo, outputTensorInfo, + queueDescriptor.m_Parameters, + reasonIfUnsupported, reasonIfUnsupportedMaxLen); + if (!result.supported) + { + return result; + } + + std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreatePooling2d(queueDescriptor, workloadInfo); + + inputHandle->Allocate(); + outputHandle->Allocate(); + + CopyDataToITensorHandle(inputHandle.get(), &input[0][0][0][0]); + + workload->Execute(); + + CopyDataFromITensorHandle(&result.output[0][0][0][0], outputHandle.get()); + + result.outputExpected = outputExpected; + + return result; +} + // // Tests max pooling with the following parameters: // @@ -263,6 +335,51 @@ LayerTestResult<T, 4> SimpleAveragePooling2dTestCommon(armnn::IWorkloadFactory& } template<typename T> +LayerTestResult<T, 4> SimpleAveragePooling2dNhwcTestCommon(armnn::IWorkloadFactory& workloadFactory, + float qScale = 1.0f, + int32_t qOffset = 0) +{ + armnn::Pooling2dDescriptor descriptor; + descriptor.m_PoolType = armnn::PoolingAlgorithm::Average; + descriptor.m_PoolWidth = descriptor.m_PoolHeight = 2; + descriptor.m_StrideX = descriptor.m_StrideY = 2; + descriptor.m_PadLeft = 1; + descriptor.m_PadRight = 1; + descriptor.m_PadTop = 1; + descriptor.m_PadBottom = 1; + descriptor.m_PaddingMethod = armnn::PaddingMethod::Exclude; + + armnn::TensorInfo inputTensorInfo({ 1, 4, 4, 1 }, armnn::GetDataType<T>()); + armnn::TensorInfo outputTensorInfo({ 1, 3, 3, 1 }, armnn::GetDataType<T>()); + + // Set quantization parameters if the requested type is a quantized type. + if(armnn::IsQuantizedType<T>()) + { + inputTensorInfo.SetQuantizationScale(qScale); + inputTensorInfo.SetQuantizationOffset(qOffset); + outputTensorInfo.SetQuantizationScale(qScale); + outputTensorInfo.SetQuantizationOffset(qOffset); + } + + auto input = MakeTensor<T, 4>(inputTensorInfo, + QuantizedVector<T>(qScale, qOffset, { + 1.0f, 2.0f, 3.0f, 4.0f, + 1.0f, 2.0f, 3.0f, 4.0f, + 1.0f, 2.0f, 3.0f, 4.0f, + 1.0f, 2.0f, 3.0f, 4.0f, + })); + + auto outputExpected = MakeTensor<T, 4>(outputTensorInfo, + QuantizedVector<T>(qScale, qOffset, { + 1.0f, 2.5f, 4.0f, + 1.0f, 2.5f, 4.0f, + 1.0f, 2.5f, 4.0f, + })); + + return SimplePooling2dNhwcTestImpl<T>(workloadFactory, descriptor, qScale, qOffset, input, outputExpected); +} + +template<typename T> LayerTestResult<T, 4> LargeTensorsAveragePooling2dTestCommon(armnn::IWorkloadFactory& workloadFactory, float qScale = 1.0f, int32_t qOffset = 0) |