diff --git a/inference-engine/src/readers/ir_reader/ie_ir_parser.cpp b/inference-engine/src/readers/ir_reader/ie_ir_parser.cpp index c3e405a7beb922..acabd6799cd2a0 100644 --- a/inference-engine/src/readers/ir_reader/ie_ir_parser.cpp +++ b/inference-engine/src/readers/ir_reader/ie_ir_parser.cpp @@ -47,33 +47,38 @@ IRParser::IRParser(size_t version, const std::vector V10Parser::XmlDeserializer::map_type_in_function(const pugi::xml_node& node, - const std::string map_type) { - std::map type_id_in_function; - uint64_t map_type_number = 0; +thread_local V10Parser::XmlDeserializer::NodeIdToIoIndexStack V10Parser::XmlDeserializer::io_map_stack; + + +V10Parser::XmlDeserializer::IoMap V10Parser::XmlDeserializer::updated_io_map(const pugi::xml_node& node) { auto body_node = node.child("body"); if (body_node.empty()) { THROW_IE_EXCEPTION << "Missing body part."; } - // Fill map: parameter/result id to parameter/result number in Function + + auto io_map = V10Parser::XmlDeserializer::io_map_stack.top(); + + using io = V10Parser::XmlDeserializer::io; FOREACH_CHILD(layer, body_node.child("layers"), "layer") { auto type = XMLParseUtils::GetStrAttr(layer, "type"); - if (type == map_type) { + if (type == "Parameter") { + auto id = XMLParseUtils::GetUIntAttr(layer, "id"); + io_map[io::INPUTS].insert({id, -1}); + } else if (type == "Result") { auto id = XMLParseUtils::GetUIntAttr(layer, "id"); - type_id_in_function.emplace(id, map_type_number); - map_type_number++; + io_map[io::INPUTS].insert({id, -1}); } } - return type_id_in_function; + return io_map; } + std::vector> V10Parser::XmlDeserializer::parseInputDescription(const pugi::xml_node& node) { std::vector> inputs; - std::map param_id_in_function = map_type_in_function(node, "Parameter"); - std::map result_id_in_function = map_type_in_function(node, "Result"); + const auto io_map = updated_io_map(node); // Parse PortMap: external_port_id for inputs does not always appear in consecutive order std::map input_map; @@ -96,9 +101,11 @@ std::vector> V10 int64_t end = XMLParseUtils::GetInt64Attr(xml_input, "end", -1); int64_t part_size = XMLParseUtils::GetInt64Attr(xml_input, "part_size", 1); + const auto input_index = io_map.at(io::INPUTS).at(body_parameter_index); + inputs.push_back(std::make_shared (ti_input_index, - param_id_in_function[body_parameter_index], + input_index, start, stride, part_size, @@ -112,10 +119,14 @@ std::vector> V10 if (to_layer == body_parameter_index) { size_t from_layer = XMLParseUtils::GetUIntAttr(xml_edge, "from-layer"); + + const auto input_index = io_map.at(io::INPUTS).at(body_parameter_index); + const auto output_index = io_map.at(io::OUTPUTS).at(from_layer); + inputs.push_back(std::make_shared (ti_input_index, - param_id_in_function[body_parameter_index], - result_id_in_function[from_layer])); + input_index, + output_index)); is_back_edge_exist = true; break; @@ -125,9 +136,11 @@ std::vector> V10 // ti_input_index = -1 means that Parameter of the body is not connected to inputs of TensorIterator // and is used only for internal needs. if (!is_back_edge_exist && ti_input_index >= 0) { + const auto input_index = io_map.at(io::INPUTS).at(body_parameter_index); + inputs.push_back(std::make_shared (ti_input_index, - param_id_in_function[body_parameter_index])); + input_index)); } } } @@ -136,7 +149,7 @@ std::vector> V10 std::vector> V10Parser::XmlDeserializer::parseOutputDescription(const pugi::xml_node& node) { std::vector> outputs; - std::map result_id_in_function = map_type_in_function(node, "Result"); + const auto io_map = updated_io_map(node); // Parse PortMap: outputs std::map output_map; @@ -162,8 +175,10 @@ std::vector> V1 int64_t end = XMLParseUtils::GetInt64Attr(xml_output, "end", -1); int64_t part_size = XMLParseUtils::GetInt64Attr(xml_output, "part_size", 1); + const auto output_index = io_map.at(io::OUTPUTS).at(body_result_index); + outputs.push_back(std::make_shared - (result_id_in_function[body_result_index], + (output_index, output_number, start, stride, @@ -172,8 +187,10 @@ std::vector> V1 axis)); } else { // otherwise create ngraph::TensorIterator::BodyOutput. -1 means last iteration. + const auto output_index = io_map.at(io::OUTPUTS).at(body_result_index); + outputs.push_back(std::make_shared - (result_id_in_function[body_result_index], + (output_index, output_number, -1)); } @@ -185,10 +202,10 @@ std::vector> V1 ngraph::op::v5::Loop::SpecialBodyPorts V10Parser::XmlDeserializer::parsePurposeAttribute(const pugi::xml_node& node) { ngraph::op::v5::Loop::SpecialBodyPorts result = {-1, -1}; - std::map params = map_type_in_function(node, "Parameter"); - std::map results = map_type_in_function(node, "Result"); + const auto io_map = updated_io_map(node); - NGRAPH_CHECK(!params.empty() || !results.empty(), "No parameters or results found in body Function."); + NGRAPH_CHECK(!io_map.at(io::INPUTS).empty() || !io_map.at(io::OUTPUTS).empty(), + "No parameters or results found in body Function."); // Parse PortMap: external_port_id for inputs/outputs does not always appear in consecutive order std::map input_map; @@ -207,7 +224,7 @@ ngraph::op::v5::Loop::SpecialBodyPorts V10Parser::XmlDeserializer::parsePurposeA auto purpose = XMLParseUtils::GetStrAttr(xml_input, "purpose", ""); size_t body_parameter_index = XMLParseUtils::GetUIntAttr(xml_input, "internal_layer_id"); if (purpose == "current_iteration") { - result.current_iteration_input_idx = params[body_parameter_index]; + result.current_iteration_input_idx = io_map.at(io::INPUTS).at(body_parameter_index); } } @@ -216,7 +233,7 @@ ngraph::op::v5::Loop::SpecialBodyPorts V10Parser::XmlDeserializer::parsePurposeA auto purpose = XMLParseUtils::GetStrAttr(xml_output, "purpose", ""); size_t body_parameter_index = XMLParseUtils::GetUIntAttr(xml_output, "internal_layer_id"); if (purpose == "execution_condition") { - result.body_condition_output_idx = results[body_parameter_index]; + result.body_condition_output_idx = io_map.at(io::OUTPUTS).at(body_parameter_index); } } @@ -316,13 +333,18 @@ void V10Parser::XmlDeserializer::on_adapter(const std::string& name, ngraph::Val adapter.set(ngraph_function); } + std::shared_ptr V10Parser::XmlDeserializer::parse_function(const pugi::xml_node& root, const Blob::CPtr& weights) { OV_ITT_TASK_CHAIN(taskChain, itt::domains::V10Reader_RT, "V10Parser", "Parse"); - using node_params = struct { + struct edge { + size_t fromLayerId, fromPortId, toPortId; + }; + struct node_params { pugi::xml_node xml; GenericLayerParams params; }; + std::map params; std::vector outputs; @@ -340,7 +362,6 @@ std::shared_ptr V10Parser::XmlDeserializer::parse_function(con } } - using edge = struct { size_t fromLayerId, fromPortId, toPortId; }; std::map> edges; std::map> id_to_node; @@ -408,10 +429,12 @@ std::shared_ptr V10Parser::XmlDeserializer::parse_function(con // } if (const auto& parameter_node = std::dynamic_pointer_cast(node)) { + io_map_stack.top()[io::INPUTS].insert({layer_id, parameter_nodes.size()}); parameter_nodes.emplace_back(parameter_node); } if (const auto& result_node = std::dynamic_pointer_cast(node)) { + io_map_stack.top()[io::OUTPUTS].insert({layer_id, result_nodes.size()}); result_nodes.emplace_back(result_node); } @@ -477,6 +500,7 @@ V10Parser::V10Parser(const std::vector& exts) : _exts(exts) { std::shared_ptr V10Parser::parse(const pugi::xml_node& root, const Blob::CPtr& weights) { std::shared_ptr function; + const XmlDeserializer::NextLevelOfIoMap l{}; XmlDeserializer visitor(root, weights, opsets, variables); visitor.on_attribute("net", function); @@ -739,6 +763,7 @@ std::shared_ptr V10Parser::XmlDeserializer::createNode( THROW_IE_EXCEPTION << "Opset " << params.version << " doesn't contain the operation with type: " << type; } ngraphNode->set_arguments(inputs); + const XmlDeserializer::NextLevelOfIoMap l{}; XmlDeserializer visitor(node, weights, opsets, variables); if (ngraphNode->visit_attributes(visitor)) { ngraphNode->constructor_validate_and_infer_types(); diff --git a/inference-engine/src/readers/ir_reader/ie_ir_parser.hpp b/inference-engine/src/readers/ir_reader/ie_ir_parser.hpp index 89a40549975c5f..17b8a680d2a5ec 100644 --- a/inference-engine/src/readers/ir_reader/ie_ir_parser.hpp +++ b/inference-engine/src/readers/ir_reader/ie_ir_parser.hpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -183,10 +184,33 @@ class V10Parser : public IParser { class XmlDeserializer : public ngraph::AttributeVisitor { public: - explicit XmlDeserializer(const pugi::xml_node& node, const Blob::CPtr& weights, - const std::unordered_map& opsets, - std::unordered_map>& variables) - : node(node), weights(weights), opsets(opsets), variables(variables) {} + /// TODO: move whole class to src file + enum class io { INPUTS, OUTPUTS }; + + using NodeIdToIoIndex = std::unordered_map; + using IoMap = std::unordered_map; + using NodeIdToIoIndexStack = std::stack; + + struct NextLevelOfIoMap { + NextLevelOfIoMap() { + io_map_stack.push(IoMap{{io::INPUTS, {}}, {io::OUTPUTS, {}}}); + } + ~NextLevelOfIoMap() { + if (!io_map_stack.empty()) { + io_map_stack.pop(); + } else { + assert(!"This should not happen"); + } + } + }; + + explicit XmlDeserializer( + const pugi::xml_node& node, + const Blob::CPtr& weights, + const std::unordered_map& opsets, + std::unordered_map>& variables) + : node(node), weights(weights), opsets(opsets), variables(variables) {} + void on_adapter(const std::string& name, ngraph::ValueAccessor& value) override { std::string val; if (!getStrAttribute(node.child("data"), name, val)) return; @@ -288,11 +312,21 @@ class V10Parser : public IParser { adapter.set(value); } + private: + //TODO move data to the bottom (or top) const pugi::xml_node node; const Blob::CPtr& weights; const std::unordered_map& opsets; std::unordered_map>& variables; + + /// + /// store information about parameters/results order in created function + /// which will be used in upper instance this class when Inputs/Outputs Description + /// will be created during SubGraph processing + /// + thread_local static NodeIdToIoIndexStack io_map_stack; + /// \brief Traverses port_map in order to create vector of InputDescription shared_ptrs. /// Shall be used only for ops which have port_map attribute. /// \param node xml op representation @@ -303,12 +337,10 @@ class V10Parser : public IParser { /// \param node xml op representation std::vector> parseOutputDescription( const pugi::xml_node& node); - /// \brief Traverses nGraph body function for specified op type and creates a map of all - /// op iterations. Map constains type id and assigned to it consecutive number starting from 0. - /// \param node xml op representation - /// \param type op type name to find - /// \return map container - std::map map_type_in_function(const pugi::xml_node& node, std::string type); + + //TODO consider to call only once per layer/TI-Loop node + static IoMap updated_io_map(const pugi::xml_node& node); + /// \brief Traverses xml node representation in order to create nGraph function for it. /// \param node xml node representation /// \param weights weights attached to current node