nGraph Transformations refactoring (#931)

This PR introduces next changes:
1. Transformations *_tbl.hpp files were replaced with direct registration in cpp files.
2. Plugins use pass::Manager to call conversion passes.
3. Transformations callback was moved to PassBase class as there is no more need to keep it in separate class
4. All pattern based transformations must be inherited from MatcherPass class. GraphRewrite class will be used only for matchers registration and execution on function.
MatcherPass class adds new features to pattern-based transformations approach:
* Allows to run matcher pass on a single node.
* Operations that were created inside transformation callback can be added to execution list to be available for pattern matching within single GraphRewrite.
5. GraphRewrite MatchClosure was replaced with MatcherPass. So all matchers will be registered as a MatcherPass.
6. Added pass::Manager::clear_state() method to avoid dependency with nodes that no longer belongs to function after replacement.
7.  Some representative transformations were updated to use MatcherPass as an example.
8.  Mul->Add sequence fusion transformation was replaced with LinOpSequenceFusion.
9. Pattern and callback registration code was moved to class c-tors (will be finished for remaining passes in other PR) .
10. Updated pass::Manager to get pass names only when NGRAPH_PROFILE_PASS_ENABLE enabled.
11. Moving towards removing PassProperty.
12. Added ngraph::pattern::wrap_type<T>(inputs, pred) to simplify pattern creation.
13. GraphRewrite was updated to execute MatcherPass more efficient.
This commit is contained in:
Gleb Kazantaev
2020-07-27 19:47:37 +03:00
committed by GitHub
parent 4ae03a0d5d
commit bd42f09e98
154 changed files with 2823 additions and 1702 deletions
@@ -86,7 +86,8 @@ void TemplatePlugin::ExecutableNetwork::CompileGraph(const std::shared_ptr<const
// Example: register CommonOptimizations transformation from transformations library
passManager.register_pass<ngraph::pass::CommonOptimizations>();
// Example: register plugin specific transformation
passManager.register_pass<ngraph::pass::MyPatternBasedTransformation>();
passManager.register_pass<ngraph::pass::DecomposeDivideMatcher>();
passManager.register_pass<ngraph::pass::ReluReluFusionMatcher>();
// Register any other transformations
// ..
@@ -10,7 +10,7 @@ using namespace ngraph;
// ! [function_pass:template_transformation_cpp]
// template_function_transformation.cpp
bool MyFunctionTransformation::run_on_function(std::shared_ptr<ngraph::Function> f) {
bool pass::MyFunctionTransformation::run_on_function(std::shared_ptr<ngraph::Function> f) {
// Example transformation code
std::vector<std::shared_ptr<Node> > nodes;
@@ -9,9 +9,17 @@
#include <ngraph/ngraph.hpp>
namespace ngraph {
namespace pass {
class MyFunctionTransformation;
} // namespace pass
} // namespace ngraph
// ! [function_pass:template_transformation_hpp]
// template_function_transformation.hpp
class MyFunctionTransformation: public ngraph::pass::FunctionPass {
class ngraph::pass::MyFunctionTransformation: public ngraph::pass::FunctionPass {
public:
MyFunctionTransformation() : FunctionPass() {}
@@ -3,21 +3,23 @@
//
#include "template_pattern_transformation.hpp"
#include "template_function_transformation.hpp"
#include <ngraph/opsets/opset3.hpp>
#include <ngraph/ngraph.hpp>
#include <ngraph/opsets/opset3.hpp>
#include <ngraph/pattern/op/wrap_type.hpp>
using namespace ngraph;
// ! [graph_rewrite:template_transformation_cpp]
// template_pattern_transformation.cpp
void ngraph::pass::MyPatternBasedTransformation::transform() {
ngraph::pass::DecomposeDivideMatcher::DecomposeDivideMatcher() {
// Pattern example
auto input0 = std::make_shared<pattern::op::Label>(element::i64, Shape{1, 1, 1, 1});
auto input1 = std::make_shared<pattern::op::Label>(element::i64, Shape{1, 1, 1, 1});
auto input0 = std::make_shared<pattern::op::Label>(element::f32, Shape{});
auto input1 = std::make_shared<pattern::op::Label>(element::f32, Shape{});
auto div = std::make_shared<ngraph::opset3::Divide>(input0, input1);
ngraph::graph_rewrite_callback callback = [](pattern::Matcher& m) {
ngraph::matcher_pass_callback callback = [](pattern::Matcher& m) {
auto div = std::dynamic_pointer_cast<ngraph::opset3::Divide> (m.get_match_root());
// We can not apply this transformation in case with integer input data type
if (!div || div->input(0).get_element_type().is_integral()) {
@@ -43,9 +45,94 @@ void ngraph::pass::MyPatternBasedTransformation::transform() {
return true;
};
// Register pattern with divide operaiton as a pattern root node
// Register pattern with Divide operation as a pattern root node
auto m = std::make_shared<ngraph::pattern::Matcher>(div, "ConvertDivide");
// Register Matcher
this->add_matcher(m, callback, ngraph::pass::PassProperty::CHANGE_DYNAMIC_STATE);
this->register_matcher(m, callback);
}
// ! [graph_rewrite:template_transformation_cpp]
// ! [matcher_pass:relu_fusion]
ngraph::pass::ReluReluFusionMatcher::ReluReluFusionMatcher() {
auto m_relu1 = ngraph::pattern::wrap_type<ngraph::opset3::Relu>(pattern::consumers_count(1));
auto m_relu2 = ngraph::pattern::wrap_type<ngraph::opset3::Relu>({m_relu1});
ngraph::matcher_pass_callback callback = [=](pattern::Matcher& m) {
// Map that helps to connect labels with matched outputs
auto& node_to_output = m.get_pattern_value_map();
// Create new Relu operation and add register it for additional execution
auto new_relu = register_new_node<ngraph::opset3::Relu>(
node_to_output.at(m_relu1).get_node_shared_ptr()->input_value(0));
// Copy runtime info attributes to newly created operation
ngraph::copy_runtime_info(m.get_matched_nodes(), new_relu);
// Save last Relu name to new Relu operation
new_relu->set_friendly_name(m.get_match_root()->get_friendly_name());
// Replace Relu->Relu with Relu
ngraph::replace_node(m.get_match_root(), new_relu);
// Return true as the root node was changed
return true;
};
// Register pattern with Relu operation as a pattern root node
auto m = std::make_shared<ngraph::pattern::Matcher>(m_relu2, "ReluReluFusion");
// Register Matcher
this->register_matcher(m, callback);
}
// ! [matcher_pass:relu_fusion]
void run_matcher_on_node(std::shared_ptr<ngraph::Node> node) {
// ! [matcher_pass:run_on_node]
if (ngraph::pass::DecomposeDivideMatcher().apply(node)) {
// successful execution (root node was replaced)
}
// ! [matcher_pass:run_on_node]
}
void run_matcher_with_manager(std::shared_ptr<ngraph::Function> f) {
// ! [matcher_pass:manager]
// Two matchers will run independently (two independent graph traversals)
// pass::Manager automatically creates GraphRewrite container for each MatcherPass
pass::Manager manager;
manager.register_pass<ngraph::pass::DecomposeDivideMatcher>();
manager.register_pass<ngraph::pass::ReluReluFusionMatcher>();
manager.run_passes(f);
// ! [matcher_pass:manager]
}
void run_matcher_with_manager2(std::shared_ptr<ngraph::Function> f) {
// ! [matcher_pass:manager2]
// Register anchor GraphRewrite pass inside manager that will execute two matchers simultaneously
pass::Manager manager;
auto anchor = manager.register_pass<ngraph::pass::GraphRewrite>();
anchor->add_matcher<ngraph::pass::DecomposeDivideMatcher>();
anchor->add_matcher<ngraph::pass::ReluReluFusionMatcher>();
manager.run_passes(f);
// ! [matcher_pass:manager2]
}
void run_matcher_with_manager3(std::shared_ptr<ngraph::Function> f) {
// ! [matcher_pass:manager3]
pass::Manager manager;
manager.register_pass<ngraph::pass::MyFunctionTransformation>();
// Two matchers will run independently (two independent graph traversals)
// pass::Manager automatically creates GraphRewrite container for each MatcherPass
manager.register_pass<ngraph::pass::DecomposeDivideMatcher>();
manager.register_pass<ngraph::pass::ReluReluFusionMatcher>();
manager.run_passes(f);
// ! [matcher_pass:manager3]
}
void run_matcher_with_gr(std::shared_ptr<ngraph::Function> f) {
// ! [matcher_pass:graph_rewrite]
// Two matcher passes will run simultaneously in a single graph traversal
ngraph::pass::GraphRewrite pass;
pass.add_matcher<ngraph::pass::DecomposeDivideMatcher>();
pass.add_matcher<ngraph::pass::ReluReluFusionMatcher>();
pass.run_on_function(f);
// ! [matcher_pass:graph_rewrite]
}
@@ -12,20 +12,21 @@
namespace ngraph {
namespace pass {
class MyPatternBasedTransformation;
class DecomposeDivideMatcher;
class ReluReluFusionMatcher;
} // namespace pass
} // namespace ngraph
// ! [graph_rewrite:template_transformation_hpp]
// template_pattern_transformation.hpp
class ngraph::pass::MyPatternBasedTransformation: public ngraph::pass::GraphRewrite {
class ngraph::pass::DecomposeDivideMatcher: public ngraph::pass::MatcherPass {
public:
MyPatternBasedTransformation() : GraphRewrite() {
transform();
}
private:
void transform();
DecomposeDivideMatcher();
};
// ! [graph_rewrite:template_transformation_hpp]
class ngraph::pass::ReluReluFusionMatcher: public ngraph::pass::MatcherPass {
public:
ReluReluFusionMatcher();
};