diff options
author | Tianle Cheng <tianle.cheng@arm.com> | 2023-06-28 13:20:47 +0100 |
---|---|---|
committer | Tianle Cheng <tianle.cheng@arm.com> | 2023-07-04 10:36:43 +0000 |
commit | 988354de127528bdebb98fd25661fbf2f39f17dd (patch) | |
tree | c06f5250bdd0182055ac9e84e20d6e338518ad08 /src | |
parent | 9414936e62ed8cd18cc33c0390bb605a782556c6 (diff) | |
download | armnn-988354de127528bdebb98fd25661fbf2f39f17dd.tar.gz |
IVGCVSW-7831: Front end and Reference Implementation for REVERSE_V2
* Descriptors added for ReverseV2
* Layer definition added
* Input validation added
* Reference workload implementation for ReverseV2 added
* Reference layer unit tests made for ReverseV2
* CompareTensors method updated to support comparison between empty tensors
* CMake and other build files updated
Signed-off-by: Tianle Cheng <tianle.cheng@arm.com>
Change-Id: I805738454421309fda77c44218a8df171d68dc18
Diffstat (limited to 'src')
25 files changed, 1770 insertions, 2 deletions
diff --git a/src/armnn/BackendHelper.cpp b/src/armnn/BackendHelper.cpp index 580c52c568..404d278efc 100644 --- a/src/armnn/BackendHelper.cpp +++ b/src/armnn/BackendHelper.cpp @@ -1,5 +1,5 @@ // -// Copyright © 2017,2022 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2017,2022-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -1211,6 +1211,21 @@ bool LayerSupportHandle::IsResizeSupported(const TensorInfo& input, reasonIfUnsupported); } +bool LayerSupportHandle::IsReverseV2Supported(const armnn::TensorInfo &input, + const armnn::TensorInfo &output, + const armnn::ReverseV2Descriptor &descriptor, + Optional<std::string &> reasonIfUnsupported) +{ + TensorInfos infos{input, output}; + + return m_LayerSupport->IsLayerSupported(LayerType::ReverseV2, + infos, + descriptor, + EmptyOptional(), + EmptyOptional(), + reasonIfUnsupported); +} + bool LayerSupportHandle::IsShapeSupported(const TensorInfo& input, const TensorInfo& output, Optional<std::string&> reasonIfUnsupported) diff --git a/src/armnn/LayersFwd.hpp b/src/armnn/LayersFwd.hpp index f634272316..d3ce6f2a67 100644 --- a/src/armnn/LayersFwd.hpp +++ b/src/armnn/LayersFwd.hpp @@ -64,6 +64,7 @@ #include "layers/ReduceLayer.hpp" #include "layers/ReshapeLayer.hpp" #include "layers/ResizeLayer.hpp" +#include "layers/ReverseV2Layer.hpp" #include "layers/ShapeLayer.hpp" #include "layers/SliceLayer.hpp" #include "layers/SoftmaxLayer.hpp" @@ -165,6 +166,7 @@ DECLARE_LAYER(Rank) DECLARE_LAYER(Reduce) DECLARE_LAYER(Reshape) DECLARE_LAYER(Resize) +DECLARE_LAYER(ReverseV2) DECLARE_LAYER(Shape) DECLARE_LAYER(Slice) DECLARE_LAYER(Softmax) diff --git a/src/armnn/Network.cpp b/src/armnn/Network.cpp index b768ea888f..2abaf44587 100644 --- a/src/armnn/Network.cpp +++ b/src/armnn/Network.cpp @@ -639,6 +639,12 @@ IConnectableLayer* INetwork::AddBatchMatMulLayer(const BatchMatMulDescriptor &de return pNetworkImpl->AddBatchMatMulLayer(descriptor, name); } +IConnectableLayer* INetwork::AddReverseV2Layer(const ReverseV2Descriptor &descriptor, + const char *name) +{ + return pNetworkImpl->AddReverseV2Layer(descriptor, name); +} + void INetwork::ExecuteStrategy(IStrategy& strategy) const { return pNetworkImpl->ExecuteStrategy(strategy); @@ -2902,6 +2908,11 @@ IConnectableLayer* NetworkImpl::AddBatchMatMulLayer(const BatchMatMulDescriptor& return m_Graph->AddLayer<BatchMatMulLayer>(desc, name); } +IConnectableLayer* NetworkImpl::AddReverseV2Layer(const ReverseV2Descriptor &desc, const char *name) +{ + return m_Graph->AddLayer<ReverseV2Layer>(desc, name); +} + IConnectableLayer* NetworkImpl::AddPrecompiledLayer(const PreCompiledDescriptor& preCompiledDescriptor, CompiledBlobPtr compiledBlobPtr, const Optional<BackendId>& backend, diff --git a/src/armnn/Network.hpp b/src/armnn/Network.hpp index eced4587b9..fc3ae42aa9 100644 --- a/src/armnn/Network.hpp +++ b/src/armnn/Network.hpp @@ -188,6 +188,9 @@ public: IConnectableLayer* AddReshapeLayer(const ReshapeDescriptor& reshapeDescriptor, const char* name = nullptr); + IConnectableLayer* AddReverseV2Layer(const ReverseV2Descriptor& ReverseV2Descriptor, + const char* name = nullptr); + IConnectableLayer* AddShapeLayer(const char* name = nullptr); IConnectableLayer* AddSliceLayer(const SliceDescriptor& sliceDescriptor, const char* name = nullptr); diff --git a/src/armnn/layers/ReverseV2Layer.cpp b/src/armnn/layers/ReverseV2Layer.cpp new file mode 100644 index 0000000000..29f8b1b781 --- /dev/null +++ b/src/armnn/layers/ReverseV2Layer.cpp @@ -0,0 +1,50 @@ +// +// Copyright © 2023 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "ReverseV2Layer.hpp" + +#include <armnn/backends/WorkloadFactory.hpp> +#include "layers/LayerCloneBase.hpp" + +namespace armnn +{ +ReverseV2Layer::ReverseV2Layer(const armnn::ReverseV2Descriptor ¶m, const char *name) + : LayerWithParameters(1, 1, LayerType::ReverseV2, param, name) +{} + +std::unique_ptr<IWorkload> ReverseV2Layer::CreateWorkload(const armnn::IWorkloadFactory &factory) const +{ + ReverseV2QueueDescriptor descriptor; + SetAdditionalInfo(descriptor); + + return factory.CreateWorkload(LayerType::ReverseV2, descriptor, PrepInfoAndDesc(descriptor)); +} + +ReverseV2Layer* ReverseV2Layer::Clone(armnn::Graph &graph) const +{ + auto layer = CloneBase<ReverseV2Layer>(graph, m_Param, GetName()); + + return std::move(layer); +} + +/// Use the default Layer::InferOutputShape method + +void ReverseV2Layer::ValidateTensorShapesFromInputs() +{ + VerifyLayerConnections(1, CHECK_LOCATION()); + + const TensorShape& outputShape = GetOutputSlot(0).GetTensorInfo().GetShape(); + + VerifyShapeInferenceType(outputShape, m_ShapeInferenceMethod); + + auto inferredShapes = InferOutputShapes({ + GetInputSlot(0).GetConnection()->GetTensorInfo().GetShape() }); + + ARMNN_ASSERT(inferredShapes.size() == 1); + + ValidateAndCopyShape(outputShape, inferredShapes[0], m_ShapeInferenceMethod, "ReverseV2Layer"); +} + +}
\ No newline at end of file diff --git a/src/armnn/layers/ReverseV2Layer.hpp b/src/armnn/layers/ReverseV2Layer.hpp new file mode 100644 index 0000000000..046670e9de --- /dev/null +++ b/src/armnn/layers/ReverseV2Layer.hpp @@ -0,0 +1,49 @@ +// +// Copyright © 2023 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include "LayerWithParameters.hpp" + +namespace armnn +{ + + /// This layer represents a ReverseV2 operation. + class ReverseV2Layer : public LayerWithParameters<ReverseV2Descriptor> + { + public: + /// Makes a workload for the ReverseV2 type. + /// @param [in] graph The graph where this layer can be found. + /// @param [in] factory The workload factory which will create the workload. + /// @return A pointer to the created workload, or nullptr if not created. + virtual std::unique_ptr<IWorkload>CreateWorkload(const IWorkloadFactory& factory) const override; + + /// Creates a dynamically-allocated copy of this layer. + /// @param [in] graph The graph into which this layer is being cloned. + ReverseV2Layer* Clone(Graph& graph) const override; + + /// By default returns inputShapes if the number of inputs are equal to number of outputs, + /// otherwise infers the output shapes from given input shapes and layer properties. + /// @param [in] inputShapes The vector of input shapes for ReverseV2. + /// @return A vector to the inferred output shape. + + /// Use the default Layer::InferOutputShape method + // std::vector<TensorShape> InferOutputShapes(const std::vector<TensorShape>& inputShapes) const override; + + /// Check if the input tensor shape(s) + /// will lead to a valid configuration of @ref ReverseV2Layer. + void ValidateTensorShapesFromInputs() override; + + protected: + /// Constructor to create a ReverseV2Layer. + /// @param [in] param ReverseV2Descriptor to configure the ReverseV2 operation. + /// @param [in] name Optional name for the layer. + ReverseV2Layer(const ReverseV2Descriptor& param, const char* name); + + /// Default destructor + ~ReverseV2Layer() = default; + }; + +} // namespace armnn diff --git a/src/backends/backendsCommon/WorkloadData.cpp b/src/backends/backendsCommon/WorkloadData.cpp index d4ae08d874..6cde89c2e1 100644 --- a/src/backends/backendsCommon/WorkloadData.cpp +++ b/src/backends/backendsCommon/WorkloadData.cpp @@ -1640,6 +1640,72 @@ void ResizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const } } +void ReverseV2QueueDescriptor::Validate(const WorkloadInfo &workloadInfo) const { + const std::string descriptorName{"ReverseV2QueueDescriptor"}; + + ValidateNumInputs(workloadInfo, descriptorName, 1); + ValidateNumOutputs(workloadInfo, descriptorName, 1); + + const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; + const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; + + auto inputTensorNumDimensions = inputTensorInfo.GetNumDimensions(); + if (inputTensorNumDimensions > m_Parameters.m_MaxDimension) + { + throw InvalidArgumentException(descriptorName + + ": Input tensors with rank greater than " + + std::to_string(m_Parameters.m_MaxDimension) + " are not supported."); + } + + std::vector<DataType> supportedTypes = + { + DataType::BFloat16, + DataType::Float16, + DataType::Float32, + DataType::QAsymmS8, + DataType::QAsymmU8, + DataType::QSymmS16 + }; + + ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); + ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); + ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); + + if (m_Parameters.m_Axis.size() > inputTensorNumDimensions) + { + throw InvalidArgumentException(descriptorName + ": More axes specified than is on the input tensor."); + } + if (m_Parameters.m_Axis.size() > m_Parameters.m_MaxDimension) + { + throw InvalidArgumentException(descriptorName + + ": More than " + std::to_string(m_Parameters.m_MaxDimension) + " axes cannot be specified."); + } + + if (! m_Parameters.m_Axis.empty()) + { + // First check that we have unique axis values + auto checkAxis = m_Parameters.m_Axis; + std::sort(checkAxis.begin(), checkAxis.end()); + auto lastUnique = std::unique(checkAxis.begin(), checkAxis.end()); + if (lastUnique != checkAxis.end()) + { + throw InvalidArgumentException(descriptorName + ": Axes values must be unique."); + } + + // Next check that the axes values are in range: [-rank, rank] + const auto minmax = + std::minmax_element(std::begin(m_Parameters.m_Axis), std::end(m_Parameters.m_Axis)); + if (((*minmax.first) < int32_t(-inputTensorNumDimensions)) || + ((*minmax.second) >= int32_t (inputTensorNumDimensions))) + { + throw InvalidArgumentException(descriptorName + + ": Axes values must in range [-" + std::to_string(inputTensorNumDimensions) + "," + + std::to_string(inputTensorNumDimensions) + "]."); + } + } +} + + void FakeQuantizationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const { const std::string descriptorName{"FakeQuantizationQueueDescriptor"}; diff --git a/src/backends/backendsCommon/WorkloadFactory.cpp b/src/backends/backendsCommon/WorkloadFactory.cpp index 7042af1127..37f9382d6e 100644 --- a/src/backends/backendsCommon/WorkloadFactory.cpp +++ b/src/backends/backendsCommon/WorkloadFactory.cpp @@ -1119,6 +1119,17 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, reason); break; } + case LayerType::ReverseV2: + { + auto cLayer = PolymorphicDowncast<const ReverseV2Layer*>(&layer); + const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo(); + const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo(); + result = layerSupportObject.IsReverseV2Supported(OverrideDataType(input, dataType), + OverrideDataType(output, dataType), + cLayer->GetParameters(), + reason); + break; + } case LayerType::Shape: { const TensorInfo& input = layer.GetInputSlot(0).GetTensorInfo(); diff --git a/src/backends/backendsCommon/common.mk b/src/backends/backendsCommon/common.mk index c868cbe87a..1e0467deba 100644 --- a/src/backends/backendsCommon/common.mk +++ b/src/backends/backendsCommon/common.mk @@ -91,6 +91,7 @@ COMMON_TEST_SOURCES := \ test/layerTests/ReduceSumTestImpl.cpp \ test/layerTests/ReshapeTestImpl.cpp \ test/layerTests/ResizeTestImpl.cpp \ + test/layerTests/ReverseV2TestImpl.cpp \ test/layerTests/RsqrtTestImpl.cpp \ test/layerTests/SliceTestImpl.cpp \ test/layerTests/SquaredDifferenceTestImpl.cpp \ diff --git a/src/backends/backendsCommon/test/CMakeLists.txt b/src/backends/backendsCommon/test/CMakeLists.txt index aba9c72e6c..0139044432 100644 --- a/src/backends/backendsCommon/test/CMakeLists.txt +++ b/src/backends/backendsCommon/test/CMakeLists.txt @@ -170,6 +170,8 @@ list(APPEND armnnBackendsCommonUnitTests_sources layerTests/ReshapeTestImpl.hpp layerTests/ResizeTestImpl.cpp layerTests/ResizeTestImpl.hpp + layerTests/ReverseV2TestImpl.cpp + layerTests/ReverseV2TestImpl.hpp layerTests/RsqrtTestImpl.cpp layerTests/RsqrtTestImpl.hpp layerTests/SinTestImpl.cpp diff --git a/src/backends/backendsCommon/test/IsLayerSupportedTestImpl.hpp b/src/backends/backendsCommon/test/IsLayerSupportedTestImpl.hpp index 182fab97be..f7a852f440 100644 --- a/src/backends/backendsCommon/test/IsLayerSupportedTestImpl.hpp +++ b/src/backends/backendsCommon/test/IsLayerSupportedTestImpl.hpp @@ -744,6 +744,8 @@ DECLARE_LAYER_POLICY_2_PARAM(Resize) DECLARE_LAYER_POLICY_2_PARAM(Reshape) +DECLARE_LAYER_POLICY_2_PARAM(ReverseV2) + DECLARE_LAYER_POLICY_1_PARAM(Shape) DECLARE_LAYER_POLICY_2_PARAM(Slice) diff --git a/src/backends/backendsCommon/test/LayerTests.hpp b/src/backends/backendsCommon/test/LayerTests.hpp index b6ddb31419..755a665ba6 100644 --- a/src/backends/backendsCommon/test/LayerTests.hpp +++ b/src/backends/backendsCommon/test/LayerTests.hpp @@ -60,6 +60,7 @@ #include <backendsCommon/test/layerTests/ReduceSumTestImpl.hpp> #include <backendsCommon/test/layerTests/ReshapeTestImpl.hpp> #include <backendsCommon/test/layerTests/ResizeTestImpl.hpp> +#include <backendsCommon/test/layerTests/ReverseV2TestImpl.hpp> #include <backendsCommon/test/layerTests/RsqrtTestImpl.hpp> #include <backendsCommon/test/layerTests/ShapeTestImpl.hpp> #include <backendsCommon/test/layerTests/SinTestImpl.hpp> diff --git a/src/backends/backendsCommon/test/layerTests/ReverseV2TestImpl.cpp b/src/backends/backendsCommon/test/layerTests/ReverseV2TestImpl.cpp new file mode 100644 index 0000000000..586b831e45 --- /dev/null +++ b/src/backends/backendsCommon/test/layerTests/ReverseV2TestImpl.cpp @@ -0,0 +1,1084 @@ +// +// Copyright © 2023 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "ReverseV2TestImpl.hpp" + +#include <armnn/backends/IBackendInternal.hpp> +#include <armnn/backends/Workload.hpp> +#include <armnn/backends/WorkloadData.hpp> +#include <armnn/backends/WorkloadFactory.hpp> + +#include <armnnTestUtils/WorkloadTestUtils.hpp> +#include <armnnUtils/QuantizeHelper.hpp> +#include <armnnTestUtils/TensorCopyUtils.hpp> +#include <armnn/Optional.hpp> +#include <armnn/BackendHelper.hpp> + +namespace +{ + template<armnn::DataType ArmnnType, typename T, std::size_t NumDims> + LayerTestResult<T, NumDims> ReverseV2TestImpl( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory, + armnn::ReverseV2Descriptor descriptor, + const std::vector<T>& input, + const std::vector<T>& outputExpected, + const armnn::TensorInfo& inputInfo, + const armnn::TensorInfo& outputInfo) + { + LayerTestResult<T, NumDims> result(outputInfo); + std::vector<T> outputActual(outputInfo.GetNumElements()); + + std::unique_ptr<armnn::ITensorHandle> inputHandle = tensorHandleFactory.CreateTensorHandle(inputInfo); + std::unique_ptr<armnn::ITensorHandle> outputHandle = tensorHandleFactory.CreateTensorHandle(outputInfo); + + armnn::ReverseV2QueueDescriptor queueDescriptor; + queueDescriptor.m_Parameters = std::move(descriptor); + armnn::WorkloadInfo workloadInfo; + + AddInputToWorkload(queueDescriptor, workloadInfo, inputInfo, inputHandle.get()); + AddOutputToWorkload(queueDescriptor, workloadInfo, outputInfo, outputHandle.get()); + + // Don't execute if ReverseV2 is not supported, as an exception will be raised. + const armnn::BackendId& backend = workloadFactory.GetBackendId(); + std::string reasonIfUnsupported; + armnn::LayerSupportHandle handle = armnn::GetILayerSupportByBackendId(backend); + result.m_Supported = handle.IsReverseV2Supported(inputInfo, + outputInfo, + queueDescriptor.m_Parameters, + reasonIfUnsupported); + if (!result.m_Supported) + { + return result; + } + + auto workload = workloadFactory.CreateWorkload(armnn::LayerType::ReverseV2, queueDescriptor, workloadInfo); + + inputHandle->Allocate(); + outputHandle->Allocate(); + + CopyDataToITensorHandle(inputHandle.get(), input.data()); + + workload->PostAllocationConfigure(); + ExecuteWorkload(*workload, memoryManager); + + CopyDataFromITensorHandle(outputActual.data(), outputHandle.get()); + + return LayerTestResult<T, NumDims>(outputActual, + outputExpected, + outputHandle->GetShape(), + outputInfo.GetShape()); + } +} + +template<armnn::DataType ArmnnType, typename T> +LayerTestResult<T, 2> ReverseV2SimpleTestEmptyAxis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + // Simple test with default descriptor. No axes set so output is the same as input + auto descriptor = armnn::ReverseV2Descriptor(); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorInfo inputInfo({2,2}, ArmnnType, qScale, qOffset); + armnn::TensorInfo outputInfo({2,2}, ArmnnType, qScale, qOffset); + + std::vector<T> input = armnnUtils::QuantizedVector<T>({ + 1, 2, + 3, 4 + }, qScale, qOffset); + + std::vector<T> outputExpected = armnnUtils::QuantizedVector<T>({ + 1, 2, + 3, 4 + }, qScale, qOffset); + + return ReverseV2TestImpl<ArmnnType, T, 2>(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + input, + outputExpected, + inputInfo, + outputInfo); +} + +template<armnn::DataType ArmnnType, typename T> +LayerTestResult<T, 2> ReverseV2SimpleTestEmptyTensor( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + // Simple test with default descriptor. Empty tensor set so output is the same as input + auto descriptor = armnn::ReverseV2Descriptor(); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorInfo inputInfo({0}, ArmnnType, qScale, qOffset); + armnn::TensorInfo outputInfo({0}, ArmnnType, qScale, qOffset); + + std::vector<T> input = armnnUtils::QuantizedVector<T>({}, qScale, qOffset); + + std::vector<T> outputExpected = armnnUtils::QuantizedVector<T>({}, qScale, qOffset); + + return ReverseV2TestImpl<ArmnnType, T, 2>(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + input, + outputExpected, + inputInfo, + outputInfo); +} + +template<armnn::DataType ArmnnType, typename T> +LayerTestResult<T, 2> ReverseV2SimpleTest1Dim( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + auto descriptor = armnn::ReverseV2Descriptor(std::vector<int> {0}); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorInfo inputInfo({4}, ArmnnType, qScale, qOffset); + armnn::TensorInfo outputInfo({4}, ArmnnType, qScale, qOffset); + + std::vector<T> input = armnnUtils::QuantizedVector<T>({ + 1, 2, + 3, 4 + }, qScale, qOffset); + + std::vector<T> outputExpected = armnnUtils::QuantizedVector<T>({ + 4, 3, + 2, 1 + }, qScale, qOffset); + + return ReverseV2TestImpl<ArmnnType, T, 2>(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + input, + outputExpected, + inputInfo, + outputInfo); +} + +template<armnn::DataType ArmnnType, typename T> +LayerTestResult<T, 2> ReverseV2SimpleTest2Dim1Axis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + auto descriptor = armnn::ReverseV2Descriptor(std::vector<int> {1}); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorInfo inputInfo({2,2}, ArmnnType, qScale, qOffset); + armnn::TensorInfo outputInfo({2,2}, ArmnnType, qScale, qOffset); + + std::vector<T> input = armnnUtils::QuantizedVector<T>({ + 1, 2, + 3, 4 + }, qScale, qOffset); + + std::vector<T> outputExpected = armnnUtils::QuantizedVector<T>({ + 2, 1, + 4, 3 + }, qScale, qOffset); + + return ReverseV2TestImpl<ArmnnType, T, 2>(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + input, + outputExpected, + inputInfo, + outputInfo); +} + +template<armnn::DataType ArmnnType, typename T> +LayerTestResult<T, 2> ReverseV2SimpleTest2Dim2Axis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + auto descriptor = armnn::ReverseV2Descriptor(std::vector<int> {1, 0}); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorInfo inputInfo({2,2}, ArmnnType, qScale, qOffset); + armnn::TensorInfo outputInfo({2,2}, ArmnnType, qScale, qOffset); + + std::vector<T> input = armnnUtils::QuantizedVector<T>({ + 1, 2, + 3, 4 + }, qScale, qOffset); + + std::vector<T> outputExpected = armnnUtils::QuantizedVector<T>({ + 4, 3, + 2, 1 + }, qScale, qOffset); + + return ReverseV2TestImpl<ArmnnType, T, 2>(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + input, + outputExpected, + inputInfo, + outputInfo); +} + +template<armnn::DataType ArmnnType, typename T> +LayerTestResult<T, 2> ReverseV2SimpleTest3Dim1Axis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + auto descriptor = armnn::ReverseV2Descriptor(std::vector<int> {1}); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorInfo inputInfo({2, 3, 4}, ArmnnType, qScale, qOffset); + armnn::TensorInfo outputInfo({2, 3, 4}, ArmnnType, qScale, qOffset); + + std::vector<T> input = armnnUtils::QuantizedVector<T>({ + 1, 2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12, + 13, 14, 15, 16, + 17, 18, 19, 20, + 21, 22, 23, 24 + }, qScale, qOffset); + + std::vector<T> outputExpected = armnnUtils::QuantizedVector<T>({ + 9, 10, 11, 12, + 5, 6, 7, 8, + 1, 2, 3, 4, + 21, 22, 23, 24, + 17, 18, 19, 20, + 13, 14, 15, 16 + }, qScale, qOffset); + + return ReverseV2TestImpl<ArmnnType, T, 2>(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + input, + outputExpected, + inputInfo, + outputInfo); +} + +template<armnn::DataType ArmnnType, typename T> +LayerTestResult<T, 2> ReverseV2SimpleTest3Dim2Axis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + auto descriptor = armnn::ReverseV2Descriptor(std::vector<int> {0, 1}); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorInfo inputInfo({2, 3, 4}, ArmnnType, qScale, qOffset); + armnn::TensorInfo outputInfo({2, 3, 4}, ArmnnType, qScale, qOffset); + + std::vector<T> input = armnnUtils::QuantizedVector<T>({ + 1, 2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12, + 13, 14, 15, 16, + 17, 18, 19, 20, + 21, 22, 23, 24 + }, qScale, qOffset); + + std::vector<T> outputExpected = armnnUtils::QuantizedVector<T>({ + 21, 22, 23, 24, + 17, 18, 19, 20, + 13, 14, 15, 16, + 9, 10, 11, 12, + 5, 6, 7, 8, + 1, 2, 3, 4 + }, qScale, qOffset); + + return ReverseV2TestImpl<ArmnnType, T, 2>(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + input, + outputExpected, + inputInfo, + outputInfo); +} + +template<armnn::DataType ArmnnType, typename T> +LayerTestResult<T, 2> ReverseV2SimpleTest3Dim3Axis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + // Simple test with default descriptor. No axes set so output is + // the same as input + auto descriptor = armnn::ReverseV2Descriptor(std::vector<int> {1, 0, 2}); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorInfo inputInfo({2, 3, 4}, ArmnnType, qScale, qOffset); + armnn::TensorInfo outputInfo({2, 3, 4}, ArmnnType, qScale, qOffset); + + std::vector<T> input = armnnUtils::QuantizedVector<T>({ + 1, 2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12, + 13, 14, 15, 16, + 17, 18, 19, 20, + 21, 22, 23, 24 + }, qScale, qOffset); + + std::vector<T> outputExpected = armnnUtils::QuantizedVector<T>({ + 24, 23, 22, 21, + 20, 19, 18, 17, + 16, 15, 14, 13, + 12, 11, 10, 9, + 8, 7, 6, 5, + 4, 3, 2, 1 + }, qScale, qOffset); + + return ReverseV2TestImpl<ArmnnType, T, 2>(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + input, + outputExpected, + inputInfo, + outputInfo); +} + +template<armnn::DataType ArmnnType, typename T> +LayerTestResult<T, 2> ReverseV2SimpleTest4Dim1Axis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + // Simple test with default descriptor. No axes set so output is + // the same as input + auto descriptor = armnn::ReverseV2Descriptor(std::vector<int> {0}); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorInfo inputInfo({2, 2, 2, 3}, ArmnnType, qScale, qOffset); + armnn::TensorInfo outputInfo({2, 2, 2, 3}, ArmnnType, qScale, qOffset); + + std::vector<T> input = armnnUtils::QuantizedVector<T>({ + 1, 2, 3, + 4, 5, 6, + 7, 8, 9, + 10, 11, 12, + 13, 14, 15, + 16, 17, 18, + 19, 20, 21, + 22, 23, 24 + }, qScale, qOffset); + + std::vector<T> outputExpected = armnnUtils::QuantizedVector<T>({ + 13, 14, 15, + 16, 17, 18, + 19, 20, 21, + 22, 23, 24, + 1, 2, 3, + 4, 5, 6, + 7, 8, 9, + 10, 11, 12 + }, qScale, qOffset); + + return ReverseV2TestImpl<ArmnnType, T, 2>(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + input, + outputExpected, + inputInfo, + outputInfo); +} + +template<armnn::DataType ArmnnType, typename T> +LayerTestResult<T, 2> ReverseV2SimpleTest4Dim2Axis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + // Simple test with default descriptor. No axes set so output is + // the same as input + auto descriptor = armnn::ReverseV2Descriptor(std::vector<int> {0, 1}); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorInfo inputInfo({2, 2, 2, 3}, ArmnnType, qScale, qOffset); + armnn::TensorInfo outputInfo({2, 2, 2, 3}, ArmnnType, qScale, qOffset); + + std::vector<T> input = armnnUtils::QuantizedVector<T>({ + 1, 2, 3, + 4, 5, 6, + 7, 8, 9, + 10, 11, 12, + 13, 14, 15, + 16, 17, 18, + 19, 20, 21, + 22, 23, 24 + }, qScale, qOffset); + + std::vector<T> outputExpected = armnnUtils::QuantizedVector<T>({ + 19, 20, 21, + 22, 23, 24, + 13, 14, 15, + 16, 17, 18, + 7, 8, 9, + 10, 11, 12, + 1, 2, 3, + 4, 5, 6 + }, qScale, qOffset); + + return ReverseV2TestImpl<ArmnnType, T, 2>(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + input, + outputExpected, + inputInfo, + outputInfo); +} + +template<armnn::DataType ArmnnType, typename T> +LayerTestResult<T, 2> ReverseV2SimpleTest4Dim3Axis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + // Simple test with default descriptor. No axes set so output is + // the same as input + auto descriptor = armnn::ReverseV2Descriptor(std::vector<int> {0, 1, 2}); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorInfo inputInfo({2, 2, 2, 3}, ArmnnType, qScale, qOffset); + armnn::TensorInfo outputInfo({2, 2, 2, 3}, ArmnnType, qScale, qOffset); + + std::vector<T> input = armnnUtils::QuantizedVector<T>({ + 1, 2, 3, + 4, 5, 6, + 7, 8, 9, + 10, 11, 12, + 13, 14, 15, + 16, 17, 18, + 19, 20, 21, + 22, 23, 24 + }, qScale, qOffset); + + std::vector<T> outputExpected = armnnUtils::QuantizedVector<T>({ + 22, 23, 24, + 19, 20, 21, + 16, 17, 18, + 13, 14, 15, + 10, 11, 12, + 7, 8, 9, + 4, 5, 6, + 1, 2, 3 + }, qScale, qOffset); + + return ReverseV2TestImpl<ArmnnType, T, 2>(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + input, + outputExpected, + inputInfo, + outputInfo); +} + +template<armnn::DataType ArmnnType, typename T> +LayerTestResult<T, 2> ReverseV2SimpleTest4Dim4Axis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + // Simple test with default descriptor. No axes set so output is + // the same as input + auto descriptor = armnn::ReverseV2Descriptor(std::vector<int> {0, 1, 2, 3}); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorInfo inputInfo({2, 2, 2, 3}, ArmnnType, qScale, qOffset); + armnn::TensorInfo outputInfo({2, 2, 2, 3}, ArmnnType, qScale, qOffset); + + std::vector<T> input = armnnUtils::QuantizedVector<T>({ + 1, 2, 3, + 4, 5, 6, + 7, 8, 9, + 10, 11, 12, + 13, 14, 15, + 16, 17, 18, + 19, 20, 21, + 22, 23, 24 + }, qScale, qOffset); + + std::vector<T> outputExpected = armnnUtils::QuantizedVector<T>({ + 24, 23, 22, + 21, 20, 19, + 18, 17, 16, + 15, 14, 13, + 12, 11, 10, + 9, 8, 7, + 6, 5, 4, + 3, 2, 1 + }, qScale, qOffset); + + return ReverseV2TestImpl<ArmnnType, T, 2>(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + input, + outputExpected, + inputInfo, + outputInfo); +} + +template<armnn::DataType ArmnnType, typename T> +LayerTestResult<T, 2> ReverseV2EvenRowOddColTest2Dim( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + // Simple test with default descriptor. No axes set so output is the same as input + auto descriptor = armnn::ReverseV2Descriptor(std::vector<int> {1}); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorInfo inputInfo({2, 3}, ArmnnType, qScale, qOffset); + armnn::TensorInfo outputInfo({2, 3}, ArmnnType, qScale, qOffset); + + std::vector<T> input = armnnUtils::QuantizedVector<T>({ + 1, 2, 3, + 4, 5, 6 + }, qScale, qOffset); + + std::vector<T> outputExpected = armnnUtils::QuantizedVector<T>({ + 3, 2, 1, + 6, 5, 4 + }, qScale, qOffset); + + return ReverseV2TestImpl<ArmnnType, T, 2>(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + input, + outputExpected, + inputInfo, + outputInfo); +} + +template<armnn::DataType ArmnnType, typename T> +LayerTestResult<T, 2> ReverseV2EvenRowOddColTest3Dim( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + // Simple test with default descriptor. No axes set so output is + // the same as input + auto descriptor = armnn::ReverseV2Descriptor(std::vector<int> {1}); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorInfo inputInfo({2, 3, 1}, ArmnnType, qScale, qOffset); + armnn::TensorInfo outputInfo({2, 3, 1}, ArmnnType, qScale, qOffset); + + std::vector<T> input = armnnUtils::QuantizedVector<T>({ + 1, 2, 3, + 4, 5, 6 + }, qScale, qOffset); + + std::vector<T> outputExpected = armnnUtils::QuantizedVector<T>({ + 3, 2, 1, + 6, 5, 4 + }, qScale, qOffset); + + return ReverseV2TestImpl<ArmnnType, T, 2>(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + input, + outputExpected, + inputInfo, + outputInfo); +} + +template<armnn::DataType ArmnnType, typename T> +LayerTestResult<T, 2> ReverseV2EvenRowEvenColTest2Dim( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + // Simple test with default descriptor. No axes set so output is + // the same as input + auto descriptor = armnn::ReverseV2Descriptor(std::vector<int> {1}); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorInfo inputInfo({2, 4}, ArmnnType, qScale, qOffset); + armnn::TensorInfo outputInfo({2, 4}, ArmnnType, qScale, qOffset); + + std::vector<T> input = armnnUtils::QuantizedVector<T>({ + 1, 2, 3, 4, + 5, 6, 7, 8 + }, qScale, qOffset); + + std::vector<T> outputExpected = armnnUtils::QuantizedVector<T>({ + 4, 3, 2, 1, + 8, 7, 6, 5 + }, qScale, qOffset); + + return ReverseV2TestImpl<ArmnnType, T, 2>(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + input, + outputExpected, + inputInfo, + outputInfo); +} + +template<armnn::DataType ArmnnType, typename T> +LayerTestResult<T, 2> ReverseV2EvenRowEvenColTest3Dim( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + // Simple test with default descriptor. No axes set so output is + // the same as input + auto descriptor = armnn::ReverseV2Descriptor(std::vector<int> {1}); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorInfo inputInfo({2, 4, 1}, ArmnnType, qScale, qOffset); + armnn::TensorInfo outputInfo({2, 4, 1}, ArmnnType, qScale, qOffset); + + std::vector<T> input = armnnUtils::QuantizedVector<T>({ + 1, 2, 3, 4, + 5, 6, 7, 8 + }, qScale, qOffset); + + std::vector<T> outputExpected = armnnUtils::QuantizedVector<T>({ + 4, 3, 2, 1, + 8, 7, 6, 5 + }, qScale, qOffset); + + return ReverseV2TestImpl<ArmnnType, T, 2>(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + input, + outputExpected, + inputInfo, + outputInfo); +} + +template<armnn::DataType ArmnnType, typename T> +LayerTestResult<T, 2> ReverseV2OddRowOddColTest2Dim( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + // Simple test with default descriptor. No axes set so output is + // the same as input + auto descriptor = armnn::ReverseV2Descriptor(std::vector<int> {1}); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorInfo inputInfo({3, 3}, ArmnnType, qScale, qOffset); + armnn::TensorInfo outputInfo({3, 3}, ArmnnType, qScale, qOffset); + + std::vector<T> input = armnnUtils::QuantizedVector<T>({ + 1, 2, 3, + 4, 5, 6, + 7, 8, 9 + }, qScale, qOffset); + + std::vector<T> outputExpected = armnnUtils::QuantizedVector<T>({ + 3, 2, 1, + 6, 5, 4, + 9, 8, 7 + }, qScale, qOffset); + + return ReverseV2TestImpl<ArmnnType, T, 2>(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + input, + outputExpected, + inputInfo, + outputInfo); +} + +template<armnn::DataType ArmnnType, typename T> +LayerTestResult<T, 2> ReverseV2OddRowOddColTest3Dim( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + // Simple test with default descriptor. No axes set so output is + // the same as input + auto descriptor = armnn::ReverseV2Descriptor(std::vector<int> {1}); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorInfo inputInfo({3, 3, 1}, ArmnnType, qScale, qOffset); + armnn::TensorInfo outputInfo({3, 3, 1}, ArmnnType, qScale, qOffset); + + std::vector<T> input = armnnUtils::QuantizedVector<T>({ + 1, 2, 3, + 4, 5, 6, + 7, 8, 9 + }, qScale, qOffset); + + std::vector<T> outputExpected = armnnUtils::QuantizedVector<T>({ + 3, 2, 1, + 6, 5, 4, + 9, 8, 7 + }, qScale, qOffset); + + return ReverseV2TestImpl<ArmnnType, T, 2>(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + input, + outputExpected, + inputInfo, + outputInfo); +} + +template<armnn::DataType ArmnnType, typename T> +LayerTestResult<T, 2> ReverseV2OddRowEvenColTest2Dim( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + // Simple test with default descriptor. No axes set so output is + // the same as input + auto descriptor = armnn::ReverseV2Descriptor(std::vector<int> {1}); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorInfo inputInfo({3, 4}, ArmnnType, qScale, qOffset); + armnn::TensorInfo outputInfo({3, 4}, ArmnnType, qScale, qOffset); + + std::vector<T> input = armnnUtils::QuantizedVector<T>({ + 1, 2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12 + }, qScale, qOffset); + + std::vector<T> outputExpected = armnnUtils::QuantizedVector<T>({ + 4, 3, 2, 1, + 8, 7, 6, 5, + 12, 11, 10, 9 + }, qScale, qOffset); + + return ReverseV2TestImpl<ArmnnType, T, 2>(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + input, + outputExpected, + inputInfo, + outputInfo); +} + +template<armnn::DataType ArmnnType, typename T> +LayerTestResult<T, 2> ReverseV2OddRowEvenColTest3Dim( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + // Simple test with default descriptor. No axes set so output is + // the same as input + auto descriptor = armnn::ReverseV2Descriptor(std::vector<int> {1}); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorInfo inputInfo({3, 4, 1}, ArmnnType, qScale, qOffset); + armnn::TensorInfo outputInfo({3, 4, 1}, ArmnnType, qScale, qOffset); + + std::vector<T> input = armnnUtils::QuantizedVector<T>({ + 1, 2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12 + }, qScale, qOffset); + + std::vector<T> outputExpected = armnnUtils::QuantizedVector<T>({ + 4, 3, 2, 1, + 8, 7, 6, 5, + 12, 11, 10, 9 + }, qScale, qOffset); + + return ReverseV2TestImpl<ArmnnType, T, 2>(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + input, + outputExpected, + inputInfo, + outputInfo); +} + +template<armnn::DataType ArmnnType, typename T> +LayerTestResult<T, 2> ReverseV2NegAxisTest2Dim1Axis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + // Simple test with default descriptor. No axes set so output is + // the same as input + auto descriptor = armnn::ReverseV2Descriptor(std::vector<int> {-1}); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorInfo inputInfo({2, 4}, ArmnnType, qScale, qOffset); + armnn::TensorInfo outputInfo({2, 4}, ArmnnType, qScale, qOffset); + + std::vector<T> input = armnnUtils::QuantizedVector<T>({ + 1, 2, 3, 4, + 5, 6, 7, 8, + }, qScale, qOffset); + + std::vector<T> outputExpected = armnnUtils::QuantizedVector<T>({ + 4, 3, 2, 1, + 8, 7, 6, 5 + }, qScale, qOffset); + + return ReverseV2TestImpl<ArmnnType, T, 2>(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + input, + outputExpected, + inputInfo, + outputInfo); +} + +template<armnn::DataType ArmnnType, typename T> +LayerTestResult<T, 2> ReverseV2NegAxisTest3Dim2Axis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + // Simple test with default descriptor. No axes set so output is + // the same as input + auto descriptor = armnn::ReverseV2Descriptor(std::vector<int> {1, -1}); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorInfo inputInfo({2, 4, 1}, ArmnnType, qScale, qOffset); + armnn::TensorInfo outputInfo({2, 4, 1}, ArmnnType, qScale, qOffset); + + std::vector<T> input = armnnUtils::QuantizedVector<T>({ + 1, 2, 3, 4, + 5, 6, 7, 8, + }, qScale, qOffset); + + std::vector<T> outputExpected = armnnUtils::QuantizedVector<T>({ + 4, 3, 2, 1, + 8, 7, 6, 5 + }, qScale, qOffset); + + return ReverseV2TestImpl<ArmnnType, T, 2>(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + input, + outputExpected, + inputInfo, + outputInfo); +} + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 2> +ReverseV2SimpleTestEmptyAxis<armnn::DataType::Float32>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 2> +ReverseV2SimpleTestEmptyTensor<armnn::DataType::Float32>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 2> +ReverseV2SimpleTest1Dim<armnn::DataType::Float32>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 2> +ReverseV2SimpleTest2Dim1Axis<armnn::DataType::Float32>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 2> +ReverseV2SimpleTest2Dim2Axis<armnn::DataType::Float32>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 2> +ReverseV2SimpleTest3Dim1Axis<armnn::DataType::Float32>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 2> +ReverseV2SimpleTest3Dim2Axis<armnn::DataType::Float32>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 2> +ReverseV2SimpleTest3Dim3Axis<armnn::DataType::Float32>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 2> +ReverseV2SimpleTest4Dim1Axis<armnn::DataType::Float32>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 2> +ReverseV2SimpleTest4Dim2Axis<armnn::DataType::Float32>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 2> +ReverseV2SimpleTest4Dim3Axis<armnn::DataType::Float32>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 2> +ReverseV2SimpleTest4Dim4Axis<armnn::DataType::Float32>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 2> +ReverseV2EvenRowOddColTest2Dim<armnn::DataType::Float32>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 2> +ReverseV2EvenRowOddColTest3Dim<armnn::DataType::Float32>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 2> +ReverseV2EvenRowEvenColTest2Dim<armnn::DataType::Float32>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 2> +ReverseV2EvenRowEvenColTest3Dim<armnn::DataType::Float32>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 2> +ReverseV2OddRowOddColTest2Dim<armnn::DataType::Float32>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 2> +ReverseV2OddRowOddColTest3Dim<armnn::DataType::Float32>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 2> +ReverseV2OddRowEvenColTest2Dim<armnn::DataType::Float32>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 2> +ReverseV2OddRowEvenColTest3Dim<armnn::DataType::Float32>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 2> +ReverseV2NegAxisTest2Dim1Axis<armnn::DataType::Float32>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 2> +ReverseV2NegAxisTest3Dim2Axis<armnn::DataType::Float32>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::Float16>, 2> +ReverseV2SimpleTest2Dim2Axis<armnn::DataType::Float16>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::QAsymmS8>, 2> +ReverseV2SimpleTest2Dim2Axis<armnn::DataType::QAsymmS8>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::QAsymmU8>, 2> +ReverseV2SimpleTest2Dim2Axis<armnn::DataType::QAsymmU8>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult<armnn::ResolveType<armnn::DataType::QSymmS16>, 2> +ReverseV2SimpleTest2Dim2Axis<armnn::DataType::QSymmS16>( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory);
\ No newline at end of file diff --git a/src/backends/backendsCommon/test/layerTests/ReverseV2TestImpl.hpp b/src/backends/backendsCommon/test/layerTests/ReverseV2TestImpl.hpp new file mode 100644 index 0000000000..a40e7734a0 --- /dev/null +++ b/src/backends/backendsCommon/test/layerTests/ReverseV2TestImpl.hpp @@ -0,0 +1,156 @@ +// +// Copyright © 2023 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include <armnnTestUtils/LayerTestResult.hpp> + +#include <ResolveType.hpp> + +#include <armnn/backends/IBackendInternal.hpp> + +// Empty test cases + +template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>> +LayerTestResult<T, 2> ReverseV2SimpleTestEmptyAxis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>> +LayerTestResult<T, 2> ReverseV2SimpleTestEmptyTensor( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +// Multidimensional input tensor and multi-axis tests +// These test cases are conducted with even-row-even-column input tensors + +template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>> +LayerTestResult<T, 2> ReverseV2SimpleTest1Dim( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>> +LayerTestResult<T, 2> ReverseV2SimpleTest2Dim1Axis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>> +LayerTestResult<T, 2> ReverseV2SimpleTest2Dim2Axis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>> +LayerTestResult<T, 2> ReverseV2SimpleTest3Dim1Axis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>> +LayerTestResult<T, 2> ReverseV2SimpleTest3Dim2Axis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>> +LayerTestResult<T, 2> ReverseV2SimpleTest3Dim3Axis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>> +LayerTestResult<T, 2> ReverseV2SimpleTest4Dim1Axis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>> +LayerTestResult<T, 2> ReverseV2SimpleTest4Dim2Axis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>> +LayerTestResult<T, 2> ReverseV2SimpleTest4Dim3Axis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>> +LayerTestResult<T, 2> ReverseV2SimpleTest4Dim4Axis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +// Even and odd row number tests +// These tests are conducted with 1-axis input param + +template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>> +LayerTestResult<T, 2> ReverseV2EvenRowOddColTest2Dim( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>> +LayerTestResult<T, 2> ReverseV2EvenRowOddColTest3Dim( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>> +LayerTestResult<T, 2> ReverseV2EvenRowEvenColTest2Dim( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>> +LayerTestResult<T, 2> ReverseV2EvenRowEvenColTest3Dim( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>> +LayerTestResult<T, 2> ReverseV2OddRowOddColTest2Dim( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>> +LayerTestResult<T, 2> ReverseV2OddRowOddColTest3Dim( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>> +LayerTestResult<T, 2> ReverseV2OddRowEvenColTest2Dim( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>> +LayerTestResult<T, 2> ReverseV2OddRowEvenColTest3Dim( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +// Negative axis input tests with even-row-even-column input + +// one negative axis +template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>> +LayerTestResult<T, 2> ReverseV2NegAxisTest2Dim1Axis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +// one negative and one positive axis +template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>> +LayerTestResult<T, 2> ReverseV2NegAxisTest3Dim2Axis( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory);
\ No newline at end of file diff --git a/src/backends/reference/RefLayerSupport.cpp b/src/backends/reference/RefLayerSupport.cpp index 81e5c837a5..1d5fab1adc 100644 --- a/src/backends/reference/RefLayerSupport.cpp +++ b/src/backends/reference/RefLayerSupport.cpp @@ -341,6 +341,11 @@ bool RefLayerSupport::IsLayerSupported(const LayerType& type, infos[1], *(PolymorphicDowncast<const ResizeDescriptor*>(&descriptor)), reasonIfUnsupported); + case LayerType::ReverseV2: + return IsReverseV2Supported(infos[0], + infos[1], + *(PolymorphicDowncast<const ReverseV2Descriptor*>(&descriptor)), + reasonIfUnsupported); case LayerType::Reduce: return IsReduceSupported(infos[0], infos[1], @@ -2356,6 +2361,36 @@ bool RefLayerSupport::IsResizeSupported(const TensorInfo& input, return supported; } +bool RefLayerSupport::IsReverseV2Supported(const TensorInfo& input, + const TensorInfo& output, + const ReverseV2Descriptor& descriptor, + Optional<std::string&> reasonIfUnsupported) const +{ + IgnoreUnused(descriptor); + bool supported = true; + // ReverseV2 is data type agnostic so it can support all the types in the Reference backend + std::array<DataType,6> supportedTypes = + { + DataType::BFloat16, + DataType::Float32, + DataType::Float16, + DataType::QAsymmS8, + DataType::QAsymmU8, + DataType::QSymmS16 + }; + + supported &= CheckSupportRule(TypeAnyOf(input, supportedTypes), reasonIfUnsupported, + "Reference ReverseV2: input type not supported"); + + supported &= CheckSupportRule(TypeAnyOf(output, supportedTypes), reasonIfUnsupported, + "Reference ReverseV2: output type not supported"); + + supported &= CheckSupportRule(TypesAreEqual(input, output), reasonIfUnsupported, + "Reference ReverseV2: input and output types not matching"); + + return supported; +} + bool RefLayerSupport::IsShapeSupported(const TensorInfo& input, const TensorInfo& output, Optional<std::string&> reasonIfUnsupported) const diff --git a/src/backends/reference/RefLayerSupport.hpp b/src/backends/reference/RefLayerSupport.hpp index 8e1f68ebfc..0afb9c2c94 100644 --- a/src/backends/reference/RefLayerSupport.hpp +++ b/src/backends/reference/RefLayerSupport.hpp @@ -299,6 +299,11 @@ public: const ResizeDescriptor& descriptor, Optional<std::string&> reasonIfUnsupported = EmptyOptional()) const override; + bool IsReverseV2Supported(const TensorInfo& input, + const TensorInfo& output, + const ReverseV2Descriptor& descriptor, + Optional<std::string&> reasonIfUnsupported = EmptyOptional()) const; + bool IsShapeSupported(const TensorInfo& input, const TensorInfo& output, Optional<std::string&> reasonIfUnsupported = EmptyOptional()) const override; diff --git a/src/backends/reference/RefWorkloadFactory.cpp b/src/backends/reference/RefWorkloadFactory.cpp index 10f623eef3..7d5f742126 100644 --- a/src/backends/reference/RefWorkloadFactory.cpp +++ b/src/backends/reference/RefWorkloadFactory.cpp @@ -560,6 +560,11 @@ std::unique_ptr<IWorkload> RefWorkloadFactory::CreateWorkload(LayerType type, auto resizeQueueDescriptor = PolymorphicDowncast<const ResizeQueueDescriptor*>(&descriptor); return std::make_unique<RefResizeWorkload>(*resizeQueueDescriptor, info); } + case LayerType::ReverseV2: + { + auto reverseV2QueueDescriptor = PolymorphicDowncast<const ReverseV2QueueDescriptor*>(&descriptor); + return std::make_unique<RefReverseV2Workload>(*reverseV2QueueDescriptor, info); + } case LayerType::Shape: { auto shapeQueueDescriptor = PolymorphicDowncast<const ShapeQueueDescriptor*>(&descriptor); diff --git a/src/backends/reference/backend.mk b/src/backends/reference/backend.mk index c23984c3e9..dfafa0ac39 100644 --- a/src/backends/reference/backend.mk +++ b/src/backends/reference/backend.mk @@ -1,5 +1,5 @@ # -# Copyright © 2017 ARM Ltd. All rights reserved. +# Copyright © 2017-2023 ARM Ltd and Contributors. All rights reserved. # SPDX-License-Identifier: MIT # @@ -94,6 +94,7 @@ BACKEND_SOURCES := \ workloads/RefReduceWorkload.cpp \ workloads/RefReshapeWorkload.cpp \ workloads/RefResizeWorkload.cpp \ + workloads/RefReverseV2Workload.cpp \ workloads/RefSliceWorkload.cpp \ workloads/RefSoftmaxWorkload.cpp \ workloads/RefSpaceToBatchNdWorkload.cpp \ @@ -105,6 +106,7 @@ BACKEND_SOURCES := \ workloads/RefTransposeWorkload.cpp \ workloads/RefUnidirectionalSequenceLstmWorkload.cpp \ workloads/Resize.cpp \ + workloads/ReverseV2Impl.cpp \ workloads/Slice.cpp \ workloads/SpaceToBatchNd.cpp \ workloads/SpaceToDepth.cpp \ diff --git a/src/backends/reference/test/RefLayerTests.cpp b/src/backends/reference/test/RefLayerTests.cpp index 6e697723e9..a68775e8e9 100644 --- a/src/backends/reference/test/RefLayerTests.cpp +++ b/src/backends/reference/test/RefLayerTests.cpp @@ -1565,6 +1565,37 @@ ARMNN_AUTO_TEST_CASE_WITH_THF(AlignCornersResizeNearestNeighbourUint16Nchw, AlignCornersResizeNearestNeighbourTest<DataType::QSymmS16>, DataLayout::NCHW) +// ReverseV2 +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2SimpleEmptyAxisFloat32, ReverseV2SimpleTestEmptyAxis<DataType::Float32>) +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2SimpleEmptyTensorFloat32, ReverseV2SimpleTestEmptyTensor <DataType::Float32>) +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2Simple1DimFloat32, ReverseV2SimpleTest1Dim<DataType::Float32>) +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2Simple2Dim1AxisFloat32, ReverseV2SimpleTest2Dim1Axis<DataType::Float32>) +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2Simple2Dim2AxisFloat32, ReverseV2SimpleTest2Dim2Axis<DataType::Float32>) +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2Simple3Dim1AxisFloat32, ReverseV2SimpleTest3Dim1Axis<DataType::Float32>) +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2Simple3Dim2AxisFloat32, ReverseV2SimpleTest3Dim2Axis<DataType::Float32>) +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2Simple3Dim3AxisFloat32, ReverseV2SimpleTest3Dim3Axis<DataType::Float32>) +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2Simple4Dim1AxisFloat32, ReverseV2SimpleTest4Dim1Axis<DataType::Float32>) +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2Simple4Dim2AxisFloat32, ReverseV2SimpleTest4Dim2Axis<DataType::Float32>) +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2Simple4Dim3AxisFloat32, ReverseV2SimpleTest4Dim3Axis<DataType::Float32>) +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2Simple4Dim4AxisFloat32, ReverseV2SimpleTest4Dim4Axis<DataType::Float32>) + +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2EvenRowOddCol2DimFloat32, ReverseV2EvenRowOddColTest2Dim<DataType::Float32>) +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2EvenRowOddCol3DimFloat32, ReverseV2EvenRowOddColTest3Dim<DataType::Float32>) +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2EvenRowEvenCol2DimFloat32, ReverseV2EvenRowEvenColTest2Dim<DataType::Float32>) +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2EvenRowEvenCol3DimFloat32, ReverseV2EvenRowEvenColTest3Dim<DataType::Float32>) +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2OddRowOddCol2DimFloat32, ReverseV2OddRowOddColTest2Dim<DataType::Float32>) +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2OddRowOddCol3DimFloat32, ReverseV2OddRowOddColTest3Dim<DataType::Float32>) +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2OddRowEvenCol2DimFloat32, ReverseV2OddRowEvenColTest2Dim<DataType::Float32>) +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2OddRowEvenCol3DimFloat32, ReverseV2OddRowEvenColTest3Dim<DataType::Float32>) + +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2NegAxis2Dim1AxisFloat32, ReverseV2NegAxisTest2Dim1Axis<DataType::Float32>) +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2NegAxis3Dim2AxisFloat32, ReverseV2NegAxisTest3Dim2Axis<DataType::Float32>) + +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2Simple2Dim2AxisFloat16, ReverseV2SimpleTest2Dim2Axis<DataType::Float16>) +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2Simple2Dim2AxisQAsymmS8, ReverseV2SimpleTest2Dim2Axis<DataType::QAsymmS8>) +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2Simple2Dim2AxisQAsymmU8, ReverseV2SimpleTest2Dim2Axis<DataType::QAsymmU8>) +ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2Simple2Dim2AxisQSymmS16, ReverseV2SimpleTest2Dim2Axis<DataType::QSymmS16>) + // Fake Quantization ARMNN_AUTO_TEST_CASE_WITH_THF(FakeQuantization, FakeQuantizationTest) diff --git a/src/backends/reference/workloads/CMakeLists.txt b/src/backends/reference/workloads/CMakeLists.txt index 3592f2293d..28f6d2f371 100644 --- a/src/backends/reference/workloads/CMakeLists.txt +++ b/src/backends/reference/workloads/CMakeLists.txt @@ -66,6 +66,8 @@ list(APPEND armnnRefBackendWorkloads_sources PreluImpl.hpp Reduce.cpp Reduce.hpp + ReverseV2Impl.cpp + ReverseV2Impl.hpp RefActivationWorkload.cpp RefActivationWorkload.hpp RefArgMinMaxWorkload.cpp @@ -161,6 +163,8 @@ list(APPEND armnnRefBackendWorkloads_sources RefReshapeWorkload.hpp RefResizeWorkload.cpp RefResizeWorkload.hpp + RefReverseV2Workload.cpp + RefReverseV2Workload.hpp RefShapeWorkload.hpp RefSliceWorkload.cpp RefSliceWorkload.hpp diff --git a/src/backends/reference/workloads/RefReverseV2Workload.cpp b/src/backends/reference/workloads/RefReverseV2Workload.cpp new file mode 100644 index 0000000000..cd2d9f930b --- /dev/null +++ b/src/backends/reference/workloads/RefReverseV2Workload.cpp @@ -0,0 +1,48 @@ +// +// Copyright © 2023 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "RefReverseV2Workload.hpp" + +#include "ReverseV2Impl.hpp" +#include "RefWorkloadUtils.hpp" +#include "Profiling.hpp" + +namespace armnn +{ + + RefReverseV2Workload::RefReverseV2Workload(const ReverseV2QueueDescriptor& descriptor, const WorkloadInfo& info) + : RefBaseWorkload(descriptor, info) + {} + + void RefReverseV2Workload::Execute() const + { + Execute(m_Data.m_Inputs, m_Data.m_Outputs); + } + + void RefReverseV2Workload::ExecuteAsync(ExecutionData& executionData) + { + WorkingMemDescriptor* workingMemDescriptor = static_cast<WorkingMemDescriptor*>(executionData.m_Data); + Execute(workingMemDescriptor->m_Inputs, workingMemDescriptor->m_Outputs); + } + + void RefReverseV2Workload::Execute(std::vector<ITensorHandle*> inputs, std::vector<ITensorHandle*> outputs) const + { + ARMNN_SCOPED_PROFILING_EVENT(Compute::CpuRef, "RefReverseV2Workload_Execute"); + + const TensorInfo& inputInfo = GetTensorInfo(inputs[0]); + + std::unique_ptr<Decoder<float>> inputDecoder = MakeDecoder<float>(GetTensorInfo(inputs[0]), + inputs[0]->Map()); + + std::unique_ptr<Encoder<float>> outputEncoder = MakeEncoder<float>(GetTensorInfo(outputs[0]), + outputs[0]->Map()); + + ReverseV2(m_Data.m_Parameters, + inputInfo, + *inputDecoder, + *outputEncoder); + } + +} // namespace armnn
\ No newline at end of file diff --git a/src/backends/reference/workloads/RefReverseV2Workload.hpp b/src/backends/reference/workloads/RefReverseV2Workload.hpp new file mode 100644 index 0000000000..89e7c9ea38 --- /dev/null +++ b/src/backends/reference/workloads/RefReverseV2Workload.hpp @@ -0,0 +1,30 @@ +// +// Copyright © 2023 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include "RefBaseWorkload.hpp" +#include <armnn/backends/WorkloadData.hpp> + +#include "ReverseV2Impl.hpp" + +namespace armnn +{ + + class RefReverseV2Workload : public RefBaseWorkload<ReverseV2QueueDescriptor> + { + public: + explicit RefReverseV2Workload(const ReverseV2QueueDescriptor& descriptor, + const WorkloadInfo& info); + + void Execute() const override; + void ExecuteAsync(ExecutionData& executionData) override; + + private: + void Execute(std::vector<ITensorHandle*> inputs, std::vector<ITensorHandle*> outputs) const; + + }; + +} // namespace armnn
\ No newline at end of file diff --git a/src/backends/reference/workloads/RefWorkloads.hpp b/src/backends/reference/workloads/RefWorkloads.hpp index dba880bafc..e15a7ca047 100644 --- a/src/backends/reference/workloads/RefWorkloads.hpp +++ b/src/backends/reference/workloads/RefWorkloads.hpp @@ -53,6 +53,7 @@ #include "RefReduceWorkload.hpp" #include "RefReshapeWorkload.hpp" #include "RefResizeWorkload.hpp" +#include "RefReverseV2Workload.hpp" #include "RefShapeWorkload.hpp" #include "RefSliceWorkload.hpp" #include "RefSplitterWorkload.hpp" diff --git a/src/backends/reference/workloads/ReverseV2Impl.cpp b/src/backends/reference/workloads/ReverseV2Impl.cpp new file mode 100644 index 0000000000..f6d5fd74d1 --- /dev/null +++ b/src/backends/reference/workloads/ReverseV2Impl.cpp @@ -0,0 +1,133 @@ +// +// Copyright © 2023 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "ReverseV2Impl.hpp" + +#include <armnn/backends/WorkloadData.hpp> +#include <armnn/Logging.hpp> +#include <armnnUtils/Permute.hpp> + +namespace armnn +{ + +// Get multi-dimensional index for input tensor +std::vector<unsigned int> ReverseGetMultIdx(const unsigned int idx, + unsigned int inputRank, + std::vector<unsigned int>& elementNumInner) +{ + std::vector<unsigned int> indexList(inputRank); + + unsigned int mIdx = idx; + + for (unsigned int iDim = 0; iDim < inputRank; ++iDim) + { + indexList[iDim] = static_cast<unsigned int>(mIdx / elementNumInner[iDim]); + mIdx %= elementNumInner[iDim]; + } + + return indexList; +} + +// Get flattened index for output encoder +unsigned int ReverseGetFlatIdx(const std::vector<unsigned int>& idxList, + unsigned int inputRank, + std::vector<unsigned int>& elementNumInner) +{ + unsigned int idx = 0; + + for (unsigned int iDim = 0; iDim < inputRank; ++iDim) + { + idx += idxList[iDim] * elementNumInner[iDim]; + } + + return idx; +} + +// Relocate the coordinate to the reversed tensor +unsigned int ReverseRelocateIdx(unsigned int idx, + unsigned int inputRank, + std::vector<bool>& axisFlag, + std::vector<unsigned int>& dimSize, + std::vector<unsigned int>& elementNumInner) +{ + // Get the multidimensional index list for input + auto inputIdxList = ReverseGetMultIdx(idx, inputRank, elementNumInner); + + std::vector<unsigned int> outputIdxList(inputRank); + + // Relocate the input index to the output one + for (unsigned int iDim = 0; iDim < inputRank; ++iDim) + { + if (axisFlag[iDim]) + { + outputIdxList[iDim] = dimSize[iDim] - inputIdxList[iDim] - 1; + } + else + { + outputIdxList[iDim] = inputIdxList[iDim]; + } + } + + // Get the 1-dimensional flattened index for output + unsigned int outputIdx = ReverseGetFlatIdx(outputIdxList, inputRank, elementNumInner); + return outputIdx; +} + +void ReverseV2(const ReverseV2Descriptor& params, + const TensorInfo& inputInfo, + Decoder<float>& inputDecoder, + Encoder<float>& outputEncoder) +{ + // Empty axis and empty tensor case: copy input to output + if (params.m_Axis.empty() || inputInfo.GetNumElements() == 0) + { + for (unsigned idx = 0; idx < inputInfo.GetNumElements(); idx++) + { + float inputValue = inputDecoder.Get(); + inputDecoder += 1; + outputEncoder.Set(inputValue); + outputEncoder += 1; + } + return; + } + + unsigned int inputRank = static_cast<unsigned int>(inputInfo.GetNumDimensions()); + + std::vector<bool>axisFlag(inputRank, false); + std::vector<unsigned int>dimSize(inputRank, 0); + + // Make sure the axes are positive + for (int32_t axisElement: params.m_Axis) + { + axisElement = axisElement < 0 ? axisElement + static_cast<int32_t>(inputRank) : axisElement; + axisFlag[static_cast<uint32_t>(axisElement)] = true; + } + + const TensorShape &inputShape = inputInfo.GetShape(); + + unsigned int elementNum = inputInfo.GetNumElements(); + unsigned int baseDimSize = 1; + + std::vector<unsigned int> elementNumInner; + + // Get the number of element within the specific dimension + for (unsigned int iDim = 0; iDim < inputRank; ++iDim) { + dimSize[iDim] = inputShape[iDim]; + baseDimSize *= dimSize[iDim]; + elementNumInner.push_back(static_cast<unsigned int>(elementNum / baseDimSize)); + } + + // Iterate through all elements + for (unsigned int idx = 0; idx < elementNum; ++idx) + { + float inputValue = inputDecoder.Get(); + inputDecoder += 1; + auto outputIdx = ReverseRelocateIdx(idx, inputRank, axisFlag, dimSize, elementNumInner); + outputEncoder[outputIdx]; + outputEncoder.Set(inputValue); + } +} + +} // namespace armnn
\ No newline at end of file diff --git a/src/backends/reference/workloads/ReverseV2Impl.hpp b/src/backends/reference/workloads/ReverseV2Impl.hpp new file mode 100644 index 0000000000..bc1fe1d432 --- /dev/null +++ b/src/backends/reference/workloads/ReverseV2Impl.hpp @@ -0,0 +1,21 @@ +// +// Copyright © 2023 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include "Encoders.hpp" +#include "Decoders.hpp" + +#include <armnn/backends/WorkloadData.hpp> + +namespace armnn +{ + +void ReverseV2(const ReverseV2Descriptor& params, + const TensorInfo& inputInfo, + Decoder<float>& inputDecoder, + Encoder<float>& outputEncoder); + +} // namespace armnn
\ No newline at end of file |