From b8a26d8f497f92643288a4c519af4d230ede1d7e Mon Sep 17 00:00:00 2001 From: Sadik Armagan Date: Mon, 4 Oct 2021 15:13:11 +0100 Subject: IVGCVSW-6300 'IMemoryOptimizerStrategy Add strategy library and add support in BackendRegistry' * Updated IRuntime interface for providing custom memory optimizer strategy. * Enabled selecting existing memory optimizer strategy by using BackendOptions * Added MemoryOptimizerStrategyLibrary that sets one of the existing memory optimizer strategies selected by user Signed-off-by: Sadik Armagan Change-Id: I037f8ac8efa79c0f71bd63e379101e3ad92d80c9 --- include/armnn/BackendOptions.hpp | 18 +++ include/armnn/BackendRegistry.hpp | 7 ++ include/armnn/IRuntime.hpp | 14 +++ include/armnn/TypesUtils.hpp | 10 ++ src/armnn/BackendRegistry.cpp | 22 ++++ src/armnn/Runtime.cpp | 40 +++++++ src/backends/backendsCommon/CMakeLists.txt | 3 + .../MemoryOptimizerStrategyFactory.hpp | 28 +++++ .../MemoryOptimizerStrategyLibrary.cpp | 68 +++++++++++ .../MemoryOptimizerStrategyLibrary.hpp | 21 ++++ src/backends/backendsCommon/common.mk | 2 + .../backendsCommon/test/BackendRegistryTests.cpp | 21 ++++ src/backends/backendsCommon/test/CMakeLists.txt | 1 + .../test/CustomMemoryOptimizerStrategyTests.cpp | 125 +++++++++++++++++++++ src/backends/cl/ClBackend.hpp | 3 +- src/backends/neon/NeonBackend.hpp | 3 +- src/backends/reference/RefBackend.hpp | 3 +- 17 files changed, 386 insertions(+), 3 deletions(-) create mode 100644 src/backends/backendsCommon/MemoryOptimizerStrategyFactory.hpp create mode 100644 src/backends/backendsCommon/MemoryOptimizerStrategyLibrary.cpp create mode 100644 src/backends/backendsCommon/MemoryOptimizerStrategyLibrary.hpp create mode 100644 src/backends/backendsCommon/test/CustomMemoryOptimizerStrategyTests.cpp diff --git a/include/armnn/BackendOptions.hpp b/include/armnn/BackendOptions.hpp index b8bf8f51f2..33cecf6614 100644 --- a/include/armnn/BackendOptions.hpp +++ b/include/armnn/BackendOptions.hpp @@ -296,4 +296,22 @@ void ParseOptions(const std::vector& options, BackendId backend, } } +inline bool ParseBooleanBackendOption(const armnn::BackendOptions::Var& value, bool defaultValue) +{ + if (value.IsBool()) + { + return value.AsBool(); + } + return defaultValue; +} + +inline std::string ParseStringBackendOption(const armnn::BackendOptions::Var& value, std::string defaultValue) +{ + if (value.IsString()) + { + return value.AsString(); + } + return defaultValue; +} + } //namespace armnn diff --git a/include/armnn/BackendRegistry.hpp b/include/armnn/BackendRegistry.hpp index c13aa9f8b6..0d09607de2 100644 --- a/include/armnn/BackendRegistry.hpp +++ b/include/armnn/BackendRegistry.hpp @@ -8,7 +8,9 @@ #include #include #include +#include +#include #include #include #include @@ -22,6 +24,7 @@ namespace profiling } class IBackendInternal; using IBackendInternalUniquePtr = std::unique_ptr; +using MemoryOptimizerStrategiesMapRef = std::unordered_map>; class BackendRegistry { @@ -38,6 +41,8 @@ public: void SetProfilingService(armnn::Optional profilingService); void RegisterAllocator(const BackendId& id, std::shared_ptr alloc); std::unordered_map> GetAllocators(); + void RegisterMemoryOptimizerStrategy(const BackendId& id, std::shared_ptr strategy); + MemoryOptimizerStrategiesMapRef GetMemoryOptimizerStrategies(); BackendRegistry() {} virtual ~BackendRegistry() {} @@ -54,6 +59,7 @@ public: void Deregister(const BackendId& id); void DeregisterAllocator(const BackendId &id); + void DeregisterMemoryOptimizerStrategy(const BackendId &id); protected: using FactoryStorage = std::unordered_map; @@ -68,6 +74,7 @@ private: FactoryStorage m_Factories; armnn::Optional m_ProfilingService; std::unordered_map> m_CustomMemoryAllocatorMap; + std::unordered_map> m_MemoryOptimizerStrategyMap; }; BackendRegistry& BackendRegistryInstance(); diff --git a/include/armnn/IRuntime.hpp b/include/armnn/IRuntime.hpp index a46830c95a..ca9a0ceec2 100644 --- a/include/armnn/IRuntime.hpp +++ b/include/armnn/IRuntime.hpp @@ -15,6 +15,7 @@ #include "profiling/ILocalPacketHandler.hpp" #include +#include #include #include @@ -106,6 +107,7 @@ public: , m_DynamicBackendsPath("") , m_ProtectedMode(false) , m_CustomAllocatorMap() + , m_MemoryOptimizerStrategyMap() {} /// If set, uses the GpuAcc tuned parameters from the given object when executing GPU workloads. @@ -135,6 +137,14 @@ public: /// @note Only supported for GpuAcc std::map> m_CustomAllocatorMap; + /// @brief A map to define a custom memory optimizer strategy for specific backend Ids. + /// + /// @details A Memory Optimizer Strategy provides a solution to an abstract representation of + /// a network's memory requirements. This can also be used to return a pre-computed solution + /// for a specific network. Set this if you want to implement a Custom Memory Optimizer Strategy + /// for a given backend. + std::map> m_MemoryOptimizerStrategyMap; + struct ExternalProfilingOptions { ExternalProfilingOptions() @@ -168,6 +178,7 @@ public: /// { /// {"TuningLevel", 2}, /// {"TuningFile", filename} + /// {"MemoryOptimizerStrategy", strategyname} /// } /// }); /// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -185,6 +196,9 @@ public: /// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /// The following backend options are available: + /// AllBackends: + /// "MemoryOptimizerStrategy" : string [stategynameString] + /// (Existing Memory Optimizer Strategies: ConstLayerMemoryOptimizerStrategy) /// GpuAcc: /// "TuningLevel" : int [0..3] (0=UseOnly(default) | 1=RapidTuning | 2=NormalTuning | 3=ExhaustiveTuning) /// "TuningFile" : string [filenameString] diff --git a/include/armnn/TypesUtils.hpp b/include/armnn/TypesUtils.hpp index 9bd9c8148f..d08f592d86 100644 --- a/include/armnn/TypesUtils.hpp +++ b/include/armnn/TypesUtils.hpp @@ -249,6 +249,16 @@ constexpr const char* GetResizeMethodAsCString(ResizeMethod method) } } +constexpr const char* GetMemBlockStrategyTypeName(MemBlockStrategyType memBlockStrategyType) +{ + switch (memBlockStrategyType) + { + case MemBlockStrategyType::SingleAxisPacking: return "SingleAxisPacking"; + case MemBlockStrategyType::MultiAxisPacking: return "MultiAxisPacking"; + default: return "Unknown"; + } +} + template struct IsHalfType : std::integral_constant::value && sizeof(T) == 2> diff --git a/src/armnn/BackendRegistry.cpp b/src/armnn/BackendRegistry.cpp index 80daed9896..ade844fc39 100644 --- a/src/armnn/BackendRegistry.cpp +++ b/src/armnn/BackendRegistry.cpp @@ -128,4 +128,26 @@ std::unordered_map> BackendRegistry return m_CustomMemoryAllocatorMap; } +void BackendRegistry::RegisterMemoryOptimizerStrategy(const BackendId& id, + std::shared_ptr strategy) +{ + if (m_MemoryOptimizerStrategyMap.find(id) != m_MemoryOptimizerStrategyMap.end()) + { + throw InvalidArgumentException( + std::string(id) + " already has an memory optimizer strategy associated with it", + CHECK_LOCATION()); + } + m_MemoryOptimizerStrategyMap[id] = strategy; +} + +void BackendRegistry::DeregisterMemoryOptimizerStrategy(const BackendId &id) +{ + m_MemoryOptimizerStrategyMap.erase(id); +} + +MemoryOptimizerStrategiesMapRef BackendRegistry::GetMemoryOptimizerStrategies() +{ + return m_MemoryOptimizerStrategyMap; +} + } // namespace armnn diff --git a/src/armnn/Runtime.cpp b/src/armnn/Runtime.cpp index 085cf2cee8..50068ebe36 100644 --- a/src/armnn/Runtime.cpp +++ b/src/armnn/Runtime.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -373,6 +374,45 @@ RuntimeImpl::RuntimeImpl(const IRuntime::CreationOptions& options) BackendRegistryInstance().RegisterAllocator(id, customAllocatorMapIterator->second); } } + + // check if custom memory optimizer strategy map is set + if (!options.m_MemoryOptimizerStrategyMap.empty()) + { + auto customMemoryOptimizerStrategyMapIterator = options.m_MemoryOptimizerStrategyMap.find(id); + // if a memory optimizer strategy is provided make the backend use that instead of the default + if (customMemoryOptimizerStrategyMapIterator != options.m_MemoryOptimizerStrategyMap.end()) + { + // no errors.. register the memory optimizer strategy with the BackendRegistry + BackendRegistryInstance().RegisterMemoryOptimizerStrategy( + id, customMemoryOptimizerStrategyMapIterator->second); + + ARMNN_LOG(info) << "MemoryOptimizerStrategy " + << customMemoryOptimizerStrategyMapIterator->second->GetName() + << " set for the backend " << id << "."; + } + } + else + { + // check if to use one of the existing memory optimizer strategies is set + std::string memoryOptimizerStrategyName = ""; + ParseOptions(options.m_BackendOptions, id, [&](std::string name, const BackendOptions::Var& value) + { + if (name == "MemoryOptimizerStrategy") + { + memoryOptimizerStrategyName = ParseStringBackendOption(value, ""); + } + }); + if (memoryOptimizerStrategyName != "") + { + MemoryOptimizerStrategyLibrary memoryOptimizerStrategyLibrary; + if (memoryOptimizerStrategyLibrary.SetMemoryOptimizerStrategy(id, memoryOptimizerStrategyName)) + { + ARMNN_LOG(info) << "MemoryOptimizerStrategy " + << memoryOptimizerStrategyName << " set for the backend " << id << "."; + } + } + } + auto context = backend->CreateBackendContext(options); // backends are allowed to return nullptrs if they diff --git a/src/backends/backendsCommon/CMakeLists.txt b/src/backends/backendsCommon/CMakeLists.txt index c894f986c9..a18ee330d4 100644 --- a/src/backends/backendsCommon/CMakeLists.txt +++ b/src/backends/backendsCommon/CMakeLists.txt @@ -26,6 +26,9 @@ list(APPEND armnnBackendsCommon_sources MemCopyWorkload.hpp MemImportWorkload.cpp MemImportWorkload.hpp + MemoryOptimizerStrategyFactory.hpp + MemoryOptimizerStrategyLibrary.cpp + MemoryOptimizerStrategyLibrary.hpp MemSyncWorkload.cpp MemSyncWorkload.hpp OptimizationViews.cpp diff --git a/src/backends/backendsCommon/MemoryOptimizerStrategyFactory.hpp b/src/backends/backendsCommon/MemoryOptimizerStrategyFactory.hpp new file mode 100644 index 0000000000..62a2182a6e --- /dev/null +++ b/src/backends/backendsCommon/MemoryOptimizerStrategyFactory.hpp @@ -0,0 +1,28 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include + +#include + +namespace armnn +{ + +class MemoryOptimizerStrategyFactory +{ +public: + MemoryOptimizerStrategyFactory() {} + + template + std::shared_ptr CreateMemoryOptimizerStrategy() + { + return std::make_shared(); + } + +}; + +} // namespace armnn \ No newline at end of file diff --git a/src/backends/backendsCommon/MemoryOptimizerStrategyLibrary.cpp b/src/backends/backendsCommon/MemoryOptimizerStrategyLibrary.cpp new file mode 100644 index 0000000000..0b48cbd176 --- /dev/null +++ b/src/backends/backendsCommon/MemoryOptimizerStrategyLibrary.cpp @@ -0,0 +1,68 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "MemoryOptimizerStrategyLibrary.hpp" +#include "MemoryOptimizerStrategyFactory.hpp" + +#include +#include +#include + +#include + +#include + +#include + +namespace +{ +// Default Memory Optimizer Strategies +static const std::vector memoryOptimizationStrategies({ + "ConstLayerMemoryOptimizerStrategy", + }); + +#define CREATE_MEMORY_OPTIMIZER_STRATEGY(strategyName, memoryOptimizerStrategy) \ +{ \ + MemoryOptimizerStrategyFactory memoryOptimizerStrategyFactory; \ + memoryOptimizerStrategy = memoryOptimizerStrategyFactory.CreateMemoryOptimizerStrategy(); \ +} \ + +} // anonymous namespace + +namespace armnn +{ + +bool MemoryOptimizerStrategyLibrary::SetMemoryOptimizerStrategy(const BackendId& id, const std::string& strategyName) +{ + auto isStrategyExist = std::find(memoryOptimizationStrategies.begin(), + memoryOptimizationStrategies.end(), + strategyName) != memoryOptimizationStrategies.end(); + if (isStrategyExist) + { + std::shared_ptr memoryOptimizerStrategy = nullptr; + CREATE_MEMORY_OPTIMIZER_STRATEGY(armnn::ConstLayerMemoryOptimizerStrategy, + memoryOptimizerStrategy); + if (memoryOptimizerStrategy) + { + using BackendCapability = BackendOptions::BackendOption; + auto strategyType = GetMemBlockStrategyTypeName(memoryOptimizerStrategy->GetMemBlockStrategyType()); + BackendCapability memOptimizeStrategyCapability {strategyType, true}; + if (HasCapability(memOptimizeStrategyCapability, id)) + { + BackendRegistryInstance().RegisterMemoryOptimizerStrategy(id, memoryOptimizerStrategy); + return true; + } + // reset shared_ptr memoryOptimizerStrategy + memoryOptimizerStrategy.reset(); + } + } + ARMNN_LOG(warning) << "Backend " + << id + << " is not registered as does not support memory optimizer strategy " + << strategyName << " \n"; + return false; +} + +} // namespace armnn \ No newline at end of file diff --git a/src/backends/backendsCommon/MemoryOptimizerStrategyLibrary.hpp b/src/backends/backendsCommon/MemoryOptimizerStrategyLibrary.hpp new file mode 100644 index 0000000000..795fc640b9 --- /dev/null +++ b/src/backends/backendsCommon/MemoryOptimizerStrategyLibrary.hpp @@ -0,0 +1,21 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// +#pragma once + +#include + +namespace armnn +{ + +class MemoryOptimizerStrategyLibrary +{ +public: + MemoryOptimizerStrategyLibrary() = default; + + bool SetMemoryOptimizerStrategy(const BackendId& id, const std::string& strategyName); + +}; + +} // namespace armnn \ No newline at end of file diff --git a/src/backends/backendsCommon/common.mk b/src/backends/backendsCommon/common.mk index 8c1037ad19..2795c9cc2f 100644 --- a/src/backends/backendsCommon/common.mk +++ b/src/backends/backendsCommon/common.mk @@ -17,6 +17,7 @@ COMMON_SOURCES := \ MapWorkload.cpp \ MemCopyWorkload.cpp \ MemImportWorkload.cpp \ + MemoryOptimizerStrategyLibrary.cpp \ MemSyncWorkload.cpp \ OptimizationViews.cpp \ TensorHandleFactoryRegistry.cpp \ @@ -32,6 +33,7 @@ COMMON_SOURCES := \ COMMON_TEST_SOURCES := \ test/CommonTestUtils.cpp \ + test/CustomMemoryOptimizerStrategyTests.cpp \ test/InstanceNormalizationEndToEndTestImpl.cpp \ test/JsonPrinterTestImpl.cpp \ test/LogSoftmaxEndToEndTestImpl.cpp \ diff --git a/src/backends/backendsCommon/test/BackendRegistryTests.cpp b/src/backends/backendsCommon/test/BackendRegistryTests.cpp index ba21b332e1..5acc61fe2c 100644 --- a/src/backends/backendsCommon/test/BackendRegistryTests.cpp +++ b/src/backends/backendsCommon/test/BackendRegistryTests.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -145,4 +146,24 @@ TEST_CASE("ThrowBackendUnavailableException") BackendRegistryInstance().Deregister(mockBackendId); } +#if defined(ARMNNREF_ENABLED) +TEST_CASE("RegisterMemoryOptimizerStrategy") +{ + using namespace armnn; + + const BackendId cpuRefBackendId(armnn::Compute::CpuRef); + CHECK(BackendRegistryInstance().GetMemoryOptimizerStrategies().empty()); + + // Register the memory optimizer + std::shared_ptr memoryOptimizerStrategy = + std::make_shared(); + BackendRegistryInstance().RegisterMemoryOptimizerStrategy(cpuRefBackendId, memoryOptimizerStrategy); + CHECK(!BackendRegistryInstance().GetMemoryOptimizerStrategies().empty()); + CHECK(BackendRegistryInstance().GetMemoryOptimizerStrategies().size() == 1); + // De-register the memory optimizer + BackendRegistryInstance().DeregisterMemoryOptimizerStrategy(cpuRefBackendId); + CHECK(BackendRegistryInstance().GetMemoryOptimizerStrategies().empty()); +} +#endif + } diff --git a/src/backends/backendsCommon/test/CMakeLists.txt b/src/backends/backendsCommon/test/CMakeLists.txt index ea33513097..e3221c5ae4 100644 --- a/src/backends/backendsCommon/test/CMakeLists.txt +++ b/src/backends/backendsCommon/test/CMakeLists.txt @@ -13,6 +13,7 @@ list(APPEND armnnBackendsCommonUnitTests_sources ChannelShuffleEndToEndTestImpl.hpp ComparisonEndToEndTestImpl.hpp CompatibilityTests.cpp + CustomMemoryOptimizerStrategyTests.cpp DefaultAsyncExecuteTest.cpp DepthToSpaceEndToEndTestImpl.hpp DequantizeEndToEndTestImpl.hpp diff --git a/src/backends/backendsCommon/test/CustomMemoryOptimizerStrategyTests.cpp b/src/backends/backendsCommon/test/CustomMemoryOptimizerStrategyTests.cpp new file mode 100644 index 0000000000..a5bf17c8b1 --- /dev/null +++ b/src/backends/backendsCommon/test/CustomMemoryOptimizerStrategyTests.cpp @@ -0,0 +1,125 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include +#include +#include + +#include + +#if defined(ARMNNREF_ENABLED) +#include +#endif + +#if defined(ARMCOMPUTENEON_ENABLED) +#include +#endif + +#include + + +// Sample implementation of IMemoryOptimizerStrategy.. +class SampleMemoryOptimizerStrategy : public armnn::IMemoryOptimizerStrategy +{ +public: + SampleMemoryOptimizerStrategy() = default; + + std::string GetName() const + { + return std::string("SampleMemoryOptimizerStrategy"); + } + + armnn::MemBlockStrategyType GetMemBlockStrategyType() const + { + return armnn::MemBlockStrategyType::SingleAxisPacking; + } + + std::vector Optimize(std::vector& memBlocks) + { + std::vector memBins; + memBins.reserve(memBlocks.size()); + return memBins; + } +}; + +TEST_SUITE("CustomMemoryOptimizerStrategyTests") +{ + +// Only run this test if CpuRef is enabled +#if defined(ARMNNREF_ENABLED) +TEST_CASE("RefCustomMemoryOptimizerStrategyTest") +{ + using namespace armnn; + + // Create ArmNN runtime + IRuntime::CreationOptions options; // default options + auto customMemoryOptimizerStrategy = std::make_shared(); + options.m_MemoryOptimizerStrategyMap = {{"CpuRef", std::move(customMemoryOptimizerStrategy)}}; + IRuntimePtr run = IRuntime::Create(options); + + CHECK(!BackendRegistryInstance().GetMemoryOptimizerStrategies().empty()); + CHECK(BackendRegistryInstance().GetMemoryOptimizerStrategies().size() == 1); + CHECK(BackendRegistryInstance().GetMemoryOptimizerStrategies().at(RefBackend::GetIdStatic())); + auto optimizerStrategy = BackendRegistryInstance().GetMemoryOptimizerStrategies().at(RefBackend::GetIdStatic()); + CHECK(optimizerStrategy->GetName() == std::string("SampleMemoryOptimizerStrategy")); + + // De-register the memory optimizer + BackendRegistryInstance().DeregisterMemoryOptimizerStrategy(RefBackend::GetIdStatic()); + CHECK(BackendRegistryInstance().GetMemoryOptimizerStrategies().empty()); + +} + +TEST_CASE("CpuRefSetMemoryOptimizerStrategyTest") +{ + using namespace armnn; + + // Create ArmNN runtime + IRuntime::CreationOptions options; // default options + options.m_BackendOptions.emplace_back( + BackendOptions{"CpuRef", + { + {"MemoryOptimizerStrategy", "ConstLayerMemoryOptimizerStrategy"} + } + }); + + IRuntimePtr run = IRuntime::Create(options); + + // ConstLayerMemoryOptimizerStrategy should be registered for CpuRef + CHECK(!BackendRegistryInstance().GetMemoryOptimizerStrategies().empty()); + CHECK(BackendRegistryInstance().GetMemoryOptimizerStrategies().size() == 1); + CHECK(BackendRegistryInstance().GetMemoryOptimizerStrategies().at(RefBackend::GetIdStatic())); + auto optimizerStrategy = BackendRegistryInstance().GetMemoryOptimizerStrategies().at(RefBackend::GetIdStatic()); + CHECK(optimizerStrategy->GetName() == std::string("ConstLayerMemoryOptimizerStrategy")); + armnn::BackendRegistryInstance().DeregisterMemoryOptimizerStrategy(RefBackend::GetIdStatic()); +} + +#endif + +// Only run this test if CpuAcc is enabled +#if defined(ARMCOMPUTENEON_ENABLED) + +TEST_CASE("CpuAccSetMemoryOptimizerStrategyTest") +{ + using namespace armnn; + + // Create ArmNN runtime + IRuntime::CreationOptions options; // default options + options.m_BackendOptions.emplace_back( + BackendOptions{"CpuAcc", + { + {"MemoryOptimizerStrategy", "NotExistMemoryOptimizerStrategy"} + } + }); + + IRuntimePtr run = IRuntime::Create(options); + + // No MemoryOptimizerStrategy should be registered.. + CHECK(armnn::BackendRegistryInstance().GetMemoryOptimizerStrategies().empty()); + armnn::BackendRegistryInstance().DeregisterMemoryOptimizerStrategy(NeonBackend::GetIdStatic()); +} + +#endif + +} // test suite CustomMemoryOptimizerStrategyTests \ No newline at end of file diff --git a/src/backends/cl/ClBackend.hpp b/src/backends/cl/ClBackend.hpp index 80e4b97ff4..e0708d18e2 100644 --- a/src/backends/cl/ClBackend.hpp +++ b/src/backends/cl/ClBackend.hpp @@ -30,7 +30,8 @@ const BackendCapabilities gpuAccCapabilities("GpuAcc", {"ConstantTensorsAsInputs", false}, {"PreImportIOTensors", false}, {"ExternallyManagedMemory", false}, - {"MultiAxisPacking", false} + {"MultiAxisPacking", false}, + {"SingleAxisPacking", true} }); class ClBackend : public IBackendInternal diff --git a/src/backends/neon/NeonBackend.hpp b/src/backends/neon/NeonBackend.hpp index d28ac3bfcd..37e1722984 100644 --- a/src/backends/neon/NeonBackend.hpp +++ b/src/backends/neon/NeonBackend.hpp @@ -18,7 +18,8 @@ const BackendCapabilities cpuAccCapabilities("GpuAcc", {"ConstantTensorsAsInputs", false}, {"PreImportIOTensors", false}, {"ExternallyManagedMemory", false}, - {"MultiAxisPacking", false} + {"MultiAxisPacking", false}, + {"SingleAxisPacking", true} }); diff --git a/src/backends/reference/RefBackend.hpp b/src/backends/reference/RefBackend.hpp index c04bf43db3..93a1cf4844 100644 --- a/src/backends/reference/RefBackend.hpp +++ b/src/backends/reference/RefBackend.hpp @@ -17,7 +17,8 @@ const BackendCapabilities cpuRefCapabilities("CpuRef", {"ConstantTensorsAsInputs", true}, {"PreImportIOTensors", false}, {"ExternallyManagedMemory", false}, - {"MultiAxisPacking", false} + {"MultiAxisPacking", false}, + {"SingleAxisPacking", true} }); const std::set oldCpuRefCapabilities { -- cgit v1.2.1