OpenVINO™ ランタイムのモデル表現#
OpenVINO™ ランタイムでは、モデルは ov::Model
クラスによって表されます。
ov::Model
オブジェクトは、入力、出力、グラフのシンクである ov::op::v0::Parameter
、ov::op::v0::Result
、および ov::op::Sink
操作への共有ポインターを格納します。グラフのシンクにはコンシューマーがなく、結果ベクトルには含まれません。他のすべての操作は共有ポインターを介して相互に保持され、子操作はハードリンクによって親を保持します。操作にコンシューマーがなく、共有ポインターカウンターが 0 である Result
操作でも Sink
操作でもない場合、操作は破棄されてアクセスできなくなります。
ov::Model
の各操作には std::shared_ptr<ov::Node>
タイプがあります。
OpenVINO ランタイムがモデルでどのように動作するか#
OpenVINO™ ランタイムを使用すると、さまざまなアプローチによりモデルの入力/出力を操作できます。
ov::Model::inputs()
/ov::Model::outputs()
メソッドは、すべての入出力ポートのベクトルを取得するために使用されます。inputs = model.inputs outputs = model.outputs
/* すべてのトポロジー入力に関する情報を取得 */ auto inputs = model->inputs(); /* すべてのトポロジー出力に関する情報を取得 */ auto outputs = model->outputs();
入力または出力が 1 つだけのモデルでは、引数なしで
ov::Model::input()
メソッドまたはov::Model::output()
メソッドを使用して、入力ポートまたは出力ポートをそれぞれ取得できます。ov::Model::input()
メソッドとov::Model::output()
メソッドをフレームワーク・モデルからの入力または出力のインデックスとともに使用して、インデックスによって特定のポートを取得できます。ov_model_input = model.input(index) ov_model_output = model.output(index)
auto ov_model_input = ov_model->input(index); auto ov_model_output = ov_model->output(index);
元のフレームワーク・モデルからの入力または出力のテンソル名を
ov::Model::input()
メソッドまたはov::Model::output()
メソッドとともに使用して、特定のポートを取得できます。これは、以前のように、フレームワークから OpenVINO への名前による追加のマッピングが必要ないことを意味します。OpenVINO ランタイムでは、次のようなネイティブ・フレームワーク・テンソル名が許可されます:
警告
ov::Model
のすべての入力/出力には番号が付加されているため、それらを取得するにはインデックスを使用することを推奨します。
テンソル名を使用すると、元のフレームワークでは入力と出力にテンソル名が必須であることが保証されていないため、信頼性の低いアプローチになる可能性があります。したがって、ov::Model
には、入力/出力の tensor_names
の空のリストが含まれる場合があります。
対応する入力/出力に関連付けられているすべてのテンソル名を取得するため、OpenVINO Runtime には get_names
メソッドがあります。特定の入力/出力に関連付けられたすべての名前から特定の名前を取得するため、get_any_name
メソッドが導入されました。名前が存在しない場合は、これらのメソッドは空の名前リスト/空の名前を返すことがあります。
ov_model_input = model.input(original_fw_in_tensor_name)
ov_model_output = model.output(original_fw_out_tensor_name)
auto ov_model_input = ov_model->input(original_fw_in_tensor_name);
auto ov_model_output = ov_model->output(original_fw_out_tensor_name);
OpenVINO™ ランタイムでモデルを構築する方法の詳細については、OpenVINO ランタイムでモデルをビルドを参照してください。
OpenVINO™ ランタイムのモデル表現は、特別なクラスを使用してモデルのデータタイプと形状を操作します。ov::element::Type
はデータタイプに使用されます。
ov_input.get_element_type()
ov_input->get_element_type();
形状の表現#
OpenVINO™ ランタイムは、形状表現に 2 つのタイプを提供します:
ov::Shape
- 静的な (完全に定義された) 形状を表現します。ov::PartialShape
- 動的な形状を表現します。これは、ランクまたは一部の次元が動的であることを意味します (次元は間隔を定義するか未定義です)。
すべての次元が静的である場合、ov::PartialShape
は get_shape()
メソッドを使用して ov::Shape
に変換できます。それ以外は、変換で例外がスローされます。次に例を示します:
partial_shape = node.output(0).get_partial_shape() # 出力がゼロ
if not partial_shape.is_dynamic: # または partial_shape.is_static になるの部分形状を取得
static_shape = partial_shape.get_shape()
ov::Shape static_shape;
ov::PartialShape partial_shape = node->output(0).get_partial_shape(); // 出力がゼロ
if (!partial_shape.is_dynamic() /* または partial_shape.is_static() になるの部分形状を取得 */) {
static_shape = partial_shape.get_shape();
}
ただし、ほとんどの場合、get_shape()
メソッドで静的な形状を取得する前に、その形状が静的であるかどうか確認する必要があります。
操作の表現#
ov::Op
クラスは、モデル表現内の抽象的な操作を表します。このクラスを使用してカスタム操作を作成します。
操作セットの表現#
操作セット (opset) は、モデルの構築に使用できる操作のコレクションです。ov::OpSet
クラスは、操作セットを操作する機能を提供します。OpenVINO™ ランタイムは、操作セットごとに、opset8
など個別の名前空間を提供します。
OpenVINO™ の各リリースでは、新しい操作が導入され、新しい操作セットに追加されます。新しい操作によって以前の操作の動作が変更されます。操作セットを使用すると、新しい操作が導入されたときにアプリケーションを変更する必要はありません。OpenVINO™ ツールキットでサポートされている操作セットの完全なリストについては、利用可能な操作セットを参照してください。カスタム操作のサポートを追加するには、OpenVINO 拡張メカニズムを参照してください。
OpenVINO™ ランタイムでモデルをビルド#
ソースからモデルを作成できます。このセクションでは、利用可能な操作セットから操作で構成されるモデルを構築する方法を説明します。
操作セット opsetX
は、この目的のため機能する事前コンパイルされた操作のリストを統合します。言い換えれば、opsetX
はグラフを構築する一連の操作を定義します。
opset8
操作から ov::Model
インスタンスを構築するには、次のファイルをインクルードします:
import openvino as ov
#include <openvino/core/model.hpp>
#include <openvino/opsets/opset8.hpp>
次のコードは、単純なモデルを作成する方法を示します:
def create_simple_model(): # この例は ov::Function を作成方法を示しています。
#
# Parameter--->Multiply--->Add--->Result
# Constant---’ /
# Constant---’
data = ops.parameter([3, 1, 2], ov.Type.f32)
mul_constant = ops.constant([1.5], ov.Type.f32)
mul = ops.multiply(data, mul_constant)
add_constant = ops.constant([0.5], ov.Type.f32)
add = ops.add(mul, add_constant)
res = ops.result(add)
return ov.Model([res], [data], "model")
std::shared_ptr<ov::Model> create_simple_model() {
// この例では ov::Model を作成する方法を示します
//
// Parameter--->Multiply--->Add--->Result
// Constant---' /
// Constant---’
// 静的シェイプで opset8::Parameter 操作を作成
auto data = std::make_shared<ov::opset8::Parameter>(ov::element::f32, ov::Shape{3, 1, 2});
auto mul_constant = ov::opset8::Constant::create(ov::element::f32, ov::Shape{1}, {1.5});
auto mul = std::make_shared<ov::opset8::Multiply>(data, mul_constant);
auto add_constant = ov::opset8::Constant::create(ov::element::f32, ov::Shape{1}, {0.5});
auto add = std::make_shared<ov::opset8::Add>(mul, add_constant);
// opset8::Result 操作を作成
auto res = std::make_shared<ov::opset8::Result>(mul);
// OpenVINO 関数を作成
return std::make_shared<ov::Model>(ov::ResultVector{res}, ov::ParameterVector{data}); }
次のコードは、複数の出力を持つモデルを作成します:
def create_advanced_model(): # マルチ出力操作の高度な例
#
# Parameter->Split---0-->Result
# | `--1-->Relu-->Result
# `----2-->Result
data = ops.parameter(ov.Shape([1, 3, 64, 64]), ov.Type.f32)
# axis の値の定数を作成する
axis_const = ops.constant(1, dtype=ov.Type.i64)
# 入力を 1 次元にわたって 3 つのスライスに分割する opset12::Split 操作を作成
split = ops.split(data, axis_const, 3)
# 1 番目の Split 出力を入力として受け取る opset12::Relu 操作を作成
relu = ops.relu(split.output(1))
# 結果操作は、提供された OutputVector に基づいて自動的に作成されます
return ov.Model([split.output(0), relu.output(0), split.output(2)], [data], "model")
std::shared_ptr<ov::Model> create_advanced_model() {
// マルチ出力操作の高度な例
//
// Parameter->Split---0-->Result
// | `--1-->Relu-->Result
// `----2-->Result
auto data = std::make_shared<ov::opset8::Parameter>(ov::element::f32, ov::Shape{1, 3, 64, 64});
// axis の値の定数を作成
auto axis_const = ov::opset8::Constant::create(ov::element::i64, ov::Shape{} /*scalar shape*/, {1});
// 入力を 1 次元にわたって 3 つのスライスに分割する opset8::Split 操作を作成
auto split = std::make_shared<ov::opset8::Split>(data, axis_const, 3);
// 1 番目の Split 出力を入力として受け取る opset8::Relu 操作を作成
auto relu = std::make_shared<ov::opset8::Relu>(split->output(1) /*specify explicit output*/);
// 結果操作は、提供された OutputVector に基づいて自動的に作成されます
return std::make_shared<ov::Model>(ov::OutputVector{split->output(0), relu, split->output(2)}, ov::ParameterVector{data});
}
モデルのデバッグ機能#
OpenVINO™ はいくつかのデバッグ機能を提供します。
適用されたモデルの変更に関する追加メッセージを受信するには、
-DENABLE_OPENVINO_DEBUG=ON
オプションを使用して OpenVINO™ ランタイム・ライブラリーを再ビルドします。モデルは xDot 形式の画像に視覚化できます:
def visualize_example(m : ov.Model):
# インポートが必要:
# * import openvino.runtime.passes as passes
pass_manager = passes.Manager()
pass_manager.register_pass(passes.VisualizeTree(file_name='image.svg'))
pass_manager.run_passes(m)
void visualize_example(const std::shared_ptr<ov::Model>& m) {
// インポートが必要:
// * openvino/pass/manager.hpp
// * openvino/pass/visualize_tree.hpp
ov::pass::Manager manager;
// 変換前に ov::Model を before.svg ファイルにシリアル化
manager.register_pass<ov::pass::VisualizeTree>("image.svg");
manager.run_passes(m);
}
`ov::pass::VisualizeTree` can be parametrized via environment variables: OV_VISUALIZE_TREE_OUTPUT_SHAPES=1 - visualize shapes
OV_VISUALIZE_TREE_OUTPUT_TYPES=1 - visualize types
OV_VISUALIZE_TREE_MIN_MAX_DENORMAL=1 - pretty denormal values
OV_VISUALIZE_TREE_RUNTIME_INFO=1 - print runtime information
OV_VISUALIZE_TREE_IO=1 - print I/O ports
OV_VISUALIZE_TREE_MEMBERS_NAME=1 - print member names
モデルを IR にシリアル化することもできます:
def serialize_example(m :
ov.Model): ov.serialize(m, xml_path='model.xml', bin_path='model.bin')
void serialize_example(const std::shared_ptr<ov::Model>& model) {
ov::serialize(model, "/path/to/file/model.xml", "/path/to/file/model.bin");
}