自動バッチ処理#

自動バッチ実行モード (略して自動バッチ) は、ユーザーによるプログラミング作業を伴わずに、推論要求をグループ化することでデバイスの使用率を向上させるため、オンザフライで自動バッチ処理を実行します。自動バッチ処理を使用すると、アプリケーション・コードに影響を与えることなく、バッチに必要な個々の推論要求からの入力の収集と出力の分散が透過的に行われます。

自動バッチ処理は、仮想デバイスとして直接使用することも、CPU/GPU/NPU での推論のオプションとして (構成/ヒントを指定) 使用することもできます。これら 2 つの方法は、ベースとなるロジックはそのままで、ユーザーが BATCH デバイスを明示的または暗黙的に有効にするために用意されています。違いの一例として、CPU デバイスは BATCH デバイスの有効化を暗黙的にサポートしていません。./benchmark_app -m <model> -d CPU -hint tput などのコマンドは暗黙的に BATCH デバイスを適用しませんが、 ./benchmark_app -m <model> -d "BATCH:CPU(16) は、BATCH デバイスを明示的にロードできます。

自動バッチ処理は主に、多くの要求を推論するために作成された既存のコードを対象としており、各インスタンスのバッチサイズは 1 です。相当するパフォーマンスの向上を得るには、アプリケーションは複数の推論要求を同時に実行する必要があります。自動バッチ処理は、特定の仮想デバイスを介して使用することもできます。

この記事では、自動バッチ機能の動作方法、構成、パフォーマンスのテストなど、自動バッチ機能のプレビューを提供します。

自動バッチ処理の動作#

バッチ処理は、GPU の計算能力を活用して通信オーバーヘッドを軽減する簡単な方法です。自動バッチ処理は、compile_model 呼び出しまたは set_property 呼び出しの ov::hint::performance_mode プロパティーに ov::hint::PerformanceMode::THROUGHPUT が指定されている場合に GPU で “暗黙的に” トリガーされます。

 import openvino.properties as props 
import openvino.properties.hint as hints 

config = {hints.performance_mode: hints.PerformanceMode.THROUGHPUT} 
compiled_model = core.compile_model(model, "GPU", config)
auto compiled_model = core.compile_model(model, "GPU", 
    ov::hint::performance_mode(ov::hint::PerformanceMode::THROUGHPUT));

パフォーマンスのヒントの概念とはかけ離れた従来のアプリケーションで自動バッチ処理を有効にするには、BATCH:GPU などの明示的なデバイスの概念を適用する必要があります。

自動バッチ処理を (GPU デバイスなどで) 無効にして、ov::hint::PerformanceMode::THROUGHPUT によってトリガーされるのを防ぐことができます。これには、以下に示すように、ov::hint::performance_mode に加えて ov::hint::allow_auto_batchingfalse に設定します。

 # 自動バッチ処理を無効にする 
# デバイスが 'スループット' ヒントに選択した他の構成オプションはそのまま残します 
config = {hints.performance_mode: hints.PerformanceMode.THROUGHPUT, 
         hints.allow_auto_batching: False} 
compiled_model = core.compile_model(model, "GPU", config)
// 自動バッチ処理を無効にする 
// デバイスが 'スループット' ヒントに選択した他の構成オプションはそのまま残します 
auto compiled_model = core.compile_model(model, "GPU", 
    ov::hint::performance_mode(ov::hint::PerformanceMode::THROUGHPUT), 
    ov::hint::allow_auto_batching(false));

自動バッチ処理の構成#

OpenVINO 命名規則に従って、バッチ処理デバイスには BATCH というラベルが割り当てられます。構成オプションは次のとおりです:

プロパティー名

パラメーターの説明

AUTO_BATCH_DEVICE

自動バッチ処理を適用するデバイスの名前。括弧内はオプションのバッチサイズ値です。

BATCH:GPU は自動バッチサイズ選択をトリガーします。BATCH:GPU(4) はバッチサイズを直接指定します。

ov::auto_batch_timeout

タイムアウト値 (ミリ秒)。デフォルト値は 1000 です。

タイムアウト値を減らすと、データの到着が不均一な場合のパフォーマンスの低下を回避できます。例えば “100” に設定するか、入力の準備に対応できる十分な大きさに設定します (シリアルプロセスの場合など)。

自動バッチサイズ選択#

THROUGHPUT ヒントと明示的な BATCH デバイスの両方では、実装がデバイスから ov::optimal_batch_size プロパティーを照会し、モデルグラフをパラメーターとして渡すため、最適なバッチサイズが自動的に選択されます。実際の値は、モデルとデバイスの仕様 (dGPU のデバイスメモリーなど) によって異なります。自動バッチ処理のサポートは GPU に限定されません。ただし、デバイスが ov::optimal_batch_size をサポートしていない場合、自動バッチ処理を使用するには、BATCH:<device>(16) など、明示的にバッチサイズを指定する必要があります。

この “自動バッチサイズ選択” は、アプリケーションが ov::optimal_number_of_infer_requests を照会して、返された数の要求を作成し、それらを同時に実行することが前提です。

 # バッチサイズが実装によって自動的に選択される場合 
# 十分なリクエストを照会/作成して実行することが重要です 
config = {hints.performance_mode: hints.PerformanceMode.THROUGHPUT} 
compiled_model = core.compile_model(model, "GPU", config) 
num_requests = compiled_model.get_property(props.optimal_number_of_infer_requests)
// バッチサイズが実装によって自動的に選択される場合 
// 十分なリクエストを照会/作成して実行することが重要です 
auto compiled_model = core.compile_model(model, "GPU", 
    ov::hint::performance_mode(ov::hint::PerformanceMode::THROUGHPUT)); 
auto num_requests = compiled_model.get_property(ov::optimal_number_of_infer_requests);

バッチサイズを制限してパフォーマンスを最適化#

十分な入力が収集されなかった場合、タイムアウト値により透過的な実行が個別の要求の実行にフォールバックされます。この値は、AUTO_BATCH_TIMEOUT プロパティーを介して構成できます。タイムアウトは要求の実行時間に加算され、パフォーマンスに大きな悪影響を及ぼします。この問題を回避するには、並列スラックが制限されている場合、OpenVINO に追加のヒントを提供します。

例えば、アプリケーションが 4 つのビデオストリームのみを処理する場合、4 より大きいバッチを使用する必要はありません。並列処理の制限を伝える最も将来性のある方法は、オプションの ov::hint::num_requests 構成キーを 4 に設定してパフォーマンス・ヒントを装備することです。これにより、GPU のバッチサイズと CPU の推論ストリームの数が制限されるため、各デバイスはヒントを実際のデバイス構成オプションに変換する際に ov::hint::num_requests を使用します:

 config = {hints.performance_mode: hints.PerformanceMode.THROUGHPUT, 
          hints.num_requests: "4"} 
# 'スループット’ に利用可能な並列余裕を制限し、 
# 特定のパラメーター (選択されたバッチサイズなど) がそれに応じて自動的に調整されるようにする 
compiled_model = core.compile_model(model, "GPU", config)
// ov::hint::num_requests を介して 'スループット' ヒントの利用可能な並列スラックを制限する 
// 特定のパラメーター (選択されたバッチサイズなど) がそれに応じて自動的に調整されるようにする 
auto compiled_model = core.compile_model(model, "GPU", 
    ov::hint::performance_mode(ov::hint::PerformanceMode::THROUGHPUT), 
    ov::hint::num_requests(4));

明示的に使用する場合は、BATCH:GPU(4) を指定してバッチサイズを制限できます。ここで、4 は並行して実行される要求数です。

明示的なデバイスとしての自動バッチ処理#

以下の例は、ユーザーが直接推論を実行する際に自動バッチ処理を指定するデバイス形式を示しています:

./benchmark_app -m <model> -d "BATCH:GPU" 
./benchmark_app -m <model> -d "BATCH:GPU(16)" 
./benchmark_app -m <model> -d "BATCH:CPU(16)"
  • BATCH – BATCH デバイスを明示的にロードします。

  • :GPU(16) – BATCH デバイス構成。バッチサイズ = 16 の GPU デバイスを適用するように BATCH デバイスに指示します。

他のデバイスに設定された自動バッチ処理#

次の例では、tput/ctput mode モードの場合、BATCH デバイスが別のデバイスに設定されます。

./benchmark_app -m <model> -d GPU -hint tput 
./benchmark_app -m <model> -d AUTO -hint tput 
./benchmark_app -m <model> -d AUTO -hint ctput 
./benchmark_app -m <model> -d AUTO:GPU -hint ctput

./benchmark_app を実行する場合は、-b <batch_size>batch_size を設定しないでください。そうしないと、AUTO モードが適用されません。

他のパフォーマンス上の考察#

自動バッチ処理で最高のパフォーマンスを達成するには、アプリケーションは次のことを行う必要があります:

  • バッチサイズの倍数となる推論要求を操作します。バッチサイズを制限してパフォーマンスを最適化セクションの例では、バッチサイズ 4 の場合、アプリケーションは 4、8、12、16 ... などの要求を処理する必要があります。

  • バッチサイズごとにグループ化した要求をまとめて使用します。例えば、最初の 4 つの要求が推論される間に、要求の 2 番目のグループを受け入れできます。基本的に、自動バッチ処理は、個々の要求からバッチを構成する要求のグループに非同期性を移行します。

  • timeout 値とバッチサイズのバランスをとります。例えば、timeout 値/バッチサイズを小さくしたほうが、要求数をすべて受け入れるには十分ではない timeout 値とより大きなバッチサイズにするよりも、パフォーマンスが向上する可能性があります。

  • 自動バッチ処理が有効になっている場合、ov::CompiledModelタイムアウト・プロパティーは、モデルのロード/コンパイル後であっても変更できます。例えば、値を 0 に設定すると、要求の収集が省略されるため、自動バッチ処理は無効になります。

  • パイプラインには自動バッチ処理を慎重に適用します。例えば、従来の “ビデオソース -> 検出 -> 分類” フローでは、検出ステージの入力に対して自動バッチ処理を適用するのが最も有益です。通常、結果として得られる検出数は流動的であるため、分類ステージに自動バッチ処理を適用するのは困難です。

制限事項#

現在の AUTO バッチ処理の実装には次の制限があります:

  • 動的モデルは BATCH デバイスではサポートされていません。

  • BATCH デバイスは tput/ctput mode モードのみをサポートできます。latency/none mode はサポートされません。

  • サポートされるのは、バッチ次元 = 1 のモデルのみです。

  • 入出力テンソルは inferRequest から取得する必要があります。そうしないと、ユーザーが作成したテンソルによってメモリーのコピーがトリガーされます。

  • OPTIMAL_BATCH_SIZE2 以上でなければいけません。そうでない場合は、モデルとデバイスに合わせてバッチサイズを指定する必要があります (CPU はこのプロパティーをサポートしていません)。

  • BATCH デバイスはデフォルトで GPU をサポートしますが、CPU は tput モードでは auto_batch をトリガーしません。

  • AUTO_BATCH を使用すると、コンパイルのレイテンシーが大幅に増加します。

  • スループット重視のシナリオではそれほど重要ではありませんが、自動バッチ処理によるロード時間はほぼ 2 倍に増加します。

  • 特定のネットワークは、 “バッチ” 次元 (レイアウト用語では N として指定) で安全に再形成することができません。さらに、バッチ処理の次元が 0 番目でない場合、自動バッチ処理はスループットのヒントから “暗黙的に” トリガーされません。

  • 例えば、緩和された次元トラッキングを使用する BATCH:GPU などの “明示的な” 概念では、多くの場合、自動バッチ処理が可能です。例えば、この方法ではほとんどの検出ネットワークのロックを解除します。

  • “明示的な” デバイスが自動バッチ処理を強制する場合、結果が正しいか必ず検証してください。

  • パフォーマンスを向上するには、メモリーの使用量が増大します。ただし、自動バッチ処理では、使用可能なメモリー (特に dGPU) が照会され、それに応じて選択されたバッチサイズが制限されます。

BATCH デバイスはデフォルトで GPU をサポートしますが、モデルまたは GPU メモリーサイズが許可されていない場合、GPU は tput モードでは auto_batch をトリガーしない可能性があります。つまり、ov::auto_batch_timeout プロパティーを使用してアクション (set/get) を実行する前に、GPU tput モードの compiled_modelsupported_properties をチェックする必要があります。BATCH デバイスがデフォルトで GPU をサポートしていることを確認するには、core.compile_modelov::model が必要です。core.compile_model へのモデル・ファイル・パスの文字列は、パフォーマンスを考慮して、BATCH を介さずに直接 GPU プラグインに渡されます。

Benchmark_app でパフォーマンスをテスト#

benchmark_app sample サンプルを使用することが、自動バッチ処理のパフォーマンスを評価する最良の方法です。

  • 最も簡単な方法は、パフォーマンスのヒントを使用することです:

    • benchmark_app -hint tput -d GPU -m ‘モデルへのパス’

  • “明示的な” デバイスの概念を使用して、バッチ次元による暗黙的な再形成の厳密なルールをオーバーライドできます。

    • benchmark_app -hint none -d BATCH:GPU -m ‘モデルへのパス’

  • また、自動的に推定されるバッチサイズもオーバーライドします:

    • $benchmark_app -hint none -d BATCH:GPU(16) -m ‘モデルへのパス’

    • この例は、一般にバッチ実行をサポートする CPU またはその他のデバイスにも当てはまります。

    • 一部のシェルバージョン (bash など) では、複雑なデバイス名を引用符で囲む場合があることに注意してください (この例では -d "BATCH:GPU(16)")。

Benchmark_app は単一要求のウォームアップ実行を行うことに注意してください。自動バッチ処理では、バッチで実行する大規模な要求が必要となるため、次の例で示されるように、ウォームアップ実行がデフォルトのタイムアウト値 (1000 ミリ秒) に達します。

[ INFO ] First inference took 1000.18ms

この値は、benchmark_app 終了時の最終実行統計としても示されます:

[ INFO ] Latency: [ INFO ] Max: 1000.18 ms

これはバッチ実行の実際のレイテンシーではないため、同じログ内の他のメトリック (実行の “中央値” や “平均” など) を参照することも推奨します。

関連情報#