IVGCVSW-3839 Add support of per-axis quantization to reference TransposeConvolution2d

Signed-off-by: Aron Virginas-Tar <Aron.Virginas-Tar@arm.com>
Change-Id: Ie0dc1204eee925adfb1e59aba3f1137178302184
diff --git a/src/backends/backendsCommon/test/layerTests/TransposeConvolution2dTestImpl.hpp b/src/backends/backendsCommon/test/layerTests/TransposeConvolution2dTestImpl.hpp
index a2b477c..438828f 100644
--- a/src/backends/backendsCommon/test/layerTests/TransposeConvolution2dTestImpl.hpp
+++ b/src/backends/backendsCommon/test/layerTests/TransposeConvolution2dTestImpl.hpp
@@ -5,553 +5,41 @@
 
 #pragma once
 
-#include <armnn/ArmNN.hpp>
+#include "LayerTestResult.hpp"
 
-#include <Permute.hpp>
-#include <QuantizeHelper.hpp>
 #include <ResolveType.hpp>
 
-#include <backendsCommon/CpuTensorHandle.hpp>
-
-#include <backendsCommon/test/DataLayoutUtils.hpp>
-#include <backendsCommon/test/TensorCopyUtils.hpp>
-#include <backendsCommon/test/WorkloadTestUtils.hpp>
-
-#include <reference/RefWorkloadFactory.hpp>
-
-#include <boost/test/unit_test.hpp>
-
-#include <string>
-#include <utility>
-#include <vector>
-
-namespace
-{
-
-template<typename T>
-using TensorData = std::pair<armnn::TensorInfo, std::vector<T>>;
-
-template<typename T>
-void VerifyInputTensorData(const TensorData<T>& data, const std::string& tensorName)
-{
-    if (data.first.GetNumElements() > data.second.size())
-    {
-        throw armnn::InvalidArgumentException("Size of data too small for " + tensorName + ": expected " +
-            std::to_string(data.first.GetNumElements()) + "but got " + std::to_string(data.second.size()));
-    }
-}
-
-template<typename T, typename BT>
-void TransposeConvolution2dTestImpl(armnn::IWorkloadFactory& workloadFactory,
-                                    const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
-                                    const armnn::TransposeConvolution2dDescriptor& descriptor,
-                                    const TensorData<T>& input,
-                                    TensorData<T>& output,
-                                    const TensorData<T>& weights,
-                                    const armnn::Optional<TensorData<BT>>& biases)
-{
-    using namespace armnn;
-
-    VerifyInputTensorData(input, "input");
-    VerifyInputTensorData(weights, "biases");
-
-    if (descriptor.m_BiasEnabled)
-    {
-        if (!biases.has_value())
-        {
-            throw InvalidArgumentException("Bias enabled but no bias data provided");
-        }
-        VerifyInputTensorData(biases.value(), "biases");
-    }
-
-    // set up weights
-    ScopedCpuTensorHandle weightsTensor(weights.first);
-
-    TransposeConvolution2dQueueDescriptor queueDescriptor;
-    queueDescriptor.m_Parameters = descriptor;
-    queueDescriptor.m_Weight     = &weightsTensor;
-
-    AllocateAndCopyDataToITensorHandle(&weightsTensor, weights.second.data());
-
-    std::unique_ptr<ScopedCpuTensorHandle> biasesTensor;
-    if (descriptor.m_BiasEnabled)
-    {
-        // set up biases
-        biasesTensor = std::make_unique<ScopedCpuTensorHandle>(biases.value().first);
-        queueDescriptor.m_Bias = biasesTensor.get();
-
-        AllocateAndCopyDataToITensorHandle(biasesTensor.get(), biases.value().second.data());
-    }
-
-    // set up input and output handles
-    std::unique_ptr<ITensorHandle> inputHandle  = workloadFactory.CreateTensorHandle(input.first);
-    std::unique_ptr<ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(output.first);
-
-    // set up workload
-    armnn::WorkloadInfo workloadInfo;
-    AddInputToWorkload(queueDescriptor, workloadInfo, input.first, inputHandle.get());
-    AddOutputToWorkload(queueDescriptor, workloadInfo, output.first, outputHandle.get());
-
-    std::unique_ptr<armnn::IWorkload> workload =
-            workloadFactory.CreateTransposeConvolution2d(queueDescriptor, workloadInfo);
-
-    inputHandle->Allocate();
-    outputHandle->Allocate();
-
-    CopyDataToITensorHandle(inputHandle.get(), input.second.data());
-
-    ExecuteWorkload(*workload, memoryManager);
-
-    // copy output
-    output.second = std::vector<T>(output.first.GetNumElements(), 0.0f);
-    CopyDataFromITensorHandle(output.second.data(), outputHandle.get());
-}
-
-template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType, typename T = armnn::ResolveType<ArmnnType>>
-LayerTestResult<T, 4> TransposeConvolution2dTest(
-    armnn::IWorkloadFactory& workloadFactory,
-    const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
-    const armnn::TransposeConvolution2dDescriptor& descriptor,
-    armnn::TensorInfo& inputInfo,
-    const std::vector<float>& inputData,
-    armnn::TensorInfo& outputInfo,
-    const std::vector<float>& expectedOutputData,
-    armnn::TensorInfo& weightsInfo,
-    const std::vector<float>& weightsData,
-    armnn::TensorInfo& biasesInfo,
-    const std::vector<float>& biasesData)
-{
-    using namespace armnn;
-
-    // set up quantization parameters
-    if (armnn::IsQuantizedType<T>())
-    {
-        constexpr float   qScale  = 0.50f;
-        constexpr int32_t qOffset = 10;
-
-        inputInfo.SetQuantizationScale(qScale);
-        inputInfo.SetQuantizationOffset(qOffset);
-
-        outputInfo.SetQuantizationScale(qScale);
-        outputInfo.SetQuantizationOffset(qOffset);
-
-        weightsInfo.SetQuantizationScale(qScale);
-        weightsInfo.SetQuantizationOffset(qOffset);
-
-        biasesInfo.SetQuantizationScale(qScale * qScale);
-        biasesInfo.SetQuantizationOffset(0);
-    }
-
-    // set up input
-    TensorData<T> input =
-    {
-        inputInfo,
-        armnnUtils::QuantizedVector<T>(inputData, inputInfo.GetQuantizationScale(), inputInfo.GetQuantizationOffset())
-    };
-
-    // set up weights
-    TensorData<T> weights =
-    {
-        weightsInfo,
-        armnnUtils::QuantizedVector<T>(weightsData,
-                                       weightsInfo.GetQuantizationScale(),
-                                       weightsInfo.GetQuantizationOffset())
-    };
-
-    // set up biases
-    using BT = armnn::ResolveType<ArmnnBType>;
-    Optional<TensorData<BT>> optionalBiases;
-    if (descriptor.m_BiasEnabled)
-    {
-        TensorData<BT> biases =
-        {
-            biasesInfo,
-            armnnUtils::QuantizedVector<BT>(biasesData,
-                                            biasesInfo.GetQuantizationScale(),
-                                            biasesInfo.GetQuantizationOffset())
-        };
-
-        optionalBiases = Optional<TensorData<BT>>(biases);
-    }
-
-    // set up output
-    TensorData<T> output = { outputInfo, {} };
-
-    // execute test
-    TransposeConvolution2dTestImpl(workloadFactory,
-                                   memoryManager,
-                                   descriptor,
-                                   input,
-                                   output,
-                                   weights,
-                                   optionalBiases);
-
-    // construct result object
-    LayerTestResult<T, 4> testResult(outputInfo);
-    testResult.output         = MakeTensor<T, 4>(outputInfo, output.second);
-    testResult.outputExpected = MakeTensor<T, 4>(outputInfo,
-                                                 armnnUtils::QuantizedVector<T>(expectedOutputData,
-                                                                                outputInfo.GetQuantizationScale(),
-                                                                                outputInfo.GetQuantizationOffset()));
-
-    return testResult;
-}
-
-template<typename T>
-void SwizzleData(armnn::TensorInfo& inputInfo,
-                 std::vector<T>& inputData,
-                 armnn::TensorInfo& outputInfo,
-                 std::vector<T>& outputData,
-                 armnn::TensorInfo& weightsInfo,
-                 std::vector<T>& weightsData)
-{
-    PermuteTensorNchwToNhwc<T>(inputInfo, inputData);
-    PermuteTensorNchwToNhwc<T>(outputInfo, outputData);
-    PermuteTensorNchwToNhwc<T>(weightsInfo, weightsData);
-}
-
-} // anonymous namespace
+#include <backendsCommon/IBackendInternal.hpp>
+#include <backendsCommon/WorkloadFactory.hpp>
 
 template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType, typename T = armnn::ResolveType<ArmnnType>>
 LayerTestResult<T, 4> SimpleTransposeConvolution2dTest(
     armnn::IWorkloadFactory& workloadFactory,
     const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
     bool biasEnabled,
-    const armnn::DataLayout layout)
-{
-    using namespace armnn;
-
-    constexpr unsigned int batches  = 1u;
-    constexpr unsigned int channels = 1u;
-
-    constexpr unsigned int wInput = 3u;
-    constexpr unsigned int hInput = wInput;
-
-    constexpr unsigned int wOutput = 5u;
-    constexpr unsigned int hOutput = wOutput;
-
-    constexpr unsigned int wWeights = 3u;
-    constexpr unsigned int hWeights = wWeights;
-
-    TensorShape inputShape   = { batches, channels, hInput,   wInput   };
-    TensorShape outputShape  = { batches, channels, hOutput,  wOutput  };
-    TensorShape weightsShape = { batches, channels, hWeights, wWeights };
-
-    TensorInfo inputInfo(inputShape, ArmnnType);
-    TensorInfo outputInfo(outputShape, ArmnnType);
-    TensorInfo weightsInfo(weightsShape, ArmnnType);
-    TensorInfo biasesInfo({ channels }, ArmnnBType);
-
-    std::vector<float> inputData =
-    {
-       1.f, 1.f, 1.f,
-       1.f, 1.f, 1.f,
-       1.f, 1.f, 1.f
-    };
-
-    std::vector<float> weightsData =
-    {
-        1.f, 2.f, 3.f,
-        4.f, 5.f, 6.f,
-        7.f, 8.f, 9.f
-    };
-
-    std::vector<float> biasesData = { 1.f };
-
-    std::vector<float> expectedOutputData =
-    {
-         1.f,  3.f,  6.f,  5.f,  3.f,
-         5.f, 12.f, 21.f, 16.f,  9.f,
-        12.f, 27.f, 45.f, 33.f, 18.f,
-        11.f, 24.f, 39.f, 28.f, 15.f,
-         7.f, 15.f, 24.f, 17.f,  9.f
-    };
-
-    if (biasEnabled)
-    {
-        // apply bias to expected output data
-        std::transform(expectedOutputData.begin(), expectedOutputData.end(), expectedOutputData.begin(),
-                       [&](float f) -> float { return f + biasesData[0]; });
-    }
-
-    TransposeConvolution2dDescriptor descriptor;
-    descriptor.m_StrideX     = 1;
-    descriptor.m_StrideY     = 1;
-    descriptor.m_BiasEnabled = biasEnabled;
-    descriptor.m_DataLayout  = layout;
-
-    // swizzle data if needed
-    if (layout == armnn::DataLayout::NHWC)
-    {
-       SwizzleData(inputInfo, inputData, outputInfo, expectedOutputData, weightsInfo, weightsData);
-    }
-
-    return TransposeConvolution2dTest<ArmnnType, ArmnnBType>(workloadFactory,
-                                                             memoryManager,
-                                                             descriptor,
-                                                             inputInfo,
-                                                             inputData,
-                                                             outputInfo,
-                                                             expectedOutputData,
-                                                             weightsInfo,
-                                                             weightsData,
-                                                             biasesInfo,
-                                                             biasesData);
-}
+    const armnn::DataLayout layout);
 
 template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType, typename T = armnn::ResolveType<ArmnnType>>
 LayerTestResult<T, 4> PaddedTransposeConvolution2dTest(
     armnn::IWorkloadFactory& workloadFactory,
     const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
     bool biasEnabled,
-    const armnn::DataLayout layout)
-{
-    using namespace armnn;
-
-    constexpr unsigned int batches  = 1u;
-    constexpr unsigned int channels = 1u;
-
-    constexpr unsigned int wInput = 4u;
-    constexpr unsigned int hInput = wInput;
-
-    constexpr unsigned int wOutput = 2u;
-    constexpr unsigned int hOutput = wOutput;
-
-    constexpr unsigned int wWeights = 3u;
-    constexpr unsigned int hWeights = wWeights;
-
-    TensorShape inputShape   = { batches, channels, hInput,   wInput   };
-    TensorShape outputShape  = { batches, channels, hOutput,  wOutput  };
-    TensorShape weightsShape = { batches, channels, hWeights, wWeights };
-
-    TensorInfo inputInfo(inputShape, ArmnnType);
-    TensorInfo outputInfo(outputShape, ArmnnType);
-    TensorInfo weightsInfo(weightsShape, ArmnnType);
-    TensorInfo biasesInfo({ channels }, ArmnnBType);
-
-    std::vector<float> inputData =
-    {
-       1.f, 3.f, 2.f, 1.f,
-       1.f, 3.f, 3.f, 1.f,
-       2.f, 1.f, 1.f, 3.f,
-       3.f, 2.f, 3.f, 3.f
-    };
-
-    std::vector<float> weightsData =
-    {
-        1.f, 2.f, 3.f,
-        0.f, 1.f, 0.f,
-        2.f, 1.f, 2.f
-    };
-
-    std::vector<float> biasesData = { 1.f };
-
-    std::vector<float> expectedOutputData =
-    {
-         21.f, 21.f,
-         28.f, 27.f
-    };
-
-    if (biasEnabled)
-    {
-        // apply bias to expected output data
-        std::transform(expectedOutputData.begin(), expectedOutputData.end(), expectedOutputData.begin(),
-                       [&](float f) -> float { return f + biasesData[0]; });
-    }
-
-    TransposeConvolution2dDescriptor descriptor;
-    descriptor.m_PadLeft     = 2;
-    descriptor.m_PadRight    = 2;
-    descriptor.m_PadTop      = 2;
-    descriptor.m_PadBottom   = 2;
-    descriptor.m_StrideX     = 1;
-    descriptor.m_StrideY     = 1;
-    descriptor.m_BiasEnabled = biasEnabled;
-    descriptor.m_DataLayout  = layout;
-
-    // swizzle data if needed
-    if (layout == armnn::DataLayout::NHWC)
-    {
-        SwizzleData(inputInfo, inputData, outputInfo, expectedOutputData, weightsInfo, weightsData);
-    }
-
-    return TransposeConvolution2dTest<ArmnnType, ArmnnBType>(workloadFactory,
-                                                             memoryManager,
-                                                             descriptor,
-                                                             inputInfo,
-                                                             inputData,
-                                                             outputInfo,
-                                                             expectedOutputData,
-                                                             weightsInfo,
-                                                             weightsData,
-                                                             biasesInfo,
-                                                             biasesData);
-}
+    const armnn::DataLayout layout);
 
 template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType, typename T = armnn::ResolveType<ArmnnType>>
 LayerTestResult<T, 4> StridedTransposeConvolution2dTest(
     armnn::IWorkloadFactory& workloadFactory,
     const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
     bool biasEnabled,
-    const armnn::DataLayout layout)
-{
-    using namespace armnn;
-
-    constexpr unsigned int batches  = 1u;
-    constexpr unsigned int channels = 1u;
-
-    constexpr unsigned int wInput = 3u;
-    constexpr unsigned int hInput = wInput;
-
-    constexpr unsigned int wOutput = 7u;
-    constexpr unsigned int hOutput = wOutput;
-
-    constexpr unsigned int wWeights = 3u;
-    constexpr unsigned int hWeights = wWeights;
-
-    TensorShape inputShape   = { batches, channels, hInput,   wInput   };
-    TensorShape outputShape  = { batches, channels, hOutput,  wOutput  };
-    TensorShape weightsShape = { batches, channels, hWeights, wWeights };
-
-    TensorInfo inputInfo(inputShape, ArmnnType);
-    TensorInfo outputInfo(outputShape, ArmnnType);
-    TensorInfo weightsInfo(weightsShape, ArmnnType);
-    TensorInfo biasesInfo({ channels }, ArmnnBType);
-
-    std::vector<float> inputData =
-    {
-        1.f, 1.f, 1.f,
-        1.f, 1.f, 1.f,
-        1.f, 1.f, 1.f
-    };
-
-    std::vector<float> weightsData =
-    {
-        1.f, 2.f, 3.f,
-        4.f, 5.f, 6.f,
-        7.f, 8.f, 9.f
-    };
-
-    std::vector<float> biasesData = { 1.f };
-
-    std::vector<float> expectedOutputData =
-    {
-        1.f,  2.f,  4.f,  2.f,  4.f,  2.f,  3.f,
-        4.f,  5.f, 10.f,  5.f, 10.f,  5.f,  6.f,
-        8.f, 10.f, 20.f, 10.f, 20.f, 10.f, 12.f,
-        4.f,  5.f, 10.f,  5.f, 10.f,  5.f,  6.f,
-        8.f, 10.f, 20.f, 10.f, 20.f, 10.f, 12.f,
-        4.f,  5.f, 10.f,  5.f, 10.f,  5.f,  6.f,
-        7.f,  8.f, 16.f,  8.f, 16.f,  8.f,  9.f
-    };
-
-    if (biasEnabled)
-    {
-        // apply bias to expected output data
-        std::transform(expectedOutputData.begin(), expectedOutputData.end(), expectedOutputData.begin(),
-                    [&](float f) -> float { return f + biasesData[0]; });
-    }
-
-    TransposeConvolution2dDescriptor descriptor;
-    descriptor.m_StrideX     = 2;
-    descriptor.m_StrideY     = 2;
-    descriptor.m_BiasEnabled = biasEnabled;
-    descriptor.m_DataLayout  = layout;
-
-    // swizzle data if needed
-    if (layout == armnn::DataLayout::NHWC)
-    {
-        SwizzleData(inputInfo, inputData, outputInfo, expectedOutputData, weightsInfo, weightsData);
-    }
-
-    return TransposeConvolution2dTest<ArmnnType, ArmnnBType>(workloadFactory,
-                                                             memoryManager,
-                                                             descriptor,
-                                                             inputInfo,
-                                                             inputData,
-                                                             outputInfo,
-                                                             expectedOutputData,
-                                                             weightsInfo,
-                                                             weightsData,
-                                                             biasesInfo,
-                                                             biasesData);
-}
+    const armnn::DataLayout layout);
 
 template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType, typename T = armnn::ResolveType<ArmnnType>>
 LayerTestResult<T, 4> MultiChannelTransposeConvolution2dTest(
     armnn::IWorkloadFactory& workloadFactory,
     const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
-    const armnn::DataLayout layout)
-{
-    using namespace armnn;
+    const armnn::DataLayout layout);
 
-    TensorShape inputShape   = { 1, 1, 2, 2 };
-    TensorShape outputShape  = { 1, 2, 5, 5 };
-
-    // OIHW for NCHW; OHWI for NHWC
-    TensorShape weightsShape = { 2, 1, 3, 3 };
-    TensorShape biasesShape  = { 2 };
-
-    TensorInfo inputInfo(inputShape, ArmnnType);
-    TensorInfo outputInfo(outputShape, ArmnnType);
-    TensorInfo weightsInfo(weightsShape, ArmnnType);
-    TensorInfo biasesInfo(biasesShape, ArmnnBType);
-
-    std::vector<float> inputData =
-    {
-        1.f, 2.f,
-        3.f, 4.f,
-    };
-
-    std::vector<float> weightsData =
-    {
-         1.f,  3.f,  5.f,
-         7.f,  9.f, 11.f,
-        13.f, 15.f, 17.f,
-
-         2.f,  4.f,  6.f,
-         8.f, 10.f, 12.f,
-        14.f, 16.f, 18.f
-    };
-
-    std::vector<float> biasesData = { -1.5f, -2.0f };
-
-    std::vector<float> expectedOutputData =
-    {
-        -0.5f,  1.5f,   5.5f,  4.5f,  8.5f,
-         5.5f,  7.5f,  23.5f, 16.5f, 20.5f,
-        14.5f, 22.5f,  60.5f, 40.5f, 52.5f,
-        19.5f, 25.5f,  59.5f, 34.5f, 42.5f,
-        37.5f, 43.5f, 101.5f, 58.5f, 66.5f,
-
-         0.0f,  2.0f,   8.0f,  6.0f, 10.0f,
-         6.0f,  8.0f,  26.0f, 18.0f, 22.0f,
-        18.0f, 26.0f,  70.0f, 46.0f, 58.0f,
-        22.0f, 28.0f,  66.0f, 38.0f, 46.0f,
-        40.0f, 46.0f, 108.0f, 62.0f, 70.0f,
-    };
-
-    TransposeConvolution2dDescriptor descriptor;
-    descriptor.m_StrideX     = 2;
-    descriptor.m_StrideY     = 2;
-    descriptor.m_BiasEnabled = true;
-    descriptor.m_DataLayout  = layout;
-
-    // swizzle data if needed
-    if (layout == armnn::DataLayout::NHWC)
-    {
-        SwizzleData(inputInfo, inputData, outputInfo, expectedOutputData, weightsInfo, weightsData);
-    }
-
-    return TransposeConvolution2dTest<ArmnnType, ArmnnBType>(workloadFactory,
-                                                             memoryManager,
-                                                             descriptor,
-                                                             inputInfo,
-                                                             inputData,
-                                                             outputInfo,
-                                                             expectedOutputData,
-                                                             weightsInfo,
-                                                             weightsData,
-                                                             biasesInfo,
-                                                             biasesData);
-}
+LayerTestResult<uint8_t, 4> TransposeConvolution2dPerAxisQuantTest(
+    armnn::IWorkloadFactory& workloadFactory,
+    const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+    const armnn::DataLayout layout);