モデル・アンサンブル・パイプラインのデモ#

このガイドでは、DAG スケジューラーを使用してモデル・アンサンブルを実装する方法を説明します。

  • 画像分類を実行するアプリケーションを開発することを前提としています。このタスクに使用できるさまざまなモデルが多数あります。目標は、2 つの異なるモデルで実行された推論の結果を結合し、argmax を計算して最も可能性の高い分類ラベルを選択することです。

  • このタスクでは、googlenet-v2resnet-50 の 2 つのモデルを選択します。さらに、独自モデル argmax を作成して、上位の結果を組み合わせて選択します。それはネットワーク経由で中間結果を渡さずに、このタスクをサーバー側で実行するためです。サーバーは、後続のモデルへの入力/出力の供給を処理する必要があります。googlenet 予測と resnet 予測は並行して実行する必要があります。

  • このパイプラインは次のようになります:

図

ステップ 1: リポジトリーの準備#

リポジトリーのクローンを作成し、model_ensemble ディレクトリーに移動します。

git clone https://github.com/openvinotoolkit/model_server.git 
cd model_server/demos/model_ensemble/python

リポジトリーの準備は make スクリプトを使用することで簡素化され、このリポジトリーで make を実行するだけです。

make

Makefile の手順は次のとおりです:

  1. Open Model Zoo からモデルをダウンロードして使用します。

  2. このリポジトリーにある python スクリプトを使用します。tensorflow を使用して保存されたモデル形式でモデルを作成するには、tensorflow pip パッケージが必要です。

  3. googlenet および resnet の出力形状の出力と一致するように、(1, 1001) の入力形状を持つ argmax モデルを準備します。生成されたモデルは入力を合計し、最も高値のインデックスを計算します。モデルの出力には、ImageNet* データセットから最も可能性の高い予測クラスが示されます。

  4. モデルを IR 形式に変換し、モデル・リポジトリーを準備します。

... 
models 
├── argmax 
│   └── 1 ├── saved_model.bin 
│       ├── saved_model.mapping 
│       └── saved_model.xml 
├── config.json 
├── googlenet-v2-tf 
│   └── 1 ├── googlenet-v2-tf.bin 
│       ├── googlenet-v2-tf.mapping 
│       └── googlenet-v2-tf.xml 
└── resnet-50-tf 
    └── 1 
        ├── resnet-50-tf.bin 
        ├── resnet-50-tf.mapping 
        └── resnet-50-tf.xml 

6 directories, 10 files

ステップ 2: 必要なモデルとパイプラインを定義#

パイプラインを使用するには、構成ファイルでパイプラインを定義する必要があります。同じ構成ファイルを使用して、提供されるモデルと提供されるパイプラインを定義します。

ここにある config.json を使用します。内容は次のとおりです:

cat config.json 
{ 
    "model_config_list": [ 
        { 
            "config": { 
                "name": "googlenet", 
                "base_path": "/models/googlenet-v2-tf" 
            } 
        }, 
        { 
            "config": { 
                "name": "resnet", 
                "base_path": "/models/resnet-50-tf" 
            } 
        }, 
        { 
            "config": { 
                "name": "argmax", 
                "base_path": "/models/argmax" 
            } 
        } 
    ], 
    "pipeline_config_list": [ 
        { 
            "name": "image_classification_pipeline", 
            "inputs": ["image"], 
            "nodes": [ 
                { 
                    "name": "googlenet_node", 
                    "model_name": "googlenet", 
                    "type": "DL model", 
                    "inputs": [ 
                        {"input": {"node_name": "request", 
                                       "data_item": "image"}} 
                    ], 
                    "outputs": [ 
                        {"data_item": "InceptionV2/Predictions/Softmax",
                         "alias": "probability"} 
                   ] 
            }, 
            { 
                "name": "resnet_node", 
                "model_name": "resnet", 
                "type": "DL model", 
                "inputs": [ 
                    {"map/TensorArrayStack/TensorArrayGatherV3": {"node_name": "request", 
                                                     "data_item": "image"}} 
                ], 
                "outputs": [ 
                    {"data_item": "softmax_tensor", 
                     "alias": "probability"} 
                ] 
            }, 
            { 
                "name": "argmax_node", 
                "model_name": "argmax", 
                "type": "DL model", 
                "inputs": [ 
                    {"input1": {"node_name": "googlenet_node", 
                                "data_item": "probability"}}, 
                    {"input2": {"node_name": "resnet_node", 
                                "data_item": "probability"}} 
                ], 
                "outputs": [ 
                    {"data_item": "argmax:0", 
                     "alias": "most_probable_label"} 
                ] 
            } 
        ], 
        "outputs": [ 
            {"label": {"node_name": "argmax_node", 
                        "data_item": "most_probable_label"}} 
        ] 
    } 
] 
}

model_config_list セクションでは、3 つのモデルが定義されています。パイプライン定義では名前参照できますが、それらに対する単一の推論を個別に要求することもできます。モデルとパイプラインの要求には、同じ推論 gRPC と REST API が使用されます。OpenVINO™ モデルサーバーは、まず、要求された名前を持つモデルを検索します。見つからない場合はパイプラインを検索します。

ステップ 3: モデルサーバーの開始#

コマンドを実行してモデルサーバーを起動します

docker run --rm -v $(pwd)/models/:/models:ro -p 9100:9100 -p 8100:8100 openvino/model_server:latest --config_path /models/config.json --port 9100 --rest_port 8100 --log_level DEBUG

ステップ 4: サービスの要求#

入力画像は、リソース名 image_classification_pipeline を要求するサービスに送信できます。以下にクライアントの例を示します:

別の端末でクライアントを実行して、パイプラインの精度を確認します:

cd ../../../client/python/tensorflow-serving-api/samples 
virtualenv .venv ..venv/bin/activate && pip3 install -r requirements.txt 
python3 grpc_predict_resnet.py --pipeline_name image_classification_pipeline --images_numpy_path ../../imgs.npy \ 
    --labels_numpy_path ../../lbs.npy --grpc_port 9100 --input_name image --output_name label --transpose_input True --transpose_method nchw2nhwc --iterations 10 
Image data range: 0.0 : 255.0 
Start processing: 
        Model name: image_classification_pipeline 
        Iterations: 10 
        Images numpy path: ../../imgs.npy 
        Numpy file shape: (10, 224, 224, 3) 

Iteration 1; Processing time: 33.51 ms; speed 29.85 fps 
imagenet top results in a single batch: 
response shape (1,) 
         0 airliner 404 ; Correct match.
Iteration 2; Processing time: 42.52 ms; speed 23.52 fps 
imagenet top results in a single batch: 
response shape (1,) 
         0 Arctic fox, white fox, Alopex lagopus 279 ; Correct match.
Iteration 3; Processing time: 34.42 ms; speed 29.05 fps 
imagenet top results in a single batch: 
response shape (1,) 
         0 bee 309 ; Correct match.
Iteration 4; Processing time: 32.34 ms; speed 30.92 fps 
imagenet top results in a single batch: 
response shape (1,) 
         0 golden retriever 207 ; Correct match.
Iteration 5; Processing time: 35.92 ms; speed 27.84 fps 
imagenet top results in a single batch: 
response shape (1,) 
         0 gorilla, Gorilla gorilla 366 ; Correct match.
Iteration 6; Processing time: 33.63 ms; speed 29.74 fps 
imagenet top results in a single batch: 
response shape (1,) 
         0 magnetic compass 635 ; Correct match.
Iteration 7; Processing time: 37.22 ms; speed 26.86 fps 
imagenet top results in a single batch: 
response shape (1,) 
         0 peacock 84 ; Correct match.
Iteration 8; Processing time: 35.84 ms; speed 27.90 fps 
imagenet top results in a single batch: 
response shape (1,) 
         0 pelican 144 ; Correct match.
Iteration 9; Processing time: 33.69 ms; speed 29.68 fps 
imagenet top results in a single batch: 
response shape (1,) 
         0 snail 113 ; Correct match.
Iteration 10; Processing time: 46.54 ms; speed 21.49 fps 
imagenet top results in a single batch: 
response shape (1,) 
         0 zebra 340 ; Correct match. 

processing time for all iterations 
average time: 36.00 ms; average speed: 27.78 fps 
median time: 34.50 ms; median speed: 28.99 fps 
max time: 46.00 ms; min speed: 21.74 fps 
min time: 32.00 ms; max speed: 31.25 fps 
time percentile 90: 42.40 ms; speed percentile 90: 23.58 fps 
time percentile 50: 34.50 ms; speed percentile 50: 28.99 fps 
time standard deviation: 4.31 
time variance: 18.60 
Classification accuracy: 100.00

ステップ 5: サーバーログ内のパイプライン実行を分析#

デバッグログとタイムスタンプを分析すると、GoogleNet と ResNet のモデル推論が並行して開始されたことがわかります。すべての入力の準備が整い、argmax ノードがジョブを開始しました。

docker logs <container_id> 
[2022-02-28 11:30:20.159][485][serving][debug][prediction_service.cpp:69] Processing gRPC request for model: image_classification_pipeline; version: 0 
[2022-02-28 11:30:20.159][485][serving][debug][prediction_service.cpp:80] Requested model: image_classification_pipeline does not exist.Searching for pipeline with that name... 
[2022-02-28 11:30:20.160][485][dag_executor][debug][pipeline.cpp:83] Started execution of pipeline: image_classification_pipeline 
[2022-02-28 11:30:20.160][485][serving][debug][modelmanager.cpp:1280] Requesting model: resnet; version: 0. 
[2022-02-28 11:30:20.160][485][serving][debug][modelmanager.cpp:1280] Requesting model: googlenet; version: 0. 
[2022-02-28 11:30:20.194][485][serving][debug][modelmanager.cpp:1280] Requesting model: argmax; version: 0.

ステップ 6: パイプライン・メタデータの要求#

モデルのメタデータの要求と同じ gRPC/REST サンプル・クライアントを使用できます。唯一の違いは、モデル名の代わりにパイプライン名を指定することです。

python3 grpc_get_model_metadata.py --grpc_port 9100 --model_name image_classification_pipeline 
Getting model metadata for model: image_classification_pipeline 
Inputs metadata: 
        Input name: image; shape: [1, 224, 224, 3]; dtype: DT_FLOAT 
Outputs metadata: 
        Output name: label; shape: [1]; dtype: DT_INT64