Skip to content

Commit

Permalink
XmlDeserializer relay on parameter/result (input/output) index which …
Browse files Browse the repository at this point in the history
…is reported during inserting to function

Xml parameter/result order is irrelevant now.
  • Loading branch information
Patryk Elszkowski committed Feb 11, 2021
1 parent 751ac1a commit 036e13a
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 35 deletions.
75 changes: 50 additions & 25 deletions inference-engine/src/readers/ir_reader/ie_ir_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,33 +47,38 @@ IRParser::IRParser(size_t version, const std::vector<InferenceEngine::IExtension
}
}

std::map<uint64_t, uint64_t> V10Parser::XmlDeserializer::map_type_in_function(const pugi::xml_node& node,
const std::string map_type) {
std::map<uint64_t, uint64_t> 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<std::shared_ptr<ngraph::op::util::SubGraphOp::InputDescription>> V10Parser::XmlDeserializer::parseInputDescription(const pugi::xml_node& node) {
std::vector<std::shared_ptr<ngraph::op::util::SubGraphOp::InputDescription>> inputs;
std::map<uint64_t, uint64_t> param_id_in_function = map_type_in_function(node, "Parameter");
std::map<uint64_t, uint64_t> 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<uint64_t, pugi::xml_node> input_map;
Expand All @@ -96,9 +101,11 @@ std::vector<std::shared_ptr<ngraph::op::util::SubGraphOp::InputDescription>> 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<ngraph::op::util::SubGraphOp::SliceInputDescription>
(ti_input_index,
param_id_in_function[body_parameter_index],
input_index,
start,
stride,
part_size,
Expand All @@ -112,10 +119,14 @@ std::vector<std::shared_ptr<ngraph::op::util::SubGraphOp::InputDescription>> 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<ngraph::op::util::SubGraphOp::MergedInputDescription>
(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;
Expand All @@ -125,9 +136,11 @@ std::vector<std::shared_ptr<ngraph::op::util::SubGraphOp::InputDescription>> 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<ngraph::op::util::SubGraphOp::InvariantInputDescription>
(ti_input_index,
param_id_in_function[body_parameter_index]));
input_index));
}
}
}
Expand All @@ -136,7 +149,7 @@ std::vector<std::shared_ptr<ngraph::op::util::SubGraphOp::InputDescription>> V10

std::vector<std::shared_ptr<ngraph::op::util::SubGraphOp::OutputDescription>> V10Parser::XmlDeserializer::parseOutputDescription(const pugi::xml_node& node) {
std::vector<std::shared_ptr<ngraph::op::util::SubGraphOp::OutputDescription>> outputs;
std::map<uint64_t, uint64_t> result_id_in_function = map_type_in_function(node, "Result");
const auto io_map = updated_io_map(node);

// Parse PortMap: outputs
std::map<int64_t, pugi::xml_node> output_map;
Expand All @@ -162,8 +175,10 @@ std::vector<std::shared_ptr<ngraph::op::util::SubGraphOp::OutputDescription>> 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<ngraph::op::util::SubGraphOp::ConcatOutputDescription>
(result_id_in_function[body_result_index],
(output_index,
output_number,
start,
stride,
Expand All @@ -172,8 +187,10 @@ std::vector<std::shared_ptr<ngraph::op::util::SubGraphOp::OutputDescription>> 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<ngraph::op::util::SubGraphOp::BodyOutputDescription>
(result_id_in_function[body_result_index],
(output_index,
output_number,
-1));
}
Expand All @@ -185,10 +202,10 @@ std::vector<std::shared_ptr<ngraph::op::util::SubGraphOp::OutputDescription>> V1

ngraph::op::v5::Loop::SpecialBodyPorts V10Parser::XmlDeserializer::parsePurposeAttribute(const pugi::xml_node& node) {
ngraph::op::v5::Loop::SpecialBodyPorts result = {-1, -1};
std::map<uint64_t, uint64_t> params = map_type_in_function(node, "Parameter");
std::map<uint64_t, uint64_t> 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<uint64_t, pugi::xml_node> input_map;
Expand All @@ -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);
}
}

Expand All @@ -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);
}
}

Expand Down Expand Up @@ -316,13 +333,18 @@ void V10Parser::XmlDeserializer::on_adapter(const std::string& name, ngraph::Val
adapter.set(ngraph_function);
}


std::shared_ptr<ngraph::Function> 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<size_t, node_params> params;

std::vector<size_t> outputs;
Expand All @@ -340,7 +362,6 @@ std::shared_ptr<ngraph::Function> V10Parser::XmlDeserializer::parse_function(con
}
}

using edge = struct { size_t fromLayerId, fromPortId, toPortId; };
std::map<size_t, std::vector<edge>> edges;
std::map<size_t, std::shared_ptr<ngraph::Node>> id_to_node;

Expand Down Expand Up @@ -408,10 +429,12 @@ std::shared_ptr<ngraph::Function> V10Parser::XmlDeserializer::parse_function(con
// }

if (const auto& parameter_node = std::dynamic_pointer_cast<ngraph::op::Parameter>(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<ngraph::op::Result>(node)) {
io_map_stack.top()[io::OUTPUTS].insert({layer_id, result_nodes.size()});
result_nodes.emplace_back(result_node);
}

Expand Down Expand Up @@ -477,6 +500,7 @@ V10Parser::V10Parser(const std::vector<IExtensionPtr>& exts) : _exts(exts) {

std::shared_ptr<ICNNNetwork> V10Parser::parse(const pugi::xml_node& root, const Blob::CPtr& weights) {
std::shared_ptr<ngraph::Function> function;
const XmlDeserializer::NextLevelOfIoMap l{};
XmlDeserializer visitor(root, weights, opsets, variables);
visitor.on_attribute("net", function);

Expand Down Expand Up @@ -739,6 +763,7 @@ std::shared_ptr<ngraph::Node> 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();
Expand Down
52 changes: 42 additions & 10 deletions inference-engine/src/readers/ir_reader/ie_ir_parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <memory>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <vector>

Expand Down Expand Up @@ -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<std::string, ngraph::OpSet>& opsets,
std::unordered_map<std::string, std::shared_ptr<ngraph::Variable>>& 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<size_t /*xml node id*/, uint64_t /*body io index*/>;
using IoMap = std::unordered_map<io, NodeIdToIoIndex>;
using NodeIdToIoIndexStack = std::stack<IoMap>;

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<std::string, ngraph::OpSet>& opsets,
std::unordered_map<std::string, std::shared_ptr<ngraph::Variable>>& variables)
: node(node), weights(weights), opsets(opsets), variables(variables) {}

void on_adapter(const std::string& name, ngraph::ValueAccessor<std::string>& value) override {
std::string val;
if (!getStrAttribute(node.child("data"), name, val)) return;
Expand Down Expand Up @@ -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<std::string, ngraph::OpSet>& opsets;
std::unordered_map<std::string, std::shared_ptr<ngraph::Variable>>& 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
Expand All @@ -303,12 +337,10 @@ class V10Parser : public IParser {
/// \param node xml op representation
std::vector<std::shared_ptr<ngraph::op::util::SubGraphOp::OutputDescription>> 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<uint64_t, uint64_t> 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
Expand Down

0 comments on commit 036e13a

Please sign in to comment.