Offline transformations exposed to python with pybind11 (#7987)

* New approach to offline transformations

* Include paths fix

* Imports fix

* offline_transformations target dependency simplification

* MakeStatefulTransformation exposed to python

* Python bindings build configuration fix

* Test variable name refactor

* Stop crying (snow)flake

* Snake cased offline transformations API

* Removal of old offline transformations from python

* Imports adaptation to new code style

* offline_transformations as a part of the common wheel

* Cmake simplification and refactor

* Correct transform invocation

* CI fix

* Proper dependency check in MO

* _pyngraph as a dependency of MO in cmake

* IR serialization fix in MO

* POT adaptation to the new API

* Revert "Removal of old offline transformations from python"

This reverts commit f9a0551ead.

* Merge of old& new bindings for offline_transformations

* Revert "POT adaptation to the new API"

This reverts commit 499554e68c.

* Obsolete cmake line removal

* Missing comma and merge conflict fix

* Offline transformations tests fix

* IE imports removal from check_ie_bindings

* Installation of opevino/__init__.py fix

* Obsolete line removal

* MO serialization switched to the new API

* Revert of preliminary MO adaptation to the new API

* Another magic spell that will hopefully make CI pass

* Python api cmake dependencies reorg

* Temporary solution for the CI/cpack errors

* Installation fix and code formatting

* ie_api & pyopenvino dependency removal

* Explicit cpack configuration for the new API

* cpack configuration adaptation

* Revert of obsolete cpack changes

Co-authored-by: Alexander Zhogov <alexander.zhogov@intel.com>
This commit is contained in:
Tomasz Dołbniak
2021-11-03 18:00:14 +01:00
committed by GitHub
parent db27dcce94
commit b5f0ca5d10
10 changed files with 192 additions and 6 deletions

View File

@@ -70,4 +70,4 @@ if __name__ == "__main__":
parser.add_argument("--transform")
args = parser.parse_args()
apply_offline_transformations(args.input_model, args.framework, parse_transform(args.transform))
apply_offline_transformations(args.input_model, args.framework, parse_transform(args.transform))

View File

@@ -6,6 +6,10 @@ cmake_minimum_required (VERSION 3.13)
project(OpenVINOPython DESCRIPTION "OpenVINO Runtime Python bindings")
if(NOT DEFINED OpenVINO_SOURCE_DIR)
find_package(InferenceEngineDeveloperPackage REQUIRED)
endif()
add_subdirectory(thirdparty/pybind11 EXCLUDE_FROM_ALL)
set(LIBRARY_OUTPUT_DIRECTORY_BIN ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
@@ -24,3 +28,7 @@ if(NGRAPH_UNIT_TEST_ENABLE)
add_subdirectory(tests/mock/pyngraph_fe_mock_api)
add_dependencies(_pyngraph pybind_mock_frontend)
endif()
if(InferenceEngineDeveloperPackage_FOUND)
ie_cpack(${IE_CPACK_COMPONENTS_ALL})
endif()

View File

@@ -41,6 +41,8 @@ packages = [
"ngraph.impl.passes",
"ngraph.frontend",
"openvino",
# TODO: change the module name according to the description in 69196
"openvino.offline_transformations_pybind",
"openvino.opset1",
"openvino.opset2",
"openvino.opset3",
@@ -168,13 +170,13 @@ class BuildCMakeExt(build_ext):
bin_dir = os.path.join(OPENVINO_ROOT_DIR, "bin")
if os.environ.get("OpenVINO_DIR") is not None:
root_dir = PYTHON_API_ROOT_DIR
bin_dir = build_dir
self.announce("Configuring cmake project", level=3)
ext_args = self.cmake_args.split() if self.cmake_args else []
ov_build_dir = os.path.join(OPENVINO_ROOT_DIR, "build")
self.spawn(["cmake", "-S" + root_dir, "-B" + self.build_temp,
f"-DCMAKE_BUILD_TYPE={self.config}",
f"-DInferenceEngine_DIR={os.path.join(OPENVINO_ROOT_DIR, 'build')}",
f"-DInferenceEngineDeveloperPackage_DIR={ov_build_dir}",
"-DENABLE_PYTHON=ON",
"-DNGRAPH_ONNX_FRONTEND_ENABLE=ON"] + ext_args)

View File

@@ -6,7 +6,7 @@
from pkg_resources import get_distribution, DistributionNotFound
__path__ = __import__('pkgutil').extend_path(__path__, __name__) # type: ignore # mypy issue #1422
__path__ = __import__('pkgutil').extend_path(__path__, __name__) # type: ignore # mypy issue #1422
try:
__version__ = get_distribution("openvino-core").version

View File

@@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2021 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
from openvino.pyopenvino.offline_transformations_pybind import apply_moc_transformations
from openvino.pyopenvino.offline_transformations_pybind import apply_pot_transformations
from openvino.pyopenvino.offline_transformations_pybind import apply_low_latency_transformation
from openvino.pyopenvino.offline_transformations_pybind import apply_pruning_transformation
from openvino.pyopenvino.offline_transformations_pybind import generate_mapping_file
from openvino.pyopenvino.offline_transformations_pybind import apply_make_stateful_transformation

View File

@@ -4,7 +4,7 @@
project (pyopenvino)
if(NOT DEFINED OpenVINO_SOURCE_DIR)
find_package(OpenVINO REQUIRED)
find_package(InferenceEngineDeveloperPackage REQUIRED)
endif()
# PYTHON_VERSION_MAJOR and PYTHON_VERSION_MINOR are defined inside pybind11
@@ -30,8 +30,14 @@ file(GLOB_RECURSE SOURCES *.cpp)
pybind11_add_module(${PROJECT_NAME} MODULE ${SOURCES})
if(TARGET offline_transformations)
set(OFFLINE_TRANSFORMATIONS_LIB offline_transformations)
else()
set(OFFLINE_TRANSFORMATIONS_LIB IE::offline_transformations)
endif()
target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/..")
target_link_libraries(${PROJECT_NAME} PRIVATE openvino::runtime)
target_link_libraries(${PROJECT_NAME} PRIVATE openvino::runtime ${OFFLINE_TRANSFORMATIONS_LIB})
# perform copy
if(OpenVINO_SOURCE_DIR)

View File

@@ -0,0 +1,84 @@
// Copyright (C) 2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "pyopenvino/core/offline_transformations.hpp"
#include <pybind11/stl.h>
#include <generate_mapping_file.hpp>
#include <openvino/pass/make_stateful.hpp>
#include <pot_transformations.hpp>
#include <pruning.hpp>
#include <transformations/common_optimizations/moc_transformations.hpp>
#include "openvino/pass/low_latency.hpp"
#include "openvino/pass/manager.hpp"
namespace py = pybind11;
void regmodule_offline_transformations(py::module m) {
// TODO: change the submodule name according to the description in 69196
py::module m_offline_transformations =
m.def_submodule("offline_transformations_pybind", "Offline transformations module");
m_offline_transformations.def(
"apply_moc_transformations",
[](std::shared_ptr<ov::Function> function, bool cf) {
ov::pass::Manager manager;
manager.register_pass<ngraph::pass::MOCTransformations>(cf);
manager.run_passes(function);
},
py::arg("function"),
py::arg("cf"));
m_offline_transformations.def(
"apply_pot_transformations",
[](std::shared_ptr<ov::Function> function, std::string device) {
ov::pass::Manager manager;
manager.register_pass<ngraph::pass::POTTransformations>(std::move(device));
manager.run_passes(function);
},
py::arg("function"),
py::arg("device"));
m_offline_transformations.def(
"apply_low_latency_transformation",
[](std::shared_ptr<ov::Function> function, bool use_const_initializer = true) {
ov::pass::Manager manager;
manager.register_pass<ov::pass::LowLatency2>(use_const_initializer);
manager.run_passes(function);
},
py::arg("function"),
py::arg("use_const_initializer") = true);
m_offline_transformations.def(
"apply_pruning_transformation",
[](std::shared_ptr<ngraph::Function> function) {
ov::pass::Manager manager;
manager.register_pass<ngraph::pass::Pruning>();
manager.run_passes(function);
},
py::arg("function"));
m_offline_transformations.def(
"generate_mapping_file",
[](std::shared_ptr<ov::Function> function, std::string path, bool extract_names) {
ov::pass::Manager manager;
manager.register_pass<ngraph::pass::GenerateMappingFile>(path, extract_names);
manager.run_passes(function);
},
py::arg("function"),
py::arg("path"),
py::arg("extract_names"));
m_offline_transformations.def(
"apply_make_stateful_transformation",
[](std::shared_ptr<ov::Function> function, const std::map<std::string, std::string>& param_res_names) {
ngraph::pass::Manager manager;
manager.register_pass<ov::pass::MakeStateful>(param_res_names);
manager.run_passes(function);
},
py::arg("function"),
py::arg("param_res_names"));
}

View File

@@ -0,0 +1,11 @@
// Copyright (C) 2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <pybind11/pybind11.h>
namespace py = pybind11;
void regmodule_offline_transformations(py::module m);

View File

@@ -32,6 +32,7 @@
#include "pyopenvino/core/ie_parameter.hpp"
#include "pyopenvino/core/ie_preprocess_info.hpp"
#include "pyopenvino/core/ie_version.hpp"
#include "pyopenvino/core/offline_transformations.hpp"
#include "pyopenvino/core/tensor.hpp"
#include "pyopenvino/core/tensor_description.hpp"
#include "pyopenvino/graph/dimension.hpp"
@@ -149,4 +150,6 @@ PYBIND11_MODULE(pyopenvino, m) {
regclass_InputInfo(m);
regclass_InferQueue(m);
regclass_PreProcessInfo(m);
regmodule_offline_transformations(m);
}

View File

@@ -0,0 +1,62 @@
# Copyright (C) 2018-2021 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# TODO: change the module name according to the description in 69196
from openvino.offline_transformations_pybind import apply_moc_transformations, apply_pot_transformations, \
apply_low_latency_transformation, apply_pruning_transformation, apply_make_stateful_transformation
from openvino import Function, PartialShape
import openvino as ov
def get_test_function():
param = ov.opset8.parameter(PartialShape([1, 3, 22, 22]), name="parameter")
relu = ov.opset8.relu(param)
res = ov.opset8.result(relu, name="result")
return Function([res], [param], "test")
def test_moc_transformations():
function = get_test_function()
apply_moc_transformations(function, False)
assert function is not None
assert len(function.get_ops()) == 3
def test_pot_transformations():
function = get_test_function()
apply_pot_transformations(function, "GNA")
assert function is not None
assert len(function.get_ops()) == 3
def test_low_latency_transformation():
function = get_test_function()
apply_low_latency_transformation(function, True)
assert function is not None
assert len(function.get_ops()) == 3
def test_pruning_transformation():
function = get_test_function()
apply_pruning_transformation(function)
assert function is not None
assert len(function.get_ops()) == 3
def test_make_stateful_transformations():
function = get_test_function()
apply_make_stateful_transformation(function, {"parameter": "result"})
assert function is not None
assert len(function.get_parameters()) == 0
assert len(function.get_results()) == 0