Added RemoveConcatZeroDimInput and RemoveMultiSubGraphOpDanglingParams transformations (#8035)

* fix expand_onnx_functions

* refactor + unit test

* fixed function in function case

* fixed expand_onnx_functions

* fixed default value of shape in ValueInfo

* enable xpass model

* changed MergeFrom to Swap

* added xfail with missing test data

* added more unit tests

* styles applied

* used std::rotate, review remarks

* removed debug code

* after offline discussion remarks

* fix checking input/output names on Windows

* names comparator refactor

* replace regex with custom comparison

* review remarks

* added RemoveConcatZeroDimInput transformation

* added RemoveLoopDanglingParameters transformation

* chage place of passes during replace

* missing comment

* code refactor + unit tests

* remove unused headers

* used std::any_of in RemoveConcatZeroDimInput

* changed headers and namespaces to new ov convention

* used std::any_of in RemoveConcatZeroDimInput

* RemoveLoopDanglingParameters refactored

* changed names to RemoveMultiSubGraphOpDanglingParams

* handling multi-body cases

* Handling If case during RemoveMultiSubGraphOpDanglingParams

* comments and names refactor

* More tests for If and TensorIterator

* handle removing dagling param from one body and update all descriptors

* fixed test

* revert if change

* moved RemoveConcatZeroDimInput and RemoveMultiSubGraphOpDanglingParams to NopElimantion

* return false if node is not replaced

* added validate_nodes_and_infer_types

* Revert "moved RemoveConcatZeroDimInput and RemoveMultiSubGraphOpDanglingParams to NopElimantion" + remarks

* review remarks

* review remarks

* fixed subgraph rtti

* adjust passes to new structure
This commit is contained in:
Mateusz Bencer 2021-11-30 21:19:26 +01:00 committed by GitHub
parent 1b0ff2979c
commit 461d6e8a1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 791 additions and 2 deletions

View File

@ -0,0 +1,140 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <gtest/gtest.h>
#include <string>
#include <memory>
#include <openvino/core/function.hpp>
#include <openvino/opsets/opset8.hpp>
#include <openvino/pass/manager.hpp>
#include <transformations/common_optimizations/remove_concat_zero_dim_input.hpp>
#include <transformations/init_node_info.hpp>
#include <transformations/utils/utils.hpp>
#include "common_test_utils/ngraph_test_utils.hpp"
using namespace testing;
TEST_F(TransformationTestsF, RemoveConcatZeroDimInputStaticShape) {
auto input1 = std::make_shared<ov::opset8::Parameter>(ov::element::f32, ov::PartialShape{1, 2, 3});
auto input3 = std::make_shared<ov::opset8::Parameter>(ov::element::f32, ov::PartialShape{1, 2, 3});
int64_t axis = 1;
{
auto input2 = std::make_shared<ov::opset8::Parameter>(ov::element::f32, ov::PartialShape{1, 0, 3});
auto concat = std::make_shared<ov::opset8::Concat>(ov::OutputVector{input1, input2, input3}, axis);
function = std::make_shared<ov::Function>(ov::NodeVector{concat}, ov::ParameterVector{input1, input2, input3});
manager.register_pass<ov::pass::RemoveConcatZeroDimInput>();
}
{
auto concat = std::make_shared<ov::opset8::Concat>(ov::OutputVector{input1, input3}, axis);
function_ref = std::make_shared<ov::Function>(ov::NodeVector{concat}, ov::ParameterVector{input1, input3});
}
}
TEST_F(TransformationTestsF, RemoveConcatZeroDimInputSubgraph) {
auto input1 = std::make_shared<ov::opset8::Parameter>(ov::element::f32, ov::PartialShape{1, 2, 3});
auto input3 = std::make_shared<ov::opset8::Parameter>(ov::element::f32, ov::PartialShape{1, 2, 3});
int64_t axis = 1;
{
auto in_abs = std::make_shared<ov::opset8::Parameter>(ov::element::f32, ov::PartialShape{1, 0, 3});
auto abs = std::make_shared<ov::opset8::Abs>(in_abs);
auto concat = std::make_shared<ov::opset8::Concat>(ov::OutputVector{input1, abs, input3}, axis);
function = std::make_shared<ov::Function>(ov::NodeVector{concat}, ov::ParameterVector{input1, input3, in_abs});
manager.register_pass<ov::pass::RemoveConcatZeroDimInput>();
}
{
auto concat = std::make_shared<ov::opset8::Concat>(ov::OutputVector{input1, input3}, axis);
function_ref = std::make_shared<ov::Function>(ov::NodeVector{concat}, ov::ParameterVector{input1, input3});
}
}
TEST_F(TransformationTestsF, RemoveConcatZeroDimInputSubgraph2) {
auto input1 = std::make_shared<ov::opset8::Parameter>(ov::element::f32, ov::PartialShape{1, ov::Dimension::dynamic(), 3});
auto input3 = std::make_shared<ov::opset8::Parameter>(ov::element::f32, ov::PartialShape{1, 2, 3});
auto abs = std::make_shared<ov::opset8::Abs>(input1);
int64_t axis = 1;
{
auto in_mul = std::make_shared<ov::opset8::Parameter>(ov::element::f32, ov::PartialShape{1, 0, 3});
auto mul = std::make_shared<ov::opset8::Multiply>(in_mul, abs);
auto concat = std::make_shared<ov::opset8::Concat>(ov::OutputVector{mul, input3}, axis);
function = std::make_shared<ov::Function>(ov::NodeVector{concat}, ov::ParameterVector{input1, input3, in_mul});
manager.register_pass<ov::pass::RemoveConcatZeroDimInput>();
}
{
auto concat = std::make_shared<ov::opset8::Concat>(ov::OutputVector{input3}, axis);
function_ref = std::make_shared<ov::Function>(ov::NodeVector{concat}, ov::ParameterVector{input3});
}
}
TEST_F(TransformationTestsF, RemoveConcatZeroDimInputPartiallyKnowShape) {
std::shared_ptr<ov::Function> f(nullptr), f_ref(nullptr);
auto input1 = std::make_shared<ov::opset8::Parameter>(ov::element::f32, ov::PartialShape::dynamic());
auto input3 = std::make_shared<ov::opset8::Parameter>(ov::element::f32, ov::PartialShape::dynamic());
int64_t axis = 0;
{
auto input2 = std::make_shared<ov::opset8::Parameter>(ov::element::f32,
ov::PartialShape{0, ov::Dimension::dynamic(), ov::Dimension::dynamic()});
auto concat = std::make_shared<ov::opset8::Concat>(ov::OutputVector{input1, input2, input3}, axis);
function = std::make_shared<ov::Function>(ov::NodeVector{concat}, ov::ParameterVector{input1, input2, input3});
manager.register_pass<ov::pass::RemoveConcatZeroDimInput>();
}
{
auto concat = std::make_shared<ov::opset8::Concat>(ov::OutputVector{input1, input3}, axis);
function_ref = std::make_shared<ov::Function>(ov::NodeVector{concat}, ov::ParameterVector{input1, input3});
}
}
TEST_F(TransformationTestsF, RemoveConcatZeroDimInputDynamicRank) {
auto input1 = std::make_shared<ov::opset8::Parameter>(ov::element::f32, ov::PartialShape::dynamic());
auto input2 = std::make_shared<ov::opset8::Parameter>(ov::element::f32, ov::PartialShape::dynamic());
auto input3 = std::make_shared<ov::opset8::Parameter>(ov::element::f32, ov::PartialShape::dynamic());
int64_t axis = 0;
{
auto concat = std::make_shared<ov::opset8::Concat>(ov::OutputVector{input1, input2, input3}, axis);
function = std::make_shared<ov::Function>(ov::NodeVector{concat}, ov::ParameterVector{input1, input2, input3});
manager.register_pass<ov::pass::RemoveConcatZeroDimInput>();
}
{
auto concat = std::make_shared<ov::opset8::Concat>(ov::OutputVector{input1, input2, input3}, axis);
function_ref = std::make_shared<ov::Function>(ov::NodeVector{concat}, ov::ParameterVector{input1, input2, input3});
}
}
TEST_F(TransformationTestsF, RemoveConcatZeroDimTwoInputs) {
auto input1 = std::make_shared<ov::opset8::Parameter>(ov::element::f32,
ov::PartialShape{1, ov::Dimension::dynamic(), ov::Dimension::dynamic()});
int64_t axis = 1;
{
auto input2 = std::make_shared<ov::opset8::Parameter>(ov::element::f32,
ov::PartialShape{1, 0, ov::Dimension::dynamic()});
auto input3 = std::make_shared<ov::opset8::Parameter>(ov::element::f32,
ov::PartialShape{1, ov::Dimension::dynamic(), 0});
auto concat = std::make_shared<ov::opset8::Concat>(ov::OutputVector{input1, input2, input3}, axis);
function = std::make_shared<ov::Function>(ov::NodeVector{concat}, ov::ParameterVector{input1, input2, input3});
manager.register_pass<ov::pass::RemoveConcatZeroDimInput>();
}
{
auto concat = std::make_shared<ov::opset8::Concat>(ov::OutputVector{input1}, axis);
function_ref = std::make_shared<ov::Function>(ov::NodeVector{concat}, ov::ParameterVector{input1});
}
}

View File

@ -0,0 +1,423 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <gtest/gtest.h>
#include <string>
#include <memory>
#include <openvino/core/function.hpp>
#include <openvino/opsets/opset8.hpp>
#include <ngraph/pass/manager.hpp>
#include <transformations/common_optimizations/remove_multi_subgraph_op_dangling_params.hpp>
#include <transformations/common_optimizations/remove_concat_zero_dim_input.hpp>
#include <transformations/init_node_info.hpp>
#include <transformations/utils/utils.hpp>
#include "common_test_utils/ngraph_test_utils.hpp"
using namespace testing;
using namespace ov;
using namespace ov::opset8;
TEST_F(TransformationTestsF, RemoveLoopDanglingParameters) {
auto trip_count = std::make_shared<Constant>(element::i64, Shape{}, 10);
auto condition = std::make_shared<Constant>(element::boolean, Shape{}, true);
auto a = std::make_shared<Parameter>(element::f32, Shape{2, 2});
auto ai = std::make_shared<Parameter>(element::f32, Shape{2, 2});
auto b = std::make_shared<Parameter>(element::f32, Shape{2, 2});
auto bi = std::make_shared<Parameter>(element::f32, Shape{2, 2});
auto mul = std::make_shared<Multiply>(bi, bi);
auto abs = std::make_shared<Abs>(mul);
{
auto body = std::make_shared<Function>(OutputVector{condition, abs}, ParameterVector{ai, bi});
auto loop = std::make_shared<Loop>(trip_count, condition);
loop->set_special_body_ports({-1, 0});
loop->set_function(body);
loop->set_invariant_input(ai, a);
loop->set_invariant_input(bi, b);
auto loop_res = std::make_shared<Result>(loop->get_iter_value(abs));
function = std::make_shared<Function>(OutputVector{loop_res}, ParameterVector{a, b});
manager.register_pass<pass::RemoveMultiSubGraphOpDanglingParams>();
}
{
auto body = std::make_shared<Function>(OutputVector{condition, abs}, ParameterVector{bi});
auto loop = std::make_shared<Loop>(trip_count, condition);
loop->set_special_body_ports({-1, 0});
loop->set_function(body);
loop->set_invariant_input(bi, b);
auto loop_res = std::make_shared<Result>(loop->get_iter_value(abs));
function_ref = std::make_shared<Function>(OutputVector{loop_res}, ParameterVector{a, b});
}
}
TEST_F(TransformationTestsF, RemoveLoopManyDanglingParameters) {
auto trip_count = std::make_shared<Constant>(element::i64, Shape{}, 10);
auto condition = std::make_shared<Constant>(element::boolean, Shape{}, true);
auto a = std::make_shared<Parameter>(element::f32, Shape{2, 2});
auto ai = std::make_shared<Parameter>(element::f32, Shape{2, 2});
auto b = std::make_shared<Parameter>(element::f32, Shape{2, 2});
auto bi = std::make_shared<Parameter>(element::f32, Shape{2, 2});
auto c = std::make_shared<Parameter>(element::f32, Shape{2, 2});
auto ci = std::make_shared<Parameter>(element::f32, Shape{2, 2});
auto mul = std::make_shared<Multiply>(bi, bi);
auto abs = std::make_shared<Abs>(mul);
{
auto body = std::make_shared<Function>(OutputVector{condition, abs}, ParameterVector{ai, bi, ci});
auto loop = std::make_shared<Loop>(trip_count, condition);
loop->set_special_body_ports({-1, 0});
loop->set_function(body);
loop->set_invariant_input(ai, a);
loop->set_invariant_input(bi, b);
loop->set_invariant_input(ci, c);
auto loop_res = std::make_shared<Result>(loop->get_iter_value(abs));
function = std::make_shared<Function>(OutputVector{loop_res}, ParameterVector{a, b, c});
manager.register_pass<pass::RemoveMultiSubGraphOpDanglingParams>();
}
{
auto body = std::make_shared<Function>(OutputVector{condition, abs}, ParameterVector{bi});
auto loop = std::make_shared<Loop>(trip_count, condition);
loop->set_special_body_ports({-1, 0});
loop->set_function(body);
loop->set_invariant_input(bi, b);
auto loop_res = std::make_shared<Result>(loop->get_iter_value(abs));
function_ref = std::make_shared<Function>(OutputVector{loop_res}, ParameterVector{a, b, c});
}
}
TEST_F(TransformationTestsF, RemoveLoopManyDanglingParameters2) {
auto trip_count = std::make_shared<Constant>(element::i64, Shape{}, 10);
auto condition = std::make_shared<Constant>(element::boolean, Shape{}, true);
auto a = std::make_shared<Parameter>(element::f32, Shape{2, 2});
auto ai = std::make_shared<Parameter>(element::f32, Shape{2, 2});
auto b = std::make_shared<Parameter>(element::f32, Shape{2, 2});
auto bi = std::make_shared<Parameter>(element::f32, Shape{2, 2});
auto c = std::make_shared<Parameter>(element::f32, Shape{2, 2});
auto ci = std::make_shared<Parameter>(element::f32, Shape{2, 2});
auto d = std::make_shared<Parameter>(element::f32, Shape{2, 2});
auto di = std::make_shared<Parameter>(element::f32, Shape{2, 2});
auto mul = std::make_shared<Multiply>(bi, bi);
auto sub = std::make_shared<Multiply>(mul, di);
auto abs = std::make_shared<Abs>(sub);
{
auto body = std::make_shared<Function>(OutputVector{condition, abs}, ParameterVector{ai, bi, ci, di});
auto loop = std::make_shared<Loop>(trip_count, condition);
loop->set_special_body_ports({-1, 0});
loop->set_function(body);
loop->set_invariant_input(ai, a);
loop->set_invariant_input(bi, b);
loop->set_invariant_input(ci, c);
loop->set_invariant_input(di, d);
auto loop_res = std::make_shared<Result>(loop->get_iter_value(abs));
function = std::make_shared<Function>(OutputVector{loop_res}, ParameterVector{a, b, c, d});
manager.register_pass<pass::RemoveMultiSubGraphOpDanglingParams>();
}
{
auto body = std::make_shared<Function>(OutputVector{condition, abs}, ParameterVector{bi, di});
auto loop = std::make_shared<Loop>(trip_count, condition);
loop->set_special_body_ports({-1, 0});
loop->set_function(body);
loop->set_invariant_input(bi, b);
loop->set_invariant_input(di, d);
auto loop_res = std::make_shared<Result>(loop->get_iter_value(abs));
function_ref = std::make_shared<Function>(OutputVector{loop_res}, ParameterVector{a, b, c, d});
}
}
TEST_F(TransformationTestsF, RemoveLoopDanglingParametersIfConcatEmptyTensor) {
auto trip_count = std::make_shared<Constant>(element::i64, Shape{}, 10);
auto condition = std::make_shared<Constant>(element::boolean, Shape{}, true);
auto a = std::make_shared<Parameter>(element::f32, Shape{2, 2});
auto ai = std::make_shared<Parameter>(element::f32, Shape{2, 2});
auto b = std::make_shared<Parameter>(element::f32, Shape{0, 2}); // empty tensor
auto bi = std::make_shared<Parameter>(element::f32, Shape{0, 2});
{
auto concat = std::make_shared<Concat>(NodeVector{ai, bi}, 0);
auto body = std::make_shared<Function>(OutputVector{condition, concat}, ParameterVector{ai, bi});
auto loop = std::make_shared<Loop>(trip_count, condition);
loop->set_special_body_ports({-1, 0});
loop->set_function(body);
loop->set_invariant_input(ai, a);
loop->set_invariant_input(bi, b);
auto loop_res = std::make_shared<Result>(loop->get_iter_value(concat));
function = std::make_shared<Function>(OutputVector{loop_res}, ParameterVector{a, b});
manager.register_pass<pass::RemoveConcatZeroDimInput>();
manager.register_pass<pass::RemoveMultiSubGraphOpDanglingParams>();
}
{
auto concat = std::make_shared<Concat>(NodeVector{ai}, 0);
auto body = std::make_shared<Function>(OutputVector{condition, concat}, ParameterVector{ai});
auto loop = std::make_shared<Loop>(trip_count, condition);
loop->set_special_body_ports({-1, 0});
loop->set_function(body);
loop->set_invariant_input(ai, a);
auto loop_res = std::make_shared<Result>(loop->get_iter_value(concat));
function_ref = std::make_shared<Function>(OutputVector{loop_res}, ParameterVector{a, b});
}
}
TEST_F(TransformationTestsF, RemoveIfDanglingParametersFromBodiesAndInputs) {
auto X = std::make_shared<Parameter>(element::f32, Shape{2, 4, 1});
auto Y = std::make_shared<Parameter>(element::f32, Shape{3, 4, 1});
auto cond = std::make_shared<Constant>(element::boolean, Shape{1}, true);
auto Xte = std::make_shared<Parameter>(element::f32, PartialShape::dynamic());
auto Yte = std::make_shared<Parameter>(element::f32, PartialShape::dynamic());
auto then_op = std::make_shared<Add>(Xte, Xte);
auto then_op_res = std::make_shared<Result>(then_op);
auto else_op = std::make_shared<Maximum>(Xte, Xte);
auto else_op_res = std::make_shared<Result>(else_op);
{
auto then_body = std::make_shared<Function>(OutputVector{then_op_res}, ParameterVector{Xte, Yte});
auto else_body = std::make_shared<Function>(OutputVector{else_op_res}, ParameterVector{Xte, Yte});
auto if_op = std::make_shared<If>(cond);
if_op->set_then_body(then_body);
if_op->set_else_body(else_body);
if_op->set_input(X, Xte, Xte);
if_op->set_input(Y, Yte, Yte);
auto res = if_op->set_output(then_op_res, else_op_res);
function = std::make_shared<Function>(OutputVector{res}, ParameterVector{X, Y});
manager.register_pass<pass::RemoveMultiSubGraphOpDanglingParams>();
}
{
auto then_body = std::make_shared<Function>(OutputVector{then_op_res}, ParameterVector{Xte});
auto else_body = std::make_shared<Function>(OutputVector{else_op_res}, ParameterVector{Xte});
auto if_op = std::make_shared<If>(cond);
if_op->set_then_body(then_body);
if_op->set_else_body(else_body);
if_op->set_input(X, Xte, Xte);
auto res = if_op->set_output(then_op_res, else_op_res);
function_ref = std::make_shared<Function>(OutputVector{res}, ParameterVector{X, Y});
}
}
TEST_F(TransformationTestsF, RemoveIfDanglingParametersOnlyFromBodies) {
auto X = std::make_shared<Parameter>(element::f32, Shape{2, 4, 1});
auto Y = std::make_shared<Parameter>(element::f32, Shape{3, 4, 1});
auto cond = std::make_shared<Constant>(element::boolean, Shape{1}, true);
auto Xt = std::make_shared<Parameter>(element::f32, PartialShape::dynamic());
auto Yt = std::make_shared<Parameter>(element::f32, PartialShape::dynamic());
auto then_op = std::make_shared<Add>(Xt, Xt);
auto then_op_res = std::make_shared<Result>(then_op);
auto Xe = std::make_shared<Parameter>(element::f32, PartialShape::dynamic());
auto Ye = std::make_shared<Parameter>(element::f32, PartialShape::dynamic());
auto else_op = std::make_shared<Maximum>(Ye, Ye);
auto else_op_res = std::make_shared<Result>(else_op);
{
auto then_body = std::make_shared<Function>(OutputVector{then_op_res}, ParameterVector{Xt, Yt});
auto else_body = std::make_shared<Function>(OutputVector{else_op_res}, ParameterVector{Xe, Ye});
auto if_op = std::make_shared<If>(cond);
if_op->set_then_body(then_body);
if_op->set_else_body(else_body);
if_op->set_input(X, Xt, Xe);
if_op->set_input(Y, Yt, Ye);
auto res = if_op->set_output(then_op_res, else_op_res);
function = std::make_shared<Function>(OutputVector{res}, ParameterVector{X, Y});
manager.register_pass<pass::RemoveMultiSubGraphOpDanglingParams>();
}
{
auto then_body = std::make_shared<Function>(OutputVector{then_op_res}, ParameterVector{Xt});
auto else_body = std::make_shared<Function>(OutputVector{else_op_res}, ParameterVector{Ye});
auto if_op = std::make_shared<If>(cond);
if_op->set_then_body(then_body);
if_op->set_else_body(else_body);
if_op->set_input(X, Xt, nullptr);
if_op->set_input(Y, nullptr, Ye);
auto res = if_op->set_output(then_op_res, else_op_res);
function_ref = std::make_shared<Function>(OutputVector{res}, ParameterVector{X, Y});
}
}
TEST_F(TransformationTestsF, RemoveIfManyDanglingParameters) {
auto X = std::make_shared<Parameter>(element::f32, Shape{2, 4, 1});
auto Y = std::make_shared<Parameter>(element::f32, Shape{3, 4, 1});
auto Z = std::make_shared<Parameter>(element::f32, Shape{2, 4, 1});
auto cond = std::make_shared<Constant>(element::boolean, Shape{1}, true);
auto Xt = std::make_shared<Parameter>(element::f32, PartialShape::dynamic());
auto Yt = std::make_shared<Parameter>(element::f32, PartialShape::dynamic());
auto Zt = std::make_shared<Parameter>(element::f32, PartialShape::dynamic());
auto then_op = std::make_shared<Add>(Xt, Zt);
auto then_op_res = std::make_shared<Result>(then_op);
auto Xe = std::make_shared<Parameter>(element::f32, PartialShape::dynamic());
auto Ye = std::make_shared<Parameter>(element::f32, PartialShape::dynamic());
auto Ze = std::make_shared<Parameter>(element::f32, PartialShape::dynamic());
auto else_op = std::make_shared<Maximum>(Xe, Xe);
auto else_op_res = std::make_shared<Result>(else_op);
{
auto then_body = std::make_shared<Function>(OutputVector{then_op_res}, ParameterVector{Xt, Yt, Zt});
auto else_body = std::make_shared<Function>(OutputVector{else_op_res}, ParameterVector{Xe, Ye, Ze});
auto if_op = std::make_shared<If>(cond);
if_op->set_then_body(then_body);
if_op->set_else_body(else_body);
if_op->set_input(X, Xt, Xe);
if_op->set_input(Y, Yt, Ye);
if_op->set_input(Z, Zt, Ze);
auto res = if_op->set_output(then_op_res, else_op_res);
function = std::make_shared<Function>(OutputVector{res}, ParameterVector{X, Y, Z});
manager.register_pass<pass::RemoveMultiSubGraphOpDanglingParams>();
}
{
auto then_body = std::make_shared<Function>(OutputVector{then_op_res}, ParameterVector{Xt, Zt});
auto else_body = std::make_shared<Function>(OutputVector{else_op_res}, ParameterVector{Xe});
auto if_op = std::make_shared<If>(cond);
if_op->set_then_body(then_body);
if_op->set_else_body(else_body);
if_op->set_input(X, Xt, Xe);
if_op->set_input(Z, Zt, nullptr);
auto res = if_op->set_output(then_op_res, else_op_res);
function_ref = std::make_shared<Function>(OutputVector{res}, ParameterVector{X, Y, Z});
}
}
TEST_F(TransformationTestsF, RemoveIfDanglingParamFromOneBodyAndUpdateAllDescriptions) {
std::shared_ptr<Function> f(nullptr), f_ref(nullptr);
auto X = std::make_shared<Parameter>(element::f32, Shape{2, 4, 1});
auto Y = std::make_shared<Parameter>(element::f32, Shape{2, 4, 1});
auto Z = std::make_shared<Parameter>(element::f32, Shape{2, 4, 1});
auto cond = std::make_shared<Constant>(element::boolean, Shape{1}, true);
auto Xt = std::make_shared<Parameter>(element::f32, PartialShape::dynamic());
auto Yt = std::make_shared<Parameter>(element::f32, PartialShape::dynamic());
auto Zt = std::make_shared<Parameter>(element::f32, PartialShape::dynamic());
auto then_op = std::make_shared<Add>(Zt, Zt);
auto then_op_res = std::make_shared<Result>(then_op);
auto Xe = std::make_shared<Parameter>(element::f32, PartialShape::dynamic());
auto Ze = std::make_shared<Parameter>(element::f32, PartialShape::dynamic());
auto else_op = std::make_shared<Add>(std::make_shared<Maximum>(Xe, Ze), Ze);
auto else_op_res = std::make_shared<Result>(else_op);
{
auto then_body = std::make_shared<Function>(OutputVector{then_op_res}, ParameterVector{Xt, Yt, Zt});
auto else_body = std::make_shared<Function>(OutputVector{else_op_res}, ParameterVector{Xe, Ze});
auto if_op = std::make_shared<If>(cond);
if_op->set_then_body(then_body);
if_op->set_else_body(else_body);
if_op->set_input(X, Xt, Xe);
if_op->set_input(Y, Yt, nullptr);
if_op->set_input(Z, Zt, Ze);
auto res = if_op->set_output(then_op_res, else_op_res);
function = std::make_shared<Function>(OutputVector{res}, ParameterVector{X, Y, Z});
manager.register_pass<pass::RemoveMultiSubGraphOpDanglingParams>();
}
{
auto then_body = std::make_shared<Function>(OutputVector{then_op_res}, ParameterVector{Zt});
auto else_body = std::make_shared<Function>(OutputVector{else_op_res}, ParameterVector{Xe, Ze});
auto if_op = std::make_shared<If>(cond);
if_op->set_then_body(then_body);
if_op->set_else_body(else_body);
if_op->set_input(X, nullptr, Xe);
if_op->set_input(Z, Zt, Ze);
auto res = if_op->set_output(then_op_res, else_op_res);
function_ref = std::make_shared<Function>(OutputVector{res}, ParameterVector{X, Y, Z});
}
}
TEST_F(TransformationTestsF, RemoveTensorIteratorDanglingParameter) {
auto X = std::make_shared<Parameter>(element::f32, Shape{32, 40, 10});
auto Y = std::make_shared<Parameter>(element::f32, Shape{32, 40, 10});
auto M = std::make_shared<Parameter>(element::f32, Shape{32, 2, 10});
auto Xi = std::make_shared<Parameter>(element::f32, Shape{32, 2, 10});
auto Yi = std::make_shared<Parameter>(element::f32, Shape{32, 2, 10});
auto M_body = std::make_shared<Parameter>(element::f32, Shape{32, 2, 10});
auto Zo = std::make_shared<Abs>(std::make_shared<Add>(Xi, Yi));
{
auto body = std::make_shared<Function>(OutputVector{Zo}, ParameterVector{Xi, Yi, M_body});
auto tensor_iterator = std::make_shared<TensorIterator>();
tensor_iterator->set_body(body);
tensor_iterator->set_sliced_input(Xi, X, 0, 2, 2, 39, 1);
tensor_iterator->set_sliced_input(Yi, Y, 0, 2, 2, -1, 1);
tensor_iterator->set_invariant_input(M_body, M);
auto out = tensor_iterator->get_iter_value(Zo, -1);
auto res = std::make_shared<Result>(out);
function = std::make_shared<Function>(OutputVector{res}, ParameterVector{X, Y, M});
manager.register_pass<pass::RemoveMultiSubGraphOpDanglingParams>();
}
{
auto body = std::make_shared<Function>(OutputVector{Zo}, ParameterVector{Xi, Yi});
auto tensor_iterator = std::make_shared<TensorIterator>();
tensor_iterator->set_body(body);
tensor_iterator->set_sliced_input(Xi, X, 0, 2, 2, 39, 1);
tensor_iterator->set_sliced_input(Yi, Y, 0, 2, 2, -1, 1);
auto out = tensor_iterator->get_iter_value(Zo, -1);
auto res = std::make_shared<Result>(out);
function_ref = std::make_shared<Function>(OutputVector{res}, ParameterVector{X, Y, M});
}
}
TEST_F(TransformationTestsF, RemoveTensorIteratorManyDanglingParameters) {
auto X = std::make_shared<Parameter>(element::f32, Shape{32, 40, 10});
auto Y = std::make_shared<Parameter>(element::f32, Shape{32, 40, 10});
auto Z = std::make_shared<Parameter>(element::f32, Shape{32, 40, 10});
auto M = std::make_shared<Parameter>(element::f32, Shape{32, 2, 10});
auto Xi = std::make_shared<Parameter>(element::f32, Shape{32, 2, 10});
auto Yi = std::make_shared<Parameter>(element::f32, Shape{32, 2, 10});
auto Zi = std::make_shared<Parameter>(element::f32, Shape{32, 2, 10});
auto M_body = std::make_shared<Parameter>(element::f32, Shape{32, 2, 10});
auto Zo = std::make_shared<Abs>(std::make_shared<Add>(Xi, Zi));
{
auto body = std::make_shared<Function>(OutputVector{Zo}, ParameterVector{Xi, Yi, Zi, M_body});
auto tensor_iterator = std::make_shared<TensorIterator>();
tensor_iterator->set_body(body);
tensor_iterator->set_sliced_input(Xi, X, 0, 2, 2, 39, 1);
tensor_iterator->set_sliced_input(Yi, Y, 0, 2, 2, -1, 1);
tensor_iterator->set_sliced_input(Zi, Z, 0, 2, 2, -1, 1);
tensor_iterator->set_invariant_input(M_body, M);
auto out = tensor_iterator->get_iter_value(Zo, -1);
auto res = std::make_shared<Result>(out);
function = std::make_shared<Function>(OutputVector{res}, ParameterVector{X, Y, Z, M});
manager.register_pass<pass::RemoveMultiSubGraphOpDanglingParams>();
}
{
auto body = std::make_shared<Function>(OutputVector{Zo}, ParameterVector{Xi, Zi});
auto tensor_iterator = std::make_shared<TensorIterator>();
tensor_iterator->set_body(body);
tensor_iterator->set_sliced_input(Xi, X, 0, 2, 2, 39, 1);
tensor_iterator->set_sliced_input(Zi, Z, 0, 2, 2, -1, 1);
auto out = tensor_iterator->get_iter_value(Zo, -1);
auto res = std::make_shared<Result>(out);
function_ref = std::make_shared<Function>(OutputVector{res}, ParameterVector{X, Y, Z, M});
}
}

View File

@ -0,0 +1,31 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <vector>
#include <memory>
#include <transformations_visibility.hpp>
#include <openvino/pass/graph_rewrite.hpp>
namespace ov {
namespace pass {
class TRANSFORMATIONS_API RemoveConcatZeroDimInput;
} // namespace pass
} // namespace ov
/**
* @ingroup ie_transformation_common_api
* @brief RemoveConcatZeroDimInput transformation
* removes input of Concat if the tensor size is equal to 0
*/
class ov::pass::RemoveConcatZeroDimInput: public ov::pass::MatcherPass {
public:
NGRAPH_RTTI_DECLARATION;
RemoveConcatZeroDimInput();
};

View File

@ -0,0 +1,32 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <vector>
#include <memory>
#include <transformations_visibility.hpp>
#include <openvino/pass/graph_rewrite.hpp>
namespace ov {
namespace pass {
class TRANSFORMATIONS_API RemoveMultiSubGraphOpDanglingParams;
} // namespace pass
} // namespace ov
/*
* @ingroup ie_transformation_common_api
* @brief RemoveMultiSubGraphOpDanglingParams transformation
* removed MultiSubGraphOp inputs which are not connected to other nodes
* in the bodies of a MultiSubGraphOp
*/
class ov::pass::RemoveMultiSubGraphOpDanglingParams: public ov::pass::MatcherPass {
public:
NGRAPH_RTTI_DECLARATION;
RemoveMultiSubGraphOpDanglingParams();
};

View File

@ -48,6 +48,8 @@
#include <transformations/common_optimizations/transpose_to_reshape.hpp>
#include <transformations/common_optimizations/batch_to_space_fusion.hpp>
#include <transformations/common_optimizations/mul_conv_fusion.hpp>
#include <transformations/common_optimizations/remove_concat_zero_dim_input.hpp>
#include <transformations/common_optimizations/remove_multi_subgraph_op_dangling_params.hpp>
#include <transformations/common_optimizations/split_concat_pair_to_interpolate_fusion.hpp>
#include <transformations/op_conversions/convert_divide.hpp>
#include <transformations/common_optimizations/divide_fusion.hpp>
@ -79,6 +81,15 @@ bool ngraph::pass::MOCTransformations::run_on_function(std::shared_ptr<ngraph::F
if (!m_use_shapes) {
manager.register_pass<ngraph::pass::DisableShapeOfConstantFolding>();
}
// RemoveConcatZeroDimInput and RemoveMultiSubGraphOpDanglingParams
// should be performed before first ConstantFolding call.
// The passes can deteach graph branches where zero dimesion is calculated.
// Zero dimensions in shape causes creation empty tensors, which are incorrect during CF.
// In particular, if zero dim tensor is consumed in body of MultiSubGraphOp
// RemoveConcatZeroDimInput and RemoveMultiSubGraphOpDanglingParams should be called together.
manager.register_pass<ov::pass::RemoveConcatZeroDimInput>();
manager.register_pass<ov::pass::Validate>();
manager.register_pass<ov::pass::RemoveMultiSubGraphOpDanglingParams>();
manager.register_pass<ngraph::pass::DisableRandomUniformConstantFolding>();
manager.register_pass<ngraph::pass::ConstantFolding>();
manager.register_pass<ngraph::pass::Validate>();

View File

@ -0,0 +1,47 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "transformations/common_optimizations/remove_concat_zero_dim_input.hpp"
#include "transformations/utils/utils.hpp"
#include <memory>
#include <vector>
#include <algorithm>
#include <openvino/opsets/opset8.hpp>
#include "openvino/pass/pattern/op/wrap_type.hpp"
#include <ngraph/rt_info.hpp>
#include "itt.hpp"
NGRAPH_RTTI_DEFINITION(ov::pass::RemoveConcatZeroDimInput, "RemoveConcatZeroDimInput", 0);
ov::pass::RemoveConcatZeroDimInput::RemoveConcatZeroDimInput() {
MATCHER_SCOPE(RemoveConcatZeroDimInput);
auto concat_pattern = pattern::wrap_type<opset8::Concat>();
ngraph::matcher_pass_callback callback = [=](pattern::Matcher& m) {
auto concat = m.get_match_root();
auto concat_inputs = concat->input_values();
concat_inputs.erase(std::remove_if(concat_inputs.begin(), concat_inputs.end(),
[](const Output<Node>& input) {
const auto& in_shape = input.get_partial_shape();
if (in_shape.rank().is_static()) {
return std::any_of(std::begin(in_shape), std::end(in_shape), [](const ov::Dimension& dim) {
if (dim.is_static() && dim.get_length() == 0) {
return true;
}
return false;
});}
return false;
}), concat_inputs.end());
bool inputs_removed = concat->get_input_size() > concat_inputs.size();
if (inputs_removed) {
concat->set_arguments(concat_inputs);
}
return inputs_removed;
};
auto m = std::make_shared<ngraph::pattern::Matcher>(concat_pattern, matcher_name);
this->register_matcher(m, callback);
}

View File

@ -0,0 +1,101 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "transformations/common_optimizations/remove_multi_subgraph_op_dangling_params.hpp"
#include "transformations/utils/utils.hpp"
#include <memory>
#include <vector>
#include <openvino/opsets/opset8.hpp>
#include <openvino/op/util/multi_subgraph_base.hpp>
#include "openvino/pass/pattern/op/wrap_type.hpp"
#include <ngraph/rt_info.hpp>
#include "itt.hpp"
NGRAPH_RTTI_DEFINITION(ov::pass::RemoveMultiSubGraphOpDanglingParams, "RemoveMultiSubGraphOpDanglingParams", 0);
ov::pass::RemoveMultiSubGraphOpDanglingParams::RemoveMultiSubGraphOpDanglingParams() {
MATCHER_SCOPE(RemoveMultiSubGraphOpDanglingParams);
auto multi_subgraph_op_pattern = pattern::wrap_type<op::util::MultiSubGraphOp>();
ov::matcher_pass_callback callback = [=](pattern::Matcher& m) {
auto multi_subgraph_op = std::dynamic_pointer_cast<op::util::MultiSubGraphOp>(m.get_match_root());
if (multi_subgraph_op == nullptr) {
return false;
}
bool pass_required = false;
std::set<ov::Output<ov::Node>> required_inputs;
auto op_inputs = multi_subgraph_op->input_values();
std::vector<std::vector<size_t>> to_remove_descriptors_indexes;
const auto subgraphs_size = multi_subgraph_op->get_internal_subgraphs_size();
to_remove_descriptors_indexes.resize(subgraphs_size);
for (size_t body_idx=0; body_idx < subgraphs_size; ++body_idx) {
auto& body_func = multi_subgraph_op->get_function(body_idx);
auto& body_params = body_func->get_parameters();
auto& body_in_descriptors = multi_subgraph_op->get_input_descriptions(body_idx);
// collect all descriptors which should be removed and reqired inputs
for (size_t i = 0; i < body_in_descriptors.size(); ++i) {
auto& body_param = body_params[body_in_descriptors[i]->m_body_parameter_index];
if (body_param->get_output_target_inputs(0).size() == 0) {
to_remove_descriptors_indexes[body_idx].push_back(i);
pass_required = true;
} else {
// collecting required inputs is needed to detect cases where the input
// is not needed in a one body, but the other one uses it (for example If case)
required_inputs.insert(op_inputs[body_in_descriptors[i]->m_input_index]); // only unique
}
}
}
if (pass_required) {
using DescType = op::util::MultiSubGraphOp::MultiSubgraphInputDescriptionVector;
auto update_body_param_desc = [](DescType& descriptors, uint64_t removed_body_idx){
for (auto& desc : descriptors) {
if (desc->m_body_parameter_index > removed_body_idx) {
desc->m_body_parameter_index--;
}
}};
auto update_op_inputs_desc = [&subgraphs_size](const std::shared_ptr<op::util::MultiSubGraphOp>& op, uint64_t removed_loop_idx){
for (size_t body_idx=0; body_idx < subgraphs_size; ++body_idx) {
auto& descriptors = op->get_input_descriptions(body_idx);
for (auto& desc : descriptors) {
if (desc->m_input_index > removed_loop_idx) {
desc->m_input_index--;
}
}
}};
// Remove dangling body params and input and update input descriptors
for (size_t body_idx=0; body_idx < subgraphs_size; ++body_idx) {
auto& body_in_descriptors = multi_subgraph_op->get_input_descriptions(body_idx);
auto& body_func = multi_subgraph_op->get_function(body_idx);
auto& body_params = body_func->get_parameters();
op::util::MultiSubGraphOp::MultiSubgraphInputDescriptionVector updated_body_in_descriptors;
for (size_t desc_idx = 0; desc_idx < body_in_descriptors.size(); ++desc_idx) {
if (std::count(std::begin(to_remove_descriptors_indexes[body_idx]), std::end(to_remove_descriptors_indexes[body_idx]), desc_idx) > 0) {
auto& body_param = body_params[body_in_descriptors[desc_idx]->m_body_parameter_index];
body_func->remove_parameter(body_param);
// Move all body indexes which are after these indicated by to_remove_descriptors_indexes
update_body_param_desc(body_in_descriptors, body_in_descriptors[desc_idx]->m_body_parameter_index);
// remove dangling input of MultiSubGraphOp which was not removed earlier
auto& current_input = op_inputs[body_in_descriptors[desc_idx]->m_input_index];
if (std::count(std::begin(required_inputs), std::end(required_inputs), current_input) == 0
&& std::count(std::begin(op_inputs), std::end(op_inputs), current_input) > 0) {
op_inputs.erase(std::next(op_inputs.begin(), body_in_descriptors[desc_idx]->m_input_index));
// Move all input indexes (in all bodies) which are after these indicated by to_remove_descriptors_indexes
// and are not used in any body
update_op_inputs_desc(multi_subgraph_op, body_in_descriptors[desc_idx]->m_input_index);
}
} else {
updated_body_in_descriptors.emplace_back(body_in_descriptors[desc_idx]);
}
}
multi_subgraph_op->set_input_descriptions(body_idx, updated_body_in_descriptors);
}
multi_subgraph_op->set_arguments(op_inputs);
}
return false;
};
auto m = std::make_shared<ngraph::pattern::Matcher>(multi_subgraph_op_pattern, matcher_name);
this->register_matcher(m, callback);
}

View File

@ -16,7 +16,7 @@ namespace util {
///
class OPENVINO_API MultiSubGraphOp : public Op {
public:
OPENVINO_RTTI("MultiSubGraphOp", "util");
OPENVINO_OP("MultiSubGraphOp", "util");
BWDCMP_RTTI_DECLARATION;
/// \brief Abstract class describes a connection between a MultiSubGraphOp input and
/// the body.

View File

@ -15,7 +15,7 @@ namespace util {
///
class OPENVINO_API SubGraphOp : public MultiSubGraphOp {
public:
OPENVINO_OP("SubGraphOp", "util");
OPENVINO_OP("SubGraphOp", "util", op::util::MultiSubGraphOp);
BWDCMP_RTTI_DECLARATION;
virtual const std::shared_ptr<Function>& get_function() const {

View File

@ -31,6 +31,8 @@
// TODO: remove this pass usage
#include <legacy/transformations/convert_opset1_to_legacy/convert_nms_5_to_legacy.hpp>
#include <legacy/transformations/convert_opset1_to_legacy/convert_one_hot_to_one_hot_ie.hpp>
#include <transformations/common_optimizations/remove_concat_zero_dim_input.hpp>
#include <transformations/common_optimizations/remove_multi_subgraph_op_dangling_params.hpp>
#include <transformations/low_precision/disable_convert_constant_folding_on_const_path.hpp>
#include <transformations/op_conversions/convert_matrix_nms_to_matrix_nms_ie.hpp>
#include <transformations/op_conversions/convert_multiclass_nms_to_multiclass_nms_ie.hpp>
@ -422,6 +424,8 @@ void CNNNetworkNGraphImpl::reshape(const std::map<std::string, ngraph::PartialSh
OV_ITT_SCOPED_TASK(ov::itt::domains::IE, "CNNNetworkNGraphImpl::ConvertToLegacy");
::ngraph::pass::Manager manager;
// resolves dynamism by replacing dynamic operation with static version
manager.register_pass<ov::pass::RemoveConcatZeroDimInput>();
manager.register_pass<ov::pass::RemoveMultiSubGraphOpDanglingParams>();
manager.register_pass<::ngraph::pass::ConvertNMS5ToLegacyMatcher>(false);
// TODO [DS NMS]: remove when nodes from models where nms is not last node in model supports DS
manager.register_pass<::ngraph::pass::ConvertMulticlassNmsToMulticlassNmsIE>(false);