From 0a088a61d016bf7af77e2d73d0988223a5f98ef1 Mon Sep 17 00:00:00 2001 From: jimfly01 Date: Thu, 25 Oct 2018 17:05:05 +0100 Subject: IVGCVSW-2074: SimpleConvolution2dTestImpl updated for NHWC * Added a defaulted DataLayoutIndexed argument to the SimpleConvolution2dTestImpl * Permute test data tensors just before use if necessary * Add DataLayout to descriptor * Added a DataLayoutIndexed argument to SimpleConvolution2d3x5TestCommon * Added NHWC versions of the SimpleConvolution2d3x5Test for Neon and CL Change-Id: I10e3ece42a50108baeabe4d8b0f0ac3e6d532261 --- src/backends/cl/test/ClLayerTests.cpp | 8 ++- src/backends/neon/test/NeonLayerTests.cpp | 7 +- src/backends/reference/test/RefLayerTests.cpp | 8 +-- src/backends/test/Conv2dTestImpl.hpp | 94 ++++++++++++++++++++------- src/backends/test/LayerTests.cpp | 18 +++-- src/backends/test/LayerTests.hpp | 6 +- 6 files changed, 102 insertions(+), 39 deletions(-) diff --git a/src/backends/cl/test/ClLayerTests.cpp b/src/backends/cl/test/ClLayerTests.cpp index 937c58c689..4946515c36 100755 --- a/src/backends/cl/test/ClLayerTests.cpp +++ b/src/backends/cl/test/ClLayerTests.cpp @@ -54,10 +54,12 @@ ARMNN_AUTO_TEST_CASE(FullyConnectedLargeTransposed, FullyConnectedLargeTest, tru // Convolution ARMNN_AUTO_TEST_CASE(SimpleConvolution1d, Convolution1dTest, true) -ARMNN_AUTO_TEST_CASE(SimpleConvolution2d, SimpleConvolution2d3x5Test, true) -ARMNN_AUTO_TEST_CASE(SimpleConvolution2dSquare, SimpleConvolution2d3x3Test, true) +ARMNN_AUTO_TEST_CASE(SimpleConvolution2d, SimpleConvolution2d3x5Test, true, armnn::DataLayout::NCHW) +ARMNN_AUTO_TEST_CASE(SimpleConvolution2dNhwc, SimpleConvolution2d3x5Test, true, armnn::DataLayout::NHWC) ARMNN_AUTO_TEST_CASE(SimpleConvolution2d3x3Uint8, SimpleConvolution2d3x3Uint8Test, true) -ARMNN_AUTO_TEST_CASE(UnbiasedConvolution2d, SimpleConvolution2d3x5Test, false) +ARMNN_AUTO_TEST_CASE(UnbiasedConvolution2d, SimpleConvolution2d3x5Test, false, armnn::DataLayout::NCHW) +ARMNN_AUTO_TEST_CASE(UnbiasedConvolution2dNhwc, SimpleConvolution2d3x5Test, false, armnn::DataLayout::NHWC) + ARMNN_AUTO_TEST_CASE(UnbiasedConvolution2dSquare, SimpleConvolution2d3x3Test, false) ARMNN_AUTO_TEST_CASE(SimpleConvolution2dAsymmetricPadding, Convolution2dAsymmetricPaddingTest) diff --git a/src/backends/neon/test/NeonLayerTests.cpp b/src/backends/neon/test/NeonLayerTests.cpp index 568a2367c6..ffd0d292df 100644 --- a/src/backends/neon/test/NeonLayerTests.cpp +++ b/src/backends/neon/test/NeonLayerTests.cpp @@ -26,9 +26,12 @@ using FactoryType = armnn::NeonWorkloadFactory; // Convolution ARMNN_AUTO_TEST_CASE(SimpleConvolution1d, Convolution1dTest, true) -ARMNN_AUTO_TEST_CASE(SimpleConvolution2d, SimpleConvolution2d3x5Test, true) +ARMNN_AUTO_TEST_CASE(SimpleConvolution2d, SimpleConvolution2d3x5Test, true, armnn::DataLayout::NCHW) +ARMNN_AUTO_TEST_CASE(SimpleConvolution2dNhwc, SimpleConvolution2d3x5Test, true, armnn::DataLayout::NHWC) ARMNN_AUTO_TEST_CASE(SimpleConvolution2dSquare, SimpleConvolution2d3x3Test, true) -ARMNN_AUTO_TEST_CASE(UnbiasedConvolution2d, SimpleConvolution2d3x5Test, false) +ARMNN_AUTO_TEST_CASE(UnbiasedConvolution2d, SimpleConvolution2d3x5Test, false, armnn::DataLayout::NCHW) +ARMNN_AUTO_TEST_CASE(UnbiasedConvolution2dNhwc, SimpleConvolution2d3x5Test, false, armnn::DataLayout::NHWC) + ARMNN_AUTO_TEST_CASE(UnbiasedConvolution2dSquare, SimpleConvolution2d3x3Test, false) ARMNN_AUTO_TEST_CASE(SimpleConvolution2dAsymmetricPadding, Convolution2dAsymmetricPaddingTest) diff --git a/src/backends/reference/test/RefLayerTests.cpp b/src/backends/reference/test/RefLayerTests.cpp index 38ce94d257..45239be8c1 100644 --- a/src/backends/reference/test/RefLayerTests.cpp +++ b/src/backends/reference/test/RefLayerTests.cpp @@ -18,11 +18,11 @@ using FactoryType = armnn::RefWorkloadFactory; // UNIT tests // Convolution -ARMNN_AUTO_TEST_CASE(SimpleConvolution2d3x5, SimpleConvolution2d3x5Test, true) -ARMNN_AUTO_TEST_CASE(SimpleConvolution2d3x5Uint8, SimpleConvolution2d3x5Uint8Test, true) +ARMNN_AUTO_TEST_CASE(SimpleConvolution2d3x5, SimpleConvolution2d3x5Test, true, armnn::DataLayout::NCHW) +ARMNN_AUTO_TEST_CASE(SimpleConvolution2d3x5Uint8, SimpleConvolution2d3x5Uint8Test, true, armnn::DataLayout::NCHW) -ARMNN_AUTO_TEST_CASE(UnbiasedConvolution2d, SimpleConvolution2d3x5Test, false) -ARMNN_AUTO_TEST_CASE(UnbiasedConvolutionUint8, SimpleConvolution2d3x5Uint8Test, false) +ARMNN_AUTO_TEST_CASE(UnbiasedConvolution2d, SimpleConvolution2d3x5Test, false, armnn::DataLayout::NCHW) +ARMNN_AUTO_TEST_CASE(UnbiasedConvolutionUint8, SimpleConvolution2d3x5Uint8Test, false, armnn::DataLayout::NCHW) ARMNN_AUTO_TEST_CASE(SimpleConvolution1d, Convolution1dTest, true) ARMNN_AUTO_TEST_CASE(SimpleConvolution1dUint8, Convolution1dUint8Test, true) diff --git a/src/backends/test/Conv2dTestImpl.hpp b/src/backends/test/Conv2dTestImpl.hpp index d8c104007c..41a0d1b095 100755 --- a/src/backends/test/Conv2dTestImpl.hpp +++ b/src/backends/test/Conv2dTestImpl.hpp @@ -4,6 +4,7 @@ // #pragma once +#include #include #include #include @@ -13,6 +14,8 @@ #include #include +#include "Permute.hpp" +#include // Mapping from input type to bias type for fully connected layers. // float => float, uint8_t => int32_t @@ -59,33 +62,55 @@ void ApplyBias(std::vector& v, float vScale, int32_t vOffset, } } +template +armnn::TensorInfo GetTensorInfo(unsigned int numberOfBatches, + unsigned int numberOfChannels, + unsigned int height, + unsigned int width, + const armnn::DataLayoutIndexed& layout) +{ + switch (layout.GetDataLayout()) + { + case armnn::DataLayout::NCHW: + return armnn::TensorInfo({numberOfBatches, numberOfChannels, height, width}, armnn::GetDataType()); + case armnn::DataLayout ::NHWC: + return armnn::TensorInfo({numberOfBatches, height, width, numberOfChannels}, armnn::GetDataType()); + default: + throw armnn::InvalidArgumentException("unknown data layout [" + + std::to_string(static_cast(layout.GetDataLayout())) + "]"); + } +} + + + template LayerTestResult SimpleConvolution2dTestImpl(armnn::IWorkloadFactory& workloadFactory, - const boost::multi_array& input, - const boost::multi_array& kernel, + const boost::multi_array& originalInput, + const boost::multi_array& originalKernel, const boost::multi_array& bias, - const boost::multi_array& outputExpected, + const boost::multi_array& originalOutputExpected, float qScale, int32_t qOffset, + const armnn::DataLayoutIndexed& layout = armnn::DataLayout::NCHW, uint32_t padLeft = 0, uint32_t padTop = 0, uint32_t padRight = 0, uint32_t padBottom = 0) { - unsigned int inputHeight = boost::numeric_cast(input.shape()[2]); - unsigned int inputWidth = boost::numeric_cast(input.shape()[3]); - unsigned int inputChannels = boost::numeric_cast(input.shape()[1]); - unsigned int inputNum = boost::numeric_cast(input.shape()[0]); + unsigned int inputHeight = boost::numeric_cast(originalInput.shape()[2]); + unsigned int inputWidth = boost::numeric_cast(originalInput.shape()[3]); + unsigned int inputChannels = boost::numeric_cast(originalInput.shape()[1]); + unsigned int inputNum = boost::numeric_cast(originalInput.shape()[0]); - unsigned int outputHeight = boost::numeric_cast(outputExpected.shape()[2]); - unsigned int outputWidth = boost::numeric_cast(outputExpected.shape()[3]); - unsigned int outputChannels = boost::numeric_cast(outputExpected.shape()[1]); - unsigned int outputNum = boost::numeric_cast(outputExpected.shape()[0]); + unsigned int outputHeight = boost::numeric_cast(originalOutputExpected.shape()[2]); + unsigned int outputWidth = boost::numeric_cast(originalOutputExpected.shape()[3]); + unsigned int outputChannels = boost::numeric_cast(originalOutputExpected.shape()[1]); + unsigned int outputNum = boost::numeric_cast(originalOutputExpected.shape()[0]); - unsigned int kernelHeight = boost::numeric_cast(kernel.shape()[2]); - unsigned int kernelWidth = boost::numeric_cast(kernel.shape()[3]); - unsigned int kernelChannels = boost::numeric_cast(kernel.shape()[1]); - unsigned int kernelDepthMul = boost::numeric_cast(kernel.shape()[0]); + unsigned int kernelHeight = boost::numeric_cast(originalKernel.shape()[2]); + unsigned int kernelWidth = boost::numeric_cast(originalKernel.shape()[3]); + unsigned int kernelChannels = boost::numeric_cast(originalKernel.shape()[1]); + unsigned int kernelDepthMul = boost::numeric_cast(originalKernel.shape()[0]); bool biasEnabled = bias.size() > 0; @@ -98,10 +123,11 @@ LayerTestResult SimpleConvolution2dTestImpl(armnn::IWorkloadFactory& workl // Note these tensors will use two (identical) batches. - armnn::TensorInfo inputTensorInfo({2*inputNum, inputChannels, inputHeight, inputWidth}, armnn::GetDataType()); - armnn::TensorInfo outputTensorInfo({2*outputNum, outputChannels, outputHeight, outputWidth}, - armnn::GetDataType()); - armnn::TensorInfo kernelDesc({kernelDepthMul, kernelChannels, kernelHeight, kernelWidth}, armnn::GetDataType()); + // NOTE: if layout is unknown we will get an exception at this point. + armnn::TensorInfo inputTensorInfo = GetTensorInfo(2*inputNum, inputChannels, inputHeight, inputWidth, layout); + armnn::TensorInfo outputTensorInfo = GetTensorInfo( + 2*outputNum, outputChannels, outputHeight, outputWidth, layout); + armnn::TensorInfo kernelDesc = GetTensorInfo(kernelDepthMul, kernelChannels, kernelHeight, kernelWidth, layout); armnn::TensorInfo biasDesc({static_cast(bias.size())}, armnn::GetDataType()); // Set quantization parameters if the requested type is a quantized type. @@ -121,14 +147,25 @@ LayerTestResult SimpleConvolution2dTestImpl(armnn::IWorkloadFactory& workl // Construct input data - two batches of the same input image. std::vector inputImage; - inputImage.assign(input.data(), input.data() + 1*inputChannels*inputHeight*inputWidth); + inputImage.assign(originalInput.data(), originalInput.data() + 1*inputChannels*inputHeight*inputWidth); std::vector inputData; inputData.insert(inputData.end(), inputImage.begin(), inputImage.end()); inputData.insert(inputData.end(), inputImage.begin(), inputImage.end()); + + // at this point if we require it permute the input data + const armnn::PermutationVector NCHWToNHWC = { 0, 3, 1, 2 }; + if (layout.GetDataLayout() == armnn::DataLayout::NHWC) + { + std::vector tmp(inputData.size()); + armnnUtils::Permute(inputTensorInfo.GetShape(), NCHWToNHWC, inputData.data(), tmp.data()); + inputData = tmp; + } + auto batchedInput = MakeTensor(inputTensorInfo, inputData); std::vector outputImage; - outputImage.assign(outputExpected.data(), outputExpected.data() + outputChannels*outputHeight*outputWidth); + outputImage.assign(originalOutputExpected.data(), + originalOutputExpected.data() + outputChannels*outputHeight*outputWidth); // Apply bias to output image if it is enabled. if(biasEnabled) @@ -145,6 +182,13 @@ LayerTestResult SimpleConvolution2dTestImpl(armnn::IWorkloadFactory& workl outputData.insert(outputData.end(), outputImage.begin(), outputImage.end()); outputData.insert(outputData.end(), outputImage.begin(), outputImage.end()); + // at this point if we require it permute the expected output + if (layout.GetDataLayout() == armnn::DataLayout::NHWC) + { + std::vector tmp(outputData.size()); + armnnUtils::Permute(outputTensorInfo.GetShape(), NCHWToNHWC, outputData.data(), tmp.data()); + outputData = tmp; + } ret.outputExpected = MakeTensor(outputTensorInfo, outputData); // Todo: nontrivial padding and strides. @@ -158,7 +202,12 @@ LayerTestResult SimpleConvolution2dTestImpl(armnn::IWorkloadFactory& workl armnn::WorkloadInfo info; armnn::ScopedCpuTensorHandle weightsTensor(kernelDesc); armnn::ScopedCpuTensorHandle biasTensor(biasDesc); - + // Permute the kernel if necessary + boost::multi_array kernel = boost::multi_array(originalKernel); + if (layout.GetDataLayout() == armnn::DataLayout::NHWC) + { + armnnUtils::Permute(kernelDesc.GetShape(), NCHWToNHWC, originalKernel.data(), kernel.data()); + } AllocateAndCopyDataToITensorHandle(&weightsTensor, &kernel[0][0][0][0]); if(biasEnabled) @@ -178,6 +227,7 @@ LayerTestResult SimpleConvolution2dTestImpl(armnn::IWorkloadFactory& workl data.m_Parameters.m_PadTop = padTop; data.m_Parameters.m_PadBottom = padBottom; data.m_Parameters.m_BiasEnabled = biasEnabled; + data.m_Parameters.m_DataLayout = layout.GetDataLayout(); std::unique_ptr workload = workloadFactory.CreateConvolution2d(data, info); inputHandle->Allocate(); diff --git a/src/backends/test/LayerTests.cpp b/src/backends/test/LayerTests.cpp index e5a4258043..e536cc9798 100755 --- a/src/backends/test/LayerTests.cpp +++ b/src/backends/test/LayerTests.cpp @@ -85,7 +85,8 @@ template LayerTestResult SimpleConvolution2d3x5TestCommon(armnn::IWorkloadFactory& workloadFactory, float qScale, int32_t qOffset, - bool biasEnabled) + bool biasEnabled, + const armnn::DataLayoutIndexed& layout) { // Use common single-batch 3-channel 16x8 image. armnn::TensorInfo inputDesc({1, 3, 8, 16}, armnn::GetDataType()); @@ -156,7 +157,8 @@ LayerTestResult SimpleConvolution2d3x5TestCommon(armnn::IWorkloadFactory& GetBias2::Type>(biasEnabled, qScale, qOffset), expectedOutput, qScale, - qOffset); + qOffset, + layout); } template @@ -278,15 +280,17 @@ LayerTestResult SimpleConvolution2d3x3NhwcTestCommon(armnn::IWorkloadFacto } LayerTestResult SimpleConvolution2d3x5Test(armnn::IWorkloadFactory& workloadFactory, - bool biasEnabled) + bool biasEnabled, + const armnn::DataLayoutIndexed& layout) { - return SimpleConvolution2d3x5TestCommon(workloadFactory, 0.f, 0, biasEnabled); + return SimpleConvolution2d3x5TestCommon(workloadFactory, 0.f, 0, biasEnabled, layout); } LayerTestResult SimpleConvolution2d3x5Uint8Test(armnn::IWorkloadFactory& workloadFactory, - bool biasEnabled) + bool biasEnabled, + const armnn::DataLayoutIndexed& layout) { - return SimpleConvolution2d3x5TestCommon(workloadFactory, 0.5f, 50, biasEnabled); + return SimpleConvolution2d3x5TestCommon(workloadFactory, 0.5f, 50, biasEnabled, layout); } LayerTestResult SimpleConvolution2d3x3Test(armnn::IWorkloadFactory& workloadFactory, @@ -359,6 +363,7 @@ LayerTestResult Convolution2dAsymmetricPaddingLargerThanHalfKernelSizeTest expectedOutput, qScale, qOffset, + armnn::DataLayout::NCHW, 1, // Padding left. 2, // Padding top. 3, // Padding right. @@ -410,6 +415,7 @@ LayerTestResult SimpleConvolution2dAsymmetricPaddingTestCommon(armnn::IWor expectedOutput, qScale, qOffset, + armnn::DataLayout::NCHW, 1, // Padding left. 1, // Padding top. 2, // Padding right. diff --git a/src/backends/test/LayerTests.hpp b/src/backends/test/LayerTests.hpp index ebd38419c4..6c3b9e138f 100644 --- a/src/backends/test/LayerTests.hpp +++ b/src/backends/test/LayerTests.hpp @@ -50,7 +50,8 @@ struct LayerTestResult }; LayerTestResult SimpleConvolution2d3x5Test(armnn::IWorkloadFactory& workloadFactory, - bool biasEnabled); + bool biasEnabled, + const armnn::DataLayoutIndexed& layout); LayerTestResult SimpleConvolution2d3x3Test(armnn::IWorkloadFactory& workloadFactory, bool biasEnabled); @@ -312,7 +313,8 @@ LayerTestResult DivisionBroadcast1ElementUint8Test(armnn::IWorkloadF LayerTestResult DivisionBroadcast1DVectorUint8Test(armnn::IWorkloadFactory& workloadFactory); LayerTestResult SimpleConvolution2d3x5Uint8Test(armnn::IWorkloadFactory& workloadFactory, - bool biasEnabled); + bool biasEnabled, + const armnn::DataLayoutIndexed& layout); LayerTestResult SimpleConvolution2d3x3Uint8Test(armnn::IWorkloadFactory& workloadFactory, bool biasEnabled); -- cgit v1.2.1