[従来] モデル・オプティマイザーの操作

危険

ここで説明されているコードは非推奨になりました。従来のソリューションの適用を避けるため使用しないでください。下位互換性を確保するためにしばらく保持されますが、最新のアプリケーションでは使用してはなりません

このガイドでは、非推奨である TensorFlow 変換方法について説明します。新しい推奨方法に関するガイドは、フロントエンド拡張に記載されています。

モデル・オプティマイザーは、使用する操作の基本クラスである mo.ops.Op クラス (Op はドキュメントの後半で使用) を定義します。Op クラスのインスタンスは、次のようないくつかの目的を持ちます。

  1. 操作属性を格納します。

  2. 操作の形状/値とタイプ推論関数を格納します。

  3. 対応する IR セクションに保存される操作属性を定義します。

  4. Op オブジェクトのインスタンスからグラフノードを作成して、既存のグラフに接続する便利なメソッドが含まれています。

  5. 解析された属性と操作固有の属性を専用のグラフノードに保存するためエクストラクターで使用されます。

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):
    # The class attribute defines a name of the operation so the operation class can be obtained using the
    # "Op.get_op_class_by_name()" static method
    op = 'SoftMax'

    # The operation works as an extractor by default. This is a legacy behavior, currently not recommended for use,
    # thus "enabled" class attribute is set to False. The recommended approach is to use dedicated extractor extension.
    enabled = False

    def __init__(self, graph: Graph, attrs: dict):
        super().__init__(graph, {  # The constructor of the base class Op is called with additional default attributes.
            'type': __class__.op,  # The operation is from the opset so the type is set to 'SoftMax'.
            'op': __class__.op,  # Internal Model Optimizer operation has the same type.
            'version': 'opset1',  # The operation corresponds to opset1.
            'infer': Softmax.infer,  # Shape inference function is defined below.
            'axis': 1,  # Default value for the "axis" attribute of the operation SoftMax.
            'in_ports_count': 1,  # The operation has one input.
            'out_ports_count': 1,  # The operation produces one output.
        }, attrs)

    # The method returns operation specific attributes list. This method is important when implementing
    # extractor inherited from CaffePythonFrontExtractorOp class to extract attribute for Caffe Python operation.
    # However, it is currently used interchangeably with the "backend_attrs()" method. If the "backend_attrs()" is not used,
    # then the "supported_attrs()" is used instead. In this particular case, the operation has just one attribute "axis".
    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() 関数はレコードのリストを返します。レコードは次のいずれかの形式になります。

  1. IR に保存される属性を定義する文字列。属性の値が None の場合、属性は保存されません。このケースの例として、rounding_typeauto_pad があります。

  2. 最初の要素が IR に出現する属性の名前を定義する文字列で、2 番目の要素がこの属性の値を生成する関数のタプル。この関数は、唯一のパラメーターとしてノードのインスタンスを取得し、IR に保存される値を含む文字列を返します。このケースの例として、strideskernelpads_begin および pads_end があります。

  3. 最初の要素が IR に出現する属性の名前を定義する文字列で、2 番目の要素が値を取得するノード属性の名前のタプル。このケースの例として、pool-methodexclude-pad があります。