From a2493a0483f19fe9654be63a15badfb0834aaff6 Mon Sep 17 00:00:00 2001 From: Narumol Prangnawarat Date: Wed, 19 Aug 2020 14:39:07 +0100 Subject: IVGCVSW-5012 Add importEnabled option for OptimizerOptions * Default importEnabled to false * Improve error messages Signed-off-by: Narumol Prangnawarat Change-Id: I17f78986aa1d23e48b0844297a52029b1a9bbe3e --- include/armnn/INetwork.hpp | 8 +- src/armnn/Network.cpp | 12 +- src/armnn/Network.hpp | 1 + src/armnn/test/TensorHandleStrategyTest.cpp | 2 +- .../backendsCommon/test/CompatibilityTests.cpp | 2 +- src/backends/neon/NeonTensorHandle.hpp | 8 ++ src/backends/neon/test/NeonFallbackTests.cpp | 148 ++++++++++++++++++++- src/backends/neon/test/NeonTensorHandleTests.cpp | 2 +- .../TfLiteYoloV3Big-Armnn.cpp | 4 +- 9 files changed, 174 insertions(+), 13 deletions(-) diff --git a/include/armnn/INetwork.hpp b/include/armnn/INetwork.hpp index 6a143b05fb..5e8a6f2476 100644 --- a/include/armnn/INetwork.hpp +++ b/include/armnn/INetwork.hpp @@ -613,14 +613,17 @@ struct OptimizerOptions , m_Debug(false) , m_ReduceFp32ToBf16(false) , m_shapeInferenceMethod(armnn::ShapeInferenceMethod::ValidateOnly) + , m_ImportEnabled(false) {} OptimizerOptions(bool reduceFp32ToFp16, bool debug, bool reduceFp32ToBf16 = false, - ShapeInferenceMethod shapeInferenceMethod = armnn::ShapeInferenceMethod::ValidateOnly) + ShapeInferenceMethod shapeInferenceMethod = armnn::ShapeInferenceMethod::ValidateOnly, + bool importEnabled = false) : m_ReduceFp32ToFp16(reduceFp32ToFp16) , m_Debug(debug) , m_ReduceFp32ToBf16(reduceFp32ToBf16) , m_shapeInferenceMethod(shapeInferenceMethod) + , m_ImportEnabled(importEnabled) { if (m_ReduceFp32ToFp16 && m_ReduceFp32ToBf16) { @@ -639,6 +642,9 @@ struct OptimizerOptions // Infer output size when not available ShapeInferenceMethod m_shapeInferenceMethod; + + // Enable Import + bool m_ImportEnabled; }; /// Create an optimized version of the network diff --git a/src/armnn/Network.cpp b/src/armnn/Network.cpp index 94a9961a81..dec9468d7b 100644 --- a/src/armnn/Network.cpp +++ b/src/armnn/Network.cpp @@ -861,7 +861,8 @@ EdgeStrategy CalculateEdgeStrategy(BackendsMap& backends, ITensorHandleFactory::FactoryId srcFactoryId, const Layer& layer, const Layer& connectedLayer, - TensorHandleFactoryRegistry& registry) + TensorHandleFactoryRegistry& registry, + bool importEnabled) { auto toBackend = backends.find(connectedLayer.GetBackendId()); ARMNN_ASSERT_MSG(toBackend != backends.end(), "Backend id not found for the connected layer"); @@ -899,7 +900,7 @@ EdgeStrategy CalculateEdgeStrategy(BackendsMap& backends, // Search for export/import options ITensorHandleFactory* srcFactory = registry.GetFactory(srcFactoryId); - if (srcFactory->GetExportFlags() != 0) + if (srcFactory->GetExportFlags() != 0 && importEnabled) { for (auto&& pref : dstPrefs) { @@ -945,11 +946,12 @@ EdgeStrategy CalculateEdgeStrategy(BackendsMap& backends, OptimizationResult SelectTensorHandleStrategy(Graph& optGraph, BackendsMap& backends, TensorHandleFactoryRegistry& registry, + bool importEnabled, Optional&> errMessages) { OptimizationResult result; - optGraph.ForEachLayer([&backends, ®istry, &result, &errMessages](Layer* layer) + optGraph.ForEachLayer([&backends, ®istry, &result, &errMessages, importEnabled](Layer* layer) { ARMNN_ASSERT(layer); @@ -985,7 +987,8 @@ OptimizationResult SelectTensorHandleStrategy(Graph& optGraph, { const Layer& connectedLayer = connection->GetOwningLayer(); - EdgeStrategy strategy = CalculateEdgeStrategy(backends, slotOption, *layer, connectedLayer, registry); + EdgeStrategy strategy = CalculateEdgeStrategy(backends, slotOption, *layer, connectedLayer, + registry, importEnabled); if (strategy == EdgeStrategy::Undefined) { @@ -1122,6 +1125,7 @@ IOptimizedNetworkPtr Optimize(const INetwork& inNetwork, OptimizationResult strategyResult = SelectTensorHandleStrategy(optGraph, backends, tensorHandleFactoryRegistry, + options.m_ImportEnabled, messages); if (strategyResult.m_Error) { diff --git a/src/armnn/Network.hpp b/src/armnn/Network.hpp index 77d6b04919..7136ee4d32 100644 --- a/src/armnn/Network.hpp +++ b/src/armnn/Network.hpp @@ -323,6 +323,7 @@ BackendsMap CreateSupportedBackends(TensorHandleFactoryRegistry& handleFactoryRe OptimizationResult SelectTensorHandleStrategy(Graph& optGraph, BackendsMap& backends, TensorHandleFactoryRegistry& registry, + bool importEnabled, Optional&> errMessages); OptimizationResult AssignBackends(OptimizedNetwork* optNetObjPtr, diff --git a/src/armnn/test/TensorHandleStrategyTest.cpp b/src/armnn/test/TensorHandleStrategyTest.cpp index 976e58eb50..c7aa30f701 100644 --- a/src/armnn/test/TensorHandleStrategyTest.cpp +++ b/src/armnn/test/TensorHandleStrategyTest.cpp @@ -339,7 +339,7 @@ BOOST_AUTO_TEST_CASE(TensorHandleSelectionStrategy) graph.TopologicalSort(); std::vector errors; - auto result = SelectTensorHandleStrategy(graph, backends, registry, errors); + auto result = SelectTensorHandleStrategy(graph, backends, registry, true, errors); BOOST_TEST(result.m_Error == false); BOOST_TEST(result.m_Warning == false); diff --git a/src/backends/backendsCommon/test/CompatibilityTests.cpp b/src/backends/backendsCommon/test/CompatibilityTests.cpp index 599c9842b1..90aa76e3f3 100644 --- a/src/backends/backendsCommon/test/CompatibilityTests.cpp +++ b/src/backends/backendsCommon/test/CompatibilityTests.cpp @@ -64,7 +64,7 @@ BOOST_AUTO_TEST_CASE(Neon_Cl_DirectCompatibility_Test) graph.TopologicalSort(); std::vector errors; - auto result = SelectTensorHandleStrategy(graph, backends, registry, errors); + auto result = SelectTensorHandleStrategy(graph, backends, registry, true, errors); BOOST_TEST(result.m_Error == false); BOOST_TEST(result.m_Warning == false); diff --git a/src/backends/neon/NeonTensorHandle.hpp b/src/backends/neon/NeonTensorHandle.hpp index 4cc610c85a..be5bd45956 100644 --- a/src/backends/neon/NeonTensorHandle.hpp +++ b/src/backends/neon/NeonTensorHandle.hpp @@ -159,6 +159,14 @@ public: return m_Imported; } } + else + { + throw MemoryImportException("NeonTensorHandle::Import is disabled"); + } + } + else + { + throw MemoryImportException("NeonTensorHandle::Incorrect import flag"); } return false; } diff --git a/src/backends/neon/test/NeonFallbackTests.cpp b/src/backends/neon/test/NeonFallbackTests.cpp index cf4d91b119..9a07ed236f 100644 --- a/src/backends/neon/test/NeonFallbackTests.cpp +++ b/src/backends/neon/test/NeonFallbackTests.cpp @@ -60,7 +60,9 @@ BOOST_AUTO_TEST_CASE(FallbackImportToCpuAcc) // optimize the network std::vector backends = { "MockRef", Compute::CpuAcc }; - IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec()); + OptimizerOptions optOptions; + optOptions.m_ImportEnabled = true; + IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec(), optOptions); OptimizedNetwork* optNetObjPtr = PolymorphicDowncast(optNet.get()); Graph& graph = optNetObjPtr->GetGraph(); @@ -196,7 +198,9 @@ BOOST_AUTO_TEST_CASE(FallbackPaddingCopyToCpuAcc) // optimize the network std::vector backends = { "MockRef", Compute::CpuAcc }; - IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec()); + OptimizerOptions optOptions; + optOptions.m_ImportEnabled = true; + IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec(), optOptions); OptimizedNetwork* optNetObjPtr = PolymorphicDowncast(optNet.get()); Graph& graph = optNetObjPtr->GetGraph(); @@ -325,7 +329,9 @@ BOOST_AUTO_TEST_CASE(FallbackImportFromCpuAcc) // optimize the network std::vector backends = { "MockRef", Compute::CpuAcc }; - IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec()); + OptimizerOptions optOptions; + optOptions.m_ImportEnabled = true; + IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec(), optOptions); OptimizedNetwork* optNetObjPtr = PolymorphicDowncast(optNet.get()); Graph& graph = optNetObjPtr->GetGraph(); @@ -461,7 +467,9 @@ BOOST_AUTO_TEST_CASE(FallbackPaddingCopyFromCpuAcc) // optimize the network std::vector backends = { "MockRef", Compute::CpuAcc }; - IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec()); + OptimizerOptions optOptions; + optOptions.m_ImportEnabled = true; + IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec(), optOptions); OptimizedNetwork* optNetObjPtr = PolymorphicDowncast(optNet.get()); Graph& graph = optNetObjPtr->GetGraph(); @@ -544,4 +552,136 @@ BOOST_AUTO_TEST_CASE(FallbackPaddingCopyFromCpuAcc) BOOST_TEST(outputData == expectedOutput); } +BOOST_AUTO_TEST_CASE(FallbackDisableImportFromCpuAcc) +{ + using namespace armnn; + + // Create a mock backend object + MockImportBackendInitialiser initialiser; // Register the Mock Backend + auto backendObjPtr = CreateBackendObject(MockImportBackendId()); + BOOST_TEST((backendObjPtr != nullptr)); + + BackendIdSet backendIds = BackendRegistryInstance().GetBackendIds(); + if (backendIds.find("MockRef") == backendIds.end()) + { + std::string message = "Cannot load MockRef"; + BOOST_FAIL(message); + } + + // Create runtime in which test will run and allow fallback to CpuRef. + IRuntime::CreationOptions options; + IRuntimePtr runtime(IRuntime::Create(options)); + + // Builds up the structure of the network. + INetworkPtr net(INetwork::Create()); + + IConnectableLayer* input0 = net->AddInputLayer(0, "input0"); + IConnectableLayer* input1 = net->AddInputLayer(1, "input1"); + IConnectableLayer* input2 = net->AddInputLayer(2, "input2"); + IConnectableLayer* sub = net->AddSubtractionLayer("sub"); + IConnectableLayer* add = net->AddAdditionLayer("add"); + IConnectableLayer* output = net->AddOutputLayer(0, "output"); + + input0->GetOutputSlot(0).Connect(sub->GetInputSlot(0)); + input1->GetOutputSlot(0).Connect(sub->GetInputSlot(1)); + input2->GetOutputSlot(0).Connect(add->GetInputSlot(0)); + sub->GetOutputSlot(0).Connect(add->GetInputSlot(1)); + add->GetOutputSlot(0).Connect(output->GetInputSlot(0)); + + TensorInfo info = TensorInfo({ 1, 2, 3, 2 }, DataType::Float32); + + input0->GetOutputSlot(0).SetTensorInfo(info); + input1->GetOutputSlot(0).SetTensorInfo(info); + input2->GetOutputSlot(0).SetTensorInfo(info); + sub->GetOutputSlot(0).SetTensorInfo(info); + add->GetOutputSlot(0).SetTensorInfo(info); + + // optimize the network + std::vector backends = { "MockRef", Compute::CpuAcc }; + IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec()); + + OptimizedNetwork* optNetObjPtr = PolymorphicDowncast(optNet.get()); + Graph& graph = optNetObjPtr->GetGraph(); + + armnn::Layer* const layer0 = GetFirstLayerWithName(graph, "input0"); + armnn::Layer* const layer1 = GetFirstLayerWithName(graph, "input1"); + armnn::Layer* const layer2 = GetFirstLayerWithName(graph, "input2"); + armnn::Layer* const layer3 = GetFirstLayerWithName(graph, "sub"); + armnn::Layer* const layer4 = GetFirstLayerWithName(graph, "[ sub (0) -> add (1) ]"); + armnn::Layer* const layer5 = GetFirstLayerWithName(graph, "add"); + armnn::Layer* const layer6 = GetFirstLayerWithName(graph, "output"); + + // Checks order is valid. + BOOST_TEST(CheckOrder(graph, layer0, layer1)); + BOOST_TEST(CheckOrder(graph, layer1, layer2)); + BOOST_TEST(CheckOrder(graph, layer2, layer3)); + BOOST_TEST(CheckOrder(graph, layer3, layer4)); + BOOST_TEST(CheckOrder(graph, layer4, layer5)); + BOOST_TEST(CheckOrder(graph, layer5, layer6)); + + // Load it into the runtime. It should pass. + NetworkId netId; + std::string ignoredErrorMessage; + INetworkProperties networkProperties(false, false); + + runtime->LoadNetwork(netId, std::move(optNet), ignoredErrorMessage, networkProperties); + + // Creates structures for input & output + std::vector inputData0 + { + 1.0f, 1.0f, 2.0f, 2.0f, 2.0f, 3.0f, 4.0f, 4.0f, 5.0f, 5.0f, 6.0f, 0.0f + }; + std::vector inputData1 + { + 0.0f, 1.0f, 1.0f, 2.0f, 3.0f, 3.0f, 3.0f, 4.0f, 4.0f, 5.0f, 5.0f, 6.0f + }; + std::vector inputData2 + { + 12.0f, 11.0f, 10.0f, 9.0f, 8.0f, 7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f + }; + + std::vector outputData(12); + + std::vector expectedOutput + { + 13.0f, 11.0f, 11.0f, 9.0f, 7.0f, 7.0f, 7.0f, 5.0f, 5.0f, 3.0f, 3.0f, -5.0f + }; + + InputTensors inputTensors + { + { 0, armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData0.data()) }, + { 1, armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 1), inputData1.data()) }, + { 2, armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 2), inputData2.data()) } + }; + OutputTensors outputTensors + { + { 0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data()) } + }; + + runtime->GetProfiler(netId)->EnableProfiling(true); + + // Do the inference + runtime->EnqueueWorkload(netId, inputTensors, outputTensors); + + // Retrieve the Profiler.Print() output to get the workload execution + ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance(); + std::stringstream ss; + profilerManager.GetProfiler()->Print(ss);; + std::string dump = ss.str(); + + // Contains CopyMemGeneric between the backends + std::size_t found = dump.find("CopyMemGeneric"); + BOOST_TEST(found != std::string::npos); + + // Does not contain ImportMemGeneric + found = dump.find("ImportMemGeneric"); + BOOST_TEST(found == std::string::npos); + + // Use memory import between backends + BOOST_TEST((layer4->GetType() == LayerType::MemCopy)); + + // Check output is as expected + BOOST_TEST(outputData == expectedOutput); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/backends/neon/test/NeonTensorHandleTests.cpp b/src/backends/neon/test/NeonTensorHandleTests.cpp index c88163227a..97c7dd3474 100644 --- a/src/backends/neon/test/NeonTensorHandleTests.cpp +++ b/src/backends/neon/test/NeonTensorHandleTests.cpp @@ -661,7 +661,7 @@ BOOST_AUTO_TEST_CASE(NeonTensorHandleFactoryMemoryManaged) float testPtr[2] = { 2.5f, 5.5f }; // Cannot import as import is disabled - BOOST_CHECK(!handle->Import(static_cast(testPtr), MemorySource::Malloc)); + BOOST_CHECK_THROW(handle->Import(static_cast(testPtr), MemorySource::Malloc), MemoryImportException); } BOOST_AUTO_TEST_CASE(NeonTensorHandleFactoryImport) diff --git a/tests/TfLiteYoloV3Big-Armnn/TfLiteYoloV3Big-Armnn.cpp b/tests/TfLiteYoloV3Big-Armnn/TfLiteYoloV3Big-Armnn.cpp index 93982fdb98..2d373cd1dd 100644 --- a/tests/TfLiteYoloV3Big-Armnn/TfLiteYoloV3Big-Armnn.cpp +++ b/tests/TfLiteYoloV3Big-Armnn/TfLiteYoloV3Big-Armnn.cpp @@ -119,7 +119,9 @@ int LoadModel(const char* filename, ARMNN_LOG(debug) << "Model loaded ok: " << filename; // Optimize backbone model - auto optimizedModel = Optimize(*model, backendPreferences, runtime.GetDeviceSpec()); + OptimizerOptions options; + options.m_ImportEnabled = enableImport; + auto optimizedModel = Optimize(*model, backendPreferences, runtime.GetDeviceSpec(), options); if (!optimizedModel) { ARMNN_LOG(fatal) << "Could not optimize the model:" << filename; -- cgit v1.2.1