NVIDIA - CUDA
CUDA 実行プロバイダー
Section titled “CUDA 実行プロバイダー”CUDA実行プロバイダーは、Nvidia CUDA対応GPUでのハードウェアアクセラレーションによる計算を可能にします。
インストール
Section titled “インストール”CUDA EPを搭載したONNX Runtimeのビルド済みバイナリは、ほとんどの言語バインディングで公開されています。 ORTのインストールを参照してください。
ソースからビルド
Section titled “ソースからビルド”ビルド手順を参照してください。
ONNX Runtime推論パッケージの公式GPUパッケージ依存関係については、以下の表を参照してください。 ONNX RuntimeトレーニングはPyTorch CUDAバージョンと連携していることに注意してください。サポートされているバージョンについては、onnxruntime.aiの「トレーニングの最適化」タブを参照してください。
Nvidia CUDAマイナーバージョン互換性のため、CUDA 11.8でビルドされたONNX Runtimeは任意のCUDA 11.xバージョンと互換性があり、CUDA 12.xでビルドされたONNX Runtimeは任意のCUDA 12.xバージョンと互換性があります。
cuDNN 8.xでビルドされたONNX RuntimeはcuDNN 9.xと互換性がなく、その逆も同様です。ランタイム環境に一致するCUDAおよびcuDNNのメジャーバージョンに基づいてパッケージを選択できます(例:PyTorch 2.3はcuDNN 8.xを使用し、PyTorch 2.4以降はcuDNN 9.xを使用します)。
注意:バージョン1.19以降、PyPIでONNX Runtime GPUパッケージを配布する際、CUDA 12.xがデフォルトバージョンになります。
CUDAとcuDNNの手動インストールを減らし、ONNX RuntimeとPyTorch間のシームレスな統合を確保するために、onnxruntime-gpu PythonパッケージはCUDAとcuDNNのダイナミックリンクライブラリ(DLL)を適切にロードするAPIを提供します。詳細については、PyTorchとの互換性およびDLLのプリロードセクションを参照してください。
CUDA 12.x
Section titled “CUDA 12.x”| ONNX Runtime | CUDA | cuDNN | 注意事項 |
|---|---|---|---|
| 1.20.x | 12.x | 9.x | PyPIで利用可能。CUDA 12.x用のPyTorch >= 2.4.0と互換性があります。 |
| 1.19.x | 12.x | 9.x | PyPIで利用可能。CUDA 12.x用のPyTorch >= 2.4.0と互換性があります。 |
| 1.18.1 | 12.x | 9.x | cuDNN 9が必要です。Javaパッケージはありません。 |
| 1.18.0 | 12.x | 8.x | Javaパッケージが追加されました。 |
| 1.17.x | 12.x | 8.x | C++/C# NugetとPythonパッケージのみがリリースされています。Javaパッケージはありません。 |
CUDA 11.x
Section titled “CUDA 11.x”| ONNX Runtime | CUDA | cuDNN | 注意事項 |
|---|---|---|---|
| 1.20.x | 11.8 | 8.x | PyPIでは利用できません。ORTのインストールで詳細を確認してください。CUDA 11.8用のPyTorch <= 2.3.1と互換性があります。 |
| 1.19.x | 11.8 | 8.x | PyPIでは利用できません。ORTのインストールで詳細を確認してください。CUDA 11.8用のPyTorch <= 2.3.1と互換性があります。 |
| 1.18.x | 11.8 | 8.x | PyPIで利用可能です。 |
| 1.17 1.16 1.15 | 11.8 | 8.2.4 (Linux) 8.5.0.96 (Windows) | CUDA 11.6から11.8までのバージョン、cuDNN 8.2から8.9までのバージョンでテスト済み |
| 1.14 1.13 | 11.6 | 8.2.4 (Linux) 8.5.0.96 (Windows) | libcudart 11.4.43 libcufft 10.5.2.100 libcurand 10.2.5.120 libcublasLt 11.6.5.2 libcublas 11.6.5.2 libcudnn 8.2.4 |
| 1.12 1.11 | 11.4 | 8.2.4 (Linux) 8.2.2.26 (Windows) | libcudart 11.4.43 libcufft 10.5.2.100 libcurand 10.2.5.120 libcublasLt 11.6.5.2 libcublas 11.6.5.2 libcudnn 8.2.4 |
| 1.10 | 11.4 | 8.2.4 (Linux) 8.2.2.26 (Windows) | libcudart 11.4.43 libcufft 10.5.2.100 libcurand 10.2.5.120 libcublasLt 11.6.1.51 libcublas 11.6.1.51 libcudnn 8.2.4 |
| 1.9 | 11.4 | 8.2.4 (Linux) 8.2.2.26 (Windows) | libcudart 11.4.43 libcufft 10.5.2.100 libcurand 10.2.5.120 libcublasLt 11.6.1.51 libcublas 11.6.1.51 libcudnn 8.2.4 |
| 1.8 | 11.0.3 | 8.0.4 (Linux) 8.0.2.39 (Windows) | libcudart 11.0.221 libcufft 10.2.1.245 libcurand 10.2.1.245 libcublasLt 11.2.0.252 libcublas 11.2.0.252 libcudnn 8.0.4 |
| 1.7 | 11.0.3 | 8.0.4 (Linux) 8.0.2.39 (Windows) | libcudart 11.0.221 libcufft 10.2.1.245 libcurand 10.2.1.245 libcublasLt 11.2.0.252 libcublas 11.2.0.252 libcudnn 8.0.4 |
CUDA 10.x
Section titled “CUDA 10.x”| ONNX Runtime | CUDA | cuDNN | 注意事項 |
|---|---|---|---|
| 1.5-1.6 | 10.2 | 8.0.3 | CUDA 11はソースからビルド可能 |
| 1.2-1.4 | 10.1 | 7.6.5 | cublas10-10.2.1.243が必要です。cublas 10.1.xは動作しません |
| 1.0-1.1 | 10.0 | 7.6.4 | CUDA 9.1から10.1までのバージョン、cuDNN 7.1から7.4までのバージョンもVisual Studio 2017で動作するはずです |
古いバージョンについては、リリースブランチのREADMEとビルドページを参照してください。
ビルド手順については、BUILDページを参照してください。
PyTorchとの互換性
Section titled “PyTorchとの互換性”onnxruntime-gpuパッケージは、PyTorchと同じメジャーバージョンのCUDAとcuDNNに対してビルドされている限り、シームレスに動作するように設計されています。CUDAサポート付きでPyTorchをインストールすると、必要なCUDAとcuDNNのDLLが含まれるため、CUDAツールキットやcuDNNを別途インストールする必要はありません。
ONNX RuntimeがPyTorchによってインストールされたDLLを利用するようにするには、推論セッションを作成する前にこれらのライブラリをプリロードします。これは、PyTorchをインポートするか、onnxruntime.preload_dlls()関数を使用することで実現できます。
例1:PyTorchのインポート
# torchをインポートすると、必要なDLLがプリロードされます。セッションを作成する前に行う必要があります。import torchimport onnxruntime
# CUDA実行プロバイダーで推論セッションを作成session = onnxruntime.InferenceSession("model.onnx", providers=["CUDAExecutionProvider"])例2:preload_dlls関数の使用
import onnxruntime
# 必要なDLLをプリロードonnxruntime.preload_dlls()
# CUDA実行プロバイダーで推論セッションを作成session = onnxruntime.InferenceSession("model.onnx", providers=["CUDAExecutionProvider"])DLLのプリロード
Section titled “DLLのプリロード”バージョン1.21.0以降、onnxruntime-gpuパッケージはpreload_dlls関数を提供し、CUDA、cuDNN、およびMicrosoft Visual C++(MSVC)ランタイムDLLをプリロードします。この関数は、どのライブラリをどのディレクトリからロードするかを指定する柔軟性を提供します。
関数シグネチャ:
onnxruntime.preload_dlls(cuda=True, cudnn=True, msvc=True, directory=None)パラメータ:
cuda(bool):Trueに設定するとCUDA DLLをプリロードします。cudnn(bool):Trueに設定するとcuDNN DLLをプリロードします。msvc(bool):Trueに設定するとMSVCランタイムDLLをプリロードします。directory(str or None): DLLをロードするディレクトリ。None: デフォルトのディレクトリで検索します。""(空文字列): NVIDIAサイトパッケージで検索します。- 特定のパス: 指定されたディレクトリからDLLをロードします。
デフォルトの検索順序:
directory=Noneの場合、関数は次の順序でCUDAおよびcuDNN DLLを検索します。
- Windowsでは、PyTorchインストールの下の
libディレクトリ。 - NVIDIA CUDAまたはcuDNNライブラリ用のPythonサイトパッケージディレクトリ(例:
nvidia_cuda_runtime_cu12、nvidia_cudnn_cu12)。 - デフォルトのDLLロード動作にフォールバックします。
デフォルトの検索順序を使用して必要なDLLをプリロードすることにより、ONNX RuntimeがPyTorchとシームレスに動作することを保証できます。
onnxruntime-gpuを介したCUDAおよびcuDNNのインストール:
pipを使用して、onnxruntime-gpuパッケージと一緒に必要なCUDAおよびcuDNNランタイムDLLをインストールできます。
pip install onnxruntime-gpu[cuda,cudnn]NVIDIAサイトパッケージからのDLLのプリロード:
NVIDIAサイトパッケージからCUDAおよびcuDNN DLLをプリロードし、デバッグ情報を表示するには:
import onnxruntime
# NVIDIAサイトパッケージからDLLをプリロードonnxruntime.preload_dlls(directory="")
# デバッグ情報を表示onnxruntime.print_debug_info()特定のディレクトリからのDLLのロード:
指定された場所からDLLをロードするには、directoryパラメータを絶対パスまたはONNX Runtimeパッケージルートからの相対パスに設定します。
例:システムインストールからCUDAをロードし、NVIDIAサイトパッケージからcuDNNをロード
import osimport onnxruntime
# システムインストールからCUDA DLLをロードcuda_path = os.path.join(os.environ["CUDA_PATH"], "bin")onnxruntime.preload_dlls(cuda=True, cudnn=False, directory=cuda_path)
# NVIDIAサイトパッケージからcuDNN DLLをロードonnxruntime.preload_dlls(cuda=False, cudnn=True, directory="..\\nvidia\\cudnn\\bin")
# デバッグ情報を表示onnxruntime.print_debug_info()設定オプション
Section titled “設定オプション”CUDA実行プロバイダーは、次の設定オプションをサポートしています。
device_id
Section titled “device_id”デバイスID。
デフォルト値:0
user_compute_stream
Section titled “user_compute_stream”推論を実行する計算ストリームを定義します。
暗黙的にhas_user_compute_streamオプションを設定します。UpdateCUDAProviderOptionsではなく、UpdateCUDAProviderOptionsWithValueを介して設定する必要があります。
これは外部アロケータと組み合わせて使用することはできません。
Pythonの使用例:
providers = [("CUDAExecutionProvider", {"device_id": torch.cuda.current_device(), "user_compute_stream": str(torch.cuda.current_stream().cuda_stream)})]sess_options = ort.SessionOptions()sess = ort.InferenceSession("my_model.onnx", sess_options=sess_options, providers=providers)ユーザー計算ストリームを利用するには、 I/Oバインディングを使用して、入力と出力をデバイスのテンソルにバインドすることをお勧めします。
do_copy_in_default_stream
Section titled “do_copy_in_default_stream”デフォルトストリームでコピーを行うか、別のストリームを使用するか。推奨設定はtrueです。falseの場合、 競合状態が発生し、パフォーマンスが向上する可能性があります。
デフォルト値:true
use_ep_level_unified_stream
Section titled “use_ep_level_unified_stream”CUDA EPのすべてのスレッドに同じCUDAストリームを使用します。これは、has_user_compute_stream、enable_cuda_graphによって、または外部アロケータを使用する場合に暗黙的に有効になります。
デフォルト値:false
gpu_mem_limit
Section titled “gpu_mem_limit”デバイスメモリアリーナのサイズ制限(バイト単位)。このサイズ制限は、実行プロバイダーのアリーナ専用です。 デバイスメモリの総使用量はこれより高くなる場合があります。 s: C++ size_t型の最大値(事実上無制限)
注意: default_memory_arena_cfg(指定されている場合)の内容によって上書きされます。
arena_extend_strategy
Section titled “arena_extend_strategy”デバイスメモリアリーナを拡張するための戦略。
| 値 | 説明 |
|---|---|
| kNextPowerOfTwo (0) | 後続の拡張は、より大きな量で拡張します(2の累乗で乗算) |
| kSameAsRequested (1) | 要求された量だけ拡張します |
デフォルト値:kNextPowerOfTwo
注意: default_memory_arena_cfg(指定されている場合)の内容によって上書きされます。
cudnn_conv_algo_search
Section titled “cudnn_conv_algo_search”cuDNN畳み込みアルゴリズムに対して実行される検索の種類。
| 値 | 説明 |
|---|---|
| EXHAUSTIVE (0) | cudnnFindConvolutionForwardAlgorithmExを使用した高価な網羅的なベンチマーク |
| HEURISTIC (1) | cudnnGetConvolutionForwardAlgorithm_v7を使用した軽量なヒューリスティックベースの検索 |
| DEFAULT (2) | CUDNN_CONVOLUTION_FWD_ALGO_IMPLICIT_PRECOMP_GEMMを使用したデフォルトアルゴリズム |
デフォルト値:EXHAUSTIVE
cudnn_conv_use_max_workspace
Section titled “cudnn_conv_use_max_workspace”このフラグが何をするかについての詳細は、畳み込みヘビーモデルのパフォーマンスチューニングを確認してください。 このフラグは、C APIを使用する場合のプロバイダーオプション構造体のV2バージョンからのみサポートされます(以下のサンプル)。
デフォルト値:バージョン1.14以降は1、 以前のバージョンは0
cudnn_conv1d_pad_to_nc1d
Section titled “cudnn_conv1d_pad_to_nc1d”このフラグが何をするかについての詳細は、CUDA EPでの畳み込み入力パディングを確認してください。 このフラグは、C APIを使用する場合のプロバイダーオプション構造体のV2バージョンからのみサポートされます。(以下のサンプル)
デフォルト値:0
enable_cuda_graph
Section titled “enable_cuda_graph”このフラグが何をするかについての詳細は、CUDA EPでCUDAグラフを使用するを確認してください。 このフラグは、C APIを使用する場合のプロバイダーオプション構造体のV2バージョンからのみサポートされます。(以下のサンプル)
デフォルト値:0
enable_skip_layer_norm_strict_mode
Section titled “enable_skip_layer_norm_strict_mode”SkipLayerNormalization cuda実装で厳密モードを使用するかどうか。デフォルトおよび推奨設定はfalseです。 有効にすると、精度の向上とパフォーマンスの低下が予想されます。 このフラグは、C APIを使用する場合のプロバイダーオプション構造体のV2バージョンからのみサポートされます。(以下のサンプル)
デフォルト値:0
use_tf32
Section titled “use_tf32”TF32は、Ampere以降のNVIDIA GPUで利用可能な数学モードです。特定のfloat32行列乗算と畳み込みを、TensorFloat-32の精度を下げてテンソルコアではるかに高速に実行できます。float32入力は10ビットの仮数で丸められ、結果はfloat32精度で累積されます。
デフォルト値:1
TensorFloat-32はデフォルトで有効になっています。ONNX Runtime 1.18以降、このフラグを使用して推論セッションで無効にすることができます。
Pythonの使用例:
providers = [("CUDAExecutionProvider", {"use_tf32": 0})]sess_options = ort.SessionOptions()sess = ort.InferenceSession("my_model.onnx", sess_options=sess_options, providers=providers)このフラグは、C APIを使用する場合のプロバイダーオプション構造体のV2バージョンからのみサポートされます。(以下のサンプル)
gpu_external_[alloc|free|empty_cache]
Section titled “gpu_external_[alloc|free|empty_cache]”gpu_external_*は、外部アロケータを渡すために使用されます。 Pythonの使用例:
from onnxruntime.training.ortmodule.torch_cpp_extensions import torch_gpu_allocator
provider_option_map["gpu_external_alloc"] = str(torch_gpu_allocator.gpu_caching_allocator_raw_alloc_address())provider_option_map["gpu_external_free"] = str(torch_gpu_allocator.gpu_caching_allocator_raw_delete_address())provider_option_map["gpu_external_empty_cache"] = str(torch_gpu_allocator.gpu_caching_allocator_empty_cache_address())デフォルト値:0
prefer_nhwc
Section titled “prefer_nhwc”このオプションは、ビルドにデフォルトでonnxruntime_USE_CUDA_NHWC_OPS=ONが含まれるONNX Runtime 1.20以降で利用可能です。
このオプションが有効な場合、実行プロバイダーはNCHW演算子よりもNHWC演算子を優先します。必要なレイアウト変換はモデルに自動的に適用されます。NVIDIAテンソルコアはNHWCレイアウトでより効率的に動作するため、このオプションを有効にすると、モデルが多くのサポートされている演算子で構成され、過度の追加の転置操作を必要としない場合にパフォーマンスが向上する可能性があります。NHWCのより広い演算子サポートは、将来のリリースで計画されています。
このフラグは、C APIを使用する場合のプロバイダーオプション構造体のV2バージョンでのみサポートされます。V2プロバイダーオプション構造体は、CreateCUDAProviderOptionsを使用して作成し、UpdateCUDAProviderOptionsを使用して更新できます。
デフォルト値:0
パフォーマンスチューニング
Section titled “パフォーマンスチューニング”I/Oバインディング機能は、入力と出力のコピーによるオーバーヘッドを回避するために利用する必要があります。理想的には、入力のアップロードとダウンロードは推論の背後に隠すことができます。これは、推論の実行中に非同期コピーを行うことで実現できます。これは このPRで実証されています。
Ort::RunOptions run_options;run_options.AddConfigEntry("disable_synchronize_execution_providers", "1");session->Run(run_options, io_binding);推論の同期を無効にすることにより、ユーザーは 実行後に計算ストリームを同期する必要があります。 この機能は、デバイスのローカルメモリまたはピン留めされたメモリに割り当てられたORT値でのみ使用する必要があります。そうしないと、発行された ダウンロードがブロックされ、意図したとおりに動作しません。
畳み込みヘビーモデル
Section titled “畳み込みヘビーモデル”ORTは畳み込み操作にCuDNNを活用しており、このプロセスの最初のステップは、各Convノードの特定の入力構成(入力形状、
フィルター形状など)に対して畳み込み操作を実行する際に使用する「最適な」
畳み込みアルゴリズムを決定することです。このサブステップでは、CuDNNに「ワークスペース」メモリサイズを問い合わせ、
これを割り当てて、CuDNNがこの補助メモリを使用して「最適な」畳み込みアルゴリズムを決定できるようにします。
cudnn_conv_use_max_workspaceのデフォルト値は、バージョン1.14以降では1、以前のバージョンでは0です。
値が0の場合、ORTはワークスペースサイズを32 MBにクランプするため、CuDNNによって最適ではない畳み込みアルゴリズムが
選択される可能性があります。CuDNNによって決定された最大限のワークスペースをORTに割り当てさせるには、
cudnn_conv_use_max_workspaceという名前のプロバイダーオプションを設定する必要があります(以下に示すように)。
このフラグを使用すると、ピークメモリ使用量が数倍(場合によっては数GB)増加する可能性があることに注意してください。しかし、これは
CuDNNが特定の入力に最適な畳み込みアルゴリズムを選択するのに役立ちます。fp16モデルを使用する場合、これは重要なフラグであることがわかっています。これにより、CuDNNは畳み込み操作にテンソルコアアルゴリズムを選択できます(
ハードウェアがテンソルコア操作をサポートしている場合)。このフラグは、他のデータ型(floatおよびdouble)ではパフォーマンスの向上をもたらす場合とそうでない場合があります。
-
Python
providers = [("CUDAExecutionProvider", {"cudnn_conv_use_max_workspace": '1'})]sess_options = ort.SessionOptions()sess = ort.InferenceSession("my_conv_heavy_fp16_model.onnx", sess_options=sess_options, providers=providers) -
C/C++
OrtCUDAProviderOptionsV2* cuda_options = nullptr;CreateCUDAProviderOptions(&cuda_options);std::vector<const char*> keys{"cudnn_conv_use_max_workspace"};std::vector<const char*> values{"1"};UpdateCUDAProviderOptions(cuda_options, keys.data(), values.data(), 1);OrtSessionOptions* session_options = /* ... */;SessionOptionsAppendExecutionProvider_CUDA_V2(session_options, cuda_options);// 最後に、プロバイダーオプションを解放することを忘れないでくださいReleaseCUDAProviderOptions(cuda_options); -
C#
var cudaProviderOptions = new OrtCUDAProviderOptions(); // 最後にこれを破棄しますvar providerOptionsDict = new Dictionary<string, string>();providerOptionsDict["cudnn_conv_use_max_workspace"] = "1";cudaProviderOptions.UpdateOptions(providerOptionsDict);SessionOptions options = SessionOptions.MakeSessionOptionWithCudaProvider(cudaProviderOptions); // 最後にこれを破棄します
畳み込み入力パディング
Section titled “畳み込み入力パディング”ORTは畳み込み操作にCuDNNを活用します。CuDNNは畳み込み操作の入力として4-Dまたは5-Dテンソルしか受け付けませんが、入力が3-Dテンソルの場合は次元パディングが必要です。形状[N, C, D]の入力テンソルが与えられた場合、[N, C, D, 1]または[N, C, 1, D]にパディングできます。これら2つのパディング方法はどちらも同じ出力を生成しますが、選択される畳み込みアルゴリズムが異なるため、特にA100などの一部のデバイスではパフォーマンスが大きく異なる場合があります。デフォルトでは、入力は[N, C, D, 1]にパディングされます。[N, C, 1, D]が推奨される場合は、cudnn_conv1d_pad_to_nc1dという名前のプロバイダーオプションを設定する必要があります(以下に示すように)。
- Python
providers = [("CUDAExecutionProvider", {"cudnn_conv1d_pad_to_nc1d": '1'})]sess_options = ort.SessionOptions()sess = ort.InferenceSession("my_conv_model.onnx", sess_options=sess_options, providers=providers)
- C/C++
OrtCUDAProviderOptionsV2* cuda_options = nullptr;CreateCUDAProviderOptions(&cuda_options);std::vector<const char*> keys{"cudnn_conv1d_pad_to_nc1d"};std::vector<const char*> values{"1"};UpdateCUDAProviderOptions(cuda_options, keys.data(), values.data(), 1);OrtSessionOptions* session_options = /* ... */;SessionOptionsAppendExecutionProvider_CUDA_V2(session_options, cuda_options);// 最後に、プロバイダーオプションを解放することを忘れないでくださいReleaseCUDAProviderOptions(cuda_options);
- C#
var cudaProviderOptions = new OrtCUDAProviderOptions(); // 最後にこれを破棄しますvar providerOptionsDict = new Dictionary<string, string>();providerOptionsDict["cudnn_conv1d_pad_to_nc1d"] = "1";cudaProviderOptions.UpdateOptions(providerOptionsDict);SessionOptions options = SessionOptions.MakeSessionOptionWithCudaProvider(cudaProviderOptions); // 最後にこれを破棄します
CUDAグラフの使用(プレビュー)
Section titled “CUDAグラフの使用(プレビュー)”CUDA EPを使用している間、ORTはCUDAグラフを使用して、CUDAカーネルを順番に起動することに関連するCPUオーバーヘッドを排除することをサポートしています。CUDAグラフの使用を有効にするには、以下のサンプルのようにプロバイダーオプションを使用します。ORTは、ユーザー指定のgpu_graph_idを実行オプションに渡すことにより、マルチグラフキャプチャ機能をサポートします。 セッションが1つのcudaグラフを使用する場合、gpu_graph_idはオプションです。設定されていない場合、デフォルト値は0です。gpu_graph_idが -1に設定されている場合、その実行ではcudaグラフのキャプチャ/再生が無効になります。
現在、CUDAグラフ機能の使用に関しては、いくつかの制約があります。
-
制御フロー演算子(つまり、
If、Loop、Scan演算子)を持つモデルはサポートされていません。 -
CUDAグラフの使用は、すべてのモデル演算子(グラフノード)をCUDA EPにパーティション分割できるモデルに限定されます。
-
モデルの入力/出力タイプはテンソルである必要があります。
-
同じグラフアノテーションIDの推論呼び出し間で、入力/出力の形状とアドレスを変更することはできません。 再生用の入力テンソルは、グラフキャプチャで使用された入力テンソルのアドレスにコピーする必要があります。
-
マルチグラフキャプチャモードでは、キャプチャされたグラフはセッションの有効期間中保持され、キャプチャされたグラフの削除機能は現在サポートされていません。
-
設計上、CUDAグラフは、グラフキャプチャステップ中と同じCUDA仮想メモリアドレスから読み取り/書き込みを行うように設計されています。 この要件のため、この機能を使用するにはIOBindingを使用して、CUDAグラフ機構が読み取り/書き込みを行うための入力/出力として使用されるメモリをバインドする必要があります(以下のサンプルを参照してください)。
-
後続の推論呼び出しの入力を更新する際、新しい入力は、バインドされた
OrtValue入力の対応するCUDAメモリ位置にコピーする必要があります(これを実現する方法については、以下のサンプルを参照してください)。これは、「グラフ再生」が同じCUDA仮想メモリアドレスから入力を読み取る必要があるためです。 -
現在、マルチスレッドでの使用はサポートされていません。つまり、CUDAグラフを使用している間、同じ
InferenceSessionオブジェクトで複数のスレッドからRun()を呼び出すことはできません。
注意:最初のRun()は、CUDAメモリ割り当て、モデルのCUDAグラフのキャプチャ、グラフが実行されることを保証するためのグラフ再生など、内部でさまざまなタスクを実行します。このため、最初のRun()に関連するレイテンシは高くなる可能性があります。後続のRun()は、最初のRun()でキャプチャされキャッシュされたグラフのグラフ再生のみを実行します。
-
Python
providers = [("CUDAExecutionProvider", {"enable_cuda_graph": '1'})]sess_options = ort.SessionOptions()sess = ort.InferenceSession("my_model.onnx", sess_options=sess_options, providers=providers)providers = [("CUDAExecutionProvider", {'enable_cuda_graph': True})]x = np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], dtype=np.float32)y = np.array([[0.0], [0.0], [0.0]], dtype=np.float32)x_ortvalue = onnxrt.OrtValue.ortvalue_from_numpy(x, 'cuda', 0)y_ortvalue = onnxrt.OrtValue.ortvalue_from_numpy(y, 'cuda', 0)session = onnxrt.InferenceSession("matmul_2.onnx", providers=providers)io_binding = session.io_binding()# RunConfigsを介してRunOptionsにgpu_graph_idを渡すro = onnxrt.RunOptions()# セッションが1つのcudaグラフのみを使用する場合、gpu_graph_idはオプションですro.add_run_config_entry("gpu_graph_id", "1")# 入力と出力をバインドするio_binding.bind_ortvalue_input('X', x_ortvalue)io_binding.bind_ortvalue_output('Y', y_ortvalue)# 必要なメモリ割り当てとcudaグラフキャプチャのための1回の通常実行session.run_with_iobinding(io_binding, ro)expected_y = np.array([[5.0], [11.0], [17.0]], dtype=np.float32)np.testing.assert_allclose(expected_y, y_ortvalue.numpy(), rtol=1e-05, atol=1e-05)# キャプチャ後、このRunからCUDAグラフの再生が行われますsession.run_with_iobinding(io_binding, ro)np.testing.assert_allclose(expected_y, y_ortvalue.numpy(), rtol=1e-05, atol=1e-05)# 入力を更新してから、更新された入力でCUDAグラフを再生するx_ortvalue.update_inplace(np.array([[10.0, 20.0], [30.0, 40.0], [50.0, 60.0]], dtype=np.float32))session.run_with_iobinding(io_binding, ro) -
C/C++
const auto& api = Ort::GetApi();struct CudaMemoryDeleter {explicit CudaMemoryDeleter(const Ort::Allocator* alloc) {alloc_ = alloc;}void operator()(void* ptr) const {alloc_->Free(ptr);}const Ort::Allocator* alloc_;};// cudaプロバイダーオプションでcudaグラフを有効にする。OrtCUDAProviderOptionsV2* cuda_options = nullptr;api.CreateCUDAProviderOptions(&cuda_options);std::unique_ptr<OrtCUDAProviderOptionsV2, decltype(api.ReleaseCUDAProviderOptions)> rel_cuda_options(cuda_options, api.ReleaseCUDAProviderOptions);std::vector<const char*> keys{"enable_cuda_graph"};std::vector<const char*> values{"1"};api.UpdateCUDAProviderOptions(rel_cuda_options.get(), keys.data(), values.data(), 1);Ort::SessionOptions session_options;api.SessionOptionsAppendExecutionProvider_CUDA_V2(static_cast<OrtSessionOptions*>(session_options), rel_cuda_options.get();// RunConfigsを介してRunOptionsにgpu_graph_idを渡すOrt::RunOptions run_option;// セッションが1つのcudaグラフのみを使用する場合、gpu_graph_idはオプションですrun_option.AddConfigEntry("gpu_graph_id", "1");// IOバインドされた入力と出力を作成します。Ort::Session session(*ort_env, ORT_TSTR("matmul_2.onnx"), session_options);Ort::MemoryInfo info_cuda("Cuda", OrtAllocatorType::OrtArenaAllocator, 0, OrtMemTypeDefault);Ort::Allocator cuda_allocator(session, info_cuda);const std::array<int64_t, 2> x_shape = {3, 2};std::array<float, 3 * 2> x_values = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f};auto input_data = std::unique_ptr<void, CudaMemoryDeleter>(cuda_allocator.Alloc(x_values.size() * sizeof(float)),CudaMemoryDeleter(&cuda_allocator));cudaMemcpy(input_data.get(), x_values.data(), sizeof(float) * x_values.size(), cudaMemcpyHostToDevice);// CUDAメモリ上のデータに裏打ちされたOrtValueテンソルを作成するOrt::Value bound_x = Ort::Value::CreateTensor(info_cuda, reinterpret_cast<float*>(input_data.get()), x_values.size(),x_shape.data(), x_shape.size());const std::array<int64_t, 2> expected_y_shape = {3, 2};std::array<float, 3 * 2> expected_y = {1.0f, 4.0f, 9.0f, 16.0f, 25.0f, 36.0f};auto output_data = std::unique_ptr<void, CudaMemoryDeleter>(cuda_allocator.Alloc(expected_y.size() * sizeof(float)),CudaMemoryDeleter(&cuda_allocator));// CUDAメモリ上のデータに裏打ちされたOrtValueテンソルを作成するOrt::Value bound_y = Ort::Value::CreateTensor(info_cuda, reinterpret_cast<float*>(output_data.get()),expected_y.size(), expected_y_shape.data(), expected_y_shape.size());Ort::IoBinding binding(session);binding.BindInput("X", bound_x);binding.BindOutput("Y", bound_y);// 必要なメモリ割り当てとグラフキャプチャのための1回の通常実行session.Run(run_option, binding);// キャプチャ後、このRunからCUDAグラフの再生が行われますsession.Run(run_option, binding);// 入力を更新してから、更新された入力でCUDAグラフを再生するx_values = {10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f};cudaMemcpy(input_data.get(), x_values.data(), sizeof(float) * x_values.size(), cudaMemcpyHostToDevice);session.Run(run_option, binding); -
C# (将来)
Python
Section titled “Python”import onnxruntime as ort
model_path = '<モデルへのパス>'
providers = [ ('CUDAExecutionProvider', { 'device_id': 0, 'arena_extend_strategy': 'kNextPowerOfTwo', 'gpu_mem_limit': 2 * 1024 * 1024 * 1024, 'cudnn_conv_algo_search': 'EXHAUSTIVE', 'do_copy_in_default_stream': True, }), 'CPUExecutionProvider',]
session = ort.InferenceSession(model_path, providers=providers)レガシープロバイダーオプション構造体の使用
Section titled “レガシープロバイダーオプション構造体の使用”OrtSessionOptions* session_options = /* ... */;
OrtCUDAProviderOptions options;options.device_id = 0;options.arena_extend_strategy = 0;options.gpu_mem_limit = 2 * 1024 * 1024 * 1024;options.cudnn_conv_algo_search = OrtCudnnConvAlgoSearchExhaustive;options.do_copy_in_default_stream = 1;
SessionOptionsAppendExecutionProvider_CUDA(session_options, &options);V2プロバイダーオプション構造体の使用
Section titled “V2プロバイダーオプション構造体の使用”OrtCUDAProviderOptionsV2* cuda_options = nullptr;CreateCUDAProviderOptions(&cuda_options);
std::vector<const char*> keys{"device_id", "gpu_mem_limit", "arena_extend_strategy", "cudnn_conv_algo_search", "do_copy_in_default_stream", "cudnn_conv_use_max_workspace", "cudnn_conv1d_pad_to_nc1d"};std::vector<const char*> values{"0", "2147483648", "kSameAsRequested", "DEFAULT", "1", "1", "1"};
UpdateCUDAProviderOptions(cuda_options, keys.data(), values.data(), keys.size());
cudaStream_t cuda_stream;cudaStreamCreate(&cuda_stream);// これは暗黙的に "has_user_compute_stream" を設定しますUpdateCUDAProviderOptionsWithValue(cuda_options, "user_compute_stream", cuda_stream);OrtSessionOptions* session_options = /* ... */;SessionOptionsAppendExecutionProvider_CUDA_V2(session_options, cuda_options);
// 最後に、プロバイダーオプションを解放することを忘れないでくださいReleaseCUDAProviderOptions(cuda_options);var cudaProviderOptions = new OrtCUDAProviderOptions(); // 最後にこれを破棄します
var providerOptionsDict = new Dictionary<string, string>();providerOptionsDict["device_id"] = "0";providerOptionsDict["gpu_mem_limit"] = "2147483648";providerOptionsDict["arena_extend_strategy"] = "kSameAsRequested";providerOptionsDict["cudnn_conv_algo_search"] = "DEFAULT";providerOptionsDict["do_copy_in_default_stream"] = "1";providerOptionsDict["cudnn_conv_use_max_workspace"] = "1";providerOptionsDict["cudnn_conv1d_pad_to_nc1d"] = "1";
cudaProviderOptions.UpdateOptions(providerOptionsDict);
SessionOptions options = SessionOptions.MakeSessionOptionWithCudaProvider(cudaProviderOptions); // 最後にこれを破棄しますまた、WindowsでC#用のCUDAを構成する方法のチュートリアルも参照してください。
OrtCUDAProviderOptions cudaProviderOptions = new OrtCUDAProviderOptions(/*device id*/0); // セッション終了後にクローズする必要があります
cudaProviderOptions.add("gpu_mem_limit","2147483648");cudaProviderOptions.add("arena_extend_strategy","kSameAsRequested");cudaProviderOptions.add("cudnn_conv_algo_search","DEFAULT");cudaProviderOptions.add("do_copy_in_default_stream","1");cudaProviderOptions.add("cudnn_conv_use_max_workspace","1");cudaProviderOptions.add("cudnn_conv1d_pad_to_nc1d","1");
OrtSession.SessionOptions options = new OrtSession.SessionOptions(); // セッション終了後にクローズする必要がありますoptions.addCUDA(cudaProviderOptions);