* [IE CLDNN] Memory allocation optimizations (#2178) * [GNA] Safety fixes (#2193) * LSTMCell test [GNA] LSTMCell fix for GNA (#2216) * [GNA] fix scale factor calculation for unfused bias after fc (2021.1) (#2195) * [GNA] fix scale factor calculation for unfused bias after fc * change check * add test * apply requested changes * cpplint fix * apply test changes * modify model for test to match ::op:: * [LPT] Copy constant with several outputs before blob update (#2197) * [LPT] Copy constant implementation * [LPT] the same Constant ops as FQ interval boundaries * [Scripts] Fixing issue with exporting path-like env when it undef (#2164) * setupvars.sh: Added logic for exporting path env in case if it not defined * setupvars: Removed duplicated colon * Kept quotes where they were * setupvars: updated copyrights * FakeQuantize + Mul fusion (#2133) * FQ+Mul fusion transform skeleton * FQ+Mul fusion transform tests prep * Basic UT for the transform * Basic implementation of the transform * Parametrized UTs for FQMul transform * Parametrization of FQ+Mul UTs * Make sure that the shapes of constants match * Check if the mul constant matches FQ data * CentOs compilation error fix * PR feedback and adjusted tests * NHWC layout of the mul constant * UT: FQ output limits 4D * Redundant CF pass removed * Rewrite the graph in a different way * Shape checking infrastructure skeleton * Handle some negative cases * Check the rt info in the fusion test * Fuse all Mul nodes detected after FQ node * Dont cast the original FQ node * Dont throw if CF fails in new output range calculation * More UTs * Accept any type of input to FQ in the transformation * Test the fusion when all FQ inputs are non-const * Fusion test when only one output limit is const * Extend error message (#2174) * some nGraph KW fixes (#2176) * Removed redundant methods * Fixed KW for linux * Fix QueryNetwork for networks with KSO (#2202) * Added a test to reproduce QueryNetwork with KSO * Fixed QueryNetwork for networks with KSO * Added additional test * Fixed output names for case with redundant ops before result (#2209) * [IE][VPU]: Workaround to support parameter Beta for layer Swish (#2207) * Workaround to full support Swish layer. It is faster than native Swish for now. * [IE][VPU]: Remove the second call of ngraph::CommonOptimizations (#2221) * Remove the second call of ngraph::CommonOptimizations in myriad plugin * Reuse code with vpu ngraph transformations * Duplicate PR 2167 for release branch: GatherTree description was extended and outdated link fixed (#2235) * add more alrifications to description * move clarification to comment * pseudo code become more accurate * review changes * Add exposing function signatures via Cython (#2244) * [DOC] Reshape feature (#2194) * [IE][VPU][OpenCL] 2021.1 release compiler (#2189) * Statically analyzed issues. (#2261) * [IE][VPU]: Fix K propagation through Reshape (2021.1) (#2180) * Fix K propagation through Reshape * Add test cases * Revert "[IE TESTS] dynavic batch for mvn layer (#1010)" (#2256) This reverts commit2e3378c50f. * Fixed KW warning and review issues (#2262) * [IE][VPU]: update firmware 1381 (#2236) * Reverting devicePriorities to be vector and respect the order, as opposed to the incorrect (recent?) refactoring that introduced the unordered_map that effectively ignores the priorities (#2251) * update OpenCV version to 4.5.0 (#2260) * Add VPUX configuration to compile_tool (#2248) * [IE][TESTS] Fix compareRawBuffers and compareBlobData methods (#2246) Use `<=` comparison instead of `<` with thresholds. This allows to use `0` threshold for bit-exact comparison. * [IE][VPU]: KW fixes (#2186) * Some KW fixes * Fix printTo in vpu ngraph transformations * Fix for static PartialShape detection algorithm (#2177) * Fixes for Interpolate-4. (#2281) * Update get_ov_update_message.py (#2286) * Clone a specific tag for pybind11 (#2296) * [Scripts] Fix setting PYTHONPATH logic (#2305) * setupvars.sh: Added logic for exporting path env in case if it not defined * setupvars: Removed duplicated colon * install_openvino_dependencies: Updated copyrights setupvars.bat: Updated notification about incorrect Python version. Removed checking ICC2019 setupvars.sh: Removed logic with choosing higher version of installed Python. Added dynamic detecting python3 major and minor version for setting path. Add checking minimum required Python version(now 3.6) * Added python3-gi package and fixed libglib2.0-0 package location. (#2294) * [IE TESTS] CoreThreading_LoadNetwork tests were disabled for GPU plugin (#2245) (#2283) * setupvars: Updated notifications, fixed calling python in Windows case (#2318) * Updated operations specification documents (2021.1) (#2268) * Updated documentation structure and remove incorrect added files for Acosh-1, Asinh-1 and Atanh-1 * Fixed broken links * Fixed c samples build (#2278) (#2304) * Fixed c samples build fixed CVS-38816 - Failure to build samples in C * Fixed issue with gflags * Revert "[IE][VPU]: Fix K propagation through Reshape (2021.1) (#2180)" (#2322) This reverts commitd604a03ac0. * Added ONNX Resize-11 and ONNX Resize-13 to supported frameworks layers list. (#2325) * Implement `run_executable.py` to run `TimeTests` several times (#2125) (#2188) CI passed * install_NEO_OCL_driver: Updated exit codes, messages. Updated way to remove old driver on Ubuntu (#2333) * Bump cmake version to 3.13 (#2339) * install_NEO_OCL_driver: Added checking of installed packages before trying to remove them. Added quotes for echo. (#2350) * convert to doxygen comments * add doxygen doc build configurations (#2191) Co-authored-by: Nikolay Tyukaev <ntyukaev_lo@jenkins.inn.intel.com> * [DOCS] Added an evaluate method for custom operation (#2272) * Added an evaluate method for custom operation * Fixed comments * Downgrade cmake for samples (#2372) * Downgrade cmake for samples Downgraded cmake version to default version for Ubuntu 18.04 * Updated supported python version The minimal python version in 2021.1 is 3.5 * Added notes about cmake requirements for samples and demo * Install dependency refactoring. (#2381) * Updated Transformation development doc (#2370) * Delete xfail for resolved known issue (#2385) * Fix layout links for dl streamer and c api (#2375) * fix layouts * change the dl-streamer link Co-authored-by: Nikolay Tyukaev <ntyukaev_lo@jenkins.inn.intel.com> * Added link options for cross-compilation (#2397) * Added new GSG for macOS, made minor changes in Windows GSG (#2070) (#2405) * Added new GSG for macOS, made minor changes in Windows GSG * Update get_started_macos.md Co-authored-by: Anastasiya Ageeva <anastasiya.ageeva@intel.com> * Fixed docs build on Windows (#2383) * layouts and code comments * Replace absolute links to docs.openvinotoolkit.org by relative ones (#2439) * Replaced direct links to docs.openvinotoolkit.org with relative links * Replaced direct links to docs.openvinotoolkit.org with relative links. Added GSGs for Win and macOS * Minor fixes in GSGs * Replaced direct links to docs.openvinotoolkit.org with relative links * Removed links to OpenVINO markdown files that contain anchor - they don't work in the current implementation of the doc process * Fixed Notes * Removed links to OpenVINO markdown files that contain anchor - they don't work in the current implementation of the doc process * fixed link to installing-openvino-linux.md * Update the menu to align with POT doc headers (#2433) * Update the menu to align with POT doc headers It changes the menu to align with Post-training Optimization Toolkit documentation titles. * Corrected one title Run Examples => How to Run Examples * Added closing braсket (#2466) Fixed syntax error (b4b03b1) * Remove the deprecation notice (#2314) * Removed deprecation notice * Removed the note from other files * [DOCS] Update Installation Guide - GPU steps (#2308) * Initial commit * fixing lists * Update installing-openvino-linux.md * Get rid of the note * Added the scrrenshot * Update installing-openvino-linux.md * fixes * separate layout * [Docs] Update MO What's new description (#2481) * Azure CI: Add separated pipelines for Windows, Linux, Mac * Feature/azaytsev/benchmarks 2021 1 (#2501) * Initial changes for 2021.1 * Inserted Graphtool scripts, updated configurations info * Updated FAQ and minor changes to performance_benchmarks.md * Updated for 2021.1 * Updated * incorporated review comments * incorporated review comments for FAQ * fixed link * Update build-instruction.md for MacOsX (#2457) * Update build-instruction.md for MacOsX * Removed call of install_dependencies.sh from the steps * Changed layouts * Feature/azaytsev/cvs-38240 (#2469) * Updated for 2020 version, replaced Ubuntu 16.04 with Ubuntu 20.04 * Updated the release package numbers * Removed FPGA from the documentation * Updated according to the comments in the ticket CVS-37827 (#2448) * Updated according to CVS-38225 * some changes * Update docs for speech libs and demos (#2518) * Made changes to benchmarks according to review comments * Remove `--collect_results_only` (#2523) * Remove `--collect_results_only` from MemCheckTests * Remove CLI keys from README * Added logo info to the Legal_Information, updated Ubuntu, CentOS supported versions * Updated supported Intel® Core™ processors list * Fixed table formatting * [Jenkinsfile] Bump infra (#2546) * [GNA] Documentation updates for 2021.1 (#2460) * [GNA] Documentation updates for 2021.1 * Take Mike's comments into account * More fixes according to review * Fix processor generation names * update api layouts * Added new index page with overview * Changed CMake and Python versions * Fixed links * some layout changes * some layout changes * nGraph Python API tutorial (#2500) * nGraph Python API tutorial * Tweaks * Code review comments * Code review comments * some layout changes * COnverted svg images to png * layouts * update layout * Added a label for nGraph_Python_API.md * fixed links * Fixed image * First draft of nGraph documentation (#2271) * First draft of nGraph documentation * updated according to review comments * Updated * Reviewed the nGraph Transformation section, added missing images * Update nGraph_dg.md * Delete python_api.md Removed since there is already the nGraph_Python_API.md document with a comprehensive overview. Co-authored-by: Andrey Zaytsev <andrey.zaytsev@intel.com> Co-authored-by: CCR\avladimi <anastasiya.ageeva@intel.com> * Feature/azaytsev/docs 2021 1 (#2560) * Removed FPGA from the documentation * Updated according to CVS-38225 * Added logo info to the Legal_Information, updated Ubuntu, CentOS supported versions * Updated supported Intel® Core™ processors list * Added new index page with overview * Changed CMake and Python versions * Fixed links * COnverted svg images to png * Added a label for nGraph_Python_API.md * fixed links * Fixed image * Update SW requirements in build instructions and change latest release to 2021.1 (#2565) * removed links to ../IE_DG/Introduction.md * Removed links to tools overview page as removed * some changes * Remove link to Integrate_your_kernels_into_IE.md * remove openvino_docs_IE_DG_Graph_debug_capabilities from layout as it was removed * Fixed links to images (#2569) * update layouts * Added deprecation note for PassConfig class (#2593) * Post-release fixes and installation path changes * Added pip install documentation (#2465) * Added pip install documentation * Change references * tiny fixes of links * Update installing-openvino-pip.md Co-authored-by: Alina Alborova <alina.alborova@intel.com> * Update OpenVino ONNX CI check (#2599) * Update OpenVino ONNX CI * Change parallel execution to single * Enlarge timeout * Remove timeout * Add timeout to test execution * Added PIP installation and Build from Source to the layout * Fixed formatting issue, removed broken link * Renamed section EXAMPLES to RESOURCES according to review comments * add mo faq navigation by url param * Skip hanging test case of OpenVino ONNX CI (#2608) * Update OpenVino ONNX CI * Change parallel execution to single * Enlarge timeout * Remove timeout * Add timeout to test execution * Skip hanging test * Add description to skip issue * Removed DLDT description * Replaced wrong links * MInor fix for path to the cpp samples * fixes * Update ops.py * Fix style * Improve pip installation guide (#2644) * Improve pip installation guide * Updated after comments * Feature/ntyukaev/separate layout (#2629) * convert to doxygen comments * layouts and code comments * separate layout * Changed layouts * Removed FPGA from the documentation * Updated according to CVS-38225 * some changes * Made changes to benchmarks according to review comments * Added logo info to the Legal_Information, updated Ubuntu, CentOS supported versions * Updated supported Intel® Core™ processors list * Fixed table formatting * update api layouts * Added new index page with overview * Changed CMake and Python versions * Fixed links * some layout changes * some layout changes * some layout changes * COnverted svg images to png * layouts * update layout * Added a label for nGraph_Python_API.md * fixed links * Fixed image * removed links to ../IE_DG/Introduction.md * Removed links to tools overview page as removed * some changes * Remove link to Integrate_your_kernels_into_IE.md * remove openvino_docs_IE_DG_Graph_debug_capabilities from layout as it was removed * update layouts * Post-release fixes and installation path changes * Added PIP installation and Build from Source to the layout * Fixed formatting issue, removed broken link * Renamed section EXAMPLES to RESOURCES according to review comments * add mo faq navigation by url param * Removed DLDT description * Replaced wrong links * MInor fix for path to the cpp samples * fixes * Update ops.py * Fix style Co-authored-by: Nikolay Tyukaev <ntyukaev_lo@jenkins.inn.intel.com> Co-authored-by: Tyukaev <nikolay.tyukaev@intel.com> Co-authored-by: aalborov <alina.alborova@intel.com> Co-authored-by: Rafal Blaczkowski <rafal.blaczkowski@intel.com> Co-authored-by: Alexander Zhogov <alexander.zhogov@intel.com> * Fixed CVS-35316 (#2072) (#2670) Co-authored-by: Anastasiya Ageeva <anastasiya.ageeva@intel.com> * [install_dependencies.sh] install latest cmake if current version is lower 3.13 (#2695) (#2701) * [install_dependencies.sh] install latest cmake if current version is lower 3.13 * add shellcheck for Ubuntu * install python 2.7 for Ubuntu * Removed redundant file * Exclude files that we didn't changed from merging Co-authored-by: Sergey Shlyapnikov <sergey.shlyapnikov@intel.com> Co-authored-by: Denis Orlov <denis.orlov@intel.com> Co-authored-by: Kamil Magierski <kamil.magierski@intel.com> Co-authored-by: Anna Alberska <anna.alberska@intel.com> Co-authored-by: Edward Shogulin <edward.shogulin@intel.com> Co-authored-by: Artyom Anokhov <artyom.anokhov@intel.com> Co-authored-by: Tomasz Dołbniak <tomasz.dolbniak@intel.com> Co-authored-by: Ilya Churaev <ilya.churaev@intel.com> Co-authored-by: Roman Vyunov (Intel) <roman.vyunov@intel.com> Co-authored-by: Maksim Doronin <maksim.doronin@intel.com> Co-authored-by: Svetlana Dolinina <svetlana.a.dolinina@intel.com> Co-authored-by: Evgeny Talanin <evgeny.talanin@intel.com> Co-authored-by: Evgenya Stepyreva <evgenya.stepyreva@intel.com> Co-authored-by: Maxim Kurin <maxim.kurin@intel.com> Co-authored-by: Nikolay Shchegolev <nikolay.shchegolev@intel.com> Co-authored-by: Andrew Bakalin <andrew.bakalin@intel.com> Co-authored-by: Gorokhov Dmitriy <dmitry.gorokhov@intel.com> Co-authored-by: Evgeny Latkin <evgeny.latkin@intel.com> Co-authored-by: Maxim Shevtsov <maxim.y.shevtsov@intel.com> Co-authored-by: Alexey Suhov <alexey.suhov@intel.com> Co-authored-by: Alexander Novak <sasha-novak@yandex.ru> Co-authored-by: Vladislav Vinogradov <vlad.vinogradov@intel.com> Co-authored-by: Vladislav Volkov <vladislav.volkov@intel.com> Co-authored-by: Vladimir Gavrilov <vladimir.gavrilov@intel.com> Co-authored-by: Zoe Cayetano <zoe.cayetano@intel.com> Co-authored-by: Dmitrii Denisov <dmitrii.denisov@intel.com> Co-authored-by: Irina Efode <irina.efode@intel.com> Co-authored-by: Evgeny Lazarev <evgeny.lazarev@intel.com> Co-authored-by: Mikhail Ryzhov <mikhail.ryzhov@intel.com> Co-authored-by: Vitaliy Urusovskij <vitaliy.urusovskij@intel.com> Co-authored-by: Nikolay Tyukaev <ntyukaev_lo@jenkins.inn.intel.com> Co-authored-by: Nikolay Tyukaev <nikolay.tyukaev@intel.com> Co-authored-by: Gleb Kazantaev <gleb.kazantaev@intel.com> Co-authored-by: Rafal Blaczkowski <rafal.blaczkowski@intel.com> Co-authored-by: Ilya Lavrenov <ilya.lavrenov@intel.com> Co-authored-by: Anastasiya Ageeva <anastasiya.ageeva@intel.com> Co-authored-by: Maksim Proshin <mvproshin@gmail.com> Co-authored-by: Alina Alborova <alina.alborova@intel.com> Co-authored-by: Maxim Vafin <maxim.vafin@intel.com> Co-authored-by: azhogov <alexander.zhogov@intel.com> Co-authored-by: Alina Kladieva <alina.kladieva@intel.com> Co-authored-by: Michał Karzyński <4430709+postrational@users.noreply.github.com> Co-authored-by: Anton Romanov <anton.romanov@intel.com>
25 KiB
Overview of Transformations API
This guide contains all necessary information that you need to start implementing nGraph transformations.
Prerequisites
Before creating a transformation, do the following:
- Make sure that there is no transformation with the same functionality in the Transformation Library
- Learn how the Transformation Library is structured and how transformations are organized
- Understand where to put your transformation code
Transformation Library Structure
Transformation library is independent from Inference Engine target library named as inference_engine_transformations
and is located in the inference-engine/src/transformations directory.
Transformations root directory contains two folders:
ngraph_ops- Contains legacy opset operations needed for nGraph to CNNNetwork conversion.
Note
: This operation is prohibited inside new plugins until they are not moved to a separate directory with allowed operations.
transformations- Includes all transformations, utils, runtime info attributes, and pass managers.
Note
: Do not use transformation that belongs to
ngraph::pass::ConvertOpSet1ToLegacytransformations until they are not moved to a separate directory with allowed transformations.
Transformation Flow Layers
Transformation flow in the transformation library has several layers:
- Pass managers - Execute any type of transformations and provide additional debug capabilities.
- Transformations - Perform a particular transformation algorithm on
ngraph::Function. - Low-level functions - Take a set of nodes and perform some transformation action. They are not mandatory and all transformation code can be located inside the transformation. But if some transformation parts can potentially be reused in other transformations, we suggest keeping them as a separate functions.
Location for Your Transformation Code
To decide where to store your transformation code, please follow these rules:
- If it is a plugin-specific transformation and cannot be reused by other plugins, keep source code inside plugin.
- If this transformation relates to the OpSetXToOpSetY conversion or it is common optimization, keep sources inside the transformation library.
After you decide where to store your transformation code, you can start developing your own nGraph transformation.
ngraph::Function and graph representation
An nGraph function is a 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 the operation has no consumers and it is not a Result operation
(shared pointer counter is zero), it is destructed and is not accessible anymore. Each operation in ngraph::Function has a std::shared_ptr<ngraph::Node> type.
For examples of how to build an nGraph function, see the Build nGraph Function page.
Transformations types
nGraph has three main transformation types:
ngraph::pass::FunctionPass- straightforward way to work withngraph::Functiondirectlyngraph::pass::MatcherPass- pattern-based transformation approachngraph::pass::GraphRewrite- container for matcher passes
ngraph::pass::FunctionPass
ngraph::pass::FunctionPass is used for transformations that take entire ngraph::Function as an 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 the run_on_function method where you will write the transformation code.
Return value is true if the original function has changed during transformation (new operation was added, or operations replacement was made, or node attributes were changed); otherwise, it is false.
For transformation API, please follow the working with ngraph::Function section.
Also ngraph::FunctionPass based transformations can be executed via pass::Manager. See the examples in the Using pass manager section.
ngraph::pass::MatcherPass
ngraph::pass::MatcherPass is used for pattern-based transformations.
Template for MatcherPass transformation class @snippet src/template_pattern_transformation.hpp graph_rewrite:template_transformation_hpp
@snippet src/template_pattern_transformation.cpp graph_rewrite:template_transformation_cpp
To use ngraph::pass::MatcherPass, you need to complete these steps:
- Create a pattern
- Implement a callback
- Register the pattern and Matcher
- Execute MatcherPass
So let's go through each of these steps.
Create a pattern
Pattern is a single root ngraph::Function. But the only difference is that you do not need to create a function object, you just need to create and connect nGraph or special pattern operations. Then you need to take the last created operation and put it as a root of the pattern. This root node will be used as a root node in pattern matching.
Note
: Any nodes in a pattern that have no consumers and are not registered as root will not be used in pattern matching.
@snippet example_ngraph_utils.cpp pattern:simple_example
The Parameter operation in the example above has type and shape specified. These attributes are needed only to create Parameter operation class and will not be used in pattern matching.
For instructions on how to match a pattern where ShapeOf takes any operation as an input, follow the pattern matching section.
Implement callback
Callback is an action applied to every pattern entrance. In general, callback is the lambda function that takes Matcher object with detected subgraph.
@snippet example_ngraph_utils.cpp pattern:callback_example
The example above shows the callback structure and how Matcher can be used for accessing nodes detected by pattern.
Callback return value is true if root node was replaced and another pattern cannot be applied to the same root node; otherwise, it is false.
Note
: It is not recommended to manipulate with nodes that are under root node. This may affect GraphRewrite execution as it is expected that all nodes that come after root node in topological order are valid and can be used in pattern matching.
MatcherPass also provides functionality that allows reporting of the newly created nodes that can be used in additional pattern matching.
If MatcherPass was registered in pass::Manager or pass::GraphRewrite, these registered nodes will be added for additional pattern matching.
That means that matcher passes registered in pass::GraphRewrite will be applied to these nodes.
The example below shows how single MatcherPass can fuse sequence of operations using the register_new_node method.
@snippet src/template_pattern_transformation.cpp matcher_pass:relu_fusion
Note
: If you register multiple nodes, please add them in topological order. We do not topologically sort these nodes as it is a time-consuming operation.
Register pattern and Matcher
The last step is to register Matcher and callback inside the MatcherPass pass. To do this, call the register_matcher method.
Note
: Only one matcher can be registered for a single MatcherPass class.
// Register matcher and callback
register_matcher(m, callback);
Execute MatcherPass
MatcherPass has multiple ways to be executed:
- Run on a single node - it can be useful if you want to run MatcherPass inside another transformation. @snippet src/template_pattern_transformation.cpp matcher_pass:run_on_node
- Run on
ngraph::Functionusing GraphRewrite - this approach gives ability to run MatcherPass on wholengraph::Function. Moreover, multiple MatcherPass transformation can be registered in a single GraphRewite to be executed in a single graph traversal. @snippet src/template_pattern_transformation.cpp matcher_pass:graph_rewrite - Run on
ngraph::Functionusingpass::Manager- this approach helps you to register MatcherPass for execution onngraph::Functionas another transformation types. @snippet src/template_pattern_transformation.cpp matcher_pass:manager
ngraph::pass::GraphRewrite
GraphRewrite pass serves for running multiple matcher passes on ngraph::Function in a single graph traversal.
Example:
@snippet src/template_pattern_transformation.cpp matcher_pass:graph_rewrite
In addition, GraphRewrite handles nodes that were registered by MatcherPasses during their execution. This nodes will be added to the beginning of the sequence with nodes for pattern matching.
Note
: when using
pass::Managertemporary GraphRewrite is used to execute single MatcherPass.
GraphRewrite has two algorithms for MatcherPasses execution. First algorithm is straightforward. It applies each MatcherPass in registration order to current node.
But it is not really efficient when you have a lot of registered passes. So first of all GraphRewrite checks that all MatcherPass patterns has type-based root node (it means that type of this node is not hidden into predicate). And then creates map from registered MatcherPasses. That helps to avoid additional cost of applying each MatcherPass for each node.
Pattern Matching
Sometimes patterns cannot be expressed via regular nGraph operations or it is too complicated. For example, if you want to detect Convolution->Add sub-graph without specifying particular input type for Convolution operation or you want to create a 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:
ngraph::pattern::any_input- helps to express inputs if their types are undefined.ngraph::pattern::wrap_type<T>- helps to express nodes of pattern without specifying node attributes.
Let's go through the example to have better understanding of how it works:
Note
: Node attributes do not participate in pattern matching and are needed only for operations creation. Only operation types participate in pattern matching.
The example below shows basic usage of pattern::any_input.
Here we construct Multiply pattern with arbitrary first input and Constant as a second input.
Also as Multiply is commutative operation, it does not matter in which order we set inputs (any_input/Constant or Constant/any_input) because both cases will be matched.
@snippet example_ngraph_utils.cpp pattern:label_example
This example shows how we can construct a 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 a pattern. Also it shows how to match pattern manually on given node.
@snippet example_ngraph_utils.cpp pattern:predicate_example
Note
: Be careful with manual matching because Matcher object holds matched nodes. To clear a match, use the m->clear_state() method.
Working with ngraph::Function
In this chapter we will review nGraph API that allows us to manipulate with ngraph::Function.
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 a 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 the code example.
@snippet example_ngraph_utils.cpp ngraph:ports_example
You may notice that we usually construct operations in this way:
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, the opset3::Multiply operation takes Output<Node> and std::shared_ptr<Node> as inputs. But the 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 raises an exception.
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 is replaced with Multiply.
@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 raises an exception.
The alternative way to do the same replacement is the following:
// 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.
@snippet example_ngraph_utils.cpp ngraph:insert_node
The alternative way to the insert operation is to make a node copy and use replace_node:
@snippet example_ngraph_utils.cpp ngraph:insert_node_with_copy
ngraph::Node elimination
Another type of node replacement is its elimination.
To eliminate operation, nGraph has special method that considers 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
When developing a transformation, you need to follow these transformation rules:
###1. Operation Set (OpSet)
Use the latest version of OpSet in your transformation. An exception is ConvertOpSetXToOpSetY transformations, where you must use operations from OpSetX and OpSetY.
@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. It means that rank or some of dimensions are dynamic (undefined).
ngraph::PartialShape can be converted to ngraph::Shape using the get_shape() method if all dimensions are static; otherwise, conversion raises 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, please do not use the get_shape() method. See the example below demonstrating how to avoid using 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 a unique name (used for nGraph internals) and a friendly name. In transformations we care only about friendly name because it represents the name from intermediate representation (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 these names.
To avoid loosing friendly name when replacing node with other node or subgraph, set the original friendly name to the latest node in replacing subgraph. See the example below.
// 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 a 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 these attributes as they will not be automatically propagated.
In most cases, transformations have the following 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 the examples below.
// Replace Transpose with Reshape operation (1:1)
ngraph::copy_runtime_info(transpose, reshape);
// Replace Div operation with Power and Multiply sub-graph (1:N)
ngraph::copy_runtime_info(div, {pow, mul});
// Fuse Convolution with Add operation (N:1)
ngraph::copy_runtime_info({conv, bias}, {conv_ie});
// 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.
Note
: copy_runtime_info removes rt_info from destination nodes. If you want to keep it, you need to specify them in source nodes like this: copy_runtime_info({a, b, c}, {a, b})
###5. Constant Folding
If your transformation inserts constant sub-graphs that need to be folded, do not forget to use ngraph::pass::ConstantFolding() after your transformation or call constant folding directly for operation.
The example below shows how constant subgraph can be constructed.
// 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);
Manual constant folding is more preferable than ngraph::pass::ConstantFolding() because it is much faster.
Below you can find an example of manual constant folding:
@snippet src/template_pattern_transformation.cpp manual_constant_folding
Common mistakes in transformations
In transformation development process:
- Do not use deprecated nGraph API. Deprecated methods has the
NGRAPH_DEPRECATEDmacros in its definition. - Do not pass
shared_ptr<Node>as an 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 produces different shape, remember that new shape will not be propagated until the first
validate_nodes_and_infer_typescall forngraph::Function. If you are usingpass::Manager, it will automatically call this method after each transformation execution. - Do not forget to call the
ngraph::ConstantFoldingpass if your transformation creates constant subgraphs. - Use latest OpSet if you are not developing downgrade transformation pass.
- When developing a callback for
ngraph::pass::MatcherPass, do not change nodes that come after the root node in topological order.
Using pass manager
ngraph::pass::Manager is a container class that can store the list of transformations and execute them. The main idea of this class is to have high-level representation for grouped list of transformations.
It can register and apply any transformation types on function.
In addition, ngraph::pass::Manager has extended debug capabilities (find more information in the how to debug transformations section).
The example below shows basic usage of ngraph::pass::Manager
@snippet src/template_pattern_transformation.cpp matcher_pass:manager3
Another example shows how multiple matcher passes can be united into single GraphRewrite.
@snippet src/template_pattern_transformation.cpp matcher_pass:manager2
Note: nGraph used to have the
pass::PassConfigclass for transformation pipeline manipulation. This mechanism is now obsolete and thepass::PassConfigclass will be removed in future release.
How to debug transformations
The most popular tool for transformations debugging is the ngraph::pass::VisualizeTree transformation, which visualizes 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 does not have user-friendly interface and it will be changed in the nearest future. The intention is to move visualization abilities inside transformations.
If you are using ngraph::pass::Manager to run sequence of transformations, you can get additional debug capabilities by using the following 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
This topic is mostly related to conversion to legacy opset and plugins that are based on CNNNetwork. But this mechanism still can be applied for other cases.
Let's suppose that plugin X enabled the opset3::StridedSlice operation support and you want to disable the ngraph::pass::ConvertStridedSliceToCrop transformation for plugin X.
To do this, you need to create a callback on plugin side and pass it to transformation. And also you need to update particular transformation to use this callback.
// Update callback to be able to use m_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 callback returns true for given node
if (m_transformation_callback(node)) {
return false;
}
// Implement transformation callback and pass it directly to transformation or pass::Manager
const auto transformations_callback = [](const std::shared_ptr<const ::ngraph::Node> &node) -> bool {
return std::dynamic_pointer_cast<const ::ngraph::opset3::StridedSlice>(node) != nullptr;
};
// Register transformation and pass callback to pass::Manager
ngraph::pass::Manager manager;
manager.register_pass<ngraph::pass::ConvertStridedSliceToCrop>();
// pass::Manager will set callback to all reistered transformations automatically
manager.set_callback(transformations_callback);
manager.run_passes(f);
Transformations testing
If you are developing new transformation inside plugin, you need to add test into the 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 functions that are used inside transformations.
The basic transformation test looks like this:
@snippet tests/functional/transformations/template_transformations_test.cpp transformation:test




