From 4cc341cf8b5a6e6bb0543504cbbfde6fa11a2cdb Mon Sep 17 00:00:00 2001 From: Mike Kelly Date: Fri, 7 Jul 2023 15:43:06 +0100 Subject: IVGCVSW-7830 Add backend optimizations to remove Reshapes where possible * Added optimization to remove reshapes for Neon and Ref Backends by using overridden TensorInfos * Added ability to delete Subgraphs during Optimization * Fixed naming error in NeonEndToEndTests and CLEndToEndTests * Added LayerNameAndTypeCheck for testing. * Fixed error where layers were not marked as altered when removed in CLBackend Signed-off-by: Mike Kelly Change-Id: I1ac25cd4ec9821470d961831ae2c8d24882276cc --- src/backends/reference/RefBackend.cpp | 13 +++- src/backends/reference/RefTensorHandle.cpp | 69 +++++++++++++++-- src/backends/reference/RefTensorHandle.hpp | 88 +++++++++++++++++++++- .../reference/test/RefCreateWorkloadTests.cpp | 48 ++++++++++++ src/backends/reference/test/RefEndToEndTests.cpp | 17 +++++ 5 files changed, 223 insertions(+), 12 deletions(-) (limited to 'src/backends/reference') diff --git a/src/backends/reference/RefBackend.cpp b/src/backends/reference/RefBackend.cpp index 8c8879c8be..02749af1f9 100644 --- a/src/backends/reference/RefBackend.cpp +++ b/src/backends/reference/RefBackend.cpp @@ -1,5 +1,5 @@ // -// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -16,8 +16,6 @@ #include #include -#include - namespace armnn { @@ -116,9 +114,16 @@ OptimizationViews RefBackend::OptimizeSubgraphView(const SubgraphView& subgraph, } } } + + // Remove Reshape where possible + if (base.GetType() == LayerType::Reshape) + { + ReshapeLayer* baseLayer = PolymorphicDowncast(&base); + RemoveReshapeLayer(baseLayer, untouched, optimizationViews); + } } - if (optimizationViews.GetSubstitutions().empty()) + if (optimizationViews.GetSubstitutions().empty() && optimizationViews.GetDeletedSubgraphs().empty()) { optimizationViews.AddUntouchedSubgraph(SubgraphView(subgraph)); } diff --git a/src/backends/reference/RefTensorHandle.cpp b/src/backends/reference/RefTensorHandle.cpp index dbfa374945..cce992c947 100644 --- a/src/backends/reference/RefTensorHandle.cpp +++ b/src/backends/reference/RefTensorHandle.cpp @@ -1,29 +1,40 @@ // -// Copyright © 2017 Arm Ltd. All rights reserved. +// Copyright © 2019-2023 Arm Ltd. All rights reserved. // SPDX-License-Identifier: MIT // + #include "RefTensorHandle.hpp" namespace armnn { -RefTensorHandle::RefTensorHandle(const TensorInfo &tensorInfo, std::shared_ptr &memoryManager): +RefTensorHandle::RefTensorHandle(const TensorInfo& tensorInfo, std::shared_ptr& memoryManager): m_TensorInfo(tensorInfo), m_MemoryManager(memoryManager), m_Pool(nullptr), m_UnmanagedMemory(nullptr), - m_ImportedMemory(nullptr) + m_ImportedMemory(nullptr), + m_Decorated() { - } RefTensorHandle::RefTensorHandle(const TensorInfo& tensorInfo) : m_TensorInfo(tensorInfo), m_Pool(nullptr), m_UnmanagedMemory(nullptr), - m_ImportedMemory(nullptr) + m_ImportedMemory(nullptr), + m_Decorated() { +} +RefTensorHandle::RefTensorHandle(const TensorInfo& tensorInfo, const RefTensorHandle& parent) + : m_TensorInfo(tensorInfo), + m_MemoryManager(parent.m_MemoryManager), + m_Pool(parent.m_Pool), + m_UnmanagedMemory(parent.m_UnmanagedMemory), + m_ImportedMemory(parent.m_ImportedMemory), + m_Decorated() +{ } RefTensorHandle::~RefTensorHandle() @@ -139,4 +150,52 @@ bool RefTensorHandle::CanBeImported(void *memory, MemorySource source) return false; } +std::shared_ptr RefTensorHandle::DecorateTensorHandle(const TensorInfo& tensorInfo) +{ + auto decorated = std::make_shared(tensorInfo, *this); + m_Decorated.emplace_back(decorated); + return decorated; +} + +RefTensorHandleDecorator::RefTensorHandleDecorator(const TensorInfo& tensorInfo, const RefTensorHandle& parent) +: RefTensorHandle(tensorInfo) +, m_TensorInfo(tensorInfo) +, m_Parent(parent) +{ +} + +void RefTensorHandleDecorator::Manage() +{ +} + +void RefTensorHandleDecorator::Allocate() +{ +} + +const void* RefTensorHandleDecorator::Map(bool unused) const +{ + return m_Parent.Map(unused); +} + +MemorySourceFlags RefTensorHandleDecorator::GetImportFlags() const +{ + return static_cast(MemorySource::Malloc); +} + +bool RefTensorHandleDecorator::Import(void*, MemorySource ) +{ + return false; +} + +bool RefTensorHandleDecorator::CanBeImported(void* , MemorySource) +{ + return false; +} + +std::shared_ptr RefTensorHandleDecorator::DecorateTensorHandle(const TensorInfo&) +{ + return nullptr; +} + + } diff --git a/src/backends/reference/RefTensorHandle.hpp b/src/backends/reference/RefTensorHandle.hpp index b4dedd5e77..128f623cd3 100644 --- a/src/backends/reference/RefTensorHandle.hpp +++ b/src/backends/reference/RefTensorHandle.hpp @@ -1,7 +1,8 @@ // -// Copyright © 2017 Arm Ltd. All rights reserved. +// Copyright © 2019-2023 Arm Ltd. All rights reserved. // SPDX-License-Identifier: MIT // + #pragma once #include @@ -11,14 +12,17 @@ namespace armnn { +class RefTensorHandleDecorator; // An implementation of ITensorHandle with simple "bump the pointer" memory-management behaviour class RefTensorHandle : public ITensorHandle { public: - RefTensorHandle(const TensorInfo& tensorInfo, std::shared_ptr &memoryManager); + RefTensorHandle(const TensorInfo& tensorInfo, std::shared_ptr& memoryManager); RefTensorHandle(const TensorInfo& tensorInfo); + RefTensorHandle(const TensorInfo& tensorInfo, const RefTensorHandle& parent); + ~RefTensorHandle(); virtual void Manage() override; @@ -56,6 +60,8 @@ public: virtual bool Import(void* memory, MemorySource source) override; virtual bool CanBeImported(void* memory, MemorySource source) override; + virtual std::shared_ptr DecorateTensorHandle(const TensorInfo& tensorInfo) override; + private: // Only used for testing void CopyOutTo(void*) const override; @@ -68,10 +74,86 @@ private: TensorInfo m_TensorInfo; - std::shared_ptr m_MemoryManager; + mutable std::shared_ptr m_MemoryManager; RefMemoryManager::Pool* m_Pool; mutable void* m_UnmanagedMemory; void* m_ImportedMemory; + std::vector> m_Decorated; +}; + +class RefTensorHandleDecorator : public RefTensorHandle +{ +public: + RefTensorHandleDecorator(const TensorInfo& tensorInfo, const RefTensorHandle& parent); + + ~RefTensorHandleDecorator() = default; + + virtual void Manage() override; + + virtual void Allocate() override; + + virtual ITensorHandle* GetParent() const override + { + return nullptr; + } + + virtual const void* Map(bool /* blocking = true */) const override; + using ITensorHandle::Map; + + virtual void Unmap() const override + {} + + TensorShape GetStrides() const override + { + return GetUnpaddedTensorStrides(m_TensorInfo); + } + + TensorShape GetShape() const override + { + return m_TensorInfo.GetShape(); + } + + const TensorInfo& GetTensorInfo() const + { + return m_TensorInfo; + } + + virtual MemorySourceFlags GetImportFlags() const override; + + virtual bool Import(void* memory, MemorySource source) override; + virtual bool CanBeImported(void* memory, MemorySource source) override; + + virtual std::shared_ptr DecorateTensorHandle(const TensorInfo& tensorInfo) override; + + /// Map the tensor data for access. Must be paired with call to Unmap(). + /// \param blocking hint to block the calling thread until all other accesses are complete. (backend dependent) + /// \return pointer to the first element of the mapped data. + void* Map(bool blocking=true) + { + return const_cast(static_cast(this)->Map(blocking)); + } + + /// Unmap the tensor data that was previously mapped with call to Map(). + void Unmap() + { + return static_cast(this)->Unmap(); + } + + /// Testing support to be able to verify and set tensor data content + void CopyOutTo(void* /* memory */) const override + {}; + + void CopyInFrom(const void* /* memory */) override + {}; + + /// Unimport externally allocated memory + void Unimport() override + {}; + +private: + TensorInfo m_TensorInfo; + const RefTensorHandle& m_Parent; }; } + diff --git a/src/backends/reference/test/RefCreateWorkloadTests.cpp b/src/backends/reference/test/RefCreateWorkloadTests.cpp index 894dd75ef2..13ac7fc233 100644 --- a/src/backends/reference/test/RefCreateWorkloadTests.cpp +++ b/src/backends/reference/test/RefCreateWorkloadTests.cpp @@ -1314,4 +1314,52 @@ TEST_CASE("ReplaceFunctionsfromUint8toFloat16ActivationWorkload") RefCreateActivationWorkloadReplaceFunctionsTest(); } +bool TestRefTensorHandleInfo(armnn::RefTensorHandle* handle, const armnn::TensorInfo& expectedInfo) +{ + const TensorInfo handleInfo = handle->GetTensorInfo(); + const TensorInfo expectedAclInfo = expectedInfo; + + if (handleInfo.GetDataType() != expectedAclInfo.GetDataType()) + { + return false; + } + + if (handleInfo.GetNumDimensions() != expectedAclInfo.GetNumDimensions()) + { + return false; + } + + for (unsigned int d = 0; d < expectedAclInfo.GetNumDimensions(); ++d) + { + if (handleInfo.GetShape()[d] != expectedAclInfo.GetShape()[d]) + { + return false; + } + } + + return true; +} + +TEST_CASE("RefCreateSplitterWorkload") +{ + Graph graph; + RefWorkloadFactory factory = GetFactory(); + + auto workload = CreateSplitterWorkloadTest(factory, graph); + + // Checks that outputs are as we expect them (see definition of CreateSplitterWorkloadTest). + SplitterQueueDescriptor queueDescriptor = workload->GetData(); + auto inputHandle = PolymorphicDowncast(queueDescriptor.m_Inputs[0]); + CHECK(TestRefTensorHandleInfo(inputHandle, TensorInfo({5, 7, 7}, DataType::Float32))); + + auto outputHandle0 = PolymorphicDowncast(queueDescriptor.m_Outputs[0]); + CHECK(TestRefTensorHandleInfo(outputHandle0, TensorInfo({1, 7, 7}, DataType::Float32))); + + auto outputHandle1 = PolymorphicDowncast(queueDescriptor.m_Outputs[1]); + CHECK(TestRefTensorHandleInfo(outputHandle1, TensorInfo({2, 7, 7}, DataType::Float32))); + + auto outputHandle2 = PolymorphicDowncast(queueDescriptor.m_Outputs[2]); + CHECK(TestRefTensorHandleInfo(outputHandle2, TensorInfo({2, 7, 7}, DataType::Float32))); +} + } diff --git a/src/backends/reference/test/RefEndToEndTests.cpp b/src/backends/reference/test/RefEndToEndTests.cpp index 4bb3f2947a..eb2aabcd1e 100644 --- a/src/backends/reference/test/RefEndToEndTests.cpp +++ b/src/backends/reference/test/RefEndToEndTests.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -1618,6 +1619,22 @@ TEST_CASE("RefSquaredDifferenceEndToEndTestUint8") { ElementwiseBinarySimpleEndToEnd(defaultBackends, BinaryOperation::SqDiff); } + #endif +// Backend Optimization Tests +TEST_CASE("RefReshapeRemovalSimpleCaseEndToEnd") +{ + ReshapeRemovalEndToEnd(defaultBackends); +} + +TEST_CASE("RefReshapeRemovalNCHWFirstEndToEnd") +{ + ReshapeRemovalNCHWEndToEnd(defaultBackends, true, true); +} + +TEST_CASE("RefReshapeRemovalNCHWSecondEndToEnd") +{ + ReshapeRemovalNCHWEndToEnd(defaultBackends, true, false); +} } -- cgit v1.2.1