OpenVINO 拡張メカニズム

インテル® ディストリビューションの OpenVINO™ ツールキットは、TensorFlow、PyTorch、ONNX、TensorFlow Lite、PaddlePaddle などのフレームワークでトレーニングされたニューラル・ネットワーク・モデルをサポートします。サポートされる操作のリストは、フレームワークごとに異なります。フレームワークでサポートされている操作を確認するには、サポートされるフレームワーク操作を参照してください。

リストに含まれていないカスタム操作は、そのままでは OpenVINO で認識されません。カスタム操作が必要になるのは次の 2 つの場合です。

  1. 新しい、またはほとんど使用されない通常のフレームワーク操作は、OpenVINO ではまだサポートされていません。

  2. モデルの作成者によって、フレームワーク拡張機能を使用して特定のモデルトポロジーに対して作成された新しいユーザー操作。

このような操作でモデルをインポートするには、追加の手順が必要です。このガイドでは、カスタム操作を備えたモデルで推論を実行するワークフローを説明します。これにより、独自の実装をプラグインできるようになります。OpenVINO 拡張機能 API を使用すると、これらのカスタム操作のサポートを追加して、モデル・オプティマイザーと OpenVINO ランタイムで 1 つの実装を使用できます。

新しいカスタム操作の定義は、2 つの部分で構成されます。

  1. OpenVINO の操作セマンティクスの定義。操作が入力テンソルを消費して出力テンソルを生成する方法を定義するコードです。GPU の実行カーネルの実装については、別のガイドで説明されています。

  2. フレームワーク操作表現の OpenVINO 定義操作セマンティクスへの変換を容易にするマッピング・ルールの定義。

1 つ目は推論に必要です。2 つ目は、該当する操作を含むモデルを元のフレームワーク・モデル形式から正常にインポートするために必要です。それぞれを実装するにはいくつかのオプションがあります。次のセクションで詳しく説明します。

操作セマンティクスの定義

カスタム操作が既存の OpenVINO 操作の組み合わせ数学的に表現でき、この分解によって期待するパフォーマンスが得られる場合、低レベルの操作を実装する必要ありません。このような分解が実現できるか判断する場合、最新の OpenVINO 操作セットを参照してください。有効であるどのような終了操作の組み合わせでも使用できます。このドキュメントの次のセクションでは、カスタム操作をマップする方法について説明します。

このような分解が不可能な場合、またはうまく機能しない多数の構成操作があると思われる場合は、カスタム操作ガイドの説明に従って、カスタム操作の新しいクラスを実装する必要があります。

操作カーネルの汎用 C++ 実装がすでにある場合、カスタム操作クラスを実装することを推奨します。それ以外の場合は、前述のように最初に操作を分解してみてください。次に、推論の正確性と結果として得られるパフォーマンスを検証した後、ベアメタル C++ のオプション実装に進むことができます。

フレームワーク操作からのマッピング

カスタム操作のマッピングは、インポートで使用されるモデル形式よって異なる方法で実装されます。モデルが ONNX (ONNX の PyTorch からエクスポートされたモデルを含む)、TensorFlow Lite、PaddlePaddle、または TensorFlow 形式で表される場合、フロントエンド拡張 API のクラスの 1 つを使用する必要があります。これは、C++ で利用可能ないくつかのクラスで構成されており、モデル・オプティマイザーの --extensions オプションとともに使用するか、read_model メソッドを使用してモデルを OpenVINO ランタイムに直接インポートするときに使用できます。Python API はランタイム・モデルのインポートにも使用できます。

新しい ONNX、PaddlePaddle、TensorFlow Lite、または TensorFlow フロントエンドの拡張機能を実装しており、モデル変換にモデル・オプティマイザーの --extensions オプションを使用する予定がある場合、拡張機能は次のようになります。

  1. C++ のみで実装されます。

  2. 別の共有ライブラリーとしてコンパイルされます (この詳細についてはガイドを参照してください)。

モデル・オプティマイザーは、Python API で作成された新しいフロントエンド拡張機能をサポートしていません。

このガイドの残りのセクションでは、新しいフロントエンドのフロントエンド拡張 API のアプリケーションについて説明します。

拡張機能の登録

OpenVINO ランタイムで使用できるように、カスタム操作クラスと新しいマッピング・フロントエンド拡張クラスのオブジェクトを登録する必要があります。

このドキュメントは、拡張機能の開発の詳細を示すテンプレート拡張機能から派生したものです。これは、実際のカスタム操作のプレースホルダーである最小限の Identity 操作に基づいています。コンパイル可能な完全なコードをレビューして、それがどのように機能するかを確認します。

ov::Core::add_extension メソッドを使用して、拡張機能を ov::Core オブジェクトにロードします。このメソッドを使用すると、拡張機能を含むライブラリーやコードから拡張機能をロードすることができます。

拡張機能をコアにロード

拡張機能は、ov::Core::add_extension メソッドを使用してコードからロードできます。

# Not implemented
ov::Core core;

// Use operation type to add operation extension
core.add_extension<TemplateExtension::Identity>();

// or you can add operation extension object which is equivalent form
core.add_extension(ov::OpExtension<TemplateExtension::Identity>());

Identity は、カスタム操作ガイドで定義されているカスタム操作クラスです。これは、モデル・オプティマイザーによって発行された ID 拡張操作を使用する OpenVINO IR の読み取りを有効にするのに十分です。元のモデルをランタイムに直接ロードするには、マッピング拡張機能を追加します。

# Not implemented
// Register mapping for new frontends: FW's "TemplateIdentity" operation to TemplateExtension::Identity
core.add_extension(ov::frontend::OpExtension<TemplateExtension::Identity>("Identity"));

// Register more sophisticated mapping with decomposition
core.add_extension(ov::frontend::ConversionExtension(
    "Identity",
    [](const ov::frontend::NodeContext& context) {
        // Arbitrary decomposition code here
        // Return a vector of operation outputs
        return ov::OutputVector{ std::make_shared<TemplateExtension::Identity>(context.get_input(0)) };
    }));

Python API を使用する場合、カスタム OpenVINO 操作を実装する方法はありません。カスタム OpenVINO 操作が C++ で実装され、共有ライブラリーによってランタイムにロードされたとしても、このカスタム操作を参照するフロントエンドのマッピング拡張機能を追加する方法はまだありません。この場合、C++ 共有ライブラリーによるアプローチを使用して、操作セマンティクスとフレームワーク・マッピングの両方を実装します。

標準の OpenVINO 操作セットの操作のみが使用される場合でも、Python を使用して操作をマッピングおよび分解できます。

拡張機能を備えたライブラリーを作成

次の場合は拡張ライブラリーを作成する必要があります。

  • モデル・オプティマイザーのカスタム操作によるモデルの変換。

  • Python アプリケーションのカスタム操作を含むモデルの読み込み。これは、フレームワーク・モデルと OpenVINO IR の両方に当てはまります。

  • ライブラリーから拡張機能の読み込み (benchmark_app など) をサポートするツールで、カスタム操作を使用してモデルを読み込みます。

拡張ライブラリーを作成するには (例えば拡張機能をモデル・オプティマイザーにロードする)、次の手順を実行します。

  1. 拡張ライブラリーのエントリーポイントを作成します。OpenVINO は、OPENVINO_CREATE_EXTENSIONS() マクロを提供します。これにより、OpenVINO 拡張機能を使用してライブラリーへのエントリーポイントを定義できます。このマクロには、引数としてすべての OpenVINO 拡張機能のベクトルが必要です。

    これによる拡張クラスの宣言は次のようになります。

    OPENVINO_CREATE_EXTENSIONS(
        std::vector<ov::Extension::Ptr>({
    
            // Register operation itself, required to be read from IR
            std::make_shared<ov::OpExtension<TemplateExtension::Identity>>(),
    
            // Register operaton mapping, required when converted from framework model format
            std::make_shared<ov::frontend::OpExtension<TemplateExtension::Identity>>()
        }));
    
  2. 次の CMake スクリプトを使用して、拡張ライブラリーのビルドを構成します。

    set(CMAKE_CXX_STANDARD 11)
    
    set(TARGET_NAME "openvino_template_extension")
    
    find_package(OpenVINO REQUIRED)
    
    set(SRC identity.cpp ov_extension.cpp)
    
    add_library(${TARGET_NAME} MODULE ${SRC})
    
    target_link_libraries(${TARGET_NAME} PRIVATE openvino::runtime)
    

    この CMake スクリプトは、find_package コマンドを使用して OpenVINO を検索します。

  3. 以下のコマンドを実行して、拡張ライブラリーをビルドします。

    $ cd src/core/template_extension/new
    $ mkdir build
    $ cd build
    $ cmake -DOpenVINO_DIR=<OpenVINO_DIR> ../
    $ cmake --build .
    
  4. ビルド後、拡張ライブラリーへのパスを使用して、拡張機能を OpenVINO ランタイムにロードできます。

    core = ov.Core()
    # Load extensions library to ov.Core
    core.add_extension(path_to_extension_lib)
    
    ov::Core core;
    // Load extensions library to ov::Core
    core.add_extension("openvino_template_extension.so");