DAG での逆多重化

パイプラインの分岐

有向非巡回グラフ (DAG) スケジューラーでは、オプションのパラメーター demultiply_count: N を使用してパイプラインを作成できます。これにより、どのノードでも出力を N 個の個別のサブ出力にスライスし、パイプライン実行を N 個のサブパイプラインに分岐することができます。後続のノードはイベントループによって互いに独立して N 回実行され、応答を送信する直前に結果が収集されて 1 つの出力にパックされます。さらに、gather_from_node: <node_name> パラメーターを使用して、有向非巡回グラフ内の任意のポイントでの収集を指定できます。demultiply_count ノード・パラメーター値は、すべてのノード出力の最初の次元と一致する必要があります。すべてのノード出力は少なくとも 2 次元である必要があります。

基本的なデマルチプレクサーの例とメタデータの説明

この例には、2 つの連続したモデルが含まれています。

  • モデル A は、形状 (1,224,224)、レイアウト NHW、および浮動小数点精度 (後に (1,224,224) FP32 と呼ばれる) を持つ input という名前の 1 つの入力を受け入れ、output_A (3,1,100,100) FP32output_B (3,1,40,130) FP32 の 2 つの出力を生成します。このモデルはデマルチプレクサーとして構成されているため、最初の次元は非常に重要です。これは、config.json 構成ファイルで指定された demultiply_count パラメーターと等しくなければなりません (この場合は 3 に等しい必要があります)。これにより、スケジューラーはすべての出力をより小さなチャンクに分割し (以下の図ではいわゆる逆多重化)、新しいパイプライン分岐を生成できるようになります。

  • モデル B は、input_A (1,100,100) FP32input_B (1,40,130) FP32 の 2 つの入力を受け入れます。逆多重化後 (スライス後に最初の次元が削除された状態で) メタデータが以前のモデル出力とどのように一致するかに注意してください。ほとんどの場合、メタデータを照合することは不可能であるため、OpenVINO™ モデルサーバーでは、出力後処理 (カスタムノード開発) を実行するカスタムノードを作成できます。このモデルは 1 つの出力、output (1,50) FP32 を生成します。

この例では、config.json 構成ファイルに gather_from_node パラメーターが指定されていません。これは、収集 (図に示す) がイベントループ処理の最後に response ノードによって自動的に行われることを意味します。収集 - パイプライン分岐からのすべての結果をパックすると、次元リストの先頭にある出力形状に新しい次元が追加されます。

diagram

1 つのデマルチプレクサーを含む構成ファイルの例 (矢印を含む行の矢印以降をすべて削除):

{
    "model_config_list": [
        {"config": {
            "name": "Model_A",
            "base_path": "/models/model_a"
        }},
        {"config": {
            "name": "Model_B",
            "base_path": "/models/model_b"
        }}
    ],
    "pipeline_config_list": [
        {
            "name": "my_pipeline_with_demultiplexer",
            "inputs": ["pipeline_input_name"],
            "nodes": [
                {
                    "name": "Model_A_node",
                    "model_name": "Model_A",
                    "type": "DL model",
                    "demultiply_count": 3,  <------------------ this parameter specifies how many branches should be spawned
                    "inputs": [
                        {"input": {"node_name": "request",
                                   "data_item": "pipeline_input_name"}}
                    ], 
                    "outputs": [
                        {"data_item": "output_A",
                         "alias": "output_A"},
                        {"data_item": "output_B",
                         "alias": "output_B"}
                    ]
                },
                {
                    "name": "Model_B_node",
                    "model_name": "Model_B",
                    "type": "DL model",
                    "inputs": [
                        {"input_A": {"node_name": "Model_A_node",
                                     "data_item": "output_A"}},
                        {"input_B": {"node_name": "Model_A_node",
                                     "data_item": "output_B"}}
                    ], 
                    "outputs": [
                        {"data_item": "output",
                         "alias": "output"}
                    ]
                }
            ],
            "outputs": [
                {"pipeline_output_name": {"node_name": "Model_B_node",
                                          "data_item": "output"}}
            ]
        }
    ]
}

動的な demultiply_count パラメーター

1 つのカスタム・ノード・ライブラリーを使用して、予測できない数のバッチを生成するユースケースが考えられます。これを実現するには、demultiply_count-1 に設定します。これは、パイプラインがカスタムノードによって返される任意の数のバッチをサポートしていることを示します: (X,N,C,H,W,...) - ここで、X は動的 demultiply_count です。OpenVINO™ モデルサーバーは、このような動的バッチを解釈でき、出力を動的な数のパイプライン分岐に分割できます。動的な demultiply_count パラメーターを使用する場合、パイプライン内に存在できるデマルチプレクサーは 1 つだけです。重要な注意点 - リリース 2021.3 では、バッチ 0 が返されると、パイプラインは実行を停止し、ABORTED ステータスが返されます。これは将来のリリースで変更される可能性があります。

複数のデマルチプレクサー

有向非巡回グラフのスケジューラーは、1 つのパイプライン定義内の 1 つのデマルチプレクサー・ノードに限定されません。gather_from_node パラメーターによって参照されない各デマルチプレクサー・ノードは、response ノードに自動的に収集されます。つまり、各デマルチプレクサーは、すべてのパイプライン出力形状に demultiply_count に等しい 1 つの新しい次元を追加します。クライアント・アプリケーションで応答データを解釈するときは、これを考慮する必要があります。

diagram

構成可能な収集ステップ

OpenVINO™ モデルサーバーは、パイプライン・ノードの実行前にデマルチプレクサーから結果を収集する機能を提供しており、response ノードでの収集に限定されません。この操作では、パイプライン出力形状に新しい次元が追加されません。これにより、ノード入力の収集に新しい次元が追加されます。パイプライン内の任意のデマルチプレクサーから収集するには、gather_from_node: <node_name> パラメーターでノード名を指定します。この機能は、パイプラインがすべての分岐からの応答を収集し、収集された結果に基づいて決定を行う場合に使用します。これは、次の分岐 (逆多重化) の決定ノードになる可能性があります。これにより、中間結果をクライアントに送信することなく、複雑なパイプラインを作成できます。実際の例として、N 個の顔を検出する顔検出モデルを含むパイプラインを作成し、検出された顔ごとに感情認識モデルをセットアップできます。次に、収集ノードを設定することで、スケジューラーは N 個の感情結果を収集でき、元の画像に含まれる人々の感情に応じて次のパイプラインのステップをトリガーできます。

モデル C の実行前に gather_from_node が指定されたパイプラインの例:

diagram

モデル C の実行前に gather_from_node が指定されたパイプラインの構成ファイルの例:

{
    "model_config_list": [
        {"config": {
            "name": "Model_A",
            "base_path": "/models/model_a"
        }},
        {"config": {
            "name": "Model_B",
            "base_path": "/models/model_b"
        }}
    ],
    "pipeline_config_list": [
        {
            "name": "my_pipeline_with_demultiplexer",
            "inputs": ["pipeline_input_name"],
            "nodes": [
                {
                    "name": "Model_A_node",
                    "model_name": "Model_A",
                    "type": "DL model",
                    "demultiply_count": 3,  <----------------- this parameter specifies how many branches should be spawned
                    "inputs": [
                        {"input": {"node_name": "request",
                                   "data_item": "pipeline_input_name"}}
                    ], 
                    "outputs": [
                        {"data_item": "output_A",
                         "alias": "output_A"},
                        {"data_item": "output_B",
                         "alias": "output_B"}
                    ]
                },
                {
                    "name": "Model_B_node",
                    "model_name": "Model_B",
                    "type": "DL model",
                    "inputs": [
                        {"input_A": {"node_name": "Model_A_node",
                                     "data_item": "output_A"}},
                        {"input_B": {"node_name": "Model_A_node",
                                     "data_item": "output_B"}}
                    ], 
                    "outputs": [
                        {"data_item": "output",
                         "alias": "output"}
                    ]
                },
                {
                    "name": "Model_C_node",
                    "model_name": "Model_C",
                    "type": "DL model",
                    "gather_from_node": "Model_A_node",  <----------------- this parameter specifies which node to gather from (must be demultiplexer and in LIFO order)
                    "inputs": [
                        {"input": {"node_name": "Model_B_node",
                                     "data_item": "output"}}
                    ], 
                    "outputs": [
                        {"data_item": "output",
                         "alias": "output"}
                    ]
                }
            ],
            "outputs": [
                {"pipeline_output_name": {"node_name": "Model_C_node",
                                          "data_item": "output"}}
            ]
        }
    ]
}

逆多重化による動的なバッチ処理

逆多重化機能により、モデルを再ロードせずに動的なバッチサイズで要求を処理できます。これは、要求が連続する任意のバッチサイズのワークロードに推奨されます。単一モデルと追加フィールド ‘demultiply_count: -1’ を含むパイプラインを構成することで、要求の逆多重化により動的バッチ機能を使用できます。この機能を利用するには、入力データにバッチサイズを表す追加の先頭次元が必要です。バッチサイズ 1 で元のモデル形状に追加する必要があります。応答には、分割バッチから結合された予測が含まれます。これにより、最初にモデル出力に追加の次元が追加されます。

形状 (1,3,224,224) と N 個の画像を持つ ResNet-50 モデルの入力と出力は以下のようになります。

入力: (N,1,3,224,224) 出力: (N,1,1001)

この追加された次元により、逆多重化の実装は汎用性があり、あらゆる入出力データレイアウトをサポートできます。

この機能の使用例は、動的バッチ・サイズ・ガイドで参照できます。

注: モデル構成で追加パラメーター (‘nireq’ および ‘NUM_STREAMS’) を使用して、動的バッチのパフォーマンスを微調整できます。‘NUM_STREAMS’ により、OpenVINO™ で複数の並列推論処理が可能になり、予測要求のレイテンシーを犠牲にしてスループットを向上できます。‘nireq’ は、準備できる推論要求の数を指定します。

注: CPU とは異なるデバイスを推論に使用している場合、そのデバイスのプラグイン構成パラメーターを確認する必要があります。

パイプライン構成ルール

逆多重化と収集に関して考えられる構成には、いくつかのルールがあります。

  • demultiply_count が指定されたノード (デマルチプレクサー・ノード) からのみ収集できます。

  • 動的な demultiply_count を持つパイプラインで結果が 0 になると、実行は停止され、gRPC/REST 応答がその情報を含むエラーを返します。

  • 動的な demultiply_count を持つパイプラインでは、デマルチプレクサー・ノードは 1 つだけ許可されます。

  • パイプラインに少なくとも 1 つのデマルチプレクサーが含まれる場合、1 より大きい入力バッチでは収集ノードのみが許可されます。

  • デマルチプレクサ・ノードと収集ノードは LIFO 順序である必要があります。つまり、定義された有向非巡回グラフで上流に向かう最も近いデマルチプレクサーからノードを収集する必要があります。

diagram

  • ノード入力は、同じレベルのネストされた逆多重化由来である必要があります。逆多重化レベルを下げるため、gather_from_node パラメーターを使用して任意のステージで結果を収集できます。

diagram