diff --git a/docs/Extensibility_UG/frontend_extensions.md b/docs/Extensibility_UG/frontend_extensions.md index ba24f9edc83..e791766a611 100644 --- a/docs/Extensibility_UG/frontend_extensions.md +++ b/docs/Extensibility_UG/frontend_extensions.md @@ -116,6 +116,33 @@ So the conclusion is that each attribute of target OpenVINO operation should be This is achieved by specifying maps as arguments for `OpExtension` constructor. +### Mapping custom operations to frontends with OPENVINO_FRAMEWORK_MAP macro + +> **NOTE**: Below solution works only for ONNX and Tensorflow frontends. + +`OPENVINO_FRAMEWORK_MAP` is a macro that should be used inside OpenVINO operation's class definition and that lets you specify the mapping between this operation to a frontend operation. + +Let's consider the following example. Imagine you have an ONNX model with `CustomOp` operation (and this operation has `mode` attribute) and a Tensorflow model with `CustomOpV3` operation (this operation has `axis` attribute) and both of them can be implemented with a single OpenVINO operation `CustomOp` like follows: + +@snippet ov_extensions.cpp frontend_extension_framework_map_macro_headers +@snippet ov_extensions.cpp frontend_extension_framework_map_macro_CustomOp + +Let's take a closer look at the parameters this macro takes: +```cpp +OPENVINO_FRAMEWORK_MAP(framework, name, attributes_map, attributes_values) +``` +- `framework` - framework name. +- `name` - the framework operation name. It's optional if the OpenVINO custom operation name (that is the name that is passed as the first parameter to `OPENVINO_OP` macro) is the same as the framework operation name and both `attributes_map` and `attributes_values` are not provided. +- `attributes_map` - used to provide a mapping between OpenVINO operation attribute and framework operation attribute. Contains key-value pairs, where key is an OpenVINO operation attribute name and value is its corresponding framework operation attribute name. This parameter is optional if the number of OpenVINO operation attributes and their names match one-to-one with framework operation attributes. +- `attributes_values` - used to provide default values for OpenVINO operation attributes that are not specified in `attributes_map`. Contains key-value pairs, where key is an OpenVINO operation attribute name and the value is this attribute value. This parameter cannot be provided if `attributes_map` contains all of OpenVINO operation attributes or if `attributes_map` is not provided. + +In the example above, `OPENVINO_FRAMEWORK_MAP` is used twice. +First, OpenVINO `CustomOp` is mapped to ONNX `CustomOp` operation, `m_mode` attribute is mapped to `mode` attribute, while `m_axis` attribute gets the default value `-1`. +Secondly, OpenVINO `CustomOp` is mapped to Tensorflow `CustomOpV3` operation, `m_axis` attribute is mapped to `axis` attribute, while `m_mode` attribute gets the default value `"linear"`. + +The last step is to register this custom operation by following: +@snippet ov_extensions.cpp frontend_extension_framework_map_macro_add_extension + Mapping to Multiple Operations with ConversionExtension ####################################################### diff --git a/docs/snippets/CMakeLists.txt b/docs/snippets/CMakeLists.txt index 425e7475038..4d824e7c2bc 100644 --- a/docs/snippets/CMakeLists.txt +++ b/docs/snippets/CMakeLists.txt @@ -60,7 +60,10 @@ target_include_directories(${TARGET_NAME} PRIVATE "${OpenVINO_SOURCE_DIR}/src/in "${OpenVINO_SOURCE_DIR}/src/common/util/include" "${OpenVINO_SOURCE_DIR}/src/common/low_precision_transformations/include" "${OpenVINO_SOURCE_DIR}/src/frontends/common/include" - "${OpenVINO_SOURCE_DIR}/src/core/template_extension/new/") + "${OpenVINO_SOURCE_DIR}/src/core/template_extension/new" + "${OpenVINO_SOURCE_DIR}/src/frontends/onnx/frontend/include" + "${OpenVINO_SOURCE_DIR}/src/frontends/tensorflow/include") + ov_mark_target_as_cc(${TARGET_NAME}) if(TARGET OpenCL::OpenCL) diff --git a/docs/snippets/ov_extensions.cpp b/docs/snippets/ov_extensions.cpp index 895ee6e59d9..697224c400b 100644 --- a/docs/snippets/ov_extensions.cpp +++ b/docs/snippets/ov_extensions.cpp @@ -17,6 +17,12 @@ #include //! [frontend_extension_ThresholdedReLU_header] +//! [frontend_extension_framework_map_macro_headers] +#include +#include +#include +//! [frontend_extension_framework_map_macro_headers] + #include //! [frontend_extension_CustomOperation] @@ -40,6 +46,27 @@ public: std::shared_ptr clone_with_new_inputs(const ov::OutputVector&) const override { return nullptr; } }; +//! [frontend_extension_framework_map_macro_CustomOp] +class CustomOp : public ov::op::Op { + std::string m_mode; + int m_axis; + +public: + OPENVINO_OP("CustomOp"); + OPENVINO_FRAMEWORK_MAP(onnx, "CustomOp", { {"m_mode", "mode"} }, { {"m_axis", -1} }); + OPENVINO_FRAMEWORK_MAP(tensorflow, "CustomOpV3", { {"m_axis", "axis"} }, { {"m_mode", "linear"} }); + + bool visit_attributes(ov::AttributeVisitor& visitor) override { + visitor.on_attribute("m_mode", m_mode); + visitor.on_attribute("m_axis", m_axis); + return true; + } + + // ... implement other required methods +//! [frontend_extension_framework_map_macro_CustomOp] + std::shared_ptr clone_with_new_inputs(const ov::OutputVector&) const override { return nullptr; } +}; + int main() { { //! [add_extension] @@ -125,5 +152,12 @@ ov::Core core; core.add_extension("openvino_template_extension.so"); //! [add_extension_lib] } + +{ +//! [frontend_extension_framework_map_macro_add_extension] +ov::Core core; +core.add_extension(ov::frontend::OpExtension()); +//! [frontend_extension_framework_map_macro_add_extension] +} return 0; }