From 595408218a0e17f04d91ff131a8227a4f352ff61 Mon Sep 17 00:00:00 2001 From: James Conroy Date: Thu, 11 Oct 2018 12:39:05 +0100 Subject: IVGCVSW-1978: Support NHWC for ResizeBilinear CpuRef * Adds implementation to plumb DataLayout parameter for ResizeBilinear on CpuRef. * Adds unit tests to execute ResizeBilinear on CpuRef using the NHWC data layout. * Adds DataLayoutIndexed API, allowing easy access to the Channels, Height and Width of a tensor based on its data layout. This reduces code duplication. * Refactors original ResizeBilinear implementation and tests to use the DataLayoutIndexed API when required. Change-Id: Ic2b8916cdd2e370d070175547079d774daf6d7bf --- src/backends/WorkloadData.cpp | 9 +++--- .../cl/workloads/ClResizeBilinearFloatWorkload.cpp | 2 +- .../reference/test/RefCreateWorkloadTests.cpp | 33 +++++++++++++++++----- src/backends/reference/test/RefLayerTests.cpp | 9 +++++- .../workloads/RefResizeBilinearFloat32Workload.cpp | 3 +- .../reference/workloads/ResizeBilinear.cpp | 20 +++++++------ .../reference/workloads/ResizeBilinear.hpp | 6 +++- .../reference/workloads/TensorBufferArrayView.hpp | 21 ++++++++------ 8 files changed, 71 insertions(+), 32 deletions(-) (limited to 'src/backends') diff --git a/src/backends/WorkloadData.cpp b/src/backends/WorkloadData.cpp index a6a87f3782..d562b73053 100644 --- a/src/backends/WorkloadData.cpp +++ b/src/backends/WorkloadData.cpp @@ -663,11 +663,10 @@ void ResizeBilinearQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) c } { - // DataLayout is NCHW by default (channelsIndex = 1) - const unsigned int channelsIndex = this->m_Parameters.m_DataLayout == armnn::DataLayout::NHWC ? 3 : 1; - - const unsigned int inputChannelCount = workloadInfo.m_InputTensorInfos[0].GetShape()[channelsIndex]; - const unsigned int outputChannelCount = workloadInfo.m_OutputTensorInfos[0].GetShape()[channelsIndex]; + const unsigned int inputChannelCount = + workloadInfo.m_InputTensorInfos[0].GetShape()[this->m_Parameters.m_DataLayout.GetChannelsIndex()]; + const unsigned int outputChannelCount = + workloadInfo.m_OutputTensorInfos[0].GetShape()[this->m_Parameters.m_DataLayout.GetChannelsIndex()]; if (inputChannelCount != outputChannelCount) { throw InvalidArgumentException( diff --git a/src/backends/cl/workloads/ClResizeBilinearFloatWorkload.cpp b/src/backends/cl/workloads/ClResizeBilinearFloatWorkload.cpp index ced3a06b04..4ee6d5e7a5 100644 --- a/src/backends/cl/workloads/ClResizeBilinearFloatWorkload.cpp +++ b/src/backends/cl/workloads/ClResizeBilinearFloatWorkload.cpp @@ -26,7 +26,7 @@ ClResizeBilinearFloatWorkload::ClResizeBilinearFloatWorkload(const ResizeBilinea arm_compute::ICLTensor& input = static_cast(m_Data.m_Inputs[0])->GetTensor(); arm_compute::ICLTensor& output = static_cast(m_Data.m_Outputs[0])->GetTensor(); - arm_compute::DataLayout aclDataLayout = ConvertDataLayout(m_Data.m_Parameters.m_DataLayout); + arm_compute::DataLayout aclDataLayout = ConvertDataLayout(m_Data.m_Parameters.m_DataLayout.GetDataLayout()); input.info()->set_data_layout(aclDataLayout); output.info()->set_data_layout(aclDataLayout); diff --git a/src/backends/reference/test/RefCreateWorkloadTests.cpp b/src/backends/reference/test/RefCreateWorkloadTests.cpp index e88fbed014..e8d536f6e8 100644 --- a/src/backends/reference/test/RefCreateWorkloadTests.cpp +++ b/src/backends/reference/test/RefCreateWorkloadTests.cpp @@ -420,27 +420,46 @@ BOOST_AUTO_TEST_CASE(CreateSingleOutputMultipleInputsUint8) } template -static void RefCreateResizeBilinearTest() +static void RefCreateResizeBilinearTest(DataLayout dataLayout) { Graph graph; RefWorkloadFactory factory; - auto workload = CreateResizeBilinearWorkloadTest(factory, graph); + auto workload = CreateResizeBilinearWorkloadTest(factory, graph, dataLayout); + + TensorShape inputShape; + TensorShape outputShape; + + switch (dataLayout) + { + case DataLayout::NHWC: + inputShape = { 2, 4, 4, 3 }; + outputShape = { 2, 2, 2, 3 }; + break; + default: // NCHW + inputShape = { 2, 3, 4, 4 }; + outputShape = { 2, 3, 2, 2 }; + } // Checks that outputs and inputs are as we expect them (see definition of CreateResizeBilinearWorkloadTest). CheckInputOutput( - std::move(workload), - TensorInfo({ 2, 3, 4, 4 }, DataType), - TensorInfo({ 2, 3, 2, 2 }, DataType)); + std::move(workload), + TensorInfo(inputShape, DataType), + TensorInfo(outputShape, DataType)); } BOOST_AUTO_TEST_CASE(CreateResizeBilinearFloat32) { - RefCreateResizeBilinearTest(); + RefCreateResizeBilinearTest(DataLayout::NCHW); } BOOST_AUTO_TEST_CASE(CreateResizeBilinearUint8) { - RefCreateResizeBilinearTest(); + RefCreateResizeBilinearTest(DataLayout::NCHW); +} + +BOOST_AUTO_TEST_CASE(CreateResizeBilinearFloat32Nhwc) +{ + RefCreateResizeBilinearTest(DataLayout::NHWC); } BOOST_AUTO_TEST_CASE(CreateL2NormalizationFloat32) diff --git a/src/backends/reference/test/RefLayerTests.cpp b/src/backends/reference/test/RefLayerTests.cpp index de2c2fe332..48bffa94ef 100644 --- a/src/backends/reference/test/RefLayerTests.cpp +++ b/src/backends/reference/test/RefLayerTests.cpp @@ -178,7 +178,7 @@ ARMNN_AUTO_TEST_CASE(MultiplicationBroadcast1DVectorUint8, MultiplicationBroadca ARMNN_AUTO_TEST_CASE(BatchNorm, BatchNormTest) ARMNN_AUTO_TEST_CASE(BatchNormUint8, BatchNormUint8Test) -// Resize Bilinear +// Resize Bilinear - NCHW ARMNN_AUTO_TEST_CASE(SimpleResizeBilinear, SimpleResizeBilinearTest) ARMNN_AUTO_TEST_CASE(SimpleResizeBilinearUint8, SimpleResizeBilinearUint8Test) ARMNN_AUTO_TEST_CASE(ResizeBilinearNop, ResizeBilinearNopTest) @@ -190,6 +190,13 @@ ARMNN_AUTO_TEST_CASE(ResizeBilinearMinUint8, ResizeBilinearMinUint8Test) ARMNN_AUTO_TEST_CASE(ResizeBilinearMag, ResizeBilinearMagTest) ARMNN_AUTO_TEST_CASE(ResizeBilinearMagUint8, ResizeBilinearMagUint8Test) +// Resize Bilinear - NHWC +ARMNN_AUTO_TEST_CASE(ResizeBilinearNopNhwc, ResizeBilinearNopNhwcTest) +ARMNN_AUTO_TEST_CASE(SimpleResizeBilinearNhwc, SimpleResizeBilinearNhwcTest) +ARMNN_AUTO_TEST_CASE(ResizeBilinearSqMinNhwc, ResizeBilinearSqMinNhwcTest) +ARMNN_AUTO_TEST_CASE(ResizeBilinearMinNhwc, ResizeBilinearMinNhwcTest) +ARMNN_AUTO_TEST_CASE(ResizeBilinearMagNhwc, ResizeBilinearMagNhwcTest) + // Fake Quantization ARMNN_AUTO_TEST_CASE(FakeQuantization, FakeQuantizationTest) diff --git a/src/backends/reference/workloads/RefResizeBilinearFloat32Workload.cpp b/src/backends/reference/workloads/RefResizeBilinearFloat32Workload.cpp index 50ee7a218a..8d86bdcf34 100644 --- a/src/backends/reference/workloads/RefResizeBilinearFloat32Workload.cpp +++ b/src/backends/reference/workloads/RefResizeBilinearFloat32Workload.cpp @@ -23,7 +23,8 @@ void RefResizeBilinearFloat32Workload::Execute() const ResizeBilinear(GetInputTensorDataFloat(0, m_Data), inputInfo, GetOutputTensorDataFloat(0, m_Data), - outputInfo); + outputInfo, + m_Data.m_Parameters.m_DataLayout); } } //namespace armnn diff --git a/src/backends/reference/workloads/ResizeBilinear.cpp b/src/backends/reference/workloads/ResizeBilinear.cpp index 0bce3c7ed8..e098c6c20d 100644 --- a/src/backends/reference/workloads/ResizeBilinear.cpp +++ b/src/backends/reference/workloads/ResizeBilinear.cpp @@ -25,27 +25,31 @@ inline float Lerp(float a, float b, float w) } -void ResizeBilinear(const float* in, const TensorInfo& inputInfo, float* out, const TensorInfo& outputInfo) +void ResizeBilinear(const float* in, + const TensorInfo& inputInfo, + float* out, + const TensorInfo& outputInfo, + DataLayoutIndexed dataLayout) { // We follow the definition of TensorFlow and AndroidNN: the top-left corner of a texel in the output // image is projected into the input image to figure out the interpolants and weights. Note that this // will yield different results than if projecting the centre of output texels. const unsigned int batchSize = inputInfo.GetShape()[0]; - const unsigned int channelCount = inputInfo.GetShape()[1]; + const unsigned int channelCount = inputInfo.GetShape()[dataLayout.GetChannelsIndex()]; - const unsigned int inputHeight = inputInfo.GetShape()[2]; - const unsigned int inputWidth = inputInfo.GetShape()[3]; - const unsigned int outputHeight = outputInfo.GetShape()[2]; - const unsigned int outputWidth = outputInfo.GetShape()[3]; + const unsigned int inputHeight = inputInfo.GetShape()[dataLayout.GetHeightIndex()]; + const unsigned int inputWidth = inputInfo.GetShape()[dataLayout.GetWidthIndex()]; + const unsigned int outputHeight = outputInfo.GetShape()[dataLayout.GetHeightIndex()]; + const unsigned int outputWidth = outputInfo.GetShape()[dataLayout.GetWidthIndex()]; // How much to scale pixel coordinates in the output image, to get the corresponding pixel coordinates // in the input image. const float scaleY = boost::numeric_cast(inputHeight) / boost::numeric_cast(outputHeight); const float scaleX = boost::numeric_cast(inputWidth) / boost::numeric_cast(outputWidth); - TensorBufferArrayView input(inputInfo.GetShape(), in); - TensorBufferArrayView output(outputInfo.GetShape(), out); + TensorBufferArrayView input(inputInfo.GetShape(), in, dataLayout); + TensorBufferArrayView output(outputInfo.GetShape(), out, dataLayout); for (unsigned int n = 0; n < batchSize; ++n) { diff --git a/src/backends/reference/workloads/ResizeBilinear.hpp b/src/backends/reference/workloads/ResizeBilinear.hpp index 847b8e8bef..92b229d3bb 100644 --- a/src/backends/reference/workloads/ResizeBilinear.hpp +++ b/src/backends/reference/workloads/ResizeBilinear.hpp @@ -10,6 +10,10 @@ namespace armnn { -void ResizeBilinear(const float* in, const TensorInfo& inputInfo, float* out, const TensorInfo& outputInfo); +void ResizeBilinear(const float* in, + const TensorInfo& inputInfo, + float* out, + const TensorInfo& outputInfo, + DataLayoutIndexed dataLayout = DataLayout::NCHW); } //namespace armnn diff --git a/src/backends/reference/workloads/TensorBufferArrayView.hpp b/src/backends/reference/workloads/TensorBufferArrayView.hpp index e19810ca87..aba44e4593 100644 --- a/src/backends/reference/workloads/TensorBufferArrayView.hpp +++ b/src/backends/reference/workloads/TensorBufferArrayView.hpp @@ -15,28 +15,33 @@ template class TensorBufferArrayView { public: - TensorBufferArrayView(const TensorShape& shape, DataType* data) + TensorBufferArrayView(const TensorShape& shape, DataType* data, DataLayoutIndexed dataLayout = DataLayout::NCHW) : m_Shape(shape) , m_Data(data) + , m_DataLayout(dataLayout) { } DataType& Get(unsigned int b, unsigned int c, unsigned int h, unsigned int w) const { - BOOST_ASSERT( b < m_Shape[0] || (m_Shape[0] == 0 && b == 0) ); - BOOST_ASSERT( c < m_Shape[1] || (m_Shape[1] == 0 && c == 0) ); - BOOST_ASSERT( h < m_Shape[2] || (m_Shape[2] == 0 && h == 0) ); - BOOST_ASSERT( w < m_Shape[3] || (m_Shape[3] == 0 && w == 0) ); + BOOST_ASSERT( b < m_Shape[0] || ( m_Shape[0] == 0 && b == 0 ) ); + BOOST_ASSERT( c < m_Shape[m_DataLayout.GetChannelsIndex()] || + ( m_Shape[m_DataLayout.GetChannelsIndex()] == 0 && c == 0) ); + BOOST_ASSERT( h < m_Shape[m_DataLayout.GetHeightIndex()] || + ( m_Shape[m_DataLayout.GetHeightIndex()] == 0 && h == 0) ); + BOOST_ASSERT( w < m_Shape[m_DataLayout.GetWidthIndex()] || + ( m_Shape[m_DataLayout.GetWidthIndex()] == 0 && w == 0) ); return m_Data[b * m_Shape[1] * m_Shape[2] * m_Shape[3] - + c * m_Shape[2] * m_Shape[3] - + h * m_Shape[3] + + c * m_Shape[m_DataLayout.GetHeightIndex()] * m_Shape[m_DataLayout.GetWidthIndex()] + + h * m_Shape[m_DataLayout.GetWidthIndex()] + w]; } private: const TensorShape m_Shape; - DataType* m_Data; + DataType* m_Data; + DataLayoutIndexed m_DataLayout; }; } //namespace armnn -- cgit v1.2.1