Fix copying of tensor names in OVTF TransposeSinking transformation (#13916)

* copy tensor names to transpose

* enable TransposeSinking, codestyle

* fix layer tests

* fix segfault

* delete transposes in catch block
This commit is contained in:
Ivan Tikhonov 2022-11-11 23:31:58 +04:00 committed by GitHub
parent d1c1680a81
commit 3ec40c490b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 90 additions and 26 deletions

View File

@ -434,8 +434,7 @@ void FrontEnd::normalize(const std::shared_ptr<ov::Model>& function) const {
manager.register_pass<pass::GRUBlockCellReplacer>();
// TODO: reimplement TransposeSinking that does not corrupt filters for Convolution
// and preserve tensor names in case of sinking
// manager.register_pass<ov::frontend::tensorflow::pass::TransposeSinking>();
manager.register_pass<ov::frontend::tensorflow::pass::TransposeSinking>();
manager.run_passes(function);
}

View File

@ -53,9 +53,20 @@ static string describe(shared_ptr<Node> node) {
stringstream ss;
auto transpose = as_type_ptr<T>(node);
auto const1 = as_type_ptr<Constant>(transpose->get_input_node_shared_ptr(1));
ss << transpose->get_name() << " ( axis order = " << ov::util::vector_to_string(const1->get_axis_vector_val())
<< " , shape = " << ov::util::vector_to_string(transpose->get_shape()) << " ) "
<< " , input = " << transpose->input_value(0).get_node()->get_name();
if (transpose) {
ss << "transpose name: " << transpose->get_name();
ss << " , input = " << transpose->input_value(0).get_node()->get_name();
if (transpose->output(0).get_partial_shape().is_static()) {
ss << " , shape = " << ov::util::vector_to_string(transpose->output(0).get_shape());
}
if (const1) {
ss << " , axis order = " << ov::util::vector_to_string(const1->get_axis_vector_val());
} else {
ss << " , axis order = (unknown, not constant values)";
}
} else {
ss << "Node can not be cast to Transpose/Reshape operations.";
}
return ss.str();
}
@ -76,7 +87,7 @@ static void write_transposemap(TransposeMap& reorders,
static shared_ptr<Transpose> read_transposemap(TransposeMap& reorders, const Output<Node>& target) {
auto name = target.get_node()->get_name() + "." + to_string(target.get_index());
auto transpose = reorders[name];
auto transpose = reorders.at(name);
OPENVINO_DEBUG << "Read TransposeMap[" << name << "] -> " << describe<Transpose>(transpose);
return transpose;
}
@ -86,13 +97,16 @@ static shared_ptr<Transpose> combine_transposes(const shared_ptr<Transpose>& t1,
auto t1_const = as_type_ptr<Constant>(t1->input_value(1).get_node_shared_ptr());
auto t2_const = as_type_ptr<Constant>(t2->input_value(1).get_node_shared_ptr());
auto perm_t1 = apply_permutation(default_order, t1_const->get_axis_vector_val());
auto perm_t2 = apply_permutation(perm_t1, t2_const->get_axis_vector_val());
if (t1_const && t2_const) {
auto perm_t1 = apply_permutation(default_order, t1_const->get_axis_vector_val());
auto perm_t2 = apply_permutation(perm_t1, t2_const->get_axis_vector_val());
auto combined = make_transpose(t2->input_value(0), perm_t2);
OPENVINO_DEBUG << "Combining " << describe<Transpose>(t1) << " and " << describe<Transpose>(t2) << " into "
<< describe<Transpose>(combined);
return combined;
auto combined = make_transpose(t2->input_value(0), perm_t2);
OPENVINO_DEBUG << "Combining " << describe<Transpose>(t1) << " and " << describe<Transpose>(t2) << " into "
<< describe<Transpose>(combined);
return combined;
}
return {};
}
static void insert_transpose(const shared_ptr<Node>& target, const shared_ptr<Node>& transpose, size_t input_index) {
@ -105,6 +119,10 @@ static void insert_transpose(const shared_ptr<Node>& target, const shared_ptr<No
<< " input index " << input_index;
target->input(input_index).replace_source_output(new_transpose->output(0));
if (std::dynamic_pointer_cast<Result>(target)) {
new_transpose->output(0).add_names(arg.get_names());
arg.set_names({});
}
}
static void delete_transpose(const shared_ptr<Node>& transpose) {
@ -113,10 +131,7 @@ static void delete_transpose(const shared_ptr<Node>& transpose) {
Output<Node> output = transpose->output(0);
OPENVINO_DEBUG << "output " << output.get_node_shared_ptr()->get_name();
OPENVINO_DEBUG << "target input size " << output.get_target_inputs().size();
for (auto input : output.get_target_inputs()) {
OPENVINO_DEBUG << "input " << input.get_node()->get_name();
input.replace_source_output(transpose->input_value(0));
}
output.replace(transpose->input_value(0));
}
}
@ -203,13 +218,15 @@ static void sink_transpose(const shared_ptr<Transpose>& transpose,
auto orig_transpose = read_transposemap(reorders, transpose_in);
// combine both transposes
auto new_transpose = combine_transposes(orig_transpose, transpose);
// remove original transpose now it's combined with a new one
// should be safe to remove an already detached node
mark_transpose_for_deletion(orig_transpose, transposes_to_delete);
// replace transpose with combined one
replace_node(transpose, new_transpose);
mark_transpose_for_deletion(new_transpose, transposes_to_delete);
write_transposemap(reorders, new_transpose, new_transpose);
if (new_transpose) {
// remove original transpose now it's combined with a new one
// should be safe to remove an already detached node
mark_transpose_for_deletion(orig_transpose, transposes_to_delete);
// replace transpose with combined one
replace_node(transpose, new_transpose);
mark_transpose_for_deletion(new_transpose, transposes_to_delete);
write_transposemap(reorders, new_transpose, new_transpose);
}
}
static void sink_unary(const shared_ptr<Node>& n,
@ -365,6 +382,12 @@ static void sink_prelu(const shared_ptr<PRelu>& prelu,
}
}
void purge_transposes(const set<shared_ptr<Node>>& transposes_to_delete) {
for (const auto& r : transposes_to_delete) {
delete_transpose(r);
}
}
// The goal of TransposeSinking is to remove
// round-trip transposes(i.e. nhwc->nchw(nchw-only-op)->nhwc)
// around nchw-only-op (e.g.Convolution, Batchnorm, Avg/MaxPool)
@ -408,14 +431,13 @@ bool ov::frontend::tensorflow::pass::TransposeSinking::run_on_model(const shared
}
} catch (...) {
OPENVINO_DEBUG << "Caught exception while sinking op";
purge_transposes(transposes_to_delete);
return false;
}
// STEP 2: purge all the transposes we either sunk or swam.
OPENVINO_DEBUG << "Purging transposes ";
for (const auto& r : transposes_to_delete) {
delete_transpose(r);
}
purge_transposes(transposes_to_delete);
// STEP 3: fix wrong shape info wholesale
OPENVINO_DEBUG << "Fixing wrong shape info for the whole graph";

View File

@ -32,6 +32,49 @@ TEST(TransposeSinkingTest, PassProperty) {
ASSERT_FALSE(pass->get_property(ov::pass::PassProperty::CHANGE_DYNAMIC_STATE));
}
TEST(TransposeSinkingTest, TensorNames) {
ngraph::Shape shape_nhwc{16, 28, 28, 1};
auto a = make_shared<Parameter>(ngraph::element::i32, shape_nhwc);
auto ng_order = std::make_shared<Constant>(ngraph::element::u64, ngraph::Shape{4}, ngraph::Shape{0, 3, 1, 2});
auto transpose = make_shared<Transpose>(a, ng_order);
auto absn = make_shared<Abs>(transpose);
auto absn2 = make_shared<Abs>(absn);
absn2->output(0).set_names({"out_name"});
auto res = make_shared<Result>(absn2);
auto func = make_shared<ngraph::Function>(ngraph::OutputVector{res}, ngraph::ParameterVector{a});
ov::pass::Manager pass_manager;
pass_manager.register_pass<TransposeSinking>();
pass_manager.run_passes(func);
auto new_transpose =
ngraph::as_type_ptr<Transpose>(func->get_results().at(0)->input_value(0).get_node_shared_ptr());
ASSERT_TRUE(new_transpose);
EXPECT_EQ(new_transpose->output(0).get_names(), std::unordered_set<std::string>({"out_name"}));
}
TEST(TransposeSinkingTest, TensorNamesCombineTransposes) {
ngraph::Shape shape_nhwc{16, 28, 28, 1};
auto a = make_shared<Parameter>(ngraph::element::i32, shape_nhwc);
auto ng_order = std::make_shared<Constant>(ngraph::element::u64, ngraph::Shape{4}, ngraph::Shape{0, 3, 1, 2});
auto transpose_1 = make_shared<Transpose>(a, ng_order);
auto transpose_2 = make_shared<Transpose>(transpose_1, ng_order);
transpose_2->output(0).set_names({"out_name"});
auto res = make_shared<Result>(transpose_2);
auto func = make_shared<ngraph::Function>(ngraph::OutputVector{res}, ngraph::ParameterVector{a});
ov::pass::Manager pass_manager;
pass_manager.register_pass<TransposeSinking>();
pass_manager.run_passes(func);
auto new_transpose =
ngraph::as_type_ptr<Transpose>(func->get_results().at(0)->input_value(0).get_node_shared_ptr());
ASSERT_TRUE(new_transpose);
EXPECT_EQ(new_transpose->output(0).get_names(), std::unordered_set<std::string>({"out_name"}));
size_t transpose_cnt = count_ops_of_type<Transpose>(func);
EXPECT_EQ(transpose_cnt, 1);
}
TEST(TransposeSinkingTest, EdgeSplitting) {
// checks if Transpose is pushed through Abs, but stopped by
// ReduceSum