From aba90cd608eb65ab459cd71a6724511a1507763b Mon Sep 17 00:00:00 2001 From: James Conroy Date: Fri, 6 Nov 2020 16:28:18 +0000 Subject: IVGCVSW-5091 Add Logical ops frontend and ref impl * Add frontend and reference implementation for logical ops NOT, AND, OR. * Unary NOT uses existing ElementwiseUnary layer and ElementwiseUnary descriptor. * Binary AND/OR uses new layer LogicalBinary and new LogicalBinary descriptor. * Add serialization/deserializion support and add missing ElementwiseUnary deserializer code. * Add additional Boolean decoder in BaseIterator.hpp. Signed-off-by: James Conroy Change-Id: Id343b01174053a166de1b98b6175e04a5065f720 --- src/armnn/InternalTypes.hpp | 1 + src/armnn/LayersFwd.hpp | 2 + src/armnn/Network.cpp | 6 ++ src/armnn/Network.hpp | 3 + src/armnn/layers/LogicalBinaryLayer.cpp | 80 ++++++++++++++++++++++ src/armnn/layers/LogicalBinaryLayer.hpp | 50 ++++++++++++++ .../test/TestNameAndDescriptorLayerVisitor.cpp | 7 ++ .../test/TestNameAndDescriptorLayerVisitor.hpp | 1 + 8 files changed, 150 insertions(+) create mode 100644 src/armnn/layers/LogicalBinaryLayer.cpp create mode 100644 src/armnn/layers/LogicalBinaryLayer.hpp (limited to 'src/armnn') diff --git a/src/armnn/InternalTypes.hpp b/src/armnn/InternalTypes.hpp index 778408ae60..6e47399871 100644 --- a/src/armnn/InternalTypes.hpp +++ b/src/armnn/InternalTypes.hpp @@ -40,6 +40,7 @@ X(Input) \ X(InstanceNormalization) \ X(L2Normalization) \ + X(LogicalBinary) \ X(LogSoftmax) \ X(Lstm) \ X(QLstm) \ diff --git a/src/armnn/LayersFwd.hpp b/src/armnn/LayersFwd.hpp index ccc5ef2b4c..b9ca61a70b 100644 --- a/src/armnn/LayersFwd.hpp +++ b/src/armnn/LayersFwd.hpp @@ -34,6 +34,7 @@ #include "layers/InputLayer.hpp" #include "layers/InstanceNormalizationLayer.hpp" #include "layers/L2NormalizationLayer.hpp" +#include "layers/LogicalBinaryLayer.hpp" #include "layers/LogSoftmaxLayer.hpp" #include "layers/LstmLayer.hpp" #include "layers/MapLayer.hpp" @@ -126,6 +127,7 @@ DECLARE_LAYER(Gather) DECLARE_LAYER(Input) DECLARE_LAYER(InstanceNormalization) DECLARE_LAYER(L2Normalization) +DECLARE_LAYER(LogicalBinary) DECLARE_LAYER(LogSoftmax) DECLARE_LAYER(Lstm) DECLARE_LAYER(Map) diff --git a/src/armnn/Network.cpp b/src/armnn/Network.cpp index 347e39b4c8..5c55641c82 100644 --- a/src/armnn/Network.cpp +++ b/src/armnn/Network.cpp @@ -1999,6 +1999,12 @@ IConnectableLayer* Network::AddQLstmLayer(const QLstmDescriptor& descriptor, return layer; } +IConnectableLayer* Network::AddLogicalBinaryLayer(const LogicalBinaryDescriptor& logicalBinaryDescriptor, + const char* name) +{ + return m_Graph->AddLayer(logicalBinaryDescriptor, name); +} + void Network::Accept(ILayerVisitor& visitor) const { for (auto layer : GetGraph()) diff --git a/src/armnn/Network.hpp b/src/armnn/Network.hpp index b09ac450d5..c652edb416 100644 --- a/src/armnn/Network.hpp +++ b/src/armnn/Network.hpp @@ -250,6 +250,9 @@ public: IConnectableLayer* AddQuantizedLstmLayer(const QuantizedLstmInputParams& params, const char* name = nullptr) override; + IConnectableLayer* AddLogicalBinaryLayer(const LogicalBinaryDescriptor& logicalBinaryDescriptor, + const char* name = nullptr) override; + void Accept(ILayerVisitor& visitor) const override; private: diff --git a/src/armnn/layers/LogicalBinaryLayer.cpp b/src/armnn/layers/LogicalBinaryLayer.cpp new file mode 100644 index 0000000000..0ae5ea5641 --- /dev/null +++ b/src/armnn/layers/LogicalBinaryLayer.cpp @@ -0,0 +1,80 @@ +// +// Copyright © 2020 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "LogicalBinaryLayer.hpp" + +#include "LayerCloneBase.hpp" + +#include +#include + +#include + +namespace armnn +{ + +LogicalBinaryLayer::LogicalBinaryLayer(const LogicalBinaryDescriptor& param, const char* name) + : LayerWithParameters(2, 1, LayerType::LogicalBinary, param, name) +{ +} + +std::unique_ptr LogicalBinaryLayer::CreateWorkload(const IWorkloadFactory& factory) const +{ + LogicalBinaryQueueDescriptor descriptor; + return factory.CreateLogicalBinary(descriptor, PrepInfoAndDesc(descriptor)); +} + +LogicalBinaryLayer* LogicalBinaryLayer::Clone(Graph& graph) const +{ + return CloneBase(graph, m_Param, GetName()); +} + +std::vector LogicalBinaryLayer::InferOutputShapes(const std::vector& inputShapes) const +{ + ARMNN_ASSERT(inputShapes.size() == 2); + const TensorShape& input0 = inputShapes[0]; + const TensorShape& input1 = inputShapes[1]; + + ARMNN_ASSERT(input0.GetNumDimensions() == input1.GetNumDimensions()); + unsigned int numDims = input0.GetNumDimensions(); + + std::vector dims(numDims); + for (unsigned int i = 0; i < numDims; i++) + { + unsigned int dim0 = input0[i]; + unsigned int dim1 = input1[i]; + + ARMNN_ASSERT_MSG(dim0 == dim1 || dim0 == 1 || dim1 == 1, + "Dimensions should either match or one should be of size 1."); + + dims[i] = std::max(dim0, dim1); + } + + return std::vector({ TensorShape(numDims, dims.data()) }); +} + +void LogicalBinaryLayer::ValidateTensorShapesFromInputs() +{ + VerifyLayerConnections(2, CHECK_LOCATION()); + + const TensorShape& outputShape = GetOutputSlot(0).GetTensorInfo().GetShape(); + + VerifyShapeInferenceType(outputShape, m_ShapeInferenceMethod); + + std::vector inferredShapes = InferOutputShapes({ + GetInputSlot(0).GetConnection()->GetTensorInfo().GetShape(), + GetInputSlot(1).GetConnection()->GetTensorInfo().GetShape() + }); + ARMNN_ASSERT(inferredShapes.size() == 1); + + ValidateAndCopyShape(outputShape, inferredShapes[0], m_ShapeInferenceMethod, "LogicalBinaryLayer"); +} + +void LogicalBinaryLayer::Accept(ILayerVisitor& visitor) const +{ + visitor.VisitLogicalBinaryLayer(this, GetParameters(), GetName()); +} + +} // namespace armnn diff --git a/src/armnn/layers/LogicalBinaryLayer.hpp b/src/armnn/layers/LogicalBinaryLayer.hpp new file mode 100644 index 0000000000..c6b024b36b --- /dev/null +++ b/src/armnn/layers/LogicalBinaryLayer.hpp @@ -0,0 +1,50 @@ +// +// Copyright © 2020 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include "LayerWithParameters.hpp" + +namespace armnn +{ + +/// This layer represents a Logical Binary operation. +class LogicalBinaryLayer : public LayerWithParameters +{ +public: + /// Makes a workload for the LogicalBinary 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 + LogicalBinaryLayer* 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 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 shape(s) will lead to a valid configuration + /// of @ref LogicalBinaryLayer + /// @param [in] shapeInferenceMethod Indicates if output shape shall be overwritten or just validated. + void ValidateTensorShapesFromInputs() override; + + void Accept(ILayerVisitor& visitor) const override; + +protected: + /// Constructor to create a LogicalBinaryLayer + /// @param [in] param LogicalBinaryDescriptor to configure the LogicalBinaryLayer + /// @param [in] name Optional name for the layer + LogicalBinaryLayer(const LogicalBinaryDescriptor& param, const char* name); + + /// Default destructor + ~LogicalBinaryLayer() = default; +}; + +} // namespace armnn \ No newline at end of file diff --git a/src/armnn/test/TestNameAndDescriptorLayerVisitor.cpp b/src/armnn/test/TestNameAndDescriptorLayerVisitor.cpp index 6ab9f9e1e4..7d4dcaae0e 100644 --- a/src/armnn/test/TestNameAndDescriptorLayerVisitor.cpp +++ b/src/armnn/test/TestNameAndDescriptorLayerVisitor.cpp @@ -125,6 +125,12 @@ armnn::L2NormalizationDescriptor GetDescriptor return descriptor; } +template<> +armnn::LogicalBinaryDescriptor GetDescriptor() +{ + return armnn::LogicalBinaryDescriptor(armnn::LogicalBinaryOperation::LogicalOr); +} + template<> armnn::MeanDescriptor GetDescriptor() { @@ -280,6 +286,7 @@ TEST_SUITE_NAME_AND_DESCRIPTOR_LAYER_VISITOR(Fill) TEST_SUITE_NAME_AND_DESCRIPTOR_LAYER_VISITOR(Gather) TEST_SUITE_NAME_AND_DESCRIPTOR_LAYER_VISITOR(InstanceNormalization) TEST_SUITE_NAME_AND_DESCRIPTOR_LAYER_VISITOR(L2Normalization) +TEST_SUITE_NAME_AND_DESCRIPTOR_LAYER_VISITOR(LogicalBinary) TEST_SUITE_NAME_AND_DESCRIPTOR_LAYER_VISITOR(LogSoftmax) TEST_SUITE_NAME_AND_DESCRIPTOR_LAYER_VISITOR(Mean) TEST_SUITE_NAME_AND_DESCRIPTOR_LAYER_VISITOR(Normalization) diff --git a/src/armnn/test/TestNameAndDescriptorLayerVisitor.hpp b/src/armnn/test/TestNameAndDescriptorLayerVisitor.hpp index df0e055157..dc6d11440f 100644 --- a/src/armnn/test/TestNameAndDescriptorLayerVisitor.hpp +++ b/src/armnn/test/TestNameAndDescriptorLayerVisitor.hpp @@ -53,6 +53,7 @@ DECLARE_TEST_NAME_AND_DESCRIPTOR_LAYER_VISITOR_CLASS(Fill) DECLARE_TEST_NAME_AND_DESCRIPTOR_LAYER_VISITOR_CLASS(Gather) DECLARE_TEST_NAME_AND_DESCRIPTOR_LAYER_VISITOR_CLASS(InstanceNormalization) DECLARE_TEST_NAME_AND_DESCRIPTOR_LAYER_VISITOR_CLASS(L2Normalization) +DECLARE_TEST_NAME_AND_DESCRIPTOR_LAYER_VISITOR_CLASS(LogicalBinary) DECLARE_TEST_NAME_AND_DESCRIPTOR_LAYER_VISITOR_CLASS(LogSoftmax) DECLARE_TEST_NAME_AND_DESCRIPTOR_LAYER_VISITOR_CLASS(Mean) DECLARE_TEST_NAME_AND_DESCRIPTOR_LAYER_VISITOR_CLASS(Normalization) -- cgit v1.2.1