コンテンツにスキップ

グラフの最適化

ONNX Runtimeにおけるグラフの最適化

Section titled “ONNX Runtimeにおけるグラフの最適化”

ONNX Runtimeは、パフォーマンスを向上させるために様々なグラフ最適化を提供します。グラフ最適化は、本質的にグラフレベルの変換であり、小さなグラフの単純化やノードの削除から、より複雑なノードの融合やレイアウトの最適化まで多岐にわたります。

グラフ最適化は、その複雑さと機能に基づいていくつかのカテゴリ(またはレベル)に分類されます。これらはオンラインまたはオフラインで実行できます。オンラインモードでは、推論を実行する前に最適化が行われますが、オフラインモードでは、ランタイムは最適化されたグラフをディスクに保存します。ONNX Runtimeは、Python、C#、C++、およびC APIを提供して、さまざまな最適化レベルを有効にし、オフラインモードとオンラインモードを選択できるようにします。

以下では、最適化レベル、オンライン/オフラインモード、およびそれらを制御するためのさまざまなAPIについて詳しく説明します。

グラフ最適化は3つのレベルに分かれています。

  1. 基本
  2. 拡張
  3. レイアウト最適化

あるレベルに属する最適化は、前のレベルの最適化が適用された後に実行されます(たとえば、拡張最適化は基本最適化が適用された後に適用されます)。

すべての最適化はデフォルトで有効になっています。

これらは、冗長なノードと冗長な計算を削除する、セマンティクスを保持するグラフの書き換えです。これらはグラフの分割前に実行されるため、すべての実行プロバイダーに適用されます。利用可能な基本的なグラフ最適化は次のとおりです。

  • 定数畳み込み:定数初期化子のみに依存するグラフの一部を静的に計算します。これにより、実行時にそれらを計算する必要がなくなります。

  • 冗長なノードの削除:グラフ構造を変更せずに、すべての冗長なノードを削除します。現在、次の最適化がサポートされています。

    • Identity Elimination
    • Slice Elimination
    • Unsqueeze Elimination
    • Dropout Elimination
  • セマンティクスを保持するノードの融合:複数のノードを単一のノードに融合/折りたたみます。たとえば、Conv Add融合は、Add演算子をConv演算子のバイアスとして折りたたみます。現在、次の最適化がサポートされています。

    • Conv Add Fusion
    • Conv Mul Fusion
    • Conv BatchNorm Fusion
    • Relu Clip Fusion
    • Reshape Fusion

これらの最適化には、複雑なノードの融合が含まれます。これらはグラフの分割後に実行され、CPU、CUDA、またはROCm実行プロバイダーに割り当てられたノードにのみ適用されます。利用可能な拡張グラフ最適化は次のとおりです。

最適化実行プロバイダーコメント
GEMM活性化融合CPU
Matmul加算融合CPU
Conv活性化融合CPU
GELU融合CPU, CUDA, ROCm
レイヤー正規化融合CPU, CUDA, ROCm
BERT埋め込みレイヤー融合CPU, CUDA, ROCmBERT埋め込みレイヤー、レイヤー正規化、アテンションマスク長を融合
アテンション融合*CPU, CUDA, ROCm
スキップレイヤー正規化融合CPU, CUDA, ROCm全結合層のバイアス、スキップ接続、レイヤー正規化を融合
バイアスGELU融合CPU, CUDA, ROCm全結合層のバイアスとGELU活性化を融合
GELU近似*CUDA, ROCmデフォルトでは無効。kOrtSessionOptionsEnableGeluApproximationで有効にする
近似(クリックして展開)

BERTのパフォーマンスを最適化するために、CUDAおよびROCm実行プロバイダーのGELU近似およびアテンション融合で近似が使用されます。当社の評価に基づくと、精度への影響はごくわずかです。SQuAD v1.1でのBERTモデルのF1スコアはほぼ同じです(87.05対87.03)。

これらの最適化は、適用可能なノードのデータレイアウトを変更して、より高いパフォーマンス向上を実現します。これらはグラフの分割後に実行され、CPU実行プロバイダーに割り当てられたノードにのみ適用されます。利用可能なレイアウト最適化は次のとおりです。

  • NCHWcオプティマイザ:NCHWレイアウトの代わりにNCHWcレイアウトを使用してグラフを最適化します。

すべての最適化は、オンラインまたはオフラインで実行できます。オンラインモードでは、推論セッションを初期化するときに、モデル推論を実行する前に、有効になっているすべてのグラフ最適化も適用します。セッションを開始するたびにすべての最適化を適用すると、モデルの起動時間にオーバーヘッドが追加される可能性があり(特に複雑なモデルの場合)、これは本番シナリオでは重要になる可能性があります。ここで、オフラインモードが大きなメリットをもたらすことができます。オフラインモードでは、グラフ最適化を実行した後、ONNX Runtimeは結果のモデルをディスクにシリアル化します。その後、すでに最適化されたモデルを使用し、すべての最適化を無効にすることで、起動時間を短縮できます。

注意:

  • オフラインモードで実行する場合、モデル推論が実行されるターゲットマシンとまったく同じオプション(実行プロバイダー、最適化レベルなど)とハードウェアを使用していることを確認してください(たとえば、GPU実行プロバイダー用に事前に最適化されたモデルを、CPUのみを搭載したマシンで実行することはできません)。
  • レイアウト最適化が有効になっている場合、オフラインモードは、オフラインモデルが保存された環境と互換性のあるハードウェアでのみ使用できます。たとえば、モデルがAVX2用にレイアウト最適化されている場合、オフラインモデルにはAVX2をサポートするCPUが必要になります。

ONNX Runtimeは、前述の最適化レベルのどれを有効にするかを決定するためにGraphOptimizationLevel列挙型を定義します。レベルを選択すると、そのレベルの最適化と、先行するすべてのレベルの最適化が有効になります。たとえば、拡張最適化を有効にすると、基本最適化も有効になります。これらのレベルと列挙型のマッピングは次のとおりです。

  • GraphOptimizationLevel::ORT_DISABLE_ALL -> すべての最適化を無効にします
  • GraphOptimizationLevel::ORT_ENABLE_BASIC -> 基本的な最適化を有効にします
  • GraphOptimizationLevel::ORT_ENABLE_EXTENDED -> 基本的および拡張的な最適化を有効にします
  • GraphOptimizationLevel::ORT_ENABLE_ALL -> レイアウト最適化を含む利用可能なすべての最適化を有効にします

最適化されたモデルのディスクへのシリアル化を有効にするには、SessionOptionsオプションoptimized_model_filepathを設定します。

import onnxruntime as rt
sess_options = rt.SessionOptions()
# グラフ最適化レベルを設定
sess_options.graph_optimization_level = rt.GraphOptimizationLevel.ORT_ENABLE_EXTENDED
# グラフ最適化後のモデルのシリアル化を有効にするには、これを設定します
sess_options.optimized_model_filepath = "<model_output_path\optimized_model.onnx>"
session = rt.InferenceSession("<model_path>", sess_options)
const OrtApi* Ort::g_api = OrtGetApi(ORT_API_VERSION);
OrtEnv* env;
g_ort->CreateEnv(ORT_LOGGING_LEVEL_WARNING, "test", &env);
OrtSessionOptions* session_options;
g_ort->CreateSessionOptions(&session_options)
// グラフ最適化レベルを設定
g_ort->SetSessionGraphOptimizationLevel(session_options, ORT_ENABLE_EXTENDED);
// グラフ最適化後のモデルのシリアル化を有効にするには、これを設定します
const ORTCHAR_T* optimized_model_path = ORT_TSTR("optimized_model_path");
g_ort->SetOptimizedModelFilePath(session_options, optimized_model_path);
OrtSession* session;
const ORTCHAR_T* model_path = ORT_TSTR("model_path");
g_ort->CreateSession(env, model_path, session_options, &session);
SessionOptions so = new SessionOptions();
// グラフ最適化レベルを設定
so.GraphOptimizationLevel = GraphOptimizationLevel.ORT_ENABLE_EXTENDED;
// グラフ最適化後のモデルのシリアル化を有効にするには、これを設定します
so.OptimizedModelFilePath = "model_output_path\optimized_model.onnx"
var session = new InferenceSession(modelPath, so);
Ort::SessionOptions session_options;
// グラフ最適化レベルを設定
session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);
// グラフ最適化後のモデルのシリアル化を有効にするには、これを設定します
session_options.SetOptimizedModelFilePath("optimized_file_path");
auto session_ = Ort::Session(env, "model_file_path", session_options);