From b3021435ad91e494af01ca0778915877dc0780c0 Mon Sep 17 00:00:00 2001 From: Sadik Armagan Date: Wed, 13 Jan 2021 15:56:51 +0000 Subject: IVGCVSW-4417 'Serialise ArmNN Model on android-nn-driver' * Implemented serialization of the network on android-nn-driver !armnn:4850 Signed-off-by: Sadik Armagan Change-Id: I3caf07bd4d1d2a3068c58f0b344303c4cf977ca6 --- 1.2/ArmnnDriverImpl.cpp | 16 +++++++---- 1.3/ArmnnDriverImpl.cpp | 16 +++++++---- ArmnnDriverImpl.cpp | 16 +++++++---- ModelToINetworkConverter.cpp | 8 +++--- Utils.cpp | 64 +++++++++++++++++++++++++++++++++++++------- Utils.hpp | 12 ++++++++- 6 files changed, 104 insertions(+), 28 deletions(-) diff --git a/1.2/ArmnnDriverImpl.cpp b/1.2/ArmnnDriverImpl.cpp index d5539bc6..2ef51db8 100644 --- a/1.2/ArmnnDriverImpl.cpp +++ b/1.2/ArmnnDriverImpl.cpp @@ -125,6 +125,11 @@ Return ArmnnDriverImpl::prepareArmnnModel_1_2( return V1_0::ErrorStatus::NONE; } + // Serialize the network graph to a .armnn file if an output directory + // has been specified in the drivers' arguments. + auto serializedNetworkFileName = + SerializeNetwork(*modelConverter.GetINetwork(), options.GetRequestInputsAndOutputsDumpDir()); + // Optimize the network armnn::IOptimizedNetworkPtr optNet(nullptr, nullptr); armnn::OptimizerOptions OptOptions; @@ -195,11 +200,12 @@ Return ArmnnDriverImpl::prepareArmnnModel_1_2( return V1_0::ErrorStatus::NONE; } - // Now that we have a networkId for the graph rename the dump file to use it - // so that we can associate the graph file and the input/output tensor dump files - RenameGraphDotFile(dotGraphFileName, - options.GetRequestInputsAndOutputsDumpDir(), - netId); + // Now that we have a networkId for the graph rename the exported files to use it + // so that we can associate the graph file and the input/output tensor exported files + RenameExportedFiles(serializedNetworkFileName, + dotGraphFileName, + options.GetRequestInputsAndOutputsDumpDir(), + netId); std::unique_ptr> preparedModel( new ArmnnPreparedModel_1_2( diff --git a/1.3/ArmnnDriverImpl.cpp b/1.3/ArmnnDriverImpl.cpp index 595df0a9..c9f0340d 100644 --- a/1.3/ArmnnDriverImpl.cpp +++ b/1.3/ArmnnDriverImpl.cpp @@ -136,6 +136,11 @@ Return ArmnnDriverImpl::prepareArmnnModel_1_3( return V1_3::ErrorStatus::NONE; } + // Serialize the network graph to a .armnn file if an output directory + // has been specified in the drivers' arguments. + auto serializedNetworkFileName = + SerializeNetwork(*modelConverter.GetINetwork(), options.GetRequestInputsAndOutputsDumpDir()); + // Optimize the network armnn::IOptimizedNetworkPtr optNet(nullptr, nullptr); armnn::OptimizerOptions OptOptions; @@ -206,11 +211,12 @@ Return ArmnnDriverImpl::prepareArmnnModel_1_3( return V1_3::ErrorStatus::NONE; } - // Now that we have a networkId for the graph rename the dump file to use it - // so that we can associate the graph file and the input/output tensor dump files - RenameGraphDotFile(dotGraphFileName, - options.GetRequestInputsAndOutputsDumpDir(), - netId); + // Now that we have a networkId for the graph rename the exported files to use it + // so that we can associate the graph file and the input/output tensor exported files + RenameExportedFiles(serializedNetworkFileName, + dotGraphFileName, + options.GetRequestInputsAndOutputsDumpDir(), + netId); std::unique_ptr> preparedModel( new ArmnnPreparedModel_1_3( diff --git a/ArmnnDriverImpl.cpp b/ArmnnDriverImpl.cpp index ef37cae6..917370cf 100644 --- a/ArmnnDriverImpl.cpp +++ b/ArmnnDriverImpl.cpp @@ -100,6 +100,11 @@ Return ArmnnDriverImpl::prepareModel( return V1_0::ErrorStatus::NONE; } + // Serialize the network graph to a .armnn file if an output directory + // has been specified in the drivers' arguments. + auto serializedNetworkFileName = + SerializeNetwork(*modelConverter.GetINetwork(), options.GetRequestInputsAndOutputsDumpDir()); + // Optimize the network armnn::IOptimizedNetworkPtr optNet(nullptr, nullptr); armnn::OptimizerOptions OptOptions; @@ -169,11 +174,12 @@ Return ArmnnDriverImpl::prepareModel( return V1_0::ErrorStatus::NONE; } - // Now that we have a networkId for the graph rename the dump file to use it - // so that we can associate the graph file and the input/output tensor dump files - RenameGraphDotFile(dotGraphFileName, - options.GetRequestInputsAndOutputsDumpDir(), - netId); + // Now that we have a networkId for the graph rename the exported files to use it + // so that we can associate the graph file and the input/output tensor exported files + RenameExportedFiles(serializedNetworkFileName, + dotGraphFileName, + options.GetRequestInputsAndOutputsDumpDir(), + netId); sp> preparedModel( new ArmnnPreparedModel( diff --git a/ModelToINetworkConverter.cpp b/ModelToINetworkConverter.cpp index e8cf8a8b..c205a575 100644 --- a/ModelToINetworkConverter.cpp +++ b/ModelToINetworkConverter.cpp @@ -87,8 +87,9 @@ void ModelToINetworkConverter::Convert() const HalOperand& operand = getMainModel(m_Model).operands[inputIndex]; ALOGV("ModelToINetworkConverter::Convert(): GetTensorInfoForOperand(operand)"); const armnn::TensorInfo& tensor = GetTensorInfoForOperand(operand); - ALOGV("ModelToINetworkConverter::Convert(): m_Data.m_Network->AddInputLayer(i)"); - armnn::IConnectableLayer* layer = m_Data.m_Network->AddInputLayer(i); + const std::string layerName = "Input_" + std::to_string(i); + ALOGV("ModelToINetworkConverter::Convert(): m_Data.m_Network->AddInputLayer(i, layerName.c_str())"); + armnn::IConnectableLayer* layer = m_Data.m_Network->AddInputLayer(i, layerName.c_str()); ALOGV("ModelToINetworkConverter::Convert(): layer->GetOutputSlot(0)"); armnn::IOutputSlot& outputSlot = layer->GetOutputSlot(0); @@ -184,7 +185,8 @@ void ModelToINetworkConverter::Convert() uint32_t outputIndex = getMainModel(m_Model).outputIndexes[i]; const HalOperand& operand = getMainModel(m_Model).operands[outputIndex]; const armnn::TensorInfo& tensor = GetTensorInfoForOperand(operand); - armnn::IConnectableLayer* layer = m_Data.m_Network->AddOutputLayer(i); + const std::string layerName = "Output_" + std::to_string(i); + armnn::IConnectableLayer* layer = m_Data.m_Network->AddOutputLayer(i, layerName.c_str()); assert(m_Data.m_OutputSlotForOperand[outputIndex]); m_Data.m_OutputSlotForOperand[outputIndex]->Connect(layer->GetInputSlot(0)); diff --git a/Utils.cpp b/Utils.cpp index 895278a4..53877bad 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -8,6 +8,7 @@ #include "Utils.hpp" #include "Half.hpp" +#include #include #include @@ -22,8 +23,6 @@ #include #include - - using namespace android; using namespace android::hardware; using namespace android::hidl::memory::V1_0; @@ -572,6 +571,41 @@ std::string ExportNetworkGraphToDotFile(const armnn::IOptimizedNetwork& optimize return fileName; } +std::string SerializeNetwork(const armnn::INetwork& network, const std::string& dumpDir) +{ + std::string fileName; + // The dump directory must exist in advance. + if (dumpDir.empty()) + { + return fileName; + } + + std::string timestamp = GetFileTimestamp(); + if (timestamp.empty()) + { + return fileName; + } + + auto serializer(armnnSerializer::ISerializer::Create()); + + // Serialize the Network + serializer->Serialize(network); + + // Set the name of the output .armnn file. + fs::path dumpPath = dumpDir; + fs::path tempFilePath = dumpPath / (timestamp + "_network.armnn"); + fileName = tempFilePath.string(); + + // Save serialized network to a file + std::ofstream serializedFile(fileName, std::ios::out | std::ios::binary); + bool serialized = serializer->SaveSerializedToStream(serializedFile); + if (!serialized) + { + ALOGW("An error occurred when serializing to file %s", fileName.c_str()); + } + return fileName; +} + bool IsDynamicTensor(const armnn::TensorInfo& tensorInfo) { if (tensorInfo.GetShape().GetDimensionality() == armnn::Dimensionality::NotSpecified) @@ -613,25 +647,37 @@ std::string GetFileTimestamp() return ss.str(); } -void RenameGraphDotFile(const std::string& oldName, const std::string& dumpDir, const armnn::NetworkId networkId) +void RenameExportedFiles(const std::string& existingSerializedFileName, + const std::string& existingDotFileName, + const std::string& dumpDir, + const armnn::NetworkId networkId) { if (dumpDir.empty()) { return; } - if (oldName.empty()) + RenameFile(existingSerializedFileName, std::string("_network.armnn"), dumpDir, networkId); + RenameFile(existingDotFileName, std::string("_networkgraph.dot"), dumpDir, networkId); +} + +void RenameFile(const std::string& existingName, + const std::string& extension, + const std::string& dumpDir, + const armnn::NetworkId networkId) +{ + if (existingName.empty() || dumpDir.empty()) { return; } - fs::path dumpPath = dumpDir; - const fs::path newFileName = dumpPath / (std::to_string(networkId) + "_networkgraph.dot"); - int iRet = rename(oldName.c_str(), newFileName.c_str()); + fs::path dumpPath = dumpDir; + const fs::path newFileName = dumpPath / (std::to_string(networkId) + extension); + int iRet = rename(existingName.c_str(), newFileName.c_str()); if (iRet != 0) { std::stringstream ss; - ss << "rename of [" << oldName << "] to [" << newFileName << "] failed with errno " << std::to_string(errno) - << " : " << std::strerror(errno); + ss << "rename of [" << existingName << "] to [" << newFileName << "] failed with errno " + << std::to_string(errno) << " : " << std::strerror(errno); ALOGW(ss.str().c_str()); } } diff --git a/Utils.hpp b/Utils.hpp index e3b7d822..c4d89f7e 100644 --- a/Utils.hpp +++ b/Utils.hpp @@ -135,7 +135,17 @@ void DumpJsonProfilingIfRequired(bool gpuProfilingEnabled, std::string ExportNetworkGraphToDotFile(const armnn::IOptimizedNetwork& optimizedNetwork, const std::string& dumpDir); -void RenameGraphDotFile(const std::string& oldName, const std::string& dumpDir, const armnn::NetworkId networkId); +std::string SerializeNetwork(const armnn::INetwork& network, const std::string& dumpDir); + +void RenameExportedFiles(const std::string& existingSerializedFileName, + const std::string& existingDotFileName, + const std::string& dumpDir, + const armnn::NetworkId networkId); + +void RenameFile(const std::string& existingName, + const std::string& extension, + const std::string& dumpDir, + const armnn::NetworkId networkId); /// Checks if a tensor info represents a dynamic tensor bool IsDynamicTensor(const armnn::TensorInfo& outputInfo); -- cgit v1.2.1