// // Copyright © 2017 Arm Ltd. All rights reserved. // SPDX-License-Identifier: MIT // #pragma once #include "QuantizeHelper.hpp" #include #include #include #include #include #include namespace { INetworkPtr CreateTransposeConvolution2dNetwork(const armnn::TransposeConvolution2dDescriptor& descriptor, const armnn::TensorInfo& inputInfo, const armnn::TensorInfo& outputInfo, const armnn::ConstTensor& weights, const armnn::Optional& biases) { using namespace armnn; INetworkPtr network(INetwork::Create()); IConnectableLayer* input = network->AddInputLayer(0, "input"); IConnectableLayer* transposeConvolution2d = network->AddTransposeConvolution2dLayer(descriptor, weights, biases, "transposeConvolution2d"); IConnectableLayer* output = network->AddOutputLayer(0, "output"); Connect(input, transposeConvolution2d, inputInfo, 0, 0); Connect(transposeConvolution2d, output, outputInfo, 0, 0); return network; } } // anonymous namespace template void TransposeConvolution2dEndToEnd(const std::vector& backends, armnn::DataLayout dataLayout) { using namespace armnn; using T = ResolveType; 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, dataLayout); TensorShape outputShape = MakeTensorShape(batches, channels, hOutput, wOutput, dataLayout); TensorShape weightsShape = MakeTensorShape(batches, channels, hWeights, wWeights, dataLayout); const float qScale = IsQuantizedType() ? 0.25f : 1.0f; const int32_t qOffset = IsQuantizedType() ? 50 : 0; TensorInfo inputInfo(inputShape, ArmnnType, qScale, qOffset, true); TensorInfo outputInfo(outputShape, ArmnnType, qScale, qOffset); TensorInfo weightsInfo(weightsShape, ArmnnType, qScale, qOffset, true); TensorInfo biasesInfo({ channels }, ArmnnBType, qScale * qScale, 0, true); std::vector inputData = { 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f }; std::vector weightsData = { 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f }; std::vector biasesData = { 1.f }; std::vector expectedOutputData = { 6.f, 11.f, 6.f, 11.f, 6.f, 11.f, 21.f, 11.f, 21.f, 11.f, 6.f, 11.f, 6.f, 11.f, 6.f, 11.f, 21.f, 11.f, 21.f, 11.f, 6.f, 11.f, 6.f, 11.f, 6.f }; TransposeConvolution2dDescriptor descriptor; descriptor.m_PadLeft = 1; descriptor.m_PadRight = 1; descriptor.m_PadTop = 1; descriptor.m_PadBottom = 1; descriptor.m_StrideX = 2; descriptor.m_StrideY = 2; descriptor.m_BiasEnabled = true; descriptor.m_DataLayout = dataLayout; // swizzle data if needed if (dataLayout == armnn::DataLayout::NHWC) { constexpr size_t dataTypeSize = sizeof(float); const armnn::PermutationVector nchwToNhwc = { 0, 3, 1, 2 }; std::vector 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(expectedOutputData.size()); armnnUtils::Permute(outputInfo.GetShape(), nchwToNhwc, expectedOutputData.data(), tmp.data(), dataTypeSize); expectedOutputData = tmp; } // quantize data std::vector qInputData = armnnUtils::QuantizedVector(inputData, qScale, qOffset); std::vector qWeightsData = armnnUtils::QuantizedVector(weightsData, qScale, qOffset); std::vector qExpectedOutputData = armnnUtils::QuantizedVector(expectedOutputData, qScale, qOffset); using BT = ResolveType; std::vector qBiasesData = armnnUtils::QuantizedVector(biasesData, qScale * qScale, 0); ConstTensor weights(weightsInfo, qWeightsData); ConstTensor biases(biasesInfo, qBiasesData); INetworkPtr network = CreateTransposeConvolution2dNetwork(descriptor, inputInfo, outputInfo, weights, Optional(biases)); EndToEndLayerTestImpl(std::move(network), { { 0, qInputData } }, { { 0, qExpectedOutputData } }, backends); }