From 79a06a59bafadf736ca53c4240e87f9bbb657260 Mon Sep 17 00:00:00 2001 From: Teresa Charlin Date: Thu, 13 Jul 2023 17:16:45 +0100 Subject: IVGCVSW-7883 Front end and reference implementation for TILE Signed-off-by: Teresa Charlin Signed-off-by: Cian McGriskin Change-Id: I0afb2403fee11c5c1e58ea65e2525e99594d8f2d --- Android.mk | 1 + CMakeLists.txt | 2 + docs/02_operator_list.dox | 44 +++ include/armnn/BackendHelper.hpp | 5 + include/armnn/Descriptors.hpp | 19 + include/armnn/DescriptorsFwd.hpp | 1 + include/armnn/INetwork.hpp | 27 +- include/armnn/Types.hpp | 3 +- include/armnn/backends/WorkloadData.hpp | 5 + src/armnn/BackendHelper.cpp | 15 + src/armnn/LayersFwd.hpp | 2 + src/armnn/Network.cpp | 11 + src/armnn/Network.hpp | 3 + src/armnn/layers/TileLayer.cpp | 71 ++++ src/armnn/layers/TileLayer.hpp | 45 +++ src/backends/backendsCommon/WorkloadData.cpp | 47 ++- src/backends/backendsCommon/WorkloadFactory.cpp | 13 + src/backends/backendsCommon/common.mk | 1 + src/backends/backendsCommon/test/CMakeLists.txt | 2 + .../test/IsLayerSupportedTestImpl.hpp | 8 +- src/backends/backendsCommon/test/LayerTests.hpp | 1 + .../test/layerTests/TileTestImpl.cpp | 434 +++++++++++++++++++++ .../test/layerTests/TileTestImpl.hpp | 31 ++ src/backends/reference/RefLayerSupport.cpp | 34 ++ src/backends/reference/RefLayerSupport.hpp | 5 + src/backends/reference/RefWorkloadFactory.cpp | 5 + src/backends/reference/backend.mk | 2 + src/backends/reference/test/RefLayerTests.cpp | 38 +- src/backends/reference/workloads/CMakeLists.txt | 4 + .../reference/workloads/RefTileWorkload.cpp | 47 +++ .../reference/workloads/RefTileWorkload.hpp | 30 ++ src/backends/reference/workloads/RefWorkloads.hpp | 1 + src/backends/reference/workloads/Tile.cpp | 102 +++++ src/backends/reference/workloads/Tile.hpp | 21 + 34 files changed, 1058 insertions(+), 22 deletions(-) create mode 100644 src/armnn/layers/TileLayer.cpp create mode 100644 src/armnn/layers/TileLayer.hpp create mode 100644 src/backends/backendsCommon/test/layerTests/TileTestImpl.cpp create mode 100644 src/backends/backendsCommon/test/layerTests/TileTestImpl.hpp create mode 100644 src/backends/reference/workloads/RefTileWorkload.cpp create mode 100644 src/backends/reference/workloads/RefTileWorkload.hpp create mode 100644 src/backends/reference/workloads/Tile.cpp create mode 100644 src/backends/reference/workloads/Tile.hpp diff --git a/Android.mk b/Android.mk index bf3c195505..c32afbeb34 100644 --- a/Android.mk +++ b/Android.mk @@ -276,6 +276,7 @@ LOCAL_SRC_FILES := \ src/armnn/layers/StridedSliceLayer.cpp \ src/armnn/layers/SubtractionLayer.cpp \ src/armnn/layers/SwitchLayer.cpp \ + src/armnn/layers/TileLayer.cpp \ src/armnn/layers/TransposeConvolution2dLayer.cpp \ src/armnn/layers/TransposeLayer.cpp \ src/armnn/layers/UnidirectionalSequenceLstmLayer.cpp \ diff --git a/CMakeLists.txt b/CMakeLists.txt index 291154a491..bf598aa200 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -328,6 +328,8 @@ list(APPEND armnn_sources src/armnn/layers/SubtractionLayer.hpp src/armnn/layers/SwitchLayer.cpp src/armnn/layers/SwitchLayer.hpp + src/armnn/layers/TileLayer.cpp + src/armnn/layers/TileLayer.hpp src/armnn/layers/TransposeConvolution2dLayer.cpp src/armnn/layers/TransposeConvolution2dLayer.hpp src/armnn/layers/TransposeLayer.hpp diff --git a/docs/02_operator_list.dox b/docs/02_operator_list.dox index 8fa6178aff..02b72ca66c 100644 --- a/docs/02_operator_list.dox +++ b/docs/02_operator_list.dox @@ -3310,6 +3310,50 @@ where N = batches, C = channels, H = height, W = width FLOAT16 FLOAT32 + + TileLayer + Layer to construct a tensor by repeating in tiles a given tensor. + +
    +
  • ANEURALNETWORKS_TILE +
+ CpuRef + +
    +
  • All +
+ + +
+
FLOAT16 +
FLOAT32 +
QASYMMS8 +
QASYMMU8 +
QSYMMS16 +
SIGNED32 +
+ + CpuAcc + +
    +
  • None +
+ + +
+
None +
+ + GpuAcc + +
    +
  • None +
+ + +
+
None +
TransposeConvolution2dLayer Layer to perform 2D transpose convolution (deconvolution) operation. diff --git a/include/armnn/BackendHelper.hpp b/include/armnn/BackendHelper.hpp index 6181ba5c40..b550f9f68e 100644 --- a/include/armnn/BackendHelper.hpp +++ b/include/armnn/BackendHelper.hpp @@ -422,6 +422,11 @@ public: const TensorInfo& output1, Optional reasonIfUnsupported = EmptyOptional()); + bool IsTileSupported(const TensorInfo& input, + const TensorInfo& output, + const TileDescriptor& descriptor, + Optional reasonIfUnsupported = EmptyOptional()); + bool IsTransposeConvolution2dSupported( const TensorInfo& input, const TensorInfo& output, diff --git a/include/armnn/Descriptors.hpp b/include/armnn/Descriptors.hpp index 9ff894f1b0..3a571a66e8 100644 --- a/include/armnn/Descriptors.hpp +++ b/include/armnn/Descriptors.hpp @@ -1620,4 +1620,23 @@ struct BatchMatMulDescriptor : BaseDescriptor const TensorShape& tensorShape); }; +struct TileDescriptor : BaseDescriptor +{ + TileDescriptor() + : m_Multiples() + {} + + explicit TileDescriptor(std::vector multiples) + : m_Multiples(std::move(multiples)) + {} + + bool operator ==(const TileDescriptor& rhs) const + { + return m_Multiples == rhs.m_Multiples; + } + + /// The vector to multiply the input shape by + std::vector m_Multiples; +}; + } // namespace armnn diff --git a/include/armnn/DescriptorsFwd.hpp b/include/armnn/DescriptorsFwd.hpp index 2c25a49f00..be1a3f6782 100644 --- a/include/armnn/DescriptorsFwd.hpp +++ b/include/armnn/DescriptorsFwd.hpp @@ -49,6 +49,7 @@ struct SpaceToDepthDescriptor; struct StackDescriptor; struct StandInDescriptor; struct StridedSliceDescriptor; +struct TileDescriptor; struct TransposeConvolution2dDescriptor; struct TransposeDescriptor; struct ViewsDescriptor; diff --git a/include/armnn/INetwork.hpp b/include/armnn/INetwork.hpp index e20dd1c348..830e0bac66 100644 --- a/include/armnn/INetwork.hpp +++ b/include/armnn/INetwork.hpp @@ -740,7 +740,7 @@ public: /// @param name - Optional name for the layer. /// @return - Interface for configuring the layer. IConnectableLayer* AddGatherLayer(const GatherDescriptor& descriptor, - const char* name = nullptr); + const char* name = nullptr); /// Add GatherNd layer to the network. /// @param name - Optional name for the layer. @@ -764,23 +764,23 @@ public: /// @param name - Optional name for the layer. /// @return - Interface for configuring the layer. IConnectableLayer* AddTransposeConvolution2dLayer(const TransposeConvolution2dDescriptor& descriptor, - const ConstTensor& weights, - const Optional& biases, - const char* name = nullptr); + const ConstTensor& weights, + const Optional& biases, + const char* name = nullptr); /// Adds a transpose layer to the network. /// @param transposeDescriptor - TransposeDescriptor to configure the transpose. /// @param name - Optional name for the layer. /// @return - Interface for configuring the layer. IConnectableLayer* AddTransposeLayer(const TransposeDescriptor& transposeDescriptor, - const char* name = nullptr); + const char* name = nullptr); /// Adds a stack layer to the network. /// @param descriptor - Description of the stack layer. /// @param name - Optional name for the layer. /// @return - Interface for configuring the layer. IConnectableLayer* AddStackLayer(const StackDescriptor& descriptor, - const char* name = nullptr); + const char* name = nullptr); /// Add a stand-in layer for a type unknown to the Arm NN framework. /// Note: Due to the nature of this layer, no validation can be performed by the framework. @@ -789,14 +789,14 @@ public: /// @descriptor - Descriptor for the StandIn layer. /// @return - Interface for configuring the layer. IConnectableLayer* AddStandInLayer(const StandInDescriptor& descriptor, - const char* name = nullptr); + const char* name = nullptr); /// Add a QuantizedLstm layer to the network /// @param params - The weights and biases for the Quantized LSTM cell /// @param name - Optional name for the layer /// @return - Interface for configuring the layer. IConnectableLayer* AddQuantizedLstmLayer(const QuantizedLstmInputParams& params, - const char* name = nullptr); + const char* name = nullptr); /// Add a QLstm layer to the network /// @param descriptor - Parameters for the QLstm operation @@ -804,8 +804,8 @@ public: /// @param name - Optional name for the layer /// @return - Interface for configuring the layer. IConnectableLayer* AddQLstmLayer(const QLstmDescriptor& descriptor, - const LstmInputParams& params, - const char* name = nullptr); + const LstmInputParams& params, + const char* name = nullptr); /// Adds a Logical Binary layer to the network. /// @param descriptor - Description of the Logical Binary layer. @@ -842,6 +842,13 @@ public: /// @return - Interface for configuring the layer IConnectableLayer* AddReverseV2Layer(const char* name = nullptr); + /// Add a Tile layer to the network + /// @param descriptor - Parameters for the Tile operation + /// @param name - Optional name for the layer + /// @return - Interface for configuring the layer + IConnectableLayer* AddTileLayer(const TileDescriptor& descriptor, + const char* name = nullptr); + void ExecuteStrategy(IStrategy& strategy) const; protected: diff --git a/include/armnn/Types.hpp b/include/armnn/Types.hpp index f05f05b2a0..bf4458ee7f 100644 --- a/include/armnn/Types.hpp +++ b/include/armnn/Types.hpp @@ -474,6 +474,7 @@ using InferenceTimingPair = std::pair; X(BatchMatMul) \ X(ElementwiseBinary) \ X(ReverseV2) \ + X(Tile) \ // New layers should be added at last position to minimize instability. @@ -485,7 +486,7 @@ enum class LayerType LIST_OF_LAYER_TYPE #undef X FirstLayer = Activation, - LastLayer = ElementwiseBinary + LastLayer = Tile }; const char* GetLayerTypeAsCString(LayerType type); diff --git a/include/armnn/backends/WorkloadData.hpp b/include/armnn/backends/WorkloadData.hpp index e7d5e0e689..21a597df8a 100644 --- a/include/armnn/backends/WorkloadData.hpp +++ b/include/armnn/backends/WorkloadData.hpp @@ -755,4 +755,9 @@ struct ReverseV2QueueDescriptor : QueueDescriptor void Validate(const WorkloadInfo& workloadInfo) const; }; +struct TileQueueDescriptor : QueueDescriptorWithParameters +{ + void Validate(const WorkloadInfo& workloadInfo) const; +}; + } // namespace armnn diff --git a/src/armnn/BackendHelper.cpp b/src/armnn/BackendHelper.cpp index 18184fbfb2..0a55a08087 100644 --- a/src/armnn/BackendHelper.cpp +++ b/src/armnn/BackendHelper.cpp @@ -1409,6 +1409,21 @@ bool LayerSupportHandle::IsSwitchSupported(const TensorInfo& input0, reasonIfUnsupported); } +bool LayerSupportHandle::IsTileSupported(const TensorInfo& input, + const TensorInfo& output, + const armnn::TileDescriptor &descriptor, + Optional reasonIfUnsupported) +{ + TensorInfos infos{input, output}; + + return m_LayerSupport->IsLayerSupported(LayerType::Tile, + infos, + descriptor, + EmptyOptional(), + EmptyOptional(), + reasonIfUnsupported); +} + bool LayerSupportHandle::IsTransposeConvolution2dSupported( const TensorInfo& input, const TensorInfo& output, diff --git a/src/armnn/LayersFwd.hpp b/src/armnn/LayersFwd.hpp index d3ce6f2a67..743b8d7205 100644 --- a/src/armnn/LayersFwd.hpp +++ b/src/armnn/LayersFwd.hpp @@ -76,6 +76,7 @@ #include "layers/StridedSliceLayer.hpp" #include "layers/SubtractionLayer.hpp" #include "layers/SwitchLayer.hpp" +#include "layers/TileLayer.hpp" #include "layers/TransposeConvolution2dLayer.hpp" #include "layers/TransposeLayer.hpp" #include "layers/UnidirectionalSequenceLstmLayer.hpp" @@ -178,6 +179,7 @@ DECLARE_LAYER(StandIn) DECLARE_LAYER(StridedSlice) DECLARE_LAYER(Subtraction) DECLARE_LAYER(Switch) +DECLARE_LAYER(Tile) DECLARE_LAYER(Transpose) DECLARE_LAYER(TransposeConvolution2d) DECLARE_LAYER(UnidirectionalSequenceLstm) diff --git a/src/armnn/Network.cpp b/src/armnn/Network.cpp index 27e91ae39c..22d2c78c65 100644 --- a/src/armnn/Network.cpp +++ b/src/armnn/Network.cpp @@ -644,6 +644,12 @@ IConnectableLayer* INetwork::AddReverseV2Layer(const char *name) return pNetworkImpl->AddReverseV2Layer(name); } +IConnectableLayer* INetwork::AddTileLayer(const TileDescriptor &descriptor, + const char *name) +{ + return pNetworkImpl->AddTileLayer(descriptor, name); +} + void INetwork::ExecuteStrategy(IStrategy& strategy) const { return pNetworkImpl->ExecuteStrategy(strategy); @@ -2934,6 +2940,11 @@ IConnectableLayer* NetworkImpl::AddReverseV2Layer(const char *name) return m_Graph->AddLayer(name); } +IConnectableLayer* NetworkImpl::AddTileLayer(const TileDescriptor &desc, const char *name) +{ + return m_Graph->AddLayer(desc, name); +} + IConnectableLayer* NetworkImpl::AddPrecompiledLayer(const PreCompiledDescriptor& preCompiledDescriptor, CompiledBlobPtr compiledBlobPtr, const Optional& backend, diff --git a/src/armnn/Network.hpp b/src/armnn/Network.hpp index ae287f32d1..a84a0e9ba4 100644 --- a/src/armnn/Network.hpp +++ b/src/armnn/Network.hpp @@ -220,6 +220,9 @@ public: IConnectableLayer* AddSwitchLayer(const char* name = nullptr); + IConnectableLayer* AddTileLayer(const TileDescriptor& tileDescriptor, + const char* name = nullptr); + IConnectableLayer* AddTransposeConvolution2dLayer(const TransposeConvolution2dDescriptor& descriptor, const ConstTensor& weights, const Optional& biases, diff --git a/src/armnn/layers/TileLayer.cpp b/src/armnn/layers/TileLayer.cpp new file mode 100644 index 0000000000..3c313905fe --- /dev/null +++ b/src/armnn/layers/TileLayer.cpp @@ -0,0 +1,71 @@ +// +// Copyright © 2023 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "TileLayer.hpp" + +#include +#include "layers/LayerCloneBase.hpp" + +namespace armnn +{ +TileLayer::TileLayer(const TileDescriptor ¶m, const char *name) + : LayerWithParameters(1, 1, LayerType::Tile, param, name) +{} + +std::unique_ptr TileLayer::CreateWorkload(const IWorkloadFactory &factory) const +{ + TileQueueDescriptor descriptor; + SetAdditionalInfo(descriptor); + + return factory.CreateWorkload(LayerType::Tile, descriptor, PrepInfoAndDesc(descriptor)); +} + +TileLayer* TileLayer::Clone(armnn::Graph &graph) const +{ + auto layer = CloneBase(graph, m_Param, GetName()); + + return std::move(layer); +} + +std::vector TileLayer::InferOutputShapes(const std::vector& inputShapes) const +{ + ARMNN_ASSERT(inputShapes.size() == 1); + const TensorShape& inputShape = inputShapes[0]; + const std::vector multipleShape = m_Param.m_Multiples; + + std::vector dimSizes; + + // Check input shape and multiples have same length and multiply them together to get output shape + if(inputShape.GetNumDimensions() == multipleShape.size()) + { + for(uint32_t i = 0; i < inputShape.GetNumDimensions(); ++i) + { + dimSizes.insert(dimSizes.begin(), inputShape[i] * multipleShape[i]); + } + } + else + { + throw LayerValidationException("TileLayer: input rank and length of multiples are different."); + } + + return std::vector({TensorShape({inputShape.GetNumElements(), dimSizes.data()})}); +} + +void TileLayer::ValidateTensorShapesFromInputs() +{ + VerifyLayerConnections(1, CHECK_LOCATION()); + + const TensorShape& outputShape = GetOutputSlot(0).GetTensorInfo().GetShape(); + + VerifyShapeInferenceType(outputShape, m_ShapeInferenceMethod); + + auto inferredShapes = InferOutputShapes({ GetInputSlot(0).GetTensorInfo().GetShape() }); + + ARMNN_ASSERT(inferredShapes.size() == 1); + + ValidateAndCopyShape(outputShape, inferredShapes[0], m_ShapeInferenceMethod, "TileLayer"); +} + +} \ No newline at end of file diff --git a/src/armnn/layers/TileLayer.hpp b/src/armnn/layers/TileLayer.hpp new file mode 100644 index 0000000000..632cdb426b --- /dev/null +++ b/src/armnn/layers/TileLayer.hpp @@ -0,0 +1,45 @@ +// +// Copyright © 2023 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include "LayerWithParameters.hpp" + +namespace armnn +{ + +class TileLayer : public LayerWithParameters +{ +public: + /// Makes a workload for the Tile 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 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. + TileLayer* Clone(Graph& graph) const override; + + /// Infers the output shapes from given input shapes and layer properties. + /// @param [in] inputShapes The input shapes layer has. + /// @return A vector to the inferred output shape. + std::vector InferOutputShapes(const std::vector& inputShapes) const override; + + /// Check if the input tensor tile(s) + /// will lead to a valid configuration of @ref TileLayer. + /// @param [in] shapeInferenceMethod Indicates if output tile shall be overwritten or just validated. + void ValidateTensorShapesFromInputs() override; + +protected: + /// Constructor to create a TileLayer. + /// @param [in] name Optional name for the layer. + TileLayer(const TileDescriptor& param, const char* name); + + /// Default destructor. + ~TileLayer() = default; +}; + +} // namespace armnn diff --git a/src/backends/backendsCommon/WorkloadData.cpp b/src/backends/backendsCommon/WorkloadData.cpp index bd3c7c2760..7efca9de50 100644 --- a/src/backends/backendsCommon/WorkloadData.cpp +++ b/src/backends/backendsCommon/WorkloadData.cpp @@ -207,9 +207,9 @@ void ValidateBiasTensorQuantization(const TensorInfo& biasTensor, //--------------------------------------------------------------- void ValidateTensors(const std::vector& vec, - unsigned int numExpected, - const std::string& descName, - const std::string& varName) + unsigned int numExpected, + const std::string& descName, + const std::string& varName) { if (vec.empty() && numExpected > 0) { @@ -433,9 +433,9 @@ void QueueDescriptor::ValidateTensorNumDimensions(const TensorInfo& tensor, //--------------------------------------------------------------- void QueueDescriptor::ValidateTensorNumDimNumElem(const TensorInfo& tensorInfo, - unsigned int numDimension, - unsigned int numElements, - std::string const& tensorName) const + unsigned int numDimension, + unsigned int numElements, + std::string const& tensorName) const { const std::string functionName{"ValidateTensorNumDimNumElem"}; ValidateTensorNumDimensions(tensorInfo, functionName, numDimension, tensorName); @@ -1614,7 +1614,8 @@ void ResizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const } } -void ReverseV2QueueDescriptor::Validate(const WorkloadInfo &workloadInfo) const { +void ReverseV2QueueDescriptor::Validate(const WorkloadInfo &workloadInfo) const +{ const std::string descriptorName{"ReverseV2QueueDescriptor"}; // Backend restriction @@ -2948,7 +2949,6 @@ void ShapeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const DataType::Float32, DataType::QAsymmS8, DataType::QAsymmU8, - DataType::QAsymmS8, DataType::QSymmS8, DataType::QSymmS16, DataType::Signed32 @@ -4378,5 +4378,36 @@ void BatchMatMulQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) cons } } +void TileQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const +{ + const std::string& descriptorName{"TileQueueDescriptor"}; + + ValidateNumInputs(workloadInfo, descriptorName, 1); + ValidateNumOutputs(workloadInfo, descriptorName, 1); + + const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; + const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; + + std::vector supportedTypes = + { + DataType::Float32, + DataType::Float16, + DataType::QAsymmS8, + DataType::QAsymmU8, + DataType::QSymmS8, + DataType::QSymmS16, + DataType::Signed32 + }; + + // Multiples length must be the same as the number of dimensions in input. + if (m_Parameters.m_Multiples.size() != inputTensorInfo.GetNumDimensions()) + { + throw InvalidArgumentException(descriptorName + + ": Multiples length is not same as the number of dimensions in Input."); + } + + ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); + ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName); +} } // namespace armnn \ No newline at end of file diff --git a/src/backends/backendsCommon/WorkloadFactory.cpp b/src/backends/backendsCommon/WorkloadFactory.cpp index ee797b632c..9ab3ca5b77 100644 --- a/src/backends/backendsCommon/WorkloadFactory.cpp +++ b/src/backends/backendsCommon/WorkloadFactory.cpp @@ -1352,6 +1352,19 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, reason); break; } + case LayerType::Tile: + { + auto cLayer = PolymorphicDowncast(&layer); + const TensorInfo& input = layer.GetInputSlot(0).GetTensorInfo(); + const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo(); + + result = layerSupportObject.IsTileSupported(OverrideDataType(input, dataType), + OverrideDataType(output, dataType), + cLayer->GetParameters(), + reason); + + break; + } case LayerType::Transpose: { auto cLayer = PolymorphicDowncast(&layer); diff --git a/src/backends/backendsCommon/common.mk b/src/backends/backendsCommon/common.mk index 1e0467deba..2c41285615 100644 --- a/src/backends/backendsCommon/common.mk +++ b/src/backends/backendsCommon/common.mk @@ -106,6 +106,7 @@ COMMON_TEST_SOURCES := \ test/layerTests/StackTestImpl.cpp \ test/layerTests/StridedSliceTestImpl.cpp \ test/layerTests/SubtractionTestImpl.cpp \ + test/layerTests/TileTestImpl.cpp \ test/layerTests/TransposeConvolution2dTestImpl.cpp \ test/layerTests/UnidirectionalSequenceLstmTestImpl.cpp \ memoryOptimizerStrategyLibrary/test/ConstMemoryStrategyTests.cpp \ diff --git a/src/backends/backendsCommon/test/CMakeLists.txt b/src/backends/backendsCommon/test/CMakeLists.txt index 8d6891a68d..bbd1324010 100644 --- a/src/backends/backendsCommon/test/CMakeLists.txt +++ b/src/backends/backendsCommon/test/CMakeLists.txt @@ -199,6 +199,8 @@ list(APPEND armnnBackendsCommonUnitTests_sources layerTests/StridedSliceTestImpl.hpp layerTests/SubtractionTestImpl.cpp layerTests/SubtractionTestImpl.hpp + layerTests/TileTestImpl.cpp + layerTests/TileTestImpl.hpp layerTests/TransposeConvolution2dTestImpl.cpp layerTests/TransposeConvolution2dTestImpl.hpp layerTests/UnidirectionalSequenceLstmTestImpl.cpp diff --git a/src/backends/backendsCommon/test/IsLayerSupportedTestImpl.hpp b/src/backends/backendsCommon/test/IsLayerSupportedTestImpl.hpp index 182fab97be..ff02e06859 100644 --- a/src/backends/backendsCommon/test/IsLayerSupportedTestImpl.hpp +++ b/src/backends/backendsCommon/test/IsLayerSupportedTestImpl.hpp @@ -740,10 +740,14 @@ ARMNN_NO_DEPRECATE_WARN_END DECLARE_LAYER_POLICY_1_PARAM(Rank) +DECLARE_LAYER_POLICY_2_PARAM(Reduce) + DECLARE_LAYER_POLICY_2_PARAM(Resize) DECLARE_LAYER_POLICY_2_PARAM(Reshape) +DECLARE_LAYER_POLICY_1_PARAM(ReverseV2) + DECLARE_LAYER_POLICY_1_PARAM(Shape) DECLARE_LAYER_POLICY_2_PARAM(Slice) @@ -766,10 +770,10 @@ ARMNN_NO_DEPRECATE_WARN_BEGIN DECLARE_LAYER_POLICY_1_PARAM(Subtraction) ARMNN_NO_DEPRECATE_WARN_END -DECLARE_LAYER_POLICY_2_PARAM(Reduce) - DECLARE_LAYER_POLICY_1_PARAM(Switch) +DECLARE_LAYER_POLICY_2_PARAM(Tile) + DECLARE_LAYER_POLICY_2_PARAM(Transpose) DECLARE_LAYER_POLICY_2_PARAM(TransposeConvolution2d) diff --git a/src/backends/backendsCommon/test/LayerTests.hpp b/src/backends/backendsCommon/test/LayerTests.hpp index 755a665ba6..7182cb2d47 100644 --- a/src/backends/backendsCommon/test/LayerTests.hpp +++ b/src/backends/backendsCommon/test/LayerTests.hpp @@ -74,6 +74,7 @@ #include #include #include +#include #include #include #include diff --git a/src/backends/backendsCommon/test/layerTests/TileTestImpl.cpp b/src/backends/backendsCommon/test/layerTests/TileTestImpl.cpp new file mode 100644 index 0000000000..0b13bba425 --- /dev/null +++ b/src/backends/backendsCommon/test/layerTests/TileTestImpl.cpp @@ -0,0 +1,434 @@ +// +// Copyright © 2023 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "TileTestImpl.hpp" +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include + +namespace +{ +template +LayerTestResult TileTestImpl( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory, + armnn::TileDescriptor descriptor, + armnn::TensorInfo& inputInfo, + armnn::TensorInfo& outputInfo, + std::vector& inputData, + std::vector& expectedOutputData) +{ + + LayerTestResult result(outputInfo); + std::vector outputActual(outputInfo.GetNumElements()); + + armnn::TileQueueDescriptor queueDescriptor; + queueDescriptor.m_Parameters = std::move(descriptor); + armnn::WorkloadInfo workloadInfo; + + std::unique_ptr inputHandle = tensorHandleFactory.CreateTensorHandle(inputInfo); + std::unique_ptr outputHandle = tensorHandleFactory.CreateTensorHandle(outputInfo); + + AddInputToWorkload(queueDescriptor, workloadInfo, inputInfo, inputHandle.get()); + AddOutputToWorkload(queueDescriptor, workloadInfo, outputInfo, outputHandle.get()); + + const armnn::BackendId& backend = workloadFactory.GetBackendId(); + armnn::LayerSupportHandle handle = armnn::GetILayerSupportByBackendId(backend); + + auto workload = workloadFactory.CreateWorkload(armnn::LayerType::Tile, queueDescriptor, workloadInfo); + + inputHandle->Allocate(); + outputHandle->Allocate(); + + CopyDataToITensorHandle(inputHandle.get(), inputData.data()); + + workload->PostAllocationConfigure(); + ExecuteWorkload(*workload, memoryManager); + + CopyDataFromITensorHandle(outputActual.data(), outputHandle.get()); + return LayerTestResult(outputActual, + expectedOutputData, + outputHandle->GetShape(), + outputInfo.GetShape()); +} +} + +template +LayerTestResult Tile1dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + auto descriptor = armnn::TileDescriptor( std::vector{ 3 } ); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorShape inputShape = { 3 }; + armnn::TensorShape outputShape = { 9 }; + + armnn::TensorInfo inputInfo(inputShape, ArmnnType); + armnn::TensorInfo outputInfo(outputShape, ArmnnType); + + std::vector input = armnnUtils::QuantizedVector( + { + 0.f, 1.f, 2.f + }, qScale, qOffset); + + std::vector expectedOutput = armnnUtils::QuantizedVector( + { + 0.f, 1.f, 2.f, + 0.f, 1.f, 2.f, + 0.f, 1.f, 2.f + }, qScale, qOffset); + + return TileTestImpl(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + inputInfo, + outputInfo, + input, + expectedOutput); +} + +template +LayerTestResult Tile2dTest(armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + auto descriptor = armnn::TileDescriptor(std::vector{ 2, 2 }); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorShape inputShape = { 2, 3 }; + armnn::TensorShape outputShape = { 4, 6 }; + + armnn::TensorInfo inputInfo(inputShape, ArmnnType); + armnn::TensorInfo outputInfo(outputShape, ArmnnType); + + std::vector input = armnnUtils::QuantizedVector( + { + 0.f, 1.f, 2.f, + 3.f, 4.f, 5.f + }, qScale, qOffset); + + + std::vector expectedOutput = armnnUtils::QuantizedVector( + { + 0.f, 1.f, 2.f, 0.f, 1.f, 2.f, + 3.f, 4.f, 5.f, 3.f, 4.f, 5.f, + + 0.f, 1.f, 2.f, 0.f, 1.f, 2.f, + 3.f, 4.f, 5.f, 3.f, 4.f, 5.f + }, qScale, qOffset); + + return TileTestImpl(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + inputInfo, + outputInfo, + input, + expectedOutput); +} + +template +LayerTestResult Tile3dTest(armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + auto descriptor = armnn::TileDescriptor(std::vector{ 1, 2, 1 }); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorShape inputShape = { 2, 2, 3 }; + armnn::TensorShape outputShape = { 2, 4, 3 }; + + armnn::TensorInfo inputInfo(inputShape, ArmnnType); + armnn::TensorInfo outputInfo(outputShape, ArmnnType); + std::vector input = armnnUtils::QuantizedVector( + { + 0.f, 1.f, 2.f, + 3.f, 4.f, 5.f, + + 6.f, 7.f, 8.f, + 9.f, 10.f, 11.f + }, qScale, qOffset); + + + std::vector expectedOutput = armnnUtils::QuantizedVector( + { + 0.f, 1.f, 2.f, + 3.f, 4.f, 5.f, + 0.f, 1.f, 2.f, + 3.f, 4.f, 5.f, + + 6.f, 7.f, 8.f, + 9.f, 10.f, 11.f, + 6.f, 7.f, 8.f, + 9.f, 10.f, 11.f + }, qScale, qOffset); + + return TileTestImpl(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + inputInfo, + outputInfo, + input, + expectedOutput); +} + +template +LayerTestResult Tile4dTest(armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory) +{ + auto descriptor = armnn::TileDescriptor(std::vector{ 2, 1, 1, 1 }); + + float qScale = 1.0f; + int32_t qOffset = 0; + + armnn::TensorShape inputShape = { 2, 2, 2, 3}; + armnn::TensorShape outputShape = { 4, 2, 2, 3}; + + armnn::TensorInfo inputInfo(inputShape, ArmnnType); + armnn::TensorInfo outputInfo(outputShape, ArmnnType); + + std::vector input = armnnUtils::QuantizedVector( + { + 0.f, 1.f, 2.f, + 3.f, 4.f, 5.f, + + 6.f, 7.f, 8.f, + 9.f, 10.f, 11.f, + + 0.f, 1.f, 2.f, + 3.f, 4.f, 5.f, + + 6.f, 7.f, 8.f, + 9.f, 10.f, 11.f + }, qScale, qOffset); + + + std::vector expectedOutput = armnnUtils::QuantizedVector( + { + 0.f, 1.f, 2.f, + 3.f, 4.f, 5.f, + + 6.f, 7.f, 8.f, + 9.f, 10.f, 11.f, + + 0.f, 1.f, 2.f, + 3.f, 4.f, 5.f, + + 6.f, 7.f, 8.f, + 9.f, 10.f, 11.f, + + 0.f, 1.f, 2.f, + 3.f, 4.f, 5.f, + + 6.f, 7.f, 8.f, + 9.f, 10.f, 11.f, + + 0.f, 1.f, 2.f, + 3.f, 4.f, 5.f, + + 6.f, 7.f, 8.f, + 9.f, 10.f, 11.f + }, qScale, qOffset); + + return TileTestImpl(workloadFactory, + memoryManager, + tensorHandleFactory, + descriptor, + inputInfo, + outputInfo, + input, + expectedOutput); +} + +template LayerTestResult, 1> +Tile1dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 2> +Tile2dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 3> +Tile3dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 4> +Tile4dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 1> +Tile1dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 2> +Tile2dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 3> +Tile3dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 4> +Tile4dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 1> +Tile1dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 2> +Tile2dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 3> +Tile3dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 4> +Tile4dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 1> +Tile1dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 2> +Tile2dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 3> +Tile3dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 4> +Tile4dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 1> +Tile1dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 2> +Tile2dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 3> +Tile3dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 4> +Tile4dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 1> +Tile1dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 2> +Tile2dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 3> +Tile3dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 4> +Tile4dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 1> +Tile1dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 2> +Tile2dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 3> +Tile3dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template LayerTestResult, 4> +Tile4dTest( + armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + diff --git a/src/backends/backendsCommon/test/layerTests/TileTestImpl.hpp b/src/backends/backendsCommon/test/layerTests/TileTestImpl.hpp new file mode 100644 index 0000000000..3699bda8ef --- /dev/null +++ b/src/backends/backendsCommon/test/layerTests/TileTestImpl.hpp @@ -0,0 +1,31 @@ +// +// Copyright © 2023 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include +#include +#include +#include "ResolveType.hpp" + +template> +LayerTestResult Tile4dTest(armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template> +LayerTestResult Tile3dTest(armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template> +LayerTestResult Tile2dTest(armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const armnn::ITensorHandleFactory& tensorHandleFactory); + +template> +LayerTestResult Tile1dTest(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 e94478f088..9d396e5db9 100644 --- a/src/backends/reference/RefLayerSupport.cpp +++ b/src/backends/reference/RefLayerSupport.cpp @@ -402,6 +402,11 @@ bool RefLayerSupport::IsLayerSupported(const LayerType& type, reasonIfUnsupported); case LayerType::Subtraction: return IsSubtractionSupported(infos[0], infos[1], infos[2], reasonIfUnsupported); + case LayerType::Tile: + return IsTileSupported(infos[0], + infos[1], + *(PolymorphicDowncast(&descriptor)), + reasonIfUnsupported); case LayerType::Transpose: return IsTransposeSupported(infos[0], infos[1], @@ -2693,6 +2698,35 @@ bool RefLayerSupport::IsPreluSupported(const TensorInfo& input, return supported; } +bool RefLayerSupport::IsTileSupported(const TensorInfo& input, + const TensorInfo& output, + const TileDescriptor& descriptor, + Optional reasonIfUnsupported) const +{ + IgnoreUnused(descriptor); + + bool supported = true; + + std::array supportedTypes + { + DataType::Float32, + DataType::Float16, + DataType::QAsymmS8, + DataType::QAsymmU8, + DataType::QSymmS8, + DataType::QSymmS16, + DataType::Signed32 + }; + + supported &= CheckSupportRule(TypeAnyOf(input, supportedTypes), reasonIfUnsupported, + "Tile: input type not supported."); + + supported &= CheckSupportRule(TypeAnyOf(output, supportedTypes), reasonIfUnsupported, + "Tile: output type not supported"); + + return supported; +} + bool RefLayerSupport::IsTransposeConvolution2dSupported(const TensorInfo& input, const TensorInfo& output, const TransposeConvolution2dDescriptor& descriptor, diff --git a/src/backends/reference/RefLayerSupport.hpp b/src/backends/reference/RefLayerSupport.hpp index 21d59e27fc..42b5814380 100644 --- a/src/backends/reference/RefLayerSupport.hpp +++ b/src/backends/reference/RefLayerSupport.hpp @@ -354,6 +354,11 @@ public: const TensorInfo& output, Optional reasonIfUnsupported = EmptyOptional()) const override; + bool IsTileSupported(const TensorInfo& input, + const TensorInfo& output, + const TileDescriptor& descriptor, + Optional reasonIfUnsupported = EmptyOptional()) const; + bool IsTransposeConvolution2dSupported( const TensorInfo& input, const TensorInfo& output, diff --git a/src/backends/reference/RefWorkloadFactory.cpp b/src/backends/reference/RefWorkloadFactory.cpp index 7d5f742126..86a584452d 100644 --- a/src/backends/reference/RefWorkloadFactory.cpp +++ b/src/backends/reference/RefWorkloadFactory.cpp @@ -618,6 +618,11 @@ std::unique_ptr RefWorkloadFactory::CreateWorkload(LayerType type, return std::make_unique>(*subtractionQueueDescriptor, info); } } + case LayerType::Tile: + { + auto tileQueueDescriptor = PolymorphicDowncast(&descriptor); + return std::make_unique(*tileQueueDescriptor, info); + } case LayerType::Transpose: { auto transposeQueueDescriptor = PolymorphicDowncast(&descriptor); diff --git a/src/backends/reference/backend.mk b/src/backends/reference/backend.mk index dfafa0ac39..7f047af930 100644 --- a/src/backends/reference/backend.mk +++ b/src/backends/reference/backend.mk @@ -102,6 +102,7 @@ BACKEND_SOURCES := \ workloads/RefStackWorkload.cpp \ workloads/RefStridedSliceWorkload.cpp \ workloads/RefSplitterWorkload.cpp \ + workloads/RefTileWorkload.cpp \ workloads/RefTransposeConvolution2dWorkload.cpp \ workloads/RefTransposeWorkload.cpp \ workloads/RefUnidirectionalSequenceLstmWorkload.cpp \ @@ -115,6 +116,7 @@ BACKEND_SOURCES := \ workloads/StringMapping.cpp \ workloads/Softmax.cpp \ workloads/Splitter.cpp \ + workloads/Tile.cpp \ workloads/TransposeConvolution2d.cpp else diff --git a/src/backends/reference/test/RefLayerTests.cpp b/src/backends/reference/test/RefLayerTests.cpp index a68775e8e9..1f42397458 100644 --- a/src/backends/reference/test/RefLayerTests.cpp +++ b/src/backends/reference/test/RefLayerTests.cpp @@ -1,5 +1,5 @@ // -// Copyright © 2017,2022, 2023 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2017,2022-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -1596,6 +1596,42 @@ ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2Simple2Dim2AxisQAsymmS8, ReverseV2SimpleT ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2Simple2Dim2AxisQAsymmU8, ReverseV2SimpleTest2Dim2Axis) ARMNN_AUTO_TEST_CASE_WITH_THF(ReverseV2Simple2Dim2AxisQSymmS16, ReverseV2SimpleTest2Dim2Axis) +// Tile +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile1dTestFloat32, Tile1dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile2dTestFloat32, Tile2dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile3dTestFloat32, Tile3dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile4dTestFloat32, Tile4dTest) + +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile1dTestFloat16, Tile1dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile2dTestFloat16, Tile2dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile3dTestFloat16, Tile3dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile4dTestFloat16, Tile4dTest) + +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile1dTestQAsymmS8, Tile1dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile2dTestQAsymmS8, Tile2dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile3dTestQAsymmS8, Tile3dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile4dTestQAsymmS8, Tile4dTest) + +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile1dTestQAsymmU8, Tile1dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile2dTestQAsymmU8, Tile2dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile3dTestQAsymmU8, Tile3dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile4dTestQAsymmU8, Tile4dTest) + +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile1dTestQSymmS8, Tile1dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile2dTestQSymmS8, Tile2dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile3dTestQSymmS8, Tile3dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile4dTestQSymmS8, Tile4dTest) + +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile1dTestQSymmS16, Tile1dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile2dTestQSymmS16, Tile2dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile3dTestQSymmS16, Tile3dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile4dTestQSymmS16, Tile4dTest) + +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile1dTestSigned32, Tile1dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile2dTestSigned32, Tile2dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile3dTestSigned32, Tile3dTest) +ARMNN_AUTO_TEST_CASE_WITH_THF(Tile4dTestSigned32, Tile4dTest) + // 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 28f6d2f371..9372568133 100644 --- a/src/backends/reference/workloads/CMakeLists.txt +++ b/src/backends/reference/workloads/CMakeLists.txt @@ -180,6 +180,8 @@ list(APPEND armnnRefBackendWorkloads_sources RefStackWorkload.hpp RefStridedSliceWorkload.cpp RefStridedSliceWorkload.hpp + RefTileWorkload.cpp + RefTileWorkload.hpp RefTransposeConvolution2dWorkload.cpp RefTransposeConvolution2dWorkload.hpp RefTransposeWorkload.cpp @@ -209,6 +211,8 @@ list(APPEND armnnRefBackendWorkloads_sources StridedSlice.cpp StringMapping.cpp StringMapping.hpp + Tile.cpp + Tile.hpp TensorBufferArrayView.hpp TransposeConvolution2d.cpp TransposeConvolution2d.hpp diff --git a/src/backends/reference/workloads/RefTileWorkload.cpp b/src/backends/reference/workloads/RefTileWorkload.cpp new file mode 100644 index 0000000000..9fa8c8c3d3 --- /dev/null +++ b/src/backends/reference/workloads/RefTileWorkload.cpp @@ -0,0 +1,47 @@ +// +// Copyright © 2023 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "RefTileWorkload.hpp" +#include "RefWorkloadUtils.hpp" +#include "Tile.hpp" +#include "Profiling.hpp" + +namespace armnn +{ + + RefTileWorkload::RefTileWorkload(const TileQueueDescriptor& descriptor, const WorkloadInfo& info) + : RefBaseWorkload(descriptor, info) + {} + + void RefTileWorkload::Execute() const + { + Execute(m_Data.m_Inputs, m_Data.m_Outputs); + } + + void RefTileWorkload::ExecuteAsync(ExecutionData& executionData) + { + WorkingMemDescriptor* workingMemDescriptor = static_cast(executionData.m_Data); + Execute(workingMemDescriptor->m_Inputs, workingMemDescriptor->m_Outputs); + } + + void RefTileWorkload::Execute(std::vector inputs, std::vector outputs) const + { + ARMNN_SCOPED_PROFILING_EVENT(Compute::CpuRef, "RefTileWorkload_Execute"); + + const TensorInfo& inputInfo = GetTensorInfo(inputs[0]); + + std::unique_ptr> inputDecoder = MakeDecoder(GetTensorInfo(inputs[0]), + inputs[0]->Map()); + + std::unique_ptr> outputEncoder = MakeEncoder(GetTensorInfo(outputs[0]), + outputs[0]->Map()); + + Tile(m_Data.m_Parameters, + inputInfo, + *inputDecoder, + *outputEncoder); + } + +} // namespace armnn \ No newline at end of file diff --git a/src/backends/reference/workloads/RefTileWorkload.hpp b/src/backends/reference/workloads/RefTileWorkload.hpp new file mode 100644 index 0000000000..2fb8eab05e --- /dev/null +++ b/src/backends/reference/workloads/RefTileWorkload.hpp @@ -0,0 +1,30 @@ +// +// Copyright © 2023 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include "RefBaseWorkload.hpp" +#include + +#include "Tile.hpp" + +namespace armnn +{ + + class RefTileWorkload : public RefBaseWorkload + { + public: + explicit RefTileWorkload(const TileQueueDescriptor& descriptor, + const WorkloadInfo& info); + + void Execute() const override; + void ExecuteAsync(ExecutionData& executionData) override; + + private: + void Execute(std::vector inputs, std::vector 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 e15a7ca047..a36eae501c 100644 --- a/src/backends/reference/workloads/RefWorkloads.hpp +++ b/src/backends/reference/workloads/RefWorkloads.hpp @@ -62,6 +62,7 @@ #include "RefStackWorkload.hpp" #include "RefStridedSliceWorkload.hpp" #include "RefSpaceToDepthWorkload.hpp" +#include "RefTileWorkload.hpp" #include "RefTransposeConvolution2dWorkload.hpp" #include "RefTransposeWorkload.hpp" #include "RefUnidirectionalSequenceLstmWorkload.hpp" diff --git a/src/backends/reference/workloads/Tile.cpp b/src/backends/reference/workloads/Tile.cpp new file mode 100644 index 0000000000..148c51de2e --- /dev/null +++ b/src/backends/reference/workloads/Tile.cpp @@ -0,0 +1,102 @@ +// +// Copyright © 2023 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "Tile.hpp" +#include "Encoders.hpp" +#include +#include +#include + +namespace armnn +{ + +// Converts a flatten index into a multi-dimensional coordinate. +std::vector IndexToCoordinates(std::vector& shape, uint32_t index) +{ + std::vector coordinates; + // Iterating through dimensions starting from the last dimension to the first + for (std::size_t i = shape.size() - 1; i < shape.size(); --i) + { + // Coordinate is found by getting the index and modulus it by the current dimension size + // shape of dimension = dimension size + coordinates.insert(coordinates.begin(), index % shape[i]); + // Pass the index to next iteration making index = index / size of the current dimension + index = index/shape[i]; + } + return coordinates; +} + +// Convert a multidimensional coordinate to a flattened index. +uint32_t CoordinatesToIndex(TensorShape& shape, std::vector& coordinates) +{ + uint32_t index = 0; + uint32_t base = 1; + uint32_t rank = shape.GetNumDimensions(); + for (uint32_t i = rank; i > 0; --i) + { + index = index + coordinates[i - 1] * base; + base = base * shape[i - 1]; + } + return index; +} + +void Tile(const TileDescriptor& params, + const TensorInfo& inputInfo, + Decoder& inputDecoder, + Encoder& outputEncoder) +{ + // Input and output will always have same rank + uint32_t rank = inputInfo.GetNumDimensions(); + + TensorShape inputShape = inputInfo.GetShape(); + + std::vector outputShape(rank); + for (uint32_t i = 0; i < rank; ++i) + { + outputShape[i] = inputShape[i] * params.m_Multiples[i]; + } + + // If all values of multiples are 1, then return the input + if ( std::adjacent_find( params.m_Multiples.begin(), params.m_Multiples.end(), + std::not_equal_to<>() ) == params.m_Multiples.end() && params.m_Multiples[0] == 1) + { + for (uint32_t idx = 0; idx < inputInfo.GetNumElements(); ++idx) + { + float inputValue = inputDecoder.Get(); + ++inputDecoder; + outputEncoder.Set(inputValue); + ++outputEncoder; + } + return; + } + + std::vector inputData = inputDecoder.DecodeTensor(inputInfo.GetShape()); + std::vector outputData; + auto outputNumElements = inputData.size() * static_cast(std::accumulate(begin(params.m_Multiples), + end(params.m_Multiples), + 1, + std::multiplies<>())); + outputData.reserve(outputNumElements); + + for (uint32_t outputIndex = 0; outputIndex < outputNumElements; ++outputIndex) + { + std::vector outputCoords = IndexToCoordinates(outputShape, outputIndex); + + // Converting output coordinates to input coordinates using modulus + std::vector inputCoordinates; + inputCoordinates.reserve(rank); + for (uint32_t i = 0; i < rank; ++i) + { + inputCoordinates.push_back(outputCoords[i] % inputShape[i]); + } + + uint32_t inputIndex = CoordinatesToIndex(inputShape, inputCoordinates); + + outputEncoder[outputIndex]; + outputEncoder.Set(inputData[inputIndex]); + } +} + +} // namespace armnn \ No newline at end of file diff --git a/src/backends/reference/workloads/Tile.hpp b/src/backends/reference/workloads/Tile.hpp new file mode 100644 index 0000000000..4e7ffc9040 --- /dev/null +++ b/src/backends/reference/workloads/Tile.hpp @@ -0,0 +1,21 @@ +// +// Copyright © 2023 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include +#include "Encoders.hpp" +#include "Decoders.hpp" +#include "armnn/Descriptors.hpp" + +namespace armnn +{ + +void Tile(const TileDescriptor& params, + const TensorInfo& inputInfo, + Decoder& inputDecoder, + Encoder& outputEncoder); + +} // namespace armnn \ No newline at end of file -- cgit v1.2.1