Skip to content

Commit

Permalink
[ TRANSFORMATIONS TESTS POC] Extending conformance tools to work with…
Browse files Browse the repository at this point in the history
… transformed graphs (#24478)

### Details:
 - *item1*
 - *...*

### Tickets:
 - *ticket-id*
  • Loading branch information
iefode committed May 16, 2024
1 parent df257c5 commit 98b0a3a
Show file tree
Hide file tree
Showing 5 changed files with 261 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,27 @@ class FusedNamesExtractor final : public SubgraphExtractor {
std::vector<ExtractedPattern> extract(const std::shared_ptr<ov::Model> &modele) override;

protected:
std::unordered_set<std::string> extract_compiled_model_names(const std::shared_ptr<ov::Model>& model);
std::unordered_set<std::string> extract_not_trasformed_node_names(const std::shared_ptr<ov::Model>& model);
void set_target_device(const std::string& _device);

std::string device;

// possible solution to imrove pattern extraction
// struct NodeDescriptor {
// std::shared_ptr<ov::Node> node;
// std::unordered_set<size_t> input_idx, output_idx;
// size_t subgraph_id = std::numeric_limits<size_t>::max();

// NodeDescriptor(const std::shared_ptr<ov::Node>& in_node) : node(in_node) {}

// bool is_defined() {
// return subgraph_id != std::numeric_limits<size_t>::max();
// }
// };

// std::vector<NodeDescriptor> extract_transformed_nodes(const std::shared_ptr<ov::Model>& model);
// labeled subgraphs: {subgraph_id, NodeVector}
// std::unordered_map<size_t, ov::NodeVector> label_subgrapohs(std::vector<NodeDescriptor>& transformed_ops);
};

} // namespace subgraph_dumper
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "openvino/op/tensor_iterator.hpp"
#include "openvino/op/if.hpp"
#include "openvino/op/loop.hpp"
#include "openvino/op/shape_of.hpp"
#include "openvino/util/file_util.hpp"

#include "matchers/subgraph/fused_names.hpp"
Expand All @@ -31,8 +32,8 @@ void FusedNamesExtractor::set_target_device(const std::string& _device) {
" will be used for `fused_names` extractor" << std::endl;
return;
} else if (std::find(available_devices.begin(),
available_devices.end(),
_device) == available_devices.end()) {
available_devices.end(),
_device) == available_devices.end()) {
std::string message = "Incorrect device ";
message += _device;
message += " to enable `fused_names` extractor! Available devices: {";
Expand All @@ -47,36 +48,154 @@ void FusedNamesExtractor::set_target_device(const std::string& _device) {
std::cout << "[ INFO ][ GRAPH CACHE ] " << device << " is using for `fused_names` extractor" << std::endl;
}

inline std::string get_original_layer_name(const std::shared_ptr<ov::Node>& node) {
std::string original_layer_name = node->get_friendly_name();
const auto& rt_info = node->get_rt_info();
if (rt_info.count("originalLayersNames")) {
original_layer_name = rt_info.find("originalLayersNames")->second.as<std::string>();
}
return original_layer_name;
}

// shape of
inline bool is_node_transformed(const std::shared_ptr<ov::Node>& node) {
const auto compiled_node_name = node->get_friendly_name();
if (get_original_layer_name(node) != compiled_node_name) {
return true;
}
for (const auto& in_value : node->input_values()) {
const auto in_node = in_value.get_node_shared_ptr();
if (in_node->get_friendly_name() != get_original_layer_name(in_node)) {
return true;
}
}
for (const auto& output : node->outputs()) {
for (const auto& target_input : output.get_target_inputs()) {
auto target_in_node = target_input.get_node()->shared_from_this();
if (target_in_node->get_friendly_name() != get_original_layer_name(target_in_node)) {
return true;
}
}
}
return false;
}

std::unordered_set<std::string>
FusedNamesExtractor::extract_compiled_model_names(const std::shared_ptr<ov::Model>& model) {
FusedNamesExtractor::extract_not_trasformed_node_names(const std::shared_ptr<ov::Model>& model) {
auto compiled_model = ov::util::core->compile_model(model, device);
std::unordered_set<std::string> compiled_op_name;
std::unordered_set<std::string> not_transformed_nodes;
for (const auto& compiled_op : compiled_model.get_runtime_model()->get_ordered_ops()) {
const auto& rt_info = compiled_op->get_rt_info();
if (rt_info.count("originalLayersNames")) {
compiled_op_name.insert(rt_info.find("originalLayersNames")->second.as<std::string>());
if (!is_node_transformed(compiled_op)) {
not_transformed_nodes.insert(compiled_op->get_friendly_name());
}
}
return compiled_op_name;
for (const auto& op : model->get_ordered_ops()) {
const auto op_name = op->get_friendly_name();
if (!not_transformed_nodes.count(op_name)) {
continue;
}
if (op->get_type_info().is_castable(ov::op::v0::ShapeOf::get_type_info_static()) ||
op->get_type_info().is_castable(ov::op::v3::ShapeOf::get_type_info_static())) {
not_transformed_nodes.erase(op_name);
}
}
return not_transformed_nodes;
}

FusedNamesExtractor::FusedNamesExtractor(const std::string& device) {
set_target_device(device);
}

// std::vector<FusedNamesExtractor::NodeDescriptor>
// FusedNamesExtractor::extract_transformed_nodes(const std::shared_ptr<ov::Model>& model) {
// std::vector<NodeDescriptor> transformed_ops;
// const auto not_transformed_ops = extract_not_trasformed_node_names(model);
// {
// auto ordered_ops = model->get_ordered_ops();
// std::reverse(ordered_ops.begin(), ordered_ops.end());
// for (size_t i = 0; i < ordered_ops.size(); ++i) {
// const auto op = ordered_ops[i];
// if (not_transformed_ops.count(op->get_friendly_name()) || util::is_node_to_skip(op)) {
// continue;
// }
// transformed_ops.push_back(op);
// }
// }
// for (size_t i = 0; i < transformed_ops.size(); ++i) {
// auto& transformed_op = transformed_ops[i];
// for (const auto& input_value : transformed_op.node->input_values()) {
// const auto input_node = input_value.get_node_shared_ptr();
// if (not_transformed_ops.count(input_node->get_friendly_name()) || util::is_node_to_skip(input_node)) {
// continue;
// }
// for (size_t j = i; j < transformed_ops.size(); ++j) {
// if (transformed_ops[j].node == input_node) {
// transformed_op.input_idx.insert(j);
// break;
// }
// }
// for (const auto& j : transformed_op.input_idx) {
// transformed_ops[j].output_idx.insert(i);
// }
// }
// }
// return transformed_ops;
// }

// std::unordered_map<size_t, ov::NodeVector>
// FusedNamesExtractor::label_subgraphs(std::vector<FusedNamesExtractor::NodeDescriptor>& transformed_ops) {
// std::unordered_map<size_t, ov::NodeVector> subgraphs;
// const auto backward_propagation = [&transformed_ops, &subgraphs](size_t node_id) {
// std::deque<size_t> deque{node_id};
// const size_t subgraph_id = transformed_ops[node_id].subgraph_id;
// while (!deque.empty()) {
// size_t front_node_id = deque.front();
// deque.pop_front();
// for (const auto& out_node_id : transformed_ops[front_node_id].output_idx) {
// if (transformed_ops[out_node_id].subgraph_id == subgraph_id) {
// continue;
// }
// if (subgraphs.count(transformed_ops[out_node_id].subgraph_id)) {
// const auto node_vector = subgraphs[transformed_ops[out_node_id].subgraph_id];
// subgraphs[subgraph_id].insert(subgraphs[subgraph_id].end(), node_vector.begin(), node_vector.end());
// subgraphs.erase(transformed_ops[out_node_id].subgraph_id);
// }
// transformed_ops[out_node_id].subgraph_id = subgraph_id;
// deque.push_back(out_node_id);
// }
// }
// };

// size_t subgraph_id = 0;
// for (size_t i = 0; i < transformed_ops.size(); ++i) {
// auto& transformed_op = transformed_ops[i];
// if (!transformed_op.is_defined()) {
// transformed_op.subgraph_id = subgraph_id++;
// subgraphs.insert({transformed_op.subgraph_id, {transformed_op.node}});
// } else if (transformed_op.output_idx.size() > 1) {
// backward_propagation(i);
// }
// for (const auto& in_idx : transformed_op.input_idx) {
// transformed_ops[in_idx].subgraph_id = transformed_op.subgraph_id;
// subgraphs[transformed_op.subgraph_id].push_back(transformed_ops[in_idx].node);
// }
// }
// return subgraphs;
// }

std::vector<FusedNamesExtractor::ExtractedPattern>
FusedNamesExtractor::extract(const std::shared_ptr<ov::Model> &model) {
auto compiled_op_name = extract_compiled_model_names(model);
std::vector<FusedNamesExtractor::ExtractedPattern> matched_patterns;
const auto not_transformed_nodes = extract_not_trasformed_node_names(model);
ov::NodeVector nodes;
for (const auto& op : model->get_ordered_ops()) {
auto op_name = op->get_friendly_name();
if (ov::util::is_node_to_skip(op)) {
continue;
}
if (compiled_op_name.count(op_name)) {
if (not_transformed_nodes.count(op_name)) {
try {
auto extracted_pattern = ov::util::generate_model(nodes, is_save_const);
auto extracted_pattern = ov::util::generate_model(nodes, true);
matched_patterns.push_back({ extracted_pattern.first, extracted_pattern.second, extractor_name });
} catch(std::exception& e) {
if (std::string(e.what()).find("Incorrect node number to create model") == std::string::npos) {
Expand Down Expand Up @@ -117,5 +236,21 @@ FusedNamesExtractor::extract(const std::shared_ptr<ov::Model> &model) {
// std::cout << "[ WARNING ] Impossible to generate network and add to GraphCache: " <<e.what() << std::endl;
}
}

return matched_patterns;

// possible solution to extract transformed graphs
// problems: takes a lot of time + process ops with bodies
// auto transformed_ops = extract_transformed_nodes(model);
// for (auto& subgraph : label_subgraphs(transformed_ops)) {
// try {
// auto extracted_pattern = ov::util::generate_model(subgraph.second, is_save_const);
// matched_patterns.push_back({ extracted_pattern.first, extracted_pattern.second, extractor_name });
// } catch(std::exception& e) {
// if (std::string(e.what()).find("Incorrect node number to create model") == std::string::npos) {
// std::cout << "[ WARNING ] Impossible to generate network and add to GraphCache: " <<e.what() << std::endl;
// }
// }
// }
// return matched_patterns;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ using ShapesMap = std::map<ov::NodeTypeInfo, std::function<InputShape(
ShapesMap getShapeMap();
} // namespace utils
} // namespace test
} // namespace ov
} // namespace ov
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "utils/generate_static_shapes.hpp"

#include "read_ir_test/read_ir.hpp"
#include "utils/generate_static_shapes.hpp"

namespace ov {
namespace test {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Copyright (C) 2018-2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

from argparse import ArgumentParser
from utils.file_utils import prepare_filelist
from utils.constants import XML_EXTENSION, META_EXTENSION
from openvino.runtime import Core
import defusedxml.ElementTree as ET

def parse_arguments():
parser = ArgumentParser()

origin_help = "Path to output subgraphs dir"
ref_help = "Path to refence subgraphs dir"

parser.add_argument("-o", "--origin", help=origin_help, required=True)
parser.add_argument("-r", "--reference", help=ref_help, required=True)

return parser.parse_args()

def list_to_set(in_list: list):
result = set()
for list_item in in_list:
result.add(list_item)
return result

def models_to_names(files: set):
core = Core()
result = dict()
for model_file in files:
model = core.read_model(model_file)
nodes_name = set()
for node in model.get_ordered_ops():
if "Result" in node.get_type_info().name or "Parameter" in node.get_type_info().name or "Constant" in node.get_type_info().name:
continue
nodes_name.add(node.get_friendly_name())
result.update({model_file: nodes_name})
return result

def models_info(files: set):
result = dict()
for model_file in files:
meta_path = model_file.with_suffix(META_EXTENSION)
meta_info_root = ET.parse(meta_path).getroot()
model_node = meta_info_root.find("models")
model_names = set()
for model_name in model_node:
model_names.add(model_name.attrib.get("name"))
result.update({model_file: model_names})
return result

if __name__ == "__main__":
args = parse_arguments()
file_list_orig = prepare_filelist(args.origin, [f"*{XML_EXTENSION}"], False)
file_list_ref = prepare_filelist(args.reference, [f"*{XML_EXTENSION}"], False)

orig_irs = list_to_set(file_list_orig)
ref_irs = list_to_set(file_list_ref)

orig_dif = orig_irs.difference(ref_irs)
ref_dif = ref_irs.difference(orig_irs)

node_names_by_ir_orig = models_to_names(orig_dif)
node_names_by_ir_ref = models_to_names(ref_dif)

model_info_orig = models_info(orig_dif)
model_info_ref = models_info(ref_dif)

result_dict = dict()
result_intersection = dict()
result_orig_dif = dict()
result_ref_dif = dict()
for ir_name_orig in model_info_orig.keys():
models_name_orig = model_info_orig[ir_name_orig]
for ir_name_ref in model_info_ref.keys():
models_name_ref = model_info_ref[ir_name_ref]
if len(models_name_orig.intersection(models_name_ref)) == 0:
continue
if node_names_by_ir_orig[ir_name_orig] == node_names_by_ir_ref[ir_name_ref]:
continue
if len(node_names_by_ir_orig[ir_name_orig].intersection(node_names_by_ir_ref[ir_name_ref])) == 0:
continue
result_dict.update({ir_name_orig: ir_name_ref})
result_intersection.update({ir_name_orig: node_names_by_ir_orig[ir_name_orig].intersection(node_names_by_ir_ref[ir_name_ref])})
result_orig_dif.update({ir_name_orig: node_names_by_ir_orig[ir_name_orig].difference(node_names_by_ir_ref[ir_name_ref])})
result_ref_dif.update({ir_name_ref: node_names_by_ir_ref[ir_name_ref].difference(node_names_by_ir_orig[ir_name_orig])})
for ir_name_orig in result_dict.keys():
ir_name_ref = result_dict[ir_name_orig]
print(f"Intersected IRs: {ir_name_orig} vs {ir_name_ref}")
print(f"Intersected functional operation names: {result_intersection[ir_name_orig]}")
print(f"Orig new operation names: {result_orig_dif[ir_name_orig]}")
print(f"Ref new operation names: {result_ref_dif[ir_name_ref]}")



0 comments on commit 98b0a3a

Please sign in to comment.