[従来] モデル・オプティマイザーの操作#
危険
ここで説明されているコードは非推奨になりました。従来のソリューションの適用を避けるため使用しないでください。下位互換性を確保するためにしばらく保持されますが、最新のアプリケーションでは使用してはなりません。
このガイドでは、非推奨である TensorFlow 変換方法について説明します。新しい推奨方法に関するガイドは、フロントエンド拡張に記載されています。
モデル・オプティマイザーは、使用する操作の基本クラスである mo.ops.Op
クラス (Op
はドキュメントの後半で使用) を定義します。Op
クラスのインスタンスは、次のようないくつかの目的を持ちます:
操作属性を格納します。
操作の形状/値とタイプ推論関数を格納します。
対応する IR セクションに保存される操作属性を定義します。
Op
オブジェクトのインスタンスからグラフノードを作成して、既存のグラフに接続する便利なメソッドが含まれています。解析された属性と操作固有の属性を専用のグラフノードに保存するためエクストラクターで使用されます。
Op
クラスのインスタンスと、そこから作成された Node
オブジェクト間には接続がないことが重要です。Op
クラスは、操作を記述する属性のコンテナにすぎません。モデル・オプティマイザーは、モデル変換中に Op
クラスを使用して、Op
クラスのインスタンスからコピーされた属性を持つグラフのノードを作成します。グラフ操作はグラフ Nodes
とその属性を使用して実行され、Ops
は関与しません。
操作で使用される共通の属性が多数あります。操作で使用される共通のプロパティーが多数あります。
id
— (必須) — グラフ内のノードの一意の識別子。指定されていない場合は、グラフ内のノードの数に 1 を加えた値が自動的に生成されます。name
— (必須) — 操作名。自動的に生成され、指定されない場合はid
と同じになります。type
— (必須) — opset 仕様に従った操作のタイプ。内部モデル・オプティマイザー操作の場合、この属性はNone
に設定する必要があります。None
に等しいタイプの操作が IR エミットフェーズになると、モデル変換は失敗します。version
— (必須) — 操作が属する操作セット (opset) 名。指定されない場合、モデル・オプティマイザーは実験的な値に設定します。操作セットの詳細については、OpenVINO モデル表現を参照してください。op
— モデル・オプティマイザーの操作のタイプ。多くの場合、type
の値はop
の値と同じです。ただし、モデル・オプティマイザーがモデルの読み込み中に opset 操作をインスタンス化できない場合は、内部操作のインスタンスが作成されます。したがって、この内部操作のタイプとして属性op
が使用されます。パイプラインの後半で、内部操作から作成されたノードは、フロントフェーズ、ミドルフェーズ、またはバックフェーズ中に、opset から作成されたノードに置き換えられます。infer
— この属性は、出力テンソルの形状とオプションの値を計算する関数を定義します。この属性は、フロントフェーズ中にのみ使用される内部モデル・オプティマイザー操作に対してNone
に設定できます。形状推論関数の詳細については、部分推論を参照してください。type_infer
— この属性は、出力テンソルのデータタイプを計算する関数を定義します。属性が省略されるとデフォルト関数が使用されます。この関数は、data_type
ノード属性が設定されているか確認し、このタイプをポート 0 から出力テンソルに伝播します。それ以外の場合、入力ポート 0 に入るテンソルのデータタイプをポート 0 から出力テンソルに伝播します。in_ports_count
— 操作用に作成される入力ポートのデフォルトの数。専用のNode
クラス API メソッドを使用して、ポートを追加したり、冗長ポートを削除したりできます。out_ports_count
— 操作用に作成される出力ポートのデフォルトの数。専用のNode
クラス API メソッドを使用して、ポートを追加したり、冗長ポートを削除したりできます。
以下は、コード内のコメントと、mo/ops/softmax.py
ファイルの SoftMax 操作のモデル・オプティマイザー・クラスの例です。
class Softmax(Op): # クラス属性は操作の名前を定義するので、操作クラスは
# "Op.get_op_class_by_name()" 静的メソッドを使用して取得できます。
op = 'SoftMax’
# この操作は、デフォルトで抽出機能として機能します。これは従来の動作であり、現在は使用が推奨されていないため、
# "enabled" クラス属性は False に設定されています。推奨される方法は、専用の抽出拡張機能を使用することです。
enabled = False
def __init__(self, graph: Graph, attrs: dict):
super().__init__(graph, { # 基本クラス Op のコンストラクターは、追加のデフォルト属性を使用して呼び出されます。 'type': __class__.op, # 操作は opset からのものであるため、タイプは 'SoftMax' に設定されます。 'op': __class__.op, # 内部モデルのティマイザー操作は同じタイプです。 'version': 'opset1', # 操作は opset1 に対応します。 'infer': Softmax.infer, # 形状推定関数は以下のように定義されます。 'axis': 1, # SoftMax 操作の "axis" 属性のデフォルト値。 'in_ports_count': 1, # 操作には 1 つの入力があります。 'out_ports_count': 1, # この操作により 1 つの出力が生成されます。 }, attrs)
# このメソッドは、操作固有の属性リストを返します。このメソッドは、Caffe Python 操作の属性を抽出するため
# CaffePythonFrontExtractorOp クラスから継承された抽出機能を実装するときに重要です。# ただし、現在は "backend_attrs()" メソッドと互換的に使用されています。"backend_attrs()" が使用されない場合は、
# 代わりに "supported_attrs()" が使用されます。この特定のケースでは、操作には属性 "axis" が 1 つだけあります。
def supported_attrs(self):
return ['axis']
@staticmethod
def infer(node: Node): "some code calculating output shape and values"
IR に保存する属性のリストを定義する backend_attrs()
専用のメソッドがあります。mo/ops/pooling.py
ファイルの例を考えてみます:
def backend_attrs(self):
return [
('strides', lambda node: ','.join(map(str, node['stride'][node.spatial_dims]))),
('kernel', lambda node: ','.join(map(str, node['window'][node.spatial_dims]))),
('pads_begin', lambda node: ','.join(map(str, get_backend_pad(node.pad, node.spatial_dims, 0)))),
('pads_end', lambda node: ','.join(map(str, get_backend_pad(node.pad, node.spatial_dims, 1)))),
('pool-method', 'pool_method'), ('exclude-pad', 'exclude_pad'), 'rounding_type', 'auto_pad',
]
backend_attrs()
関数はレコードのリストを返します。レコードは次のいずれかの形式になります。
IR に保存される属性を定義する文字列。属性の値が
None
の場合、属性は保存されません。このケースの例として、rounding_type
とauto_pad
があります。最初の要素が IR に出現する属性の名前を定義する文字列で、2 番目の要素がこの属性の値を生成する関数のタプル。この関数は、唯一のパラメーターとして
Node
のインスタンスを取得し、IR に保存される値を含む文字列を返します。このケースの例として、strides
、kernel
、pads_begin
およびpads_end
があります。最初の要素が IR に出現する属性の名前を定義する文字列で、2 番目の要素が値を取得する
Node
属性の名前のタプル。このケースの例として、pool-method
とexclude-pad
があります。