IVGCVSW-3381 Break up LayerTests.hpp into more manageable files

Signed-off-by: Aron Virginas-Tar <Aron.Virginas-Tar@arm.com>
Change-Id: Icf39434f09fd340ad664cb3b97b8bee6d9da4838
diff --git a/src/backends/backendsCommon/test/layerTests/TransposeConvolution2dTestImpl.hpp b/src/backends/backendsCommon/test/layerTests/TransposeConvolution2dTestImpl.hpp
new file mode 100644
index 0000000..6191adf
--- /dev/null
+++ b/src/backends/backendsCommon/test/layerTests/TransposeConvolution2dTestImpl.hpp
@@ -0,0 +1,564 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include <armnn/ArmNN.hpp>
+
+#include <Permute.hpp>
+#include <ResolveType.hpp>
+
+#include <backendsCommon/CpuTensorHandle.hpp>
+
+#include <backendsCommon/test/CommonTestUtils.hpp>
+#include <backendsCommon/test/QuantizeHelper.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,
+        QuantizedVector<T>(inputInfo.GetQuantizationScale(), inputInfo.GetQuantizationOffset(), inputData)
+    };
+
+    // set up weights
+    TensorData<T> weights =
+    {
+        weightsInfo,
+        QuantizedVector<T>(weightsInfo.GetQuantizationScale(), weightsInfo.GetQuantizationOffset(), weightsData)
+    };
+
+    // set up biases
+    using BT = armnn::ResolveType<ArmnnBType>;
+    Optional<TensorData<BT>> optionalBiases;
+    if (descriptor.m_BiasEnabled)
+    {
+        TensorData<BT> biases =
+        {
+            biasesInfo,
+            QuantizedVector<BT>(biasesInfo.GetQuantizationScale(), biasesInfo.GetQuantizationOffset(), biasesData)
+        };
+
+        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,
+                                                 QuantizedVector<T>(outputInfo.GetQuantizationScale(),
+                                                                    outputInfo.GetQuantizationOffset(),
+                                                                    expectedOutputData));
+
+    return testResult;
+}
+
+template<typename T>
+void SwizzleData(const armnn::TensorInfo& inputInfo,
+                 std::vector<T>& inputData,
+                 const armnn::TensorInfo& outputInfo,
+                 std::vector<T>& outputData,
+                 const armnn::TensorInfo& weightsInfo,
+                 std::vector<T>& weightsData)
+{
+    constexpr size_t dataTypeSize = sizeof(float);
+    const armnn::PermutationVector nchwToNhwc = { 0, 3, 1, 2 };
+
+    std::vector<T> tmp(inputData.size());
+    armnnUtils::Permute(inputInfo.GetShape(), nchwToNhwc, inputData.data(), tmp.data(), dataTypeSize);
+    inputData = tmp;
+
+    tmp.resize(weightsData.size());
+    armnnUtils::Permute(weightsInfo.GetShape(), nchwToNhwc, weightsData.data(), tmp.data(), dataTypeSize);
+    weightsData = tmp;
+
+    tmp.resize(outputData.size());
+    armnnUtils::Permute(outputInfo.GetShape(), nchwToNhwc, outputData.data(), tmp.data(), dataTypeSize);
+    outputData = tmp;
+}
+
+} // anonymous namespace
+
+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   = MakeTensorShape(batches, channels, hInput, wInput, layout);
+    TensorShape outputShape  = MakeTensorShape(batches, channels, hOutput, wOutput, layout);
+    TensorShape weightsShape = MakeTensorShape(batches, channels, hWeights, wWeights, layout);
+
+    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);
+}
+
+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   = MakeTensorShape(batches, channels, hInput, wInput, layout);
+    TensorShape outputShape  = MakeTensorShape(batches, channels, hOutput, wOutput, layout);
+    TensorShape weightsShape = MakeTensorShape(batches, channels, hWeights, wWeights, layout);
+
+    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);
+}
+
+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   = MakeTensorShape(batches, channels, hInput, wInput, layout);
+    TensorShape outputShape  = MakeTensorShape(batches, channels, hOutput, wOutput, layout);
+    TensorShape weightsShape = MakeTensorShape(batches, channels, hWeights, wWeights, layout);
+
+    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);
+}
+
+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;
+
+    TensorShape inputShape   = MakeTensorShape(1, 1, 2, 2, layout);
+    TensorShape outputShape  = MakeTensorShape(1, 2, 5, 5, layout);
+
+    // OIHW for NCHW; OHWI for NHWC
+    TensorShape weightsShape = MakeTensorShape(2, 1, 3, 3, layout);
+    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);
+}