MLCE-101 Add dilation support for DepthWiseConv workload

Adds unit tests for dilated depthwise conv

Change-Id: Iad0a1b33d07fb0ef8f9f6edf0fd0f83a5800a36d
Signed-off-by: Bruno Goncalves <bruno.slackware@gmail.com>
Signed-off-by: Matthew Bentham <matthew.bentham@arm.com>
diff --git a/include/armnn/Descriptors.hpp b/include/armnn/Descriptors.hpp
index cf31599..5be59aa 100644
--- a/include/armnn/Descriptors.hpp
+++ b/include/armnn/Descriptors.hpp
@@ -330,9 +330,9 @@
     uint32_t   m_StrideX;
     /// Stride value when proceeding through input for the height dimension.
     uint32_t   m_StrideY;
-    /// Dilation along x axis
+    /// Dilation factor value for width dimension.
     uint32_t   m_DilationX;
-    /// Dilation along y axis
+    /// Dilation factor value for height dimension.
     uint32_t   m_DilationY;
     /// Enable/disable bias.
     bool       m_BiasEnabled;
diff --git a/src/backends/backendsCommon/WorkloadData.cpp b/src/backends/backendsCommon/WorkloadData.cpp
index 2cf9937..58f77d5 100644
--- a/src/backends/backendsCommon/WorkloadData.cpp
+++ b/src/backends/backendsCommon/WorkloadData.cpp
@@ -634,6 +634,14 @@
     ValidatePointer(m_Weight, "DepthwiseConvolution2dQueueDescriptor", "weight");
     ValidateTensorNumDimensions(m_Weight->GetTensorInfo(), "DepthwiseConvolution2dQueueDescriptor", 4, "weight");
 
+    if (m_Parameters.m_DilationX < 1 || m_Parameters.m_DilationY < 1 )
+    {
+        throw InvalidArgumentException(
+            boost::str(boost::format("DepthwiseConvolution2dQueueDescriptor: dilationX (provided %1%) "
+                                     "and dilationY (provided %2%) cannot be smaller than 1.")
+                                     % m_Parameters.m_DilationX % m_Parameters.m_DilationX));
+    }
+
     const unsigned int channelIndex = (m_Parameters.m_DataLayout == DataLayout::NCHW) ? 1 : 3;
 
     // Expected weight shape: [ M, I, H, W ] - This shape does NOT depend on the data layout
diff --git a/src/backends/backendsCommon/test/Conv2dTestImpl.hpp b/src/backends/backendsCommon/test/Conv2dTestImpl.hpp
index c2e539b..bb5656b 100755
--- a/src/backends/backendsCommon/test/Conv2dTestImpl.hpp
+++ b/src/backends/backendsCommon/test/Conv2dTestImpl.hpp
@@ -827,7 +827,9 @@
     uint32_t padRight = 0,
     uint32_t padBottom = 0,
     uint32_t strideX = 1,
-    uint32_t strideY = 1)
+    uint32_t strideY = 1,
+    uint32_t dilationX = 1,
+    uint32_t dilationY = 1)
 {
     unsigned int inputNum       = boost::numeric_cast<unsigned int>(input.shape()[0]);
     unsigned int inputChannels  = boost::numeric_cast<unsigned int>(input.shape()[3]);
@@ -894,6 +896,8 @@
     data.m_Parameters.m_PadTop = padTop;
     data.m_Parameters.m_PadBottom = padBottom;
     data.m_Parameters.m_DataLayout = armnn::DataLayout::NHWC;
+    data.m_Parameters.m_DilationX = dilationX;
+    data.m_Parameters.m_DilationY = dilationY;
 
     armnn::WorkloadInfo info;
     AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
diff --git a/src/backends/backendsCommon/test/LayerTests.cpp b/src/backends/backendsCommon/test/LayerTests.cpp
index e505b56..da6a2b2 100644
--- a/src/backends/backendsCommon/test/LayerTests.cpp
+++ b/src/backends/backendsCommon/test/LayerTests.cpp
@@ -748,6 +748,75 @@
         1);  // strideY
 }
 
+template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType,
+         typename T = armnn::ResolveType<ArmnnType>>
+LayerTestResult<T, 4> SimpleDepthwiseConvolution2d3x3Dilation3x3NhwcTestCommon(
+    armnn::IWorkloadFactory& workloadFactory,
+    const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+    float qScale,
+    int32_t qOffset,
+    bool biasEnabled)
+{
+    armnn::TensorInfo inputTensorInfo({ 1, 9, 9, 1}, ArmnnType);
+    auto input = MakeTensor<T, 4>(inputTensorInfo, std::vector<T>(
+        QuantizedVector<T>(inputTensorInfo.GetQuantizationScale(), inputTensorInfo.GetQuantizationOffset(), {
+             0, 0, 0, 0, 0, 0, 0, 0, 0,
+             0, 0, 0, 0, 0, 0, 0, 0, 0,
+             0, 0, 0, 0, 0, 0, 0, 0, 0,
+             0, 0, 0, 1, 1, 1, 0, 0, 0,
+             0, 0, 0, 1, 1, 1, 0, 0, 0,
+             0, 0, 0, 1, 1, 1, 0, 0, 0,
+             0, 0, 0, 0, 0, 0, 0, 0, 0,
+             0, 0, 0, 0, 0, 0, 0, 0, 0,
+             0, 0, 0, 0, 0, 0, 0, 0, 0
+        })));
+
+    armnn::TensorInfo kernelTensorInfo({ 1, 1, 3, 3}, ArmnnType);
+    auto kernel = MakeTensor<T, 4>(kernelTensorInfo, std::vector<T>(
+        QuantizedVector<T>(kernelTensorInfo.GetQuantizationScale(), kernelTensorInfo.GetQuantizationOffset(), {
+             1, 2, 3,
+             4, 5, 6,
+             7, 8, 9
+        })));
+
+    uint32_t padLeft = 0;
+    uint32_t padTop = 0;
+    uint32_t padRight = 0;
+    uint32_t padBottom = 0;
+    uint32_t strideX  = 1;
+    uint32_t strideY  = 1;
+    uint32_t dilationX  = 3;
+    uint32_t dilationY  = 3;
+
+    // Since the dilation rate is 3 this will reduce the size of the output from 9x9 to 3x3 of all 5s.
+    armnn::TensorInfo outputTensorInfo({ 1, 3, 3, 1}, ArmnnType);
+    boost::multi_array<T, 4> expectedOutput = MakeTensor<T, 4>(outputTensorInfo, std::vector<T>(
+        QuantizedVector<T>(outputTensorInfo.GetQuantizationScale(), outputTensorInfo.GetQuantizationOffset(), {
+             5, 5, 5,
+             5, 5, 5,
+             5, 5, 5
+        })));
+
+    return DepthwiseConvolution2dNhwcTestImpl<ArmnnType, ArmnnBType>(
+        workloadFactory,
+        memoryManager,
+        input,
+        kernel,
+        GetBias2<ArmnnBType>(biasEnabled, qScale, qOffset),
+        expectedOutput,
+        qScale,
+        qOffset,
+        padLeft,
+        padTop,
+        padRight,
+        padBottom,
+        strideX,
+        strideY,
+        dilationX,
+        dilationY);
+
+}
+
 LayerTestResult<float, 4>
 Convolution2dAsymmetricPaddingLargerThanHalfKernelSizeTest(
     armnn::IWorkloadFactory& workloadFactory,
@@ -827,6 +896,18 @@
         workloadFactory, memoryManager, 0.5f, 50, biasEnabled, layout);
 }
 
+LayerTestResult<float, 4> SimpleDepthwiseConvolution2d3x3Dilation3x3NhwcTest(
+        armnn::IWorkloadFactory& workloadFactory,
+        const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
+{
+    return SimpleDepthwiseConvolution2d3x3Dilation3x3NhwcTestCommon<armnn::DataType::Float32, armnn::DataType::Float32>(
+        workloadFactory,
+        memoryManager,
+        0.f,
+        0,
+        false);
+}
+
 LayerTestResult<float, 4> Convolution1dTest(
     armnn::IWorkloadFactory& workloadFactory,
     const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
diff --git a/src/backends/backendsCommon/test/LayerTests.hpp b/src/backends/backendsCommon/test/LayerTests.hpp
index 0e8025e..84001aa 100644
--- a/src/backends/backendsCommon/test/LayerTests.hpp
+++ b/src/backends/backendsCommon/test/LayerTests.hpp
@@ -123,6 +123,9 @@
     bool biasEnabled,
     const armnn::DataLayout layout);
 
+LayerTestResult<float, 4> SimpleDepthwiseConvolution2d3x3Dilation3x3NhwcTest(armnn::IWorkloadFactory& workloadFactory,
+        const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager);
+
 LayerTestResult<float, 4> CompareDepthwiseConvolution2dFloatTest(
     armnn::IWorkloadFactory& workloadFactory,
     const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
diff --git a/src/backends/cl/test/ClLayerTests.cpp b/src/backends/cl/test/ClLayerTests.cpp
index 58b9ba7..0af1d34 100644
--- a/src/backends/cl/test/ClLayerTests.cpp
+++ b/src/backends/cl/test/ClLayerTests.cpp
@@ -108,6 +108,8 @@
                      DepthwiseConvolution2dDepthMul1Uint8Test, true, armnn::DataLayout::NHWC)
 ARMNN_AUTO_TEST_CASE(UnbiasedDepthwiseConvolution2dDepthMul1Uint8Nhwc,
                      DepthwiseConvolution2dDepthMul1Uint8Test, false, armnn::DataLayout::NHWC)
+ARMNN_AUTO_TEST_CASE(SimpleDepthwiseConvolution2d3x3Dilation3x3Nhwc,
+                     SimpleDepthwiseConvolution2d3x3Dilation3x3NhwcTest)
 
 
 ARMNN_AUTO_TEST_CASE(DepthwiseConvolution2dDepthNhwc, DepthwiseConvolution2dDepthNhwcTest, false)
diff --git a/src/backends/neon/test/NeonLayerTests.cpp b/src/backends/neon/test/NeonLayerTests.cpp
index 9454244..dce369d 100644
--- a/src/backends/neon/test/NeonLayerTests.cpp
+++ b/src/backends/neon/test/NeonLayerTests.cpp
@@ -68,6 +68,8 @@
                      DepthwiseConvolution2dDepthMul1Uint8Test, false, armnn::DataLayout::NHWC)
 
 ARMNN_AUTO_TEST_CASE(DepthwiseConvolution2dDepthNhwc, DepthwiseConvolution2dDepthNhwcTest, false)
+ARMNN_AUTO_TEST_CASE(SimpleDepthwiseConvolution2d3x3Dilation3x3Nhwc,
+                     SimpleDepthwiseConvolution2d3x3Dilation3x3NhwcTest)
 
 
 ARMNN_AUTO_TEST_CASE(DepthwiseConvolution2dAsymmetric,
diff --git a/src/backends/neon/workloads/NeonDepthwiseConvolutionWorkload.cpp b/src/backends/neon/workloads/NeonDepthwiseConvolutionWorkload.cpp
index 0b917fc..d15b485 100644
--- a/src/backends/neon/workloads/NeonDepthwiseConvolutionWorkload.cpp
+++ b/src/backends/neon/workloads/NeonDepthwiseConvolutionWorkload.cpp
@@ -117,7 +117,7 @@
     input.info()->set_data_layout(aclDataLayout);
     output.info()->set_data_layout(aclDataLayout);
 
-   // Get the depth multiplier
+    // Get the depth multiplier
     const unsigned int depthMultiplier = weightInfo.GetShape()[0];
 
     // Check for optimisation opportunities.