[GNA] Added export input/output names (#2601)
authorAndrey Dmitriev <andrey.dmitriev@intel.com>
Tue, 3 Nov 2020 07:45:08 +0000 (10:45 +0300)
committerGitHub <noreply@github.com>
Tue, 3 Nov 2020 07:45:08 +0000 (10:45 +0300)
* [GNA] Added export input/output names

* fix comment

* Change version

inference-engine/src/gna_plugin/gna_model_serial.cpp
inference-engine/src/gna_plugin/gna_model_serial.hpp
inference-engine/src/gna_plugin/serial/headers/2dot3/gna_model_header.hpp [new file with mode: 0644]
inference-engine/src/gna_plugin/serial/headers/latest/gna_model_header.hpp
inference-engine/tests/functional/plugin/gna/import_export_network.cpp

index c74d1c7..b36e4b6 100644 (file)
@@ -107,9 +107,10 @@ GNAPluginNS::HeaderLatest::ModelHeader GNAModelSerial::ReadHeader(std::istream &
             switch (header.version.minor) {
                 case 1:
                     readBits(tempHeader2dot1, is);
-                    header = Header2dot2::ModelHeader(tempHeader2dot1);
+                    header = Header2dot3::ModelHeader(tempHeader2dot1);
                     break;
                 case 2:
+                case 3:
                     readBits(header, is);
                     break;
                 default:
@@ -166,7 +167,30 @@ void GNAModelSerial::Import(void *basePointer,
         InferenceEngine::OutputsDataMap& outputsDataMap) {
     is.exceptions(std::istream::failbit);
 
+    if (modelHeader.version.major == 2) {
+        if (modelHeader.version.minor >= 3) {
+            for (auto inputIndex = 0; inputIndex < modelHeader.nInputs; inputIndex++) {
+                uint32_t nameSize = 0;
+                readNBits<32>(nameSize, is);
+                std::string inName("", nameSize);
+                readNBytes(&inName[0], nameSize, is);
+                inputNames.push_back(inName.substr(0, nameSize - 1));
+            }
+        }
+    }
     ImportInputs(is, basePointer, inputsDesc, inputsDataMap);
+
+    if (modelHeader.version.major == 2) {
+        if (modelHeader.version.minor >= 3) {
+            for (auto inputIndex = 0; inputIndex < modelHeader.nOutputs; inputIndex++) {
+                uint32_t nameSize = 0;
+                readNBits<32>(nameSize, is);
+                std::string outName("", nameSize);
+                readNBytes(&outName[0], nameSize, is);
+                outputNames.push_back(outName.substr(0, nameSize - 1));
+            }
+        }
+    }
     ImportOutputs(is, basePointer, desc, outputsDataMap);
 
     for (auto operation = gna2Model->Operations; operation != gna2Model->Operations + gna2Model->NumberOfOperations; ++operation) {
@@ -311,9 +335,19 @@ void GNAModelSerial::Export(void * basePointer, size_t gnaGraphSize, std::ostrea
 
     writeBits(header, os);
 
+    for (auto &name : inputNames) {
+        const auto nameSize = strlen(name.c_str()) + 1;
+        writeBits(static_cast<uint32_t>(nameSize), os);
+        writeNBytes(name.c_str(), nameSize , os);
+    }
     for (const auto &input : inputs) {
         writeBits(convert_to_serial(input), os);
     }
+    for (auto &name : outputNames) {
+        const auto nameSize = strlen(name.c_str()) + 1;
+        writeBits(static_cast<uint32_t>(nameSize), os);
+        writeNBytes(name.c_str(), nameSize, os);
+    }
     for (const auto &output : outputs) {
         writeBits(convert_to_serial(output), os);
     }
@@ -691,7 +725,8 @@ void GNAModelSerial::ImportInputs(std::istream &is,
     dataMap.clear();
 
     for (auto inputIndex = 0; inputIndex < modelHeader.nInputs; inputIndex++) {
-        std::string name = "input" + std::to_string(inputIndex);
+        const std::string& name = (modelHeader.version.major == 2 && modelHeader.version.minor >= 3)
+                ? inputNames.at(inputIndex) : std::string("input" + std::to_string(inputIndex));
         HeaderLatest::RuntimeEndPoint input;
         is.read(reinterpret_cast<char *>(&input), sizeof(input));
         inputsDesc->getPtrInputsGlobal(name).push_back(reinterpret_cast<float*>(reinterpret_cast<uint8_t *> (basePtr) + input.descriptor_offset));
@@ -719,7 +754,8 @@ void GNAModelSerial::ImportOutputs(std::istream &is,
     desc.resize(modelHeader.nOutputs);
 
     for (auto outputIndex = 0; outputIndex < modelHeader.nOutputs; outputIndex++) {
-        std::string name = "output" + std::to_string(outputIndex);
+        const std::string& name = (modelHeader.version.major == 2 && modelHeader.version.minor >= 3)
+                                  ? outputNames.at(outputIndex) : std::string("input" + std::to_string(outputIndex));
         HeaderLatest::RuntimeEndPoint output;
         is.read(reinterpret_cast<char *>(&output), sizeof(output));
         OutputDesc description;
index 1db971d..807c4c4 100644 (file)
@@ -32,6 +32,8 @@ private:
 #endif
     std::vector<GNAPluginNS::HeaderLatest::RuntimeEndPoint> inputs;
     std::vector<GNAPluginNS::HeaderLatest::RuntimeEndPoint> outputs;
+    std::vector<std::string> inputNames;
+    std::vector<std::string> outputNames;
     uint32_t nRotateRows = 0;
     uint32_t nRotateColumns = 0;
     bool doRotateInput = false;
@@ -63,6 +65,13 @@ private:
         const InferenceEngine::OutputsDataMap& outputsDataMap) : gna2Model(model),
             inputs(serializeInputs(inputsDataMap, inputDesc)),
             outputs(serializeOutputs(outputsDataMap, outputsDesc)) {
+        for (auto const& input : inputsDataMap) {
+            inputNames.push_back(input.first);
+        }
+
+        for (auto const& input : outputsDataMap) {
+            outputNames.push_back(input.first);
+        }
     }
 
 #else
diff --git a/inference-engine/src/gna_plugin/serial/headers/2dot3/gna_model_header.hpp b/inference-engine/src/gna_plugin/serial/headers/2dot3/gna_model_header.hpp
new file mode 100644 (file)
index 0000000..e95f5c8
--- /dev/null
@@ -0,0 +1,122 @@
+// Copyright (C) 2018-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#pragma once
+
+#include <cstdint>
+#include "backend/dnn_types.h"
+#include "serial/headers/2dot1/gna_model_header.hpp"
+
+#pragma pack(push, 1)
+
+
+namespace GNAPluginNS {
+namespace Header2dot3 {
+
+
+/**
+ * @brief Header version 2.3
+ */
+struct ModelHeader {
+    /**
+     *@brief MagicNumber – GNAM in ascii table, equals to hex 0x474e414d
+     */
+    char gnam[4] = {};
+    /**
+     * @brief if header size is not equal to sizeof ModelHeader - some reserved data append in the end of header
+     * usually it is an indicator of working with version of model different that is current export function produce
+     */
+    uint32_t headerSize = 0u;
+    struct Version {
+        /**
+         * @details Version of format Major – unsigned int, ex: 0x0001
+         * every change in the header or in the layers definition should be reflected in version change
+         * for backward compatibility new parsers can read old versions of model with certain restrictions
+         */
+        uint16_t major = 2u;
+        /**
+         * @details Version of Format Minor – unsigned int,  corresponding to build revision for example
+         * changes in minor version are not affected layout of model
+         */
+        uint32_t minor = 3u;
+    } version;
+    /**
+     * @brief Memory required to be allocated using GNAAlloc()
+     */
+    uint64_t gnaMemSize = 0ull;
+    /**
+     * @brief Number of GNA Layers
+     */
+    uint64_t layersCount = 0ull;
+    /**
+     * @brief Grouping level
+     */
+    uint32_t nGroup = 0u;
+    /**
+     * Convolution related setting - they are affecting input transformation
+     */
+    uint32_t nRotateRows = 0u;
+    uint32_t nRotateColumns = 0u;
+    bool doRotateInput = false;
+
+    uint32_t nInputs = 0u;
+    uint32_t nOutputs = 0u;
+
+    /**
+     * Reserved Data might be here
+     */
+    ModelHeader() = default;
+    ModelHeader(GNAPluginNS::Header2dot1::ModelHeader const &old) {
+        gnaMemSize = old.gnaMemSize;
+        layersCount = old.layersCount;
+        nGroup = old.nGroup;
+        nRotateRows = old.nRotateRows;
+        nRotateColumns = old.nRotateColumns;
+        nInputs = old.nInputs;
+        nOutputs = old.nOutputs;
+    }
+};
+#pragma pack(pop)
+
+/*
+ * In runtime endpoint mostly same as in serial version, except of descriptor field
+ */
+struct RuntimeEndPoint {
+    /**
+     * if scale factor is different then pased into infer , network might need to be requantized
+     */
+    float scaleFactor = 0;
+    /**
+     * Pointer descriptor
+     */
+    void* descriptor_ptr = nullptr;
+    /**
+     * Endpoint resolution in bytes.
+     */
+    uint32_t element_size = 0;
+    /**
+     * Number of elements
+     */
+    uint32_t elements_count = 0;
+    /**
+     * Offset in bytes of pointer descriptor
+    */
+    uint64_t descriptor_offset = 0ull;
+
+    intel_dnn_orientation_t orientation = kDnnUnknownOrientation;
+
+    RuntimeEndPoint() = default;
+    RuntimeEndPoint(double scaleFactor,
+                    void* descriptor_ptr,
+                    uint32_t element_size,
+                    uint32_t elements_count,
+                    intel_dnn_orientation_t orientation) : scaleFactor(scaleFactor),
+                                                           descriptor_ptr(descriptor_ptr),
+                                                           element_size(element_size),
+                                                           elements_count(elements_count),
+                                                           orientation(orientation) {
+    }
+};
+} // namespace Header2dot3
+} // namespace GNAPluginNS
index c5fc125..716e172 100644 (file)
@@ -4,11 +4,11 @@
 
 #pragma once
 
-#include "serial/headers/2dot2/gna_model_header.hpp"
+#include "serial/headers/2dot3/gna_model_header.hpp"
 
 namespace GNAPluginNS {
 namespace HeaderLatest {
-using ModelHeader = GNAPluginNS::Header2dot2::ModelHeader;
-using RuntimeEndPoint = GNAPluginNS::Header2dot2::RuntimeEndPoint;
+using ModelHeader = GNAPluginNS::Header2dot3::ModelHeader;
+using RuntimeEndPoint = GNAPluginNS::Header2dot3::RuntimeEndPoint;
 }
 }
index 01b18a7..9c0313f 100644 (file)
@@ -70,7 +70,14 @@ class ImportNetworkTest : public testing::WithParamInterface<exportImportNetwork
             if (inputStream.fail()) {
                 FAIL() << "Cannot open file to import model: exported_model.blob";
             }
-            auto importedOutputs = CalculateImportedNetwork(inputStream);
+            auto importedNetwork = core->ImportNetwork(inputStream, targetDevice, configuration);
+            for (const auto& next_input : importedNetwork.GetInputsInfo()) {
+                ASSERT_NO_THROW(executableNetwork.GetInputsInfo()[next_input.first]);
+            }
+            for (const auto& next_output : importedNetwork.GetOutputsInfo()) {
+                ASSERT_NO_THROW(executableNetwork.GetOutputsInfo()[next_output.first]);
+            }
+            auto importedOutputs = CalculateImportedNetwork(importedNetwork);
             Compare(importedOutputs, actualOutputs);
         }
 
@@ -107,9 +114,7 @@ class ImportNetworkTest : public testing::WithParamInterface<exportImportNetwork
         std::map<std::string, std::string> exportConfiguration;
         std::map<std::string, std::string> importConfiguration;
 
-        std::vector<std::vector<std::uint8_t>> CalculateImportedNetwork(std::istream& networkModel) {
-            auto importedNetwork = core->ImportNetwork(networkModel, targetDevice, configuration);
-
+        std::vector<std::vector<std::uint8_t>> CalculateImportedNetwork(InferenceEngine::ExecutableNetwork& importedNetwork) {
             auto refInferRequest = importedNetwork.CreateInferRequest();
             std::vector<InferenceEngine::InputInfo::CPtr> refInfos;
             for (const auto& input : importedNetwork.GetInputsInfo()) {