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:
parent
d1c1680a81
commit
3ec40c490b
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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";
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user