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

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

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

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

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

diagram

ステップ 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