[Docs][PyOV] Add docstrings for transformations + python examples for stateful model (#15978)
* [Docs][PyOV] Add docstrings for transformation + python examples for stateful * add snippets + small improvements
This commit is contained in:
parent
190b64a0af
commit
b130b73f80
|
|
@ -0,0 +1,172 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import logging as log
|
||||
import numpy as np
|
||||
import sys
|
||||
|
||||
from openvino.runtime import opset10 as ops
|
||||
from openvino.runtime import Core, Model, PartialShape, Tensor, Type
|
||||
from openvino.runtime.passes import LowLatency2, MakeStateful, Manager
|
||||
|
||||
|
||||
def state_network_example():
|
||||
#! [ov:state_network]
|
||||
input = ops.parameter([1, 1], dtype=np.float32)
|
||||
read = ops.read_value(input, "variable0")
|
||||
add = ops.add(read, input)
|
||||
save = ops.assign(add, "variable0")
|
||||
result = ops.result(add)
|
||||
model = Model(results=[result], sinks=[save], parameters=[input])
|
||||
#! [ov:state_network]
|
||||
|
||||
|
||||
def low_latency_2_example():
|
||||
#! [ov:low_latency_2]
|
||||
# Precondition for Model.
|
||||
# TensorIterator and Parameter are created in body of TensorIterator with names
|
||||
tensor_iterator_name = "TI_name"
|
||||
body_parameter_name = "body_parameter_name"
|
||||
idx = "0" # this is a first variable in the network
|
||||
|
||||
# The State will be named "TI_name/param_name/variable_0"
|
||||
state_name = tensor_iterator_name + "//" + body_parameter_name + "//" + "variable_" + idx # todo
|
||||
|
||||
#! [ov:get_ov_model]
|
||||
core = Core()
|
||||
ov_model = core.read_model("path_to_the_model")
|
||||
#! [ov:get_ov_model]
|
||||
|
||||
# reshape input if needed
|
||||
|
||||
#! [ov:reshape_ov_model]
|
||||
ov_model.reshape({"X": PartialShape([1, 1, 16])})
|
||||
#! [ov:reshape_ov_model]
|
||||
|
||||
#! [ov:apply_low_latency_2]
|
||||
manager = Manager()
|
||||
manager.register_pass(LowLatency2())
|
||||
manager.run_passes(ov_model)
|
||||
#! [ov:apply_low_latency_2]
|
||||
hd_specific_model = core.compile_model(ov_model)
|
||||
# Try to find the Variable by name
|
||||
infer_request = hd_specific_model.create_infer_request()
|
||||
states = infer_request.query_state()
|
||||
for state in states:
|
||||
name = state.get_name()
|
||||
if (name == state_name):
|
||||
# some actions
|
||||
#! [ov:low_latency_2]
|
||||
|
||||
#! [ov:low_latency_2_use_parameters]
|
||||
manager.register_pass(LowLatency2(False))
|
||||
#! [ov:low_latency_2_use_parameters]
|
||||
|
||||
|
||||
def apply_make_stateful_tensor_names():
|
||||
#! [ov:make_stateful_tensor_names]
|
||||
core = Core()
|
||||
ov_model = core.read_model("path_to_the_model")
|
||||
tensor_names = {"tensor_name_1": "tensor_name_4",
|
||||
"tensor_name_3": "tensor_name_6"}
|
||||
manager = Manager()
|
||||
manager.register_pass(MakeStateful(tensor_names))
|
||||
manager.run_passes(ov_model)
|
||||
#! [ov:make_stateful_tensor_names]
|
||||
|
||||
|
||||
def apply_make_stateful_ov_nodes():
|
||||
#! [ov:make_stateful_ov_nodes]
|
||||
core = Core()
|
||||
ov_model = core.read_model("path_to_the_model")
|
||||
# Parameter_1, Result_1, Parameter_3, Result_3 are
|
||||
# ops.parameter/ops.result in the ov_model
|
||||
pairs = ["""(Parameter_1, Result_1), (Parameter_3, Result_3)"""]
|
||||
manager = Manager()
|
||||
manager.register_pass(MakeStateful(pairs))
|
||||
manager.run_passes(ov_model)
|
||||
#! [ov:make_stateful_ov_nodes]
|
||||
|
||||
|
||||
def main():
|
||||
#! [ov:state_api_usage]
|
||||
# 1. Load inference engine
|
||||
log.info("Loading Inference Engine")
|
||||
core = Core()
|
||||
|
||||
# 2. Read a model
|
||||
log.info("Loading network files")
|
||||
model = core.read_model("path_to_the_model")
|
||||
|
||||
|
||||
# 3. Load network to CPU
|
||||
hw_specific_model = core.compile_model(model, "CPU")
|
||||
|
||||
# 4. Create Infer Request
|
||||
infer_request = hw_specific_model.create_infer_request()
|
||||
|
||||
# 5. Reset memory states before starting
|
||||
states = infer_request.query_state()
|
||||
if (states.size() != 1):
|
||||
log.error(f"Invalid queried state number. Expected 1, but got {str(states.size())}")
|
||||
return -1
|
||||
|
||||
for state in states:
|
||||
state.reset()
|
||||
|
||||
# 6. Inference
|
||||
input_data = np.arange(start=1, stop=12, dtype=np.float32)
|
||||
|
||||
# This example demonstrates how to work with OpenVINO State API.
|
||||
# Input_data: some array with 12 float numbers
|
||||
|
||||
# Part1: read the first four elements of the input_data array sequentially.
|
||||
# Expected output for the first utterance:
|
||||
# sum of the previously processed elements [ 1, 3, 6, 10]
|
||||
|
||||
# Part2: reset state value (set to 0) and read the next four elements.
|
||||
# Expected output for the second utterance:
|
||||
# sum of the previously processed elements [ 5, 11, 18, 26]
|
||||
|
||||
# Part3: set state value to 5 and read the next four elements.
|
||||
# Expected output for the third utterance:
|
||||
# sum of the previously processed elements + 5 [ 14, 24, 35, 47]
|
||||
target_state = states[0]
|
||||
|
||||
# Part 1
|
||||
log.info("Infer the first utterance")
|
||||
for next_input in range(len(input_data)/3):
|
||||
infer_request.infer({0 : input_data[next_input]})
|
||||
state_buf = target_state.state.data
|
||||
log.info(state_buf[0])
|
||||
|
||||
# Part 2
|
||||
log.info("\nReset state between utterances...\n")
|
||||
target_state.reset()
|
||||
|
||||
log.info("Infer the second utterance")
|
||||
for next_input in range(len(input_data)/3, (len(input_data)/3 * 2)):
|
||||
infer_request.infer({0 : input_data[next_input]})
|
||||
state_buf = target_state.state.data
|
||||
log.info(state_buf[0])
|
||||
|
||||
# Part 3
|
||||
log.info("\nSet state value between utterances to 5...\n")
|
||||
v = np.asarray([5], dtype=np.float32)
|
||||
tensor = Tensor(v, shared_memory=True)
|
||||
target_state.state = tensor
|
||||
|
||||
log.info("Infer the third utterance")
|
||||
for next_input in range((input_data.size()/3 * 2), input_data.size()):
|
||||
infer_request.infer({0 : input_data[next_input]})
|
||||
|
||||
state_buf = target_state.state.data
|
||||
log.info(state_buf[0])
|
||||
|
||||
log.info("Execution successful")
|
||||
#! [ov:state_api_usage]
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
|
|
@ -98,15 +98,41 @@ void regclass_transformations(py::module m) {
|
|||
py::class_<ov::pass::MakeStateful, std::shared_ptr<ov::pass::MakeStateful>, ov::pass::ModelPass, ov::pass::PassBase>
|
||||
make_stateful(m, "MakeStateful");
|
||||
make_stateful.doc() = "openvino.runtime.passes.MakeStateful transformation";
|
||||
// TODO: update docstrings for c-tors below
|
||||
make_stateful.def(py::init<const ov::pass::MakeStateful::ParamResPairs&>(), py::arg("pairs_to_replace"));
|
||||
make_stateful.def(py::init<const std::map<std::string, std::string>&>());
|
||||
make_stateful.def(
|
||||
py::init<const ov::pass::MakeStateful::ParamResPairs&>(),
|
||||
py::arg("pairs_to_replace"),
|
||||
R"( The transformation replaces the provided pairs Parameter and Result with openvino Memory operations ReadValue and Assign.
|
||||
|
||||
:param pairs_to_replace:
|
||||
:type pairs_to_replace: List[Tuple[op.Parameter, op.Result]
|
||||
)");
|
||||
make_stateful.def(py::init<const std::map<std::string, std::string>&>(),
|
||||
py::arg("pairs_to_replace"),
|
||||
R"(
|
||||
The transformation replaces the provided pairs Parameter and Result with openvino Memory operations ReadValue and Assign.
|
||||
|
||||
:param pairs_to_replace: a dictionary of names of the provided Parameter and Result operations.
|
||||
:type pairs_to_replace: Dict[str, str]
|
||||
)");
|
||||
|
||||
py::class_<ov::pass::LowLatency2, std::shared_ptr<ov::pass::LowLatency2>, ov::pass::ModelPass, ov::pass::PassBase>
|
||||
low_latency(m, "LowLatency2");
|
||||
low_latency.doc() = "openvino.runtime.passes.LowLatency2 transformation";
|
||||
// TODO: update docstrings for c-tor below
|
||||
low_latency.def(py::init<bool>(), py::arg("use_const_initializer") = true);
|
||||
|
||||
low_latency.def(py::init<bool>(),
|
||||
py::arg("use_const_initializer") = true,
|
||||
R"(
|
||||
Create LowLatency2 pass which is used for changing the structure of the model,
|
||||
which contains TensorIterator/Loop operations.
|
||||
The transformation finds all TensorIterator/Loop layers in the network,
|
||||
processes all back edges that describe a connection between Result and Parameter of the TensorIterator/Loop bodies,
|
||||
and inserts ReadValue and Assign layers at the input and output corresponding to this back edge.
|
||||
|
||||
:param use_const_initializer: Changes the type of the initializing subgraph for ReadValue operations.
|
||||
If "true", then the transformation inserts Constant before ReadValue operation.
|
||||
If "false, then the transformation leaves existed initializing subgraph for ReadValue operation.
|
||||
:type use_const_initializer: bool
|
||||
)");
|
||||
|
||||
py::class_<ov::pass::ConvertFP32ToFP16,
|
||||
std::shared_ptr<ov::pass::ConvertFP32ToFP16>,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ def test_graph_function_api():
|
|||
assert parameter_a.partial_shape == PartialShape([2, 2])
|
||||
parameter_a.layout = ov.Layout("NC")
|
||||
assert parameter_a.layout == ov.Layout("NC")
|
||||
function = Model(model, [parameter_a, parameter_b, parameter_c], "TestFunction")
|
||||
function = Model(model, [parameter_a, parameter_b, parameter_c], "TestModel")
|
||||
|
||||
function.get_parameters()[1].set_partial_shape(PartialShape([3, 4, 5]))
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ def test_graph_function_api():
|
|||
assert results[0].get_output_partial_shape(0) == PartialShape([2, 2])
|
||||
results[0].layout = ov.Layout("NC")
|
||||
assert results[0].layout.to_string() == ov.Layout("NC")
|
||||
assert function.get_friendly_name() == "TestFunction"
|
||||
assert function.get_friendly_name() == "TestModel"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
|
@ -521,7 +521,7 @@ def test_sink_function_ctor():
|
|||
add = ops.add(rv, input_data, name="MemoryAdd")
|
||||
node = ops.assign(add, "var_id_667")
|
||||
res = ops.result(add, "res")
|
||||
function = Model(results=[res], sinks=[node], parameters=[input_data], name="TestFunction")
|
||||
function = Model(results=[res], sinks=[node], parameters=[input_data], name="TestModel")
|
||||
|
||||
ordered_ops = function.get_ordered_ops()
|
||||
op_types = [op.get_type_name() for op in ordered_ops]
|
||||
|
|
@ -534,7 +534,7 @@ def test_sink_function_ctor():
|
|||
assert (function.get_parameters()[0].get_partial_shape()) == PartialShape([2, 2])
|
||||
assert len(function.get_parameters()) == 1
|
||||
assert len(function.get_results()) == 1
|
||||
assert function.get_friendly_name() == "TestFunction"
|
||||
assert function.get_friendly_name() == "TestModel"
|
||||
|
||||
|
||||
def test_node_version():
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
import os
|
||||
import pytest
|
||||
import numpy as np
|
||||
import openvino.runtime as ov
|
||||
|
||||
from openvino.runtime import Model, PartialShape, Shape, opset8, Core
|
||||
from openvino.runtime import Model, PartialShape, Shape, Core
|
||||
from openvino.runtime import opset10
|
||||
from openvino.runtime.passes import (
|
||||
Manager,
|
||||
ConstantFolding,
|
||||
|
|
@ -20,16 +20,34 @@ from tests.test_utils.test_utils import create_filename_for_test
|
|||
|
||||
|
||||
def get_model():
|
||||
param = opset8.parameter(PartialShape([1, 3, 22, 22]), name="parameter")
|
||||
param = opset10.parameter(PartialShape([1, 3, 22, 22]), name="parameter")
|
||||
param.get_output_tensor(0).set_names({"parameter"})
|
||||
relu = opset8.relu(param)
|
||||
reshape = opset8.reshape(relu, opset8.shape_of(relu), False)
|
||||
res = opset8.result(reshape, name="result")
|
||||
relu = opset10.relu(param)
|
||||
reshape = opset10.reshape(relu, opset10.shape_of(relu), False)
|
||||
res = opset10.result(reshape, name="result")
|
||||
res.get_output_tensor(0).set_names({"result"})
|
||||
return Model([res], [param], "test")
|
||||
|
||||
|
||||
def test_make_stateful():
|
||||
param = opset10.parameter(PartialShape([1, 3, 22, 22]), name="parameter")
|
||||
param.get_output_tensor(0).set_names({"parameter"})
|
||||
relu = opset10.relu(param)
|
||||
reshape = opset10.reshape(relu, opset10.shape_of(relu), False)
|
||||
res = opset10.result(reshape, name="result")
|
||||
res.get_output_tensor(0).set_names({"result"})
|
||||
model = Model([res], [param], "test")
|
||||
|
||||
manager = Manager()
|
||||
manager.register_pass(MakeStateful([(param, res)]))
|
||||
manager.run_passes(model)
|
||||
|
||||
assert model is not None
|
||||
assert len(model.get_parameters()) == 0
|
||||
assert len(model.get_results()) == 0
|
||||
|
||||
|
||||
def test_make_stateful_with_dict():
|
||||
model = get_model()
|
||||
|
||||
manager = Manager()
|
||||
|
|
@ -68,20 +86,20 @@ def test_convert_precision():
|
|||
|
||||
|
||||
def test_low_latency2():
|
||||
param_x = opset8.parameter(Shape([32, 40, 10]), np.float32, "X")
|
||||
param_y = opset8.parameter(Shape([32, 40, 10]), np.float32, "Y")
|
||||
param_m = opset8.parameter(Shape([32, 2, 10]), np.float32, "M")
|
||||
param_x = opset10.parameter(Shape([32, 40, 10]), np.float32, "X")
|
||||
param_y = opset10.parameter(Shape([32, 40, 10]), np.float32, "Y")
|
||||
param_m = opset10.parameter(Shape([32, 2, 10]), np.float32, "M")
|
||||
|
||||
x_i = opset8.parameter(Shape([32, 2, 10]), np.float32, "X_i")
|
||||
y_i = opset8.parameter(Shape([32, 2, 10]), np.float32, "Y_i")
|
||||
m_body = opset8.parameter(Shape([32, 2, 10]), np.float32, "M_body")
|
||||
x_i = opset10.parameter(Shape([32, 2, 10]), np.float32, "X_i")
|
||||
y_i = opset10.parameter(Shape([32, 2, 10]), np.float32, "Y_i")
|
||||
m_body = opset10.parameter(Shape([32, 2, 10]), np.float32, "M_body")
|
||||
|
||||
add = opset8.add(x_i, y_i)
|
||||
zo = opset8.multiply(add, m_body)
|
||||
add = opset10.add(x_i, y_i)
|
||||
zo = opset10.multiply(add, m_body)
|
||||
|
||||
body = Model([zo], [x_i, y_i, m_body], "body_function")
|
||||
|
||||
ti = opset8.tensor_iterator()
|
||||
ti = opset10.tensor_iterator()
|
||||
ti.set_body(body)
|
||||
ti.set_sliced_input(x_i, param_x.output(0), 0, 2, 2, 39, 1)
|
||||
ti.set_sliced_input(y_i, param_y.output(0), 0, 2, 2, -1, 1)
|
||||
|
|
@ -90,8 +108,8 @@ def test_low_latency2():
|
|||
out0 = ti.get_iter_value(zo.output(0), -1)
|
||||
out1 = ti.get_concatenated_slices(zo.output(0), 0, 2, 2, 39, 1)
|
||||
|
||||
result0 = opset8.result(out0)
|
||||
result1 = opset8.result(out1)
|
||||
result0 = opset10.result(out0)
|
||||
result1 = opset10.result(out1)
|
||||
|
||||
model = Model([result0, result1], [param_x, param_y, param_m])
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue