Fix issue with output's friendly name after post-processing (#11095)
Scenario: - Node "Split" with multiple outputs (e.g. 3). All outputs are connected to "Result"s - Add post-processing step (e.g. convert element type, can be also implicit) Issue: after post-processing, 3 new results will be created, each will have "Split" friendly name - inconsistency with IRv10 rules Fix: - For nodes with multiple outputs, add '.<idx>' suffix to new output's friendly name - If no post-processing is applied, return immediately, keeping original results as is Tests: - Split with 3 outputs where 2 outputs have post-processing. - Split with 3 outputs, post-processing doesn't create any nodes
This commit is contained in:
1 parent
dacdf67c2c
commit
d84d00e2d6
2 files changed
+79
-5
No files matched your search
@@ -359,20 +359,33 @@ void OutputInfo::OutputInfoImpl::build(ov::ResultVector& results) {
|
||||
node = std::get<0>(action_result);
|
||||
post_processing_applied = true;
|
||||
}
|
||||
node.get_node_shared_ptr()->set_friendly_name(
|
||||
result->get_input_source_output(0).get_node_shared_ptr()->get_friendly_name());
|
||||
// Restore tensor names
|
||||
node.get_tensor().set_names(start_out_node_names);
|
||||
auto orig_parent = result->get_input_source_output(0).get_node_shared_ptr();
|
||||
bool reset_orig_friendly_name = false;
|
||||
if (!post_processing_applied) {
|
||||
return;
|
||||
}
|
||||
if (orig_parent->get_output_size() == 1) {
|
||||
node.get_node_shared_ptr()->set_friendly_name(orig_parent->get_friendly_name());
|
||||
reset_orig_friendly_name = true;
|
||||
} else if (node.get_node_shared_ptr() != orig_parent) {
|
||||
// Result node is changed - add ".<idx>" suffix
|
||||
node.get_node_shared_ptr()->set_friendly_name(orig_parent->get_friendly_name() + "." +
|
||||
std::to_string(result->get_input_source_output(0).get_index()));
|
||||
}
|
||||
|
||||
// Reset friendly name of input node to avoid names collision
|
||||
// when there is at a new node inserted by post-processing steps
|
||||
// If no new nodes are inserted by post-processing, then we need to preserve friendly name of input
|
||||
// as it's required for old API correct work
|
||||
if (post_processing_applied)
|
||||
if (reset_orig_friendly_name) {
|
||||
result->get_input_source_output(0).get_node_shared_ptr()->set_friendly_name("");
|
||||
}
|
||||
|
||||
// Create result
|
||||
auto new_result = std::make_shared<opset8::Result>(node);
|
||||
new_result->set_friendly_name(result->get_friendly_name());
|
||||
node.get_tensor().set_names(start_out_node_names);
|
||||
|
||||
// Preserve runtime info of original result
|
||||
new_result->get_rt_info() = result->get_rt_info();
|
||||
@@ -462,6 +475,7 @@ void OutputInfo::OutputInfoImpl::dump(std::ostream& str) const {
|
||||
|
||||
str << " User's output tensor: ";
|
||||
dump_tensor(str, node.get_partial_shape(), context.layout(), node.get_element_type());
|
||||
str << std::endl;
|
||||
}
|
||||
} // namespace preprocess
|
||||
} // namespace ov
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "ngraph/ngraph.hpp"
|
||||
#include "ngraph/ops.hpp"
|
||||
#include "openvino/core/preprocess/pre_post_process.hpp"
|
||||
#include "openvino/opsets/opset8.hpp"
|
||||
#include "openvino/util/common_util.hpp"
|
||||
#include "util/test_tools.hpp"
|
||||
|
||||
@@ -1331,7 +1332,6 @@ TEST(pre_post_process, preprocess_crop_wrong_dims_not_aligned) {
|
||||
} catch (const ov::Exception& err) {
|
||||
EXPECT_TRUE(std::string(err.what()).find(exp_dump.str()) != std::string::npos) << err.what();
|
||||
EXPECT_TRUE(std::string(err.what()).find(act_dump.str()) != std::string::npos) << err.what();
|
||||
std::cout << err.what();
|
||||
} catch (...) {
|
||||
FAIL() << "Expected ov::Exception";
|
||||
}
|
||||
@@ -1735,6 +1735,66 @@ TEST(pre_post_process, postprocess_many) {
|
||||
EXPECT_TRUE(custom_called);
|
||||
}
|
||||
|
||||
TEST(pre_post_process, postprocess_one_node_many_outputs) {
|
||||
auto data1 = std::make_shared<op::v0::Parameter>(element::i32, Shape{3});
|
||||
auto c1 = opset8::Constant::create(element::i32, Shape{}, {0});
|
||||
auto op = std::make_shared<opset8::Split>(data1, c1, 3);
|
||||
op->set_friendly_name("Split");
|
||||
ResultVector results;
|
||||
for (size_t i = 0; i < op->get_num_splits(); i++) {
|
||||
op->output(i).set_names({"tensor_Split" + std::to_string(i)});
|
||||
auto res = std::make_shared<op::v0::Result>(op->output(i));
|
||||
results.emplace_back(res);
|
||||
}
|
||||
auto model = std::make_shared<Model>(ResultVector{results}, ParameterVector{data1});
|
||||
EXPECT_EQ(model->output(0).get_tensor().get_names().count("tensor_Split0"), 1);
|
||||
EXPECT_EQ(model->output(1).get_tensor().get_names().count("tensor_Split1"), 1);
|
||||
EXPECT_EQ(model->output(2).get_tensor().get_names().count("tensor_Split2"), 1);
|
||||
|
||||
auto p = PrePostProcessor(model);
|
||||
p.output(0).tensor().set_element_type(element::f32);
|
||||
p.output(2).tensor().set_element_type(element::f32);
|
||||
model = p.build();
|
||||
EXPECT_EQ(model->get_results().size(), 3);
|
||||
EXPECT_EQ(model->output(0).get_tensor().get_names().count("tensor_Split0"), 1);
|
||||
EXPECT_EQ(model->output(1).get_tensor().get_names().count("tensor_Split1"), 1);
|
||||
EXPECT_EQ(model->output(2).get_tensor().get_names().count("tensor_Split2"), 1);
|
||||
EXPECT_EQ(model->get_results()[0]->input(0).get_source_output().get_node()->get_friendly_name(), "Split.0");
|
||||
EXPECT_EQ(model->get_results()[1]->input(0).get_source_output().get_node()->get_friendly_name(), "Split");
|
||||
EXPECT_EQ(model->get_results()[2]->input(0).get_source_output().get_node()->get_friendly_name(), "Split.2");
|
||||
}
|
||||
|
||||
TEST(pre_post_process, postprocess_nothing_applied) {
|
||||
auto data1 = std::make_shared<op::v0::Parameter>(element::i32, Shape{1, 3, 10, 20});
|
||||
auto c1 = opset8::Constant::create(element::i32, Shape{}, {1});
|
||||
auto op = std::make_shared<opset8::Split>(data1, c1, 3);
|
||||
op->set_friendly_name("Split");
|
||||
ResultVector results;
|
||||
for (size_t i = 0; i < op->get_num_splits(); i++) {
|
||||
op->output(i).set_names({"tensor_Split" + std::to_string(i)});
|
||||
auto res = std::make_shared<op::v0::Result>(op->output(i));
|
||||
results.emplace_back(res);
|
||||
}
|
||||
auto model = std::make_shared<Model>(ResultVector{results}, ParameterVector{data1});
|
||||
EXPECT_EQ(model->get_results()[0]->input(0).get_source_output().get_node()->get_friendly_name(), "Split");
|
||||
EXPECT_EQ(model->get_results()[1]->input(0).get_source_output().get_node()->get_friendly_name(), "Split");
|
||||
EXPECT_EQ(model->get_results()[2]->input(0).get_source_output().get_node()->get_friendly_name(), "Split");
|
||||
|
||||
ov::layout::set_layout(model->output(1), "N???");
|
||||
auto p = PrePostProcessor(model);
|
||||
p.output(1).tensor().set_layout("NCHW");
|
||||
model = p.build();
|
||||
EXPECT_EQ(model->get_results().size(), 3);
|
||||
EXPECT_EQ(ov::layout::get_layout(model->output(1)), "NCHW");
|
||||
EXPECT_EQ(model->output(1).get_shape(), (Shape{1, 1, 10, 20}));
|
||||
EXPECT_EQ(model->output(0).get_tensor().get_names().count("tensor_Split0"), 1);
|
||||
EXPECT_EQ(model->output(1).get_tensor().get_names().count("tensor_Split1"), 1);
|
||||
EXPECT_EQ(model->output(2).get_tensor().get_names().count("tensor_Split2"), 1);
|
||||
EXPECT_EQ(model->get_results()[0]->input(0).get_source_output().get_node()->get_friendly_name(), "Split");
|
||||
EXPECT_EQ(model->get_results()[1]->input(0).get_source_output().get_node()->get_friendly_name(), "Split");
|
||||
EXPECT_EQ(model->get_results()[2]->input(0).get_source_output().get_node()->get_friendly_name(), "Split");
|
||||
}
|
||||
|
||||
TEST(pre_post_process, exception_safety) {
|
||||
auto f = create_n_inputs<2>(element::f32, Shape{1, 3, 224, 224});
|
||||
auto name0 = f->input(0).get_node_shared_ptr()->get_friendly_name();
|
||||
|
||||
Reference in new issue
Block a user