[従来] Caffe Python レイヤーを使用したモデル・オプティマイザーの拡張

危険

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

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

ここでは、Python のみで記述されたカスタム Caffe 操作をサポートする方法について説明します。例えば、Caffe に実装された Faster-R-CNN モデルには、Python で記述されたカスタム提案レイヤーが含まれています。このレイヤーは、Faster-R-CNN prototxt で次のように記述されます。

layer {
  name: 'proposal'
  type: 'Python'
  bottom: 'rpn_cls_prob_reshape'
  bottom: 'rpn_bbox_pred'
  bottom: 'im_info'
  top: 'rois'
  python_param {
    module: 'rpn.proposal_layer'
    layer: 'ProposalLayer'
    param_str: "'feat_stride': 16"
  }
}

ここでは、モデル・オプティマイザーでオペレーターの属性を抽出する方法の手順のみを説明します。パイプラインを有効にする操作の残りと、他の Caffe 操作 (C++ で記述された) をサポートする方法については、モデル・オプティマイザーのカスタマイズ・ガイドで説明されています。

Caffe Python レイヤーのエクストラクターの作成

カスタム Caffe Python レイヤーには、Python と等しい属性 type (操作のタイプを定義) と、python_param 辞書内の 2 つの必須属性 module および layer があります。module はレイヤー実装で Python モジュール名を定義しますが、layer 値はユーザーによって定義された操作タイプです。このような操作の属性を抽出するには、標準フレームワーク・レイヤーに使用される FrontExtractorOp クラスの代わりに、CaffePythonFrontExtractorOp クラスから継承したエクストラクター・クラスを実装する必要があります。op クラスの属性値は module + "." + layer に設定する必要があります。これにより、この種の操作に対してエクストラクターがトリガーされます。

以下は、前述の Faster-R-CNN モデルからのカスタム操作のエクストラクターの簡略化された例です。 追加チェックを含む完全なコードはここにあります。

サンプルコードでは、利用可能な操作セットページで説明されている Proposal 操作に対応する操作 ProposalOp を使用します。エクストラクターの詳細な説明については、以下のソースコードを参照してください。

from openvino.tools.mo.ops.proposal import ProposalOp
from openvino.tools.mo.front.extractor import CaffePythonFrontExtractorOp


class ProposalPythonFrontExtractor(CaffePythonFrontExtractorOp):
    op = 'rpn.proposal_layer.ProposalLayer'  # module + "." + layer
    enabled = True  # extractor is enabled

    @staticmethod
    def extract_proposal_params(node, defaults):
        param = node.pb.python_param  # get the protobuf message representation of the layer attributes
        # parse attributes from the layer protobuf message to a Python dictionary
        attrs = CaffePythonFrontExtractorOp.parse_param_str(param.param_str)
        update_attrs = defaults

        # the operation expects ratio and scale values to be called "ratio" and "scale" while Caffe uses different names
        if 'ratios' in attrs:
            attrs['ratio'] = attrs['ratios']
            del attrs['ratios']
        if 'scales' in attrs:
            attrs['scale'] = attrs['scales']
            del attrs['scales']

        update_attrs.update(attrs)
        ProposalOp.update_node_stat(node, update_attrs)  # update the node attributes

    @classmethod
    def extract(cls, node):
        # define default values for the Proposal layer attributes
        defaults = {
            'feat_stride': 16,
            'base_size': 16,
            'min_size': 16,
            'ratio': [0.5, 1, 2],
            'scale': [8, 16, 32],
            'pre_nms_topn': 6000,
            'post_nms_topn': 300,
            'nms_thresh': 0.7
        }
        cls.extract_proposal_params(node, defaults)
        return cls.enabled