Added nGraph transformations developer guide (#947)
authorGleb Kazantaev <gleb.kazantaev@intel.com>
Tue, 30 Jun 2020 15:02:26 +0000 (18:02 +0300)
committerGitHub <noreply@github.com>
Tue, 30 Jun 2020 15:02:26 +0000 (18:02 +0300)
* Added nGraph transformations developer guide

* Added some more chapters

* Added Transformation writing essentials chapter

* Added working with ngraph::Function chapter

* Added two chapters

* Fix comments

* Moved code snippets to source files

* Moved ngraph test utils to common. Added transformations test examples to template plugin

* Added Common mistake section

* Added doxygen for CommoOptimization passes

* Fixed doxygen comments; added links in md files; fixed typos

* Fixed review comments

51 files changed:
docs/IE_PLUGIN_DG/Doxyfile
docs/IE_PLUGIN_DG/NewTransformation.md
docs/IE_PLUGIN_DG/images/ngraph_insert_node.png [new file with mode: 0644]
docs/IE_PLUGIN_DG/images/ngraph_replace_node.png [new file with mode: 0644]
docs/examples/CMakeLists.txt
docs/examples/example_ngraph_utils.cpp [new file with mode: 0644]
docs/template_plugin/src/template_executable_network.cpp
docs/template_plugin/src/template_function_transformation.cpp [new file with mode: 0644]
docs/template_plugin/src/template_function_transformation.hpp [new file with mode: 0644]
docs/template_plugin/src/template_pattern_transformation.cpp [new file with mode: 0644]
docs/template_plugin/src/template_pattern_transformation.hpp [new file with mode: 0644]
docs/template_plugin/tests/functional/transformations/template_transformations_test.cpp [new file with mode: 0644]
inference-engine/src/transformations/include/transformations/convert_scatter_elements_to_scatter.hpp
inference-engine/src/transformations/include/transformations/depth_to_space_fusion.hpp
inference-engine/src/transformations/include/transformations/init_node_info.hpp
inference-engine/src/transformations/include/transformations/optimize_strided_slice.hpp
inference-engine/src/transformations/include/transformations/rt_info/fused_names_attribute.hpp
inference-engine/src/transformations/include/transformations/rt_info/primitives_priority_attribute.hpp
inference-engine/src/transformations/src/transformations/convert_opset3_to_opset2/convert_broadcast3.cpp
inference-engine/tests/functional/inference_engine/transformations/const_folding_prior_box.cpp
inference-engine/tests/functional/inference_engine/transformations/conv_fusion_test.cpp
inference-engine/tests/functional/inference_engine/transformations/convert_broadcast3_test.cpp
inference-engine/tests/functional/inference_engine/transformations/convert_cells_to_cells_ie_test.cpp
inference-engine/tests/functional/inference_engine/transformations/convert_convolution_test.cpp
inference-engine/tests/functional/inference_engine/transformations/convert_deconvolution_test.cpp
inference-engine/tests/functional/inference_engine/transformations/convert_divide.cpp
inference-engine/tests/functional/inference_engine/transformations/convert_gather_to_gather_ie.cpp
inference-engine/tests/functional/inference_engine/transformations/convert_matmul_test.cpp
inference-engine/tests/functional/inference_engine/transformations/convert_nms3_test.cpp
inference-engine/tests/functional/inference_engine/transformations/convert_nms4_test.cpp
inference-engine/tests/functional/inference_engine/transformations/convert_nms_to_nms_ie_test.cpp
inference-engine/tests/functional/inference_engine/transformations/convert_reduce_to_pooling_test.cpp
inference-engine/tests/functional/inference_engine/transformations/convert_scatter_elements_to_scatter_test.cpp
inference-engine/tests/functional/inference_engine/transformations/convert_shapeof3.cpp
inference-engine/tests/functional/inference_engine/transformations/convert_shuffle_channels3_test.cpp
inference-engine/tests/functional/inference_engine/transformations/convert_strided_slice_to_crop_test.cpp
inference-engine/tests/functional/inference_engine/transformations/convert_topk3_test.cpp
inference-engine/tests/functional/inference_engine/transformations/convert_topk_test.cpp
inference-engine/tests/functional/inference_engine/transformations/depth_to_space_fusion_test.cpp
inference-engine/tests/functional/inference_engine/transformations/fc_bias_fusion_test.cpp
inference-engine/tests/functional/inference_engine/transformations/mul_add_conversion_test.cpp
inference-engine/tests/functional/inference_engine/transformations/ngraph_1d_ops_reshape_test.cpp
inference-engine/tests/functional/inference_engine/transformations/ngraph_depth_to_space_transform_test.cpp
inference-engine/tests/functional/inference_engine/transformations/ngraph_fq_transpose_test.cpp
inference-engine/tests/functional/inference_engine/transformations/ngraph_mode_decomposition_test.cpp
inference-engine/tests/functional/inference_engine/transformations/optimize_strided_slice_test.cpp
inference-engine/tests/functional/inference_engine/transformations/primitives_priority_test.cpp
inference-engine/tests/functional/inference_engine/transformations/reshape_fc_fusion_test.cpp
inference-engine/tests/functional/inference_engine/transformations/transpose_to_reshape_test.cpp
inference-engine/tests/ie_test_utils/common_test_utils/ngraph_test_utils.cpp [moved from inference-engine/tests/functional/inference_engine/transformations/ngraph_test_utils.cpp with 100% similarity]
inference-engine/tests/ie_test_utils/common_test_utils/ngraph_test_utils.hpp [moved from inference-engine/tests/functional/inference_engine/transformations/ngraph_test_utils.hpp with 88% similarity]

index 08f2116..1f1407e 100644 (file)
@@ -868,6 +868,7 @@ EXAMPLE_PATH           = ../template_plugin/src \
                                                 ../template_plugin/include \
                          ../template_plugin/src/CMakeLists.txt \
                          ../template_plugin/tests/functional/CMakeLists.txt \
+                         ../template_plugin/tests/functional/transformations \
                          ../examples
 
 # If the value of the EXAMPLE_PATH tag contains directories, you can use the
index ea4a78a..896150c 100644 (file)
 # Writing ngraph transformations {#new_ngraph_transformation}
 
-1. Code of such transformation MUST be directly in template plugin soruces.
-2. It must be mark with doxygen markeds like
+This guide contains all necessary information that could help you to start writing nGraph transformations.
 
+First of all before writing transformation make sure that there is no transformation with the same functionality in [Transformation Library](group__ie__transformation__api.html).
+To start writing transformation it's good to know how [Transformation Library](group__ie__transformation__api.html) is structured, how transformations are organized and where to put your transformation code.
 
-// ! [new_transformation:part1]
+Let's start from reviewing transformations library structure.
+Transformations library is independent from InferenceEngine target library named as `inference_engine_transformations` and located in `inference-engine/src/transformations` directory.
+Transformations root directory contains two folders:
+1. ngraph_ops - legacy opset operations needed for nGraph to CNNNetwork conversion.
+> **Note**: this operation are prohibited to use inside new plugins until they are not moved to separate directory with allowed operations.
+2. transformations - includes all transformations, utils, runtime info attributes and pass managers.
+> **Note**: do not use transformation that belongs to `ngraph::pass::ConvertOpSet1ToLegacy` transformations until they are not moved to separate directory with allowed transformations.
 
-bla-bla
+Transformation flow in transformation library has several layers:
+1. Pass managers - executes list of transformations using `*_tbl.hpp` file. For example conversion form OpSetX to OpSetY.
+2. Transformations - performs particular transformation algorithm on `ngraph::Function`. Find more about transformations in [Transformations types](#transformations_types).
+3. Low level functions that takes set of nodes and performs some transformation action. They are not mandatory and all transformation code can be located inside transformation. But if some transformation parts can potentially be reused in other transformations we suggest to keep them as a separate functions.
 
-// ! [new_transformation:part1]
+To decide where to store your transformation code please follow these rules:
+1. If it's plugin specific transformation and can't be reused by other plugins keep source code inside plugin.
+2. If this transformation relates to OpSetXToOpSetY conversion or it's common optimization then keep sources inside transformation library.
 
-And this file must refer to that code via
+After you decided where to store your transformation code you can start develop your own nGraph transformation.
 
-@snippet src/template_transformation.cpp new_transformation:part1
+## Table of Contents:
+
+1. [`ngraph::Function` and graph representation](#ngraph_function) 
+2. [Transformations types](#transformations_types)
+3. [Pattern matching](#pattern_matching)
+4. [Working with ngraph::Function](#working_with_ngraph_function)
+5. [Transformation writing essentials](#transformation_writing_essentials)
+6. [Common mistakes in transformations](#common_mistakes)
+7. [Using pass manager](#using_pass_manager)
+8. [How to debug transformations](#how_to_debug_transformations)
+9. [Disabling/Enabling specific transformations for plugin X](#disabling_transformation)
+10. [Transformations testing](#transformations_testing)
+
+## ngraph::Function and graph representation <a name="ngraph_function"></a>
+
+nGraph function is a very simple thing: it stores shared pointers to `ngraph::op::Result` and `ngraph::op::Parameter` operations that are inputs and outputs of the graph. 
+All other operations hold each other via shared pointers: child operation holds its parent (hard link). If operation has no consumers and it's not Result operation
+(shared pointer counter is zero) then it will be destructed and won't be accessible anymore. Each operation in `ngraph::Function` has a `std::shared_ptr<ngraph::Node>` type.
+
+Below you can find examples how `ngraph::Function` can be created:
+
+@snippet example_ngraph_utils.cpp ngraph_utils:simple_function
+
+@snippet example_ngraph_utils.cpp ngraph_utils:advanced_function
+
+## Transformations types <a name="transformations_types"></a>
+
+There are two main transformation types:
+
+###1. ngraph::pass::FunctionalPass
+
+ngraph::pass::FunctionalPass is used for transformations that take entire `ngraph::Function` as input and process it.
+
+Template for FunctionPass transformation class
+
+@snippet src/template_function_transformation.hpp function_pass:template_transformation_hpp
+
+@snippet src/template_function_transformation.cpp function_pass:template_transformation_cpp
+
+Using `ngraph::FunctionPass` you need to override `run_on_function` method where you will write transformation code. Return value must be `true` if original function has changed during transformation (new operation were added or operations replacement was made or node attributes were changed) otherwise it must be `false`. For transformation API please follow [working with ngraph::Function](#working_with_ngraph_function) section.
+
+###2. ngraph::pass::GraphRewrite
+
+`ngraph::pass::GraphRewrite` is used for pattern based transformations.
+
+Template for GraphRewrite transformation class
+@snippet src/template_pattern_transformation.hpp graph_rewrite:template_transformation_hpp
+
+@snippet src/template_pattern_transformation.cpp graph_rewrite:template_transformation_cpp
+
+Using `ngraph::GraphRewrite` you need to complete three steps:
+1. Create pattern using nGraph operations.
+2. Implement callback. 
+3. Register pattern and Matcher.
+
+So let's go though each of this steps.
+
+Pattern is a single root `ngraph::Function`. But the only difference is that you don't need to create function object, you just create and connect nGraph operations then take the last one and put it as a root of the pattern.
+
+@snippet example_ngraph_utils.cpp pattern:simple_example
+
+You may have noticed that `Parameter` operation in example has type and shape specified. These attributes are needed only to create Parameter operation class and not used in pattern matching. 
+But what if we want to match pattern where `ShapeOf` takes any operation as input? To find an answer to this question please follow [pattern matching](#pattern_matching) section.
+
+What is callback? Callback is an action applied to every pattern entrance. In general callback is lambda function that takes Matcher object with detected sub-graph.
+
+@snippet example_ngraph_utils.cpp pattern:callback_example
+
+Example above shows callback structure and how Matcher can be used for accessing nodes detected by pattern.
+Callback return value must be `true` if root node was replaced and next pattern can't be applied to the same root node otherwise it must be `false`.
+
+And the last step is to register Matcher and callback inside GraphRewrite pass. And to do this you need to call `add_matcher` method. 
+
+```cpp
+// Register matcher and callback
+this->add_matcher(m, callback, PassProperty::CHANGE_DYNAMIC_STATE);
+```
+
+Also you can have multiple matchers and callbacks and they can be registered in single Graphrewrite pass. In this case all registered patterns will be applied in a singe graph traversal. 
+
+```cpp
+// Multiple matchers example
+this->add_matcher(m1, callback1, PassProperty::CHANGE_DYNAMIC_STATE);
+this->add_matcher(m2, callback2, PassProperty::CHANGE_DYNAMIC_STATE);
+```
+
+The last argument `PassProperty::CHANGE_DYNAMIC_STATE` says that callback can be applied for ngraph::Function with dynamic shapes. In case if callback does not support dynamic shapes `PassProperty::REQUIRE_STATIC_SHAPE` can be used.
+> **Note**: property mechanism will be deprecated soon and PassProperty::CHANGE_DYNAMIC_STATE is suggested to be used by default.
+
+To run any transformation you need to call `un_on_function(f)` method where `f` is `ngraph::Function`.
+```cpp
+ngraph::pass::MyTransformationClass().run_on_function(f);
+``` 
+  
+## Pattern matching <a name="pattern_matching"></a>
+
+Sometimes patterns can't be expressed via regular nGraph operations. For example if you want to detect Convolution->Add sub-graph without specifying particular input type for Convolution operation or you want to create pattern where some of operations can have different types.
+And for these cases nGraph provides additional helpers to construct patterns for GraphRewrite transformations. 
+There are two main helpers:
+1. `ngraph::pattern::op::Label` - helps to express inputs if their type is undefined.
+2. `ngraph::pattern::op::Any` - helps to express intermediate nodes of pattern if their type is unknown.
+
+Let's go through example to have better understanding how it works:
+
+> **Note**: node attributes do not participate in pattern matching and needed only for operations creation. Only operation types participate in pattern matching.
+
+Example below shows basic usage of `pattern::op::Label` class.
+Here we construct Multiply pattern with arbitrary first input and Constant as a second input.
+
+@snippet example_ngraph_utils.cpp pattern:label_example
+
+This example show how we can construct pattern when operation has arbitrary number of inputs.
+
+@snippet example_ngraph_utils.cpp pattern:concat_example
+
+This example shows how to use predicate to construct pattern where operation has two different types.
+
+@snippet example_ngraph_utils.cpp pattern:predicate_example
+
+TODO: add examples for ngraph::pattern::op::Any
+
+## Working with ngraph::Function <a name="working_with_ngraph_function"></a>
+
+In this chapter we will review nGraph API that allows us to manipulate with `ngraph::Function`.
+
+###1. ngraph::Node input and output ports
+
+First of all let's talk about `ngraph::Node` input/output ports. Each nGraph operation has input and output ports except cases when operation has `Result`, `Parameter` or `Constant` type.
+
+Every port belongs to its node so using port we can access parent node, get shape and type for particular input/output, get all consumers in case of output port and get producer node in case of input port.
+With output port we can set inputs for newly created operations. 
+
+Lets look at code example.
+
+@snippet example_ngraph_utils.cpp ngraph:ports_example
+
+You may notice that we usually construct operations in this way:
+```cpp
+std::shared_ptr<Node> neg_const = opset1::Constant::create(sub->get_input_element_type(1), Shape{1}, {-1}));
+Output<Node> data = node->input_value(0);
+auto neg = std::make_shared<ngraph::opset1::Multiply>(data, neg_const);
+```
+In this example `opset3::Multiply` operation takes `Output<Node>` and `std::shared_ptr<Node>` as inputs. But constructor takes both as `Output<Node>`. 
+In this case `std::shared_ptr<Node>` will be automatically converted to `Output<Node>` if node has exactly one output port otherwise conversion will raise an exception.   
+
+###2. ngraph::Node replacement
+
+nGraph provides two ways for node replacement: via nGraph helper function and directly via port methods. We are going to review both of them.
+
+Let's start with nGraph helper functions. The most popular function is `ngraph::replace_node(old_node, new_node)`.
+
+We will review real replacement case where Negative operation replaces with Multiply.
+
+![ngraph_replace_node]
+
+@snippet example_ngraph_utils.cpp ngraph:replace_node
+
+`ngraph::replace_node` has a constraint that number of output ports for both of ops must be the same otherwise it will raise an exception.
+
+
+The alternative way to do the same replacement is next:
+```cpp
+// All neg->output(0) consumers will be moved to mul->output(0) port
+neg->output(0).replace(mul->output(0));
+```
+
+Another transformation example is insertion.
+
+![ngraph_insert_node]
+
+@snippet example_ngraph_utils.cpp ngraph:insert_node
+
+The alternative way to insert operation is to make a node copy and use `replace_node`:
+
+@snippet example_ngraph_utils.cpp ngraph:insert_node_with_copy
+
+###3. ngraph::Node elimination
+
+Another type of node replacement is its elimination.
+
+To eliminate operation nGraph has special method that consider all limitations related to InferenceEngine.
+
+@snippet example_ngraph_utils.cpp ngraph:eliminate_node
+
+`replace_output_update_name` in case of successful replacement it automatically preserves friendly name and runtime info.
+  
+
+## Transformation writing essentials <a name="transformation_writing_essentials"></a>
+
+When developing transformation we need to follow next transformation rules:
+
+###1. Operation Set (OpSet)
+
+Which OpSet to use in your transformation? The right answer is latest that exists at the moment. An exception is ConvertOpSetXToOpSetY transformations where operations from OpSetX and OpSetY are required to use.
+
+@snippet example_ngraph_utils.cpp ngraph:include
+
+###2. Dynamic Shape and Rank
+
+nGraph has two types for shape representation: 
+`ngraph::Shape` - represents static shape.
+`ngraph::PartialShape` - represents dynamic shape. That means that rank or some of dimensions are dynamic (undefined).
+`ngraph::PartialShape` can be converted to `ngraph::Shape` using `get_shape()` method if all dimensions are static otherwise conversion will raise an exception.
+
+@snippet example_ngraph_utils.cpp ngraph:shape
+
+But in most cases before getting static shape using `get_shape()` method you need to check that shape is static.  
+
+Also if your transformation requires only input shape rank or particular dimension value for some reason please do not use `get_shape()` method. See example below how not to use `get_shape()`
+
+@snippet example_ngraph_utils.cpp ngraph:shape_check
+
+Not using `get_shape()` method makes your transformation more flexible and applicable for more cases.
+
+###3. Friendly Names
+
+Each `ngraph::Node` has unique name (is used for nGraph internals) and friendly name. In transformations we care only about friendly name because it represents name from IR. 
+Also friendly name is used as output tensor name (until we do not have other way to represent output tensor name) and user code that requests intermediate outputs based on this names.
+So not to loose friendly name when replacing node with other node or sub-graph we need to set original friendly name to the latest node in replacing sub-garph. See example below. 
+
+```cpp
+// Replace Div operation with Power and Multiply sub-graph and set original friendly name to Multiply operation
+auto pow = std::make_shared<ngraph::opset1::Power>(div->input(1).get_source_output(),
+                                                           op::Constant::create(div->get_input_element_type(1), Shape{1}, {-1}));
+auto mul = std::make_shared<ngraph::opset1::Multiply>(div->input(0).get_source_output(), pow);
+mul->set_friendly_name(div->get_friendly_name());
+ngraph::replace_node(div, mul);
+```
+
+In more advanced cases when replaced operation has several outputs and we add additional consumers to its outputs we make decision how to set friendly name by arrangement.
+
+###4. Runtime Info
+
+Runtime info is a map `std::map<std::string, std::shared_ptr<Variant>>` located inside `ngraph::Node` class. It represents additional attributes in `ngraph::Node`.
+These attributes can be set by users or by plugins and when executing transformation that changes `ngraph::Function` we need to preserve this attributes as they won't be automatically propagated.
+In most cases transformations has next types: 1:1 (replace node with another node), 1:N (replace node with a sub-graph), N:1 (fuse sub-graph into a single node), N:M (any other transformation).
+Currently there is no mechanism that automatically detects transformation types so we need to propagate this runtime information manually. See examples below.
+
+```cpp
+// Replace Transpose with Reshape operation (1:1)
+ngraph::copy_runtime_info(transpose, reshape);
+```
+
+```cpp
+// Replace Div operation with Power and Multiply sub-graph (1:N)
+ngraph::copy_runtime_info(div, {pow, mul});
+```
+
+```cpp
+// Fuse Convolution with Add operation (N:1)
+ngraph::copy_runtime_info({conv, bias}, {conv_ie});
+```
+
+```cpp
+// Any other transformation that replaces one sub-graph with another sub-graph (N:M)
+ngraph::copy_runtime_info({a, b, c}, {e, f});
+```
+
+When transformation has multiple fusions or decompositions `ngraph::copy_runtime_info` must be called multiple times for each case. 
+
+###5. Constant Folding
+
+If your transformation inserts constant sub-graphs that needs to be folded do not forget to use `ngraph::pass::ConstantFolding()` after your transformation.
+Example below shows how constant sub-graph can be constructed.
+
+```cpp
+// After ConstantFolding pass Power will be replaced with Constant 
+auto pow = std::make_shared<ngraph::opset3::Power>(
+                    opset3::Constant::create(element::f32, Shape{1}, {2})
+                    opset3::Constant::create(element::f32, Shape{1}, {3}));
+auto mul = std::make_shared<ngraph::opset3::Multiply>(input /* not constant input */, pow);
+``` 
+
+## Common mistakes in transformations <a name="common_mistakes"></a>
+
+In transformation development process 
+
+* Do not use deprecated nGraph API. Deprecated methods has `NGRAPH_DEPRECATED` macros in its definition. 
+* Do not pass `shared_ptr<Node>` as input for other node if type of node is unknown or it has multiple outputs. Use explicit output port.
+* If you replace node with another node that produce different shape you need to remember that new shape won't be propagated until first `validate_nodes_and_infer_types` call for `ngraph::Function`. If you are using `pass::Manager` it will automatically call this method after each transformation execution.
+* Do not forget to call `ngraph::ConstantFolding` pass if your transformation creates constant sub-graphs.
+* Use latest OpSet if you are not developing downgrade transformation pass.
+
+## Using pass manager <a name="using_pass_manager"></a>
+
+`ngraph::pass::Manager` is a container class that can store list of transformations and execute them. The main idea of this class is to have high-level representation for grouped list of transformations.
+For example `ngraph::pass::CommonOptimizations` pass manager register list of transformation related to common optimizations. Also `ngraph::pass::Manager` after each transformation executes `f->validate_nodes_and_infer_types()` that help to keep function synchronized.
+In addition `ngraph::pass::Manager` has extended debug capabilities (find more information in [how to debug transformations](#how_to_debug_transformations) section). 
+
+Example below shows basic usage of `ngraph::pass::Manager`
+```cpp
+ngraph::pass::Manager pass_manager;
+pass_manager.register_pass<pass::MyTransformationA>();
+pass_manager.register_pass<pass::MyTransformationB>();
+pass_manager.run_passes(f);
+```
+
+TODO: Advanced pass manager usage.
+
+## How to debug transformations <a name="how_to_debug_transformations"></a>
+
+The most popular tool for transformations debugging is `ngraph::pass::VisualizeTree` transformation that visualize ngraph::Function.
+
+Usage example:
+
+@snippet example_ngraph_utils.cpp ngraph:visualize
+
+`ngraph::pass::VisualizeTree` can be parametrized via environment variables:
+
+```
+NGRAPH_VISUALIZE_TREE_OUTPUT_SHAPES=1 - visualize shapes
+NGRAPH_VISUALIZE_TREE_OUTPUT_TYPES=1  - visualize types
+```
+
+> **Note**: current VisualTree has not user friendly interface and it will be changed in nearest future. The intention is to move visualize abilities inside transformations.
+
+If you are using `ngraph::pass::Manager` to run sequence of transformations you can get additional debug capabilities by using next environment variables:
+
+```
+NGRAPH_PROFILE_PASS_ENABLE=1 - enables performance measurement for each transformation and prints execution status
+NGRAPH_ENABLE_VISUALIZE_TRACING=1 -  enables visualization after each transformation. By default it saves dot and svg files.
+```
+
+> **Note**: make sure that you have dot installed on your machine otherwise it will silently save only dot file without svg file.
+
+## Disabling/Enabling specific transformations for plugin X     <a name="disabling_transformation"></a>
+
+This topic mostly related to conversion to legacy opset and plugins that based on CNNNetwork but still this mechanism can be applied for other cases.
+Let's suppose that plugin X enabled `opset3::StridedSlice` operation support and you want to disable `ngraph::pass::ConvertStridedSliceToCrop` transformation for plugin X.
+To do this you need to extend transformation class with `ngraph::pass::PassParam` class. This class extends transformations class with `transformation_callback` that can be set by plugin that uses legacy conversion. 
+
+```cpp
+// Extend transformation class with PassParam
+class ngraph::pass::ConvertStridedSliceToCrop: public ngraph::pass::GraphRewrite, public ngraph::pass::PassParam {
+    ...
+}
+
+// Update callback to be able to use transformation_callback if this transformation based on GraphRewrite.
+ngraph::graph_rewrite_callback callback = [this](pattern::Matcher &m) {
+    ...
+}
+
+// Use transformation_callback not to execute transformation
+if (transformation_callback(node)) {
+    return false;
+}
+```
+
+TODO: link to existing example
+
+## Transformations testing <a name="transformations_testing"></a>
+
+If you are developing new transformation inside plugin you need to add test into `template_plugin/tests/functional/transformations` folder.
+We have two types of tests: nGraph reader tests located in `inference-engine/tests/functional/inference_engine/ngraph_reader` and transformation tests located  in `inference-engine/tests/functional/inference_engine/transformations`
+Reader tests are IR based and test end to end conversion from IR to CNNNetwork. Transformation tests test single ngraph transformations or low level functiont that are used inside transformations.
+
+The basic transformation test looks like this:
+
+@snippet tests/functional/transformations/template_transformations_test.cpp transformation:test
+
+TODO: insert advanced transformation tests
+
+[ngraph_replace_node]: ../images/ngraph_replace_node.png
+[ngraph_insert_node]: ../images/ngraph_insert_node.png
\ No newline at end of file
diff --git a/docs/IE_PLUGIN_DG/images/ngraph_insert_node.png b/docs/IE_PLUGIN_DG/images/ngraph_insert_node.png
new file mode 100644 (file)
index 0000000..f836049
Binary files /dev/null and b/docs/IE_PLUGIN_DG/images/ngraph_insert_node.png differ
diff --git a/docs/IE_PLUGIN_DG/images/ngraph_replace_node.png b/docs/IE_PLUGIN_DG/images/ngraph_replace_node.png
new file mode 100644 (file)
index 0000000..3b1a7a1
Binary files /dev/null and b/docs/IE_PLUGIN_DG/images/ngraph_replace_node.png differ
index c020ae6..9a4aa91 100644 (file)
@@ -8,6 +8,6 @@ file(GLOB SOURCES *.cpp)
 
 add_library(ie_docs_examples STATIC ${SOURCES})
 
-target_link_libraries(${TARGET_NAME} PRIVATE inference_engine_plugin_api)
+target_link_libraries(${TARGET_NAME} PRIVATE inference_engine_plugin_api ngraph)
 
 #add_cpplint_target(${TARGET_NAME}_cpplint FOR_TARGETS ${TARGET_NAME})
diff --git a/docs/examples/example_ngraph_utils.cpp b/docs/examples/example_ngraph_utils.cpp
new file mode 100644 (file)
index 0000000..a841b73
--- /dev/null
@@ -0,0 +1,251 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include <memory>
+
+// ! [ngraph:include]
+#include <ngraph/opsets/opset3.hpp>
+// ! [ngraph:include]
+
+#include <ngraph/function.hpp>
+#include <ngraph/pattern/op/label.hpp>
+#include <ngraph/rt_info.hpp>
+#include <ngraph/pass/graph_rewrite.hpp>
+#include <ngraph/pass/visualize_tree.hpp>
+
+using namespace ngraph;
+
+// ! [ngraph_utils:simple_function]
+std::shared_ptr<ngraph::Function> create_simple_function() {
+    // This example shows how to create ngraph::Function
+    //
+    // Parameter--->Multiply--->Add--->Result
+    //    Constant---'          /
+    //              Constant---'
+
+    // Create opset3::Parameter operation with static shape
+    auto data = std::make_shared<ngraph::opset3::Parameter>(ngraph::element::f32, ngraph::Shape{3, 1, 2});
+
+    auto mul_constant = ngraph::opset3::Constant::create(ngraph::element::f32, ngraph::Shape{1}, {1.5});
+    auto mul = std::make_shared<ngraph::opset3::Multiply>(data, mul_constant);
+
+    auto add_constant = ngraph::opset3::Constant::create(ngraph::element::f32, ngraph::Shape{1}, {0.5});
+    auto add = std::make_shared<ngraph::opset3::Add>(mul, add_constant);
+
+    // Create opset3::Result operation
+    auto res = std::make_shared<ngraph::opset3::Result>(mul);
+
+    // Create nGraph function
+    return std::make_shared<ngraph::Function>(ngraph::ResultVector{res}, ngraph::ParameterVector{data});
+}
+// ! [ngraph_utils:simple_function]
+
+// ! [ngraph_utils:advanced_function]
+std::shared_ptr<ngraph::Function> create_advanced_function() {
+    // Advanced example with multi output operation
+    //
+    // Parameter->Split---0-->Result
+    //               | `--1-->Relu-->Result
+    //               `----2-->Result
+
+    auto data = std::make_shared<ngraph::opset3::Parameter>(ngraph::element::f32, ngraph::Shape{1, 3, 64, 64});
+
+    // Create Constant for axis value
+    auto axis_const = ngraph::opset3::Constant::create(ngraph::element::i64, ngraph::Shape{}/*scalar shape*/, {1});
+
+    // Create opset3::Split operation that splits input to three slices across 1st dimension
+    auto split = std::make_shared<ngraph::opset3::Split>(data, axis_const, 3);
+
+    // Create opset3::Relu operation that takes 1st Split output as input
+    auto relu = std::make_shared<ngraph::opset3::Relu>(split->output(1)/*specify explicit output*/);
+
+    // Results operations will be created automatically based on provided OutputVector
+    return std::make_shared<ngraph::Function>(ngraph::OutputVector{split->output(0), relu, split->output(2)}, ngraph::ParameterVector{data});
+}
+// ! [ngraph_utils:advanced_function]
+
+void pattern_matcher_examples() {
+{
+// ! [pattern:simple_example]
+// Pattern example
+auto input = std::make_shared<ngraph::opset3::Parameter>(element::i64, Shape{1});
+auto shapeof = std::make_shared<ngraph::opset3::ShapeOf>(input);
+
+// Create Matcher with Parameter->ShapeOf pattern
+auto m = std::make_shared<ngraph::pattern::Matcher>(shapeof, "MyPatternBasedTransformation");
+// ! [pattern:simple_example]
+
+// ! [pattern:callback_example]
+ngraph::graph_rewrite_callback callback = [](pattern::Matcher& m) {
+    // Get root node
+    std::shared_ptr<Node> root_node = m.get_match_root();
+
+    // Get all nodes matched by pattern
+    NodeVector nodes = m.get_matched_nodes();
+
+    // Transformation code
+    return false;
+};
+// ! [pattern:callback_example]
+}
+
+{
+// ! [pattern:label_example]
+// Detect Multiply with arbitrary first input and second as Constant
+// ngraph::pattern::op::Label - represent arbitrary input
+auto input = std::make_shared<ngraph::pattern::op::Label>(ngraph::element::f32, ngraph::Shape{1});
+auto value = ngraph::opset3::Constant::create(ngraph::element::f32, ngraph::Shape{1}, {0.5});
+auto mul = std::make_shared<ngraph::opset3::Multiply>(input, value);
+auto m = std::make_shared<ngraph::pattern::Matcher>(mul, "MultiplyMatcher");
+// ! [pattern:label_example]
+}
+
+{
+// ! [pattern:concat_example]
+// Detect Concat operation with arbitrary number of inputs
+auto concat = std::make_shared<ngraph::pattern::op::Label>(ngraph::element::f32, ngraph::Shape{}, ngraph::pattern::has_class<ngraph::opset3::Concat>());
+auto m = std::make_shared<ngraph::pattern::Matcher>(concat, "ConcatMatcher");
+// ! [pattern:concat_example]
+}
+
+{
+// ! [pattern:predicate_example]
+// Detect Multiply or Add operation
+auto lin_op = std::make_shared<ngraph::pattern::op::Label>(ngraph::element::f32, ngraph::Shape{},
+              [](const std::shared_ptr<ngraph::Node> & node) -> bool {
+                    return std::dynamic_pointer_cast<ngraph::opset3::Multiply>(node) ||
+                    std::dynamic_pointer_cast<ngraph::opset3::Add>(node);
+              });
+auto m = std::make_shared<ngraph::pattern::Matcher>(lin_op, "MultiplyOrAddMatcher");
+// ! [pattern:predicate_example]
+}
+
+}
+
+bool ngraph_api_examples(std::shared_ptr<Node> node) {
+{
+// ! [ngraph:ports_example]
+// Let's suppose that node is opset3::Convolution operation
+// as we know opset3::Convolution has two input ports (data, weights) and one output port
+Input <Node> data = node->input(0);
+Input <Node> weights = node->input(1);
+Output <Node> output = node->output(0);
+
+// Getting shape and type
+auto pshape = data.get_partial_shape();
+auto el_type = data.get_element_type();
+
+// Ggetting parent for input port
+Output <Node> parent_output;
+parent_output = data.get_source_output();
+
+// Another short way to get partent for output port
+parent_output = node->input_value(0);
+
+// Getting all consumers for output port
+auto consumers = output.get_target_inputs();
+// ! [ngraph:ports_example]
+}
+
+{
+// ! [ngraph:shape]
+auto partial_shape = node->input(0).get_partial_shape(); // get zero input partial shape
+if (partial_shape.is_dynamic() /* or !partial_shape.is_staic() */) {
+    return false;
+}
+auto static_shape = partial_shape.get_shape();
+// ! [ngraph:shape]
+}
+
+{
+// ! [ngraph:shape_check]
+auto partial_shape = node->input(0).get_partial_shape(); // get zero input partial shape
+
+// Check that input shape rank is static
+if (!partial_shape.rank().is_static()) {
+    return false;
+}
+auto rank_size = partial_shape.rank().get_length();
+
+// Check that second dimension is not dynamic
+if (rank_size < 2 || partial_shape[1].is_dynamic()) {
+    return false;
+}
+auto dim = partial_shape[1].get_length();
+// ! [ngraph:shape_check]
+}
+
+return true;
+}
+
+// ! [ngraph:replace_node]
+bool ngraph_replace_node(std::shared_ptr<Node> node) {
+    // Step 1. Verify that node has opset3::Negative type
+    auto neg = std::dynamic_pointer_cast<ngraph::opset3::Negative>(node);
+    if (!neg) {
+        return false;
+    }
+
+    // Step 2. Create opset3::Multiply operation where the first input is negative operation input and second as Constant with -1 value
+    auto mul = std::make_shared<ngraph::opset3::Multiply>(neg->input_value(0),
+                                                          opset3::Constant::create(neg->get_element_type(), Shape{1}, {-1}));
+
+    mul->set_friendly_name(neg->get_friendly_name());
+    ngraph::copy_runtime_info(neg, mul);
+
+    // Step 3. Replace Negative operation with Multiply operation
+    ngraph::replace_node(neg, mul);
+    return true;
+
+    // Step 4. Negative operation will be removed automatically because all consumers was moved to Multiply operation
+}
+// ! [ngraph:replace_node]
+
+// ! [ngraph:insert_node]
+// Step 1. Lets suppose that we have a node with single output port and we want to insert additional operation new_node after it
+void insert_example(std::shared_ptr<ngraph::Node> node) {
+    // Get all consumers for node
+    auto consumers = node->output(0).get_target_inputs();
+
+    // Step 2. Create new node. Let it be opset1::Relu.
+    auto new_node = std::make_shared<ngraph::opset3::Relu>(node);
+
+    // Step 3. Reconnect all consumers to new_node
+    for (auto input : consumers) {
+        input.replace_source_output(new_node);
+    }
+}
+// ! [ngraph:insert_node]
+
+// ! [ngraph:insert_node_with_copy]
+void insert_example_with_copy(std::shared_ptr<ngraph::Node> node) {
+    // Make a node copy
+    auto node_copy = node->clone_with_new_inputs(node->input_values());
+    // Create new node
+    auto new_node = std::make_shared<ngraph::opset3::Relu>(node_copy);
+    ngraph::replace_node(node, new_node);
+}
+// ! [ngraph:insert_node_with_copy]
+
+void eliminate_example(std::shared_ptr<ngraph::Node> node) {
+// ! [ngraph:eliminate_node]
+// Suppose we have a node that we want to remove
+bool success = replace_output_update_name(node->output(0), node->input_value(0));
+// ! [ngraph:eliminate_node]
+}
+
+// ! [ngraph:visualize]
+void visualization_example(std::shared_ptr<ngraph::Function> f) {
+    std::vector<std::shared_ptr<ngraph::Function> > g{f};
+
+    // Serialize ngraph::Function to before.svg file before transformation
+    ngraph::pass::VisualizeTree("/path/to/file/before.svg").run_on_module(g);
+
+    // Run your transformation
+    // ngraph::pass::MyTransformation().run_on_function();
+
+    // Serialize ngraph::Function to after.svg file after transformation
+    ngraph::pass::VisualizeTree("/path/to/file/after.svg").run_on_module(g);
+}
+// ! [ngraph:visualize]
\ No newline at end of file
index 8efc04f..85604df 100644 (file)
 
 #include <ngraph/specialize_function.hpp>
 #include <ngraph/pass/manager.hpp>
-#include <ngraph/pass/constant_folding.hpp>
 
-#include <transformations/convert_divide.hpp>
+#include <transformations/common_optimizations/common_optimizations.hpp>
 
 #include "template_plugin.hpp"
 #include "template_executable_network.hpp"
+#include "template_pattern_transformation.hpp"
 
 using namespace TemplatePlugin;
 
@@ -83,12 +83,12 @@ void TemplatePlugin::ExecutableNetwork::CompileGraph(const std::shared_ptr<const
     auto copyFunction = ngraph::specialize_function(std::const_pointer_cast<ngraph::Function>(ngraphFunction),
         new_types, new_shapes, std::vector<void *>(new_types.size(), nullptr), constFolding, shareConsts);
 
-    // 2. Perform common and device-specific transformations
+    // 2. Perform common optimizations and device-specific transformations
     ngraph::pass::Manager passManager;
-    // Example: register standard ngraph transformation from ngraph::ngraph
-    passManager.register_pass<ngraph::pass::ConstantFolding>();
-    // Example: register inference engine optimization transformation for IE::inference_engine_transformations
-    passManager.register_pass<ngraph::pass::ConvertDivide>();
+    // Example: register CommonOptimizations transformation from transformations library
+    passManager.register_pass<ngraph::pass::CommonOptimizations>();
+    // Example: register plugin specific transformation
+    passManager.register_pass<ngraph::pass::MyPatternBasedTransformation>();
     // Register any other transformations
     // ..
 
diff --git a/docs/template_plugin/src/template_function_transformation.cpp b/docs/template_plugin/src/template_function_transformation.cpp
new file mode 100644 (file)
index 0000000..f23f619
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include "template_function_transformation.hpp"
+
+#include <ngraph/opsets/opset3.hpp>
+
+using namespace ngraph;
+
+// ! [function_pass:template_transformation_cpp]
+// template_function_transformation.cpp
+bool MyFunctionTransformation::run_on_function(std::shared_ptr<ngraph::Function> f) {
+    // Example transformation code
+    std::vector<std::shared_ptr<Node> > nodes;
+
+    // Traverse nGraph Function in topological order
+    for (auto & node : f->get_ordered_ops()) {
+        // Check that number of input and output ports are equal to 1
+        if (node->inputs().size() == 1 && node->outputs().size() == 1) {
+            // Check that input and output shape a fully defined (not dynamic) and number of consumers equal to 1
+            Input<Node> input = node->input(0);
+            Output<Node> output = node->output(0);
+            if (input.get_partial_shape().is_static() && output.get_partial_shape().is_static() && output.get_target_inputs().size() == 1) {
+                nodes.push_back(node);
+            }
+        }
+    }
+
+    // Print types and names for collected nodes
+    for (auto & node : nodes) {
+        std::cout << "Type: " << node->get_type_info().name << std::endl
+                  << "Name: " << node->get_friendly_name() << std::endl;
+    }
+
+    // Return false because we didn't change nGraph Function
+    return false;
+}
+// ! [function_pass:template_transformation_cpp]
\ No newline at end of file
diff --git a/docs/template_plugin/src/template_function_transformation.hpp b/docs/template_plugin/src/template_function_transformation.hpp
new file mode 100644 (file)
index 0000000..c503210
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright (C) 2018-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#pragma once
+
+#include <vector>
+#include <memory>
+
+#include <ngraph/pass/pass.hpp>
+
+// ! [function_pass:template_transformation_hpp]
+// template_function_transformation.hpp
+class MyFunctionTransformation: public ngraph::pass::FunctionPass {
+public:
+    MyFunctionTransformation() : FunctionPass() {}
+
+    bool run_on_function(std::shared_ptr<ngraph::Function> f) override;
+};
+// ! [function_pass:template_transformation_hpp]
\ No newline at end of file
diff --git a/docs/template_plugin/src/template_pattern_transformation.cpp b/docs/template_plugin/src/template_pattern_transformation.cpp
new file mode 100644 (file)
index 0000000..a10b428
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include "template_pattern_transformation.hpp"
+
+#include <ngraph/opsets/opset3.hpp>
+#include <ngraph/rt_info.hpp>
+
+using namespace ngraph;
+
+// ! [graph_rewrite:template_transformation_cpp]
+// template_pattern_transformation.cpp
+void ngraph::pass::MyPatternBasedTransformation::transform() {
+    // 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 div = std::make_shared<ngraph::opset3::Divide>(input0, input1);
+
+    ngraph::graph_rewrite_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()) {
+            return false;
+        }
+
+        // Decompose Divide into Multiply with Power operations
+        auto pow = std::make_shared<ngraph::opset3::Power>(div->input_value(1),
+                                                           opset3::Constant::create(div->get_input_element_type(1), Shape{1}, {-1}));
+
+        auto mul = std::make_shared<ngraph::opset3::Multiply>(div->input_value(0), pow);
+
+        // Save original name to last operation in replacement sub-graph
+        mul->set_friendly_name(div->get_friendly_name());
+
+        // Copy runtime info attributes to newly created operation
+        ngraph::copy_runtime_info(div, {pow, mul});
+
+        // Replace Divide operation with Multiply
+        ngraph::replace_node(div, mul);
+
+        // Return true as the root node was changed
+        return true;
+    };
+
+    // Register pattern with divide operaiton 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);
+}
+// ! [graph_rewrite:template_transformation_cpp]
\ No newline at end of file
diff --git a/docs/template_plugin/src/template_pattern_transformation.hpp b/docs/template_plugin/src/template_pattern_transformation.hpp
new file mode 100644 (file)
index 0000000..e595bbc
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright (C) 2018-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#pragma once
+
+#include <vector>
+#include <memory>
+
+#include <ngraph/pass/graph_rewrite.hpp>
+
+namespace ngraph {
+namespace pass {
+
+class MyPatternBasedTransformation;
+
+}  // namespace pass
+}  // namespace ngraph
+
+// ! [graph_rewrite:template_transformation_hpp]
+// template_pattern_transformation.hpp
+class ngraph::pass::MyPatternBasedTransformation: public ngraph::pass::GraphRewrite {
+public:
+    MyPatternBasedTransformation() : GraphRewrite() {
+        transform();
+    }
+
+private:
+    void transform();
+};
+// ! [graph_rewrite:template_transformation_hpp]
\ No newline at end of file
diff --git a/docs/template_plugin/tests/functional/transformations/template_transformations_test.cpp b/docs/template_plugin/tests/functional/transformations/template_transformations_test.cpp
new file mode 100644 (file)
index 0000000..d5d5678
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include <gtest/gtest.h>
+
+#include <string>
+#include <memory>
+#include <queue>
+
+#include <ngraph/function.hpp>
+#include <ngraph/opsets/opset3.hpp>
+#include <transformations/init_node_info.hpp>
+#include <transformations/utils/utils.hpp>
+
+#include "common_test_utils/ngraph_test_utils.hpp"
+
+using namespace testing;
+
+// ! [transformation:test]
+TEST(TransformationTests, TemplateTest) {
+    std::shared_ptr<ngraph::Function> f, f_ref;
+    // f - ngraph::Function for applying transformation
+    // f_ref - ngraph::Function that is expected after applying transformation
+    {
+        // Example function
+        auto data = std::make_shared<ngraph::opset3::Parameter>(ngraph::element::f32, ngraph::Shape{3, 1, 2});
+        auto divide_constant = ngraph::opset3::Constant::create(ngraph::element::f32, ngraph::Shape{1}, {1.5});
+        auto divide = std::make_shared<ngraph::opset3::Divide>(data, divide_constant);
+
+        f = std::make_shared<ngraph::Function>(ngraph::NodeVector{divide}, ngraph::ParameterVector{data});
+
+        // This transformation init runtime info attributes
+        ngraph::pass::InitNodeInfo().run_on_function(f);
+
+        // Run transformation
+        // ngraph::pass::MyTransformation().run_on_function(f);
+
+        // Check that after applying transformation all runtime info attributes was correctly propagated
+        ASSERT_NO_THROW(check_rt_info(f));
+    }
+
+    {
+        // Example reference function
+        auto data = std::make_shared<ngraph::opset3::Parameter>(ngraph::element::f32, ngraph::Shape{3, 1, 2});
+        auto divide_constant = ngraph::opset3::Constant::create(ngraph::element::f32, ngraph::Shape{1}, {1.5});
+        auto pow = std::make_shared<ngraph::opset3::Power>(divide_constant,
+                                                           ngraph::opset3::Constant::create(ngraph::element::f32, ngraph::Shape{1}, {-1}));
+        auto mul = std::make_shared<ngraph::opset3::Multiply>(data, pow);
+
+        f_ref = std::make_shared<ngraph::Function>(ngraph::NodeVector{mul}, ngraph::ParameterVector{data});
+    }
+
+    // Compare that processed function and expected function are the same
+    auto res = compare_functions(f, f_ref);
+    ASSERT_TRUE(res.first) << res.second;
+}
+// ! [transformation:test]
index 574a242..d37b876 100644 (file)
@@ -19,6 +19,10 @@ class TRANSFORMATIONS_API ConvertScatterElementsToScatter;
 }  // namespace pass
 }  // namespace ngraph
 
+/**
+ * @ingroup ie_transformation_common_api
+ * @brief ConvertScatterElementsToScatter convert opset3::ScatterElementsUpdate to opset3::ScatterUpdate.
+ */
 class ngraph::pass::ConvertScatterElementsToScatter: public ngraph::pass::GraphRewrite {
 public:
     ConvertScatterElementsToScatter() : GraphRewrite() {
index 0595aa7..f0c30b2 100644 (file)
@@ -20,15 +20,14 @@ namespace pass {
 }  // namespace pass
 }  // namespace ngraph
 
-/*
- * Description:
- *     DepthToSpaceFusion transformation detects Reshape-Transpose-Reshape pattern and
- *     tries to fuse it into a single DepthToSpace layer.
+/**
+ * @ingroup ie_transformation_common_api
+ * @brief DepthToSpaceFusion transformation detects Reshape-Transpose-Reshape pattern
+ * and tries to fuse it into a single DepthToSpace layer.
  *
- * Usage:
- *     DepthToSpaceFusion transformation is optional and disabled by default.
- *     The transformation can be enabled with callback using setCallback method.
- *     See the example below.
+ * DepthToSpaceFusion transformation is optional and disabled by default.
+ * The transformation can be enabled with callback using setCallback method.
+ * See the example below.
  *
  * Callback example:
  *
@@ -42,7 +41,6 @@ namespace pass {
  *     p.run_on_function(f);
  *
  */
-
 class ngraph::pass::DepthToSpaceFusion: public ngraph::pass::GraphRewrite, public ngraph::pass::PassParam {
 public:
     DepthToSpaceFusion() : GraphRewrite(), PassParam() {
index 5bb0d7c..4321774 100644 (file)
  *
  * @{
  * @defgroup ie_runtime_attr_api Runtime information
- * @brief A machnism of runtime information extension
+ * @brief A mechanism of runtime information extension
  *
  * @defgroup ie_transformation_common_api Common optimization passes
  * @brief A set of common optimization passes
  *
- * @defgroup ie_transformation_to_opset1_api Conversion from opset2 to opset1
- * @brief A set of conversion passes from opset2 to opset1
-
  * @defgroup ie_transformation_to_opset2_api Conversion from opset3 to opset2
- * @brief A set of conversion passes from opset3 to opset2
+ * @brief A set of conversion downgrade passes from opset3 to opset2
+ *
+ * @defgroup ie_transformation_to_opset1_api Conversion from opset2 to opset1
+ * @brief A set of conversion downgrade passes from opset2 to opset1
  * @}
  */
 
@@ -41,7 +41,7 @@
 namespace ngraph {
 
 /**
- * @brief ngraph::passes namespace
+ * @brief ngraph::pass namespace
  */
 namespace pass {
 
@@ -57,7 +57,7 @@ class TRANSFORMATIONS_API InitNodeInfo;
  * Every runtime info attribute that needs to be initialized should be registered
  * in run_on_function method. Also do not forget to override init methods for registered
  * attribute.
- * This transformations should be called first in transformation pipeline. If attrbute was
+ * This transformations should be called first in transformation pipeline. If attribute was
  * already set initialization will be skipped for this node.
  */
 class ngraph::pass::InitNodeInfo: public ngraph::pass::FunctionPass {
index 6312c25..47db41b 100644 (file)
@@ -25,40 +25,43 @@ class TRANSFORMATIONS_API GroupedStridedSliceOptimizer;
 }  // namespace ngraph
 
 
-/*
- * Description:
- *      UselessStridedSliceEraser transformation removes StridedSlice operations
- *      with equal input and output shapes.
+/**
+ * @ingroup ie_transformation_common_api
+ * @brief UselessStridedSliceEraser transformation removes StridedSlice operations
+ * with equal input and output shapes.
  */
-
 class ngraph::pass::UselessStridedSliceEraser: public ngraph::pass::FunctionPass {
 public:
     bool run_on_function(std::shared_ptr<ngraph::Function> f) override;
 };
 
-/*
- * Description:
- *      SharedStridedSliceEraser replaces group of StridedSlice operations with first
- *      StridedSlice in this group. All SrtideSluces in this group must be equal and
- *      consume the same output port.
+/**
+ * @ingroup ie_transformation_common_api
+ * @brief SharedStridedSliceEraser transformation replaces group of StridedSlice
+ * operations with first StridedSlice in this group. All SrtideSlices in this group
+ * must be equal and consume the same output port.
  */
-
 class ngraph::pass::SharedStridedSliceEraser: public ngraph::pass::FunctionPass {
 public:
     bool run_on_function(std::shared_ptr<ngraph::Function> f) override;
 };
 
-/*
- * Description:
- *      GroupedStridedSliceOptimizer replaces group of StridedSlice operations with VariadicSplit
- *      All StridedSlice operations must slice data with the same axis and stride = 1.
+/**
+ * @ingroup ie_transformation_common_api
+ * @brief GroupedStridedSliceOptimizer transformation replaces group of StridedSlice
+ * operations with VariadicSplit. All StridedSlice operations must slice data
+ * with the same axis and stride = 1.
  */
-
 class ngraph::pass::GroupedStridedSliceOptimizer: public ngraph::pass::FunctionPass {
 public:
     bool run_on_function(std::shared_ptr<ngraph::Function> f) override;
 };
 
+/**
+ * @ingroup ie_transformation_common_api
+ * @brief StridedSliceOptimization transformation executes all transformations
+ * related to StridedSlice optimizations.
+ */
 class ngraph::pass::StridedSliceOptimization: public ngraph::pass::FunctionPass {
 public:
     bool run_on_function(std::shared_ptr<ngraph::Function> f) override {
index 38c9983..cea8247 100644 (file)
@@ -45,14 +45,19 @@ public:
 
     /**
      * @brief Unites current set of already fused names with another FusedNames object
-     * @param names[in] Another object to fuse with
+     * @param[in] names Another object to fuse with
      */
     void fuseWith(const FusedNames &names);
 
-    // return string with operation names separated by coma in alphabetical order
+    /**
+     * @brief return string with operation names separated by coma in alphabetical order
+     */
     std::string getNames() const;
 
-    // returns vector of fused names sorted in alphabetical order
+    /**
+     * @brief return vector of fused names sorted in alphabetical order
+     * @return vector if strings
+     */
     std::vector<std::string> getVectorNames() const;
 };
 
@@ -72,8 +77,19 @@ public:
     std::shared_ptr<ngraph::Variant> init(const std::shared_ptr<ngraph::Node> & node) override;
 };
 
+/**
+ * @ingroup ie_runtime_attr_api
+ * @brief getFusedNames return string with operation names separated by coma in alphabetical order
+ * @param[in] node The node will be used to get FusedNames attribute
+ */
 TRANSFORMATIONS_API std::string getFusedNames(const std::shared_ptr<ngraph::Node> & node);
 
+/**
+ * @ingroup ie_runtime_attr_api
+ * @brief getFusedNamesVector return vector of fused names sorted in alphabetical order
+ * @param[in] node The node will be used to get FusedNames attribute
+ * @return vector of strings
+ */
 TRANSFORMATIONS_API std::vector<std::string> getFusedNamesVector(const std::shared_ptr<ngraph::Node> & node);
 
 }  // namespace ngraph
index 895df18..b5df594 100644 (file)
@@ -2,6 +2,11 @@
 // SPDX-License-Identifier: Apache-2.0
 //
 
+/**
+ * @brief Defines primitives priority attribute
+ * @file primitives_priority_attribute.hpp
+ */
+
 #include <assert.h>
 #include <functional>
 #include <memory>
 
 namespace ngraph {
 
+/**
+ * @ingroup ie_runtime_attr_api
+ * @brief PrimitivesPriority class represents runtime info attribute that
+ * can be used for plugins specific primitive choice.
+ */
 class TRANSFORMATIONS_API PrimitivesPriority {
 private:
     std::string primitives_priority;
 
 public:
+    /**
+     * A default constructor
+     */
     PrimitivesPriority() = default;
 
+    /**
+     * @brief      Constructs a new object consisting of a single name     *
+     * @param[in]  name  The primitives priority value
+     */
     explicit PrimitivesPriority(const std::string &primitives_priority) : primitives_priority(primitives_priority) {}
 
+    /**
+     * @brief return string with primitives priority value
+     */
     std::string getPrimitivesPriority() const;
 };
 
@@ -42,6 +62,11 @@ public:
     std::shared_ptr<ngraph::Variant> init(const std::shared_ptr<ngraph::Node> & node) override;
 };
 
+/**
+ * @ingroup ie_runtime_attr_api
+ * @brief getPrimitivesPriority return string with primitive priorities value
+ * @param[in] node The node will be used to get PrimitivesPriority attribute
+ */
 TRANSFORMATIONS_API std::string getPrimitivesPriority(const std::shared_ptr<ngraph::Node> & node);
 
 }  // namespace ngraph
index 7e78ba6..d1a45f0 100644 (file)
 #include <ngraph/opsets/opset3.hpp>
 
 void ngraph::pass::ConvertBroadcast3::convert_broadcast3() {
-    auto weights = std::make_shared<pattern::op::Label>(element::f32, Shape {1});
-    auto shp = std::make_shared<pattern::op::Label>(element::i64, Shape {1});
-    auto axes = std::make_shared<pattern::op::Label>(element::i64, Shape {1});
-    auto broadcast = std::make_shared<ngraph::opset3::Broadcast>(weights, shp, axes);
-
-    auto broadcast_no_axes = std::make_shared<ngraph::opset3::Broadcast>(weights, shp);
+    auto broadcast = std::make_shared<pattern::op::Label>(element::f32, Shape {}, pattern::has_class<opset3::Broadcast>());
 
     ngraph::graph_rewrite_callback callback = [](pattern::Matcher& m) {
         auto broadcast = std::dynamic_pointer_cast<ngraph::opset3::Broadcast>(m.get_match_root());
@@ -55,7 +50,5 @@ void ngraph::pass::ConvertBroadcast3::convert_broadcast3() {
     };
 
     auto m = std::make_shared<ngraph::pattern::Matcher>(broadcast, "ConvertBroadcast3");
-    auto m_no_axes = std::make_shared<ngraph::pattern::Matcher>(broadcast_no_axes, "ConvertBroadcast3NoAxes");
     this->add_matcher(m, callback, PassProperty::CHANGE_DYNAMIC_STATE);
-    this->add_matcher(m_no_axes, callback, PassProperty::CHANGE_DYNAMIC_STATE);
 }
index 44cbe6b..a820354 100644 (file)
@@ -14,7 +14,7 @@
 #include <transformations/init_node_info.hpp>
 #include <ngraph/pass/constant_folding.hpp>
 #include <ngraph/ops.hpp>
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 
index a31a2c3..3323214 100644 (file)
@@ -20,7 +20,7 @@
 #include <transformations/convert_opset1_to_legacy/conv_bias_fusion.hpp>
 #include <ngraph/pass/visualize_tree.hpp>
 
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 
index f81076b..2f0aaeb 100644 (file)
@@ -15,7 +15,7 @@
 #include <transformations/init_node_info.hpp>
 #include <transformations/utils/utils.hpp>
 
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 
index 6b8fda7..2bde0d3 100644 (file)
@@ -20,7 +20,7 @@
 #include <ngraph_ops/gru_cell_ie.hpp>
 #include <ngraph_ops/rnn_cell_ie.hpp>
 #include <ngraph_ops/lstm_cell_ie.hpp>
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 
index a82322d..7a676fe 100644 (file)
@@ -22,7 +22,7 @@
 #include <transformations/convert_opset1_to_legacy/convert_convolutions.hpp>
 #include <ngraph_ops/convolution_ie.hpp>
 
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 
index 8c7e648..6995b66 100644 (file)
@@ -14,7 +14,7 @@
 #include <transformations/init_node_info.hpp>
 #include <transformations/utils/utils.hpp>
 
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 
index afd0ded..8edd748 100644 (file)
@@ -15,7 +15,7 @@
 #include <transformations/utils/utils.hpp>
 #include <ngraph_ops/gather_ie.hpp>
 
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 using namespace ngraph;
index be2bea1..d006fda 100644 (file)
@@ -22,7 +22,7 @@
 #include <transformations/init_node_info.hpp>
 #include <transformations/utils/utils.hpp>
 
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 
index 1fc7528..fc3d968 100644 (file)
@@ -16,7 +16,7 @@
 #include <transformations/init_node_info.hpp>
 #include <transformations/utils/utils.hpp>
 
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 using namespace ngraph;
index cf54611..035e6b9 100644 (file)
@@ -14,7 +14,7 @@
 #include <transformations/init_node_info.hpp>
 #include <transformations/utils/utils.hpp>
 
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 using namespace ngraph;
index bd19243..eec1aa2 100644 (file)
@@ -16,7 +16,7 @@
 #include <ngraph_ops/nms_ie.hpp>
 #include <ngraph/pass/constant_folding.hpp>
 
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 using namespace ngraph;
index e520103..d646ec1 100644 (file)
@@ -19,7 +19,7 @@
 #include <transformations/utils/utils.hpp>
 #include <transformations/convert_reduce_to_pooling.hpp>
 
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 
index 5019643..f24e865 100644 (file)
@@ -13,7 +13,7 @@
 #include <transformations/convert_opset3_to_opset2/convert_shapeof3.hpp>
 #include <transformations/init_node_info.hpp>
 
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 
index dbeccd5..4ed49a0 100644 (file)
@@ -13,7 +13,7 @@
 #include <transformations/convert_opset3_to_opset2/convert_shuffle_channels3.hpp>
 #include <transformations/init_node_info.hpp>
 
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 using namespace ngraph;
index 94f470a..334a8cf 100644 (file)
@@ -16,7 +16,7 @@
 #include <transformations/init_node_info.hpp>
 #include <transformations/utils/utils.hpp>
 
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 
index 197661f..f8bfeae 100644 (file)
@@ -16,7 +16,7 @@
 #include <ngraph_ops/topk_ie.hpp>
 #include <ngraph/pass/constant_folding.hpp>
 
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 
index 55a9187..c9edda8 100644 (file)
@@ -20,7 +20,7 @@
 #include <transformations/utils/utils.hpp>
 #include <transformations/init_node_info.hpp>
 
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 
index 9bfdc2a..cebab50 100644 (file)
@@ -20,7 +20,7 @@
 #include <transformations/utils/utils.hpp>
 #include <transformations/init_node_info.hpp>
 
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 
index d5d8cf1..5953d23 100644 (file)
@@ -18,7 +18,7 @@
 #include <transformations/convert_opset1_to_legacy/reshape_1d_ops.hpp>
 #include <transformations/init_node_info.hpp>
 #include <ngraph/opsets/opset1.hpp>
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 using namespace ngraph;
index 0165b17..57542bf 100644 (file)
@@ -17,7 +17,7 @@
 #include <transformations/convert_depth_to_space.hpp>
 #include <transformations/convert_space_to_depth.hpp>
 #include <transformations/init_node_info.hpp>
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 
index 032dfb0..24955d6 100644 (file)
@@ -18,7 +18,7 @@
 #include <transformations/pull_transpose_through_fq.hpp>
 #include <ngraph/pass/constant_folding.hpp>
 #include <transformations/init_node_info.hpp>
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 
index 48834b1..dae7581 100644 (file)
@@ -17,7 +17,7 @@
 #include <transformations/convert_mod.hpp>
 #include <ngraph/pass/constant_folding.hpp>
 #include <transformations/init_node_info.hpp>
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 
index 0d74467..d2f622f 100644 (file)
@@ -20,7 +20,7 @@
 #include <transformations/optimize_strided_slice.hpp>
 #include <transformations/utils/utils.hpp>
 
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 
index 641ddea..ba634af 100644 (file)
@@ -18,7 +18,7 @@
 #include <ngraph_ops/fully_connected.hpp>
 #include <transformations/convert_opset1_to_legacy/reshape_fc_fusion.hpp>
 #include <transformations/init_node_info.hpp>
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;
 
index 2952e5c..a512aff 100644 (file)
@@ -20,7 +20,7 @@
 #include <ngraph/pass/algebraic_simplification.hpp>
 #include <ngraph/pass/visualize_tree.hpp>
 
-#include "ngraph_test_utils.hpp"
+#include "common_test_utils/ngraph_test_utils.hpp"
 
 using namespace testing;