Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix TI deserialization #4285

Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 44 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,34 @@ 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;
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 extend_io_map = io_map;

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");
extend_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++;
extend_io_map[io::INPUTS].insert({id, -1});
pelszkow marked this conversation as resolved.
Show resolved Hide resolved
}
}
return type_id_in_function;
return extend_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 up_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 +97,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 = up_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 +115,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 = up_io_map.at(io::INPUTS).at(body_parameter_index);
const auto output_index = up_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 +132,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 = up_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 +145,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 up_io_map = updated_io_map(node);

// Parse PortMap: outputs
std::map<int64_t, pugi::xml_node> output_map;
Expand All @@ -162,8 +171,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 = up_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 +183,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 = up_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 +198,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 up_io_map = updated_io_map(node);

NGRAPH_CHECK(!params.empty() || !results.empty(), "No parameters or results found in body Function.");
NGRAPH_CHECK(!up_io_map.at(io::INPUTS).empty() || !up_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 +220,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 = up_io_map.at(io::INPUTS).at(body_parameter_index);
}
}

Expand All @@ -216,7 +229,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 = up_io_map.at(io::OUTPUTS).at(body_parameter_index);
}
}

Expand Down Expand Up @@ -316,13 +329,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 +358,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 +425,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[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[io::OUTPUTS].insert({layer_id, result_nodes.size()});
result_nodes.emplace_back(result_node);
}

Expand Down
36 changes: 26 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 @@ -183,10 +183,19 @@ class V10Parser : public IParser {

class XmlDeserializer : public ngraph::AttributeVisitor {
pelszkow marked this conversation as resolved.
Show resolved Hide resolved
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::map<io, NodeIdToIoIndex>;

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 +297,20 @@ 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 during function creation
/// it will be used during Inputs/Outputs Description creation in SubGraph processing
///
IoMap io_map;

/// \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 +321,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
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