【CUDA】update-alternativesで複数バージョンを共存・切り替え!「libcudart.so.XX not found」エラー解決法

問題の概要:CUDAバージョン不一致によるエラー

AI開発、特に深層学習のモデル訓練や推論を行う際、異なるフレームワークやプロジェクトが要求するCUDAバージョンが異なることに悩まされることはありませんか? 一つのシステムに複数のCUDAツールキットをインストールした後、以下のような典型的なエラーメッセージに遭遇することがあります。

ImportError: libcudart.so.11.0: cannot open shared object file: No such file or directory

または、コマンドラインでnvcc --versionを実行した際のバージョンと、Pythonスクリプト内でtorch.cuda.is_available()を確認した際に参照されるバージョンが異なり、結果的にPyTorchやTensorFlowがGPUを認識しないという問題も発生します。

# 矛盾するバージョン情報の例
$ nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2022 NVIDIA Corporation
Built on_Wed_Sep_21_10:33:46_PDT_2022
Cuda compilation tools, release 11.8, V11.8.89

$ python3 -c "import torch; print(torch.version.cuda)"
10.2
# torchはCUDA 10.2を探しているが、現在のnvccは11.8を示している

この問題は、システムのパス(PATH, LD_LIBRARY_PATH)が指し示すCUDAインストールディレクトリと、アプリケーションが想定するバージョンが一致しないために発生します。手動で環境変数を切り替える方法もありますが、プロジェクトやターミナルセッションごとに管理するのは煩雑でミスの元です。

原因の解説:シンボリックリンクとランタイムリンカの仕組み

Linuxシステムでは、nvcclibcudart.soのような実行ファイルやライブラリへのパスは、多くの場合、シンボリックリンクを通じて管理されています。デフォルトでは、CUDAインストーラーは/usr/local/cuda というシンボリックリンクを最新のインストールバージョンに向けます。

問題は、この/usr/local/cudaリンクを手動で変更した場合、すべての関連するバイナリやライブラリのパスを一貫して変更する必要がある点です。nvccのパスはPATH環境変数で、ライブラリのパスはLD_LIBRARY_PATH環境変数で管理されますが、これらを個別に切り替えるのは非効率です。

より根本的な原因は、システムに「CUDAのデフォルトバージョン」を宣言する統一されたメカニズムが標準で存在しないことです。このため、異なるソフトウェアが異なる方法でCUDAバージョンを探し、結果的に不一致が生じるのです。

解決方法:update-alternativesによるシステム統合管理

Debian/Ubuntu系のLinuxディストリビューションに備わるupdate-alternativesコマンドは、この問題に対する強力な解決策です。このツールは、同じ機能を持つ複数のプログラム(代替手段)をシステムに登録し、システム全体で使用する「デフォルト」を一元的に切り替えることを可能にします。

ここでは、CUDA 11.8とCUDA 12.1が既に/usr/local/cuda-11.8/usr/local/cuda-12.1にインストールされていることを前提に、手順を説明します。

ステップ1: 既存の /usr/local/cuda リンクの確認とバックアップ

まず、現在のシステム設定を確認します。

ls -l /usr/local/cuda
# 例: lrwxrwxrwx 1 root root 20 Apr 10 12:00 /usr/local/cuda -> /usr/local/cuda-11.8

既にシンボリックリンクが存在する場合は、後で競合する可能性があるため、削除またはリネームします。

sudo rm /usr/local/cuda  # シンボリックリンクのみ削除(CUDA本体は消えません)
# またはバックアップを取る
sudo mv /usr/local/cuda /usr/local/cuda.bak

ステップ2: update-alternatives システムへのCUDA登録

update-alternatives --installコマンドを使って、各CUDAバージョンを「cuda」グループの代替候補として登録します。優先度の数字が大きいほど、自動モード時のデフォルトとして選ばれやすくなります(ここでは新しい12.1を優先度120に設定)。

# CUDA 11.8を登録
sudo update-alternatives --install /usr/local/cuda cuda /usr/local/cuda-11.8 110 
--slave /usr/local/cuda/bin nvcc /usr/local/cuda-11.8/bin/nvcc 
--slave /usr/local/cuda/lib64 libcuda.so /usr/local/cuda-11.8/lib64/libcuda.so

# CUDA 12.1を登録
sudo update-alternatives --install /usr/local/cuda cuda /usr/local/cuda-12.1 120 
--slave /usr/local/cuda/bin nvcc /usr/local/cuda-12.1/bin/nvcc 
--slave /usr/local/cuda/lib64 libcuda.so /usr/local/cuda-12.1/lib64/libcuda.so

--slaveオプションが重要です。これにより、メインの/usr/local/cudaリンクを切り替えると、連動してnvccバイナリへのパス(/usr/local/cuda/bin)や、重要なライブラリlibcuda.soへのパスも自動的に切り替わります。必要に応じて、他の重要なバイナリ(cuda-gdb, cuobjdump等)やライブラリも--slaveで登録できます。

ステップ3: 使用するCUDAバージョンの切り替え

登録が完了したら、以下のコマンドでインタラクティブにバージョンを選択できます。

sudo update-alternatives --config cuda

実行すると、以下のような選択メニューが表示されます。

There are 2 choices for the alternative cuda (providing /usr/local/cuda).

  Selection    Path                  Priority   Status
------------------------------------------------------------
* 0            /usr/local/cuda-12.1   120       auto mode
  1            /usr/local/cuda-11.8   110       manual mode
  2            /usr/local/cuda-12.1   120       manual mode

Press <enter> to keep the current choice[*], or type selection number:

使用したいバージョンの番号(ここでは1または2)を入力し、Enterキーを押します。これで、/usr/local/cudaおよび関連するすべてのスレーブリンクが一括で切り替わります。

ステップ4: 切り替えの確認

切り替えが正しく行われたか、以下のコマンドで確認します。

# メインリンクの確認
ls -l /usr/local/cuda
# nvccコンパイラのバージョン確認
nvcc --version
# ランタイムライブラリのパス確認 (例)
ldconfig -p | grep cudart

コード例・コマンド例:よくある操作とトラブルシューティング

登録されている代替候補の一覧表示

update-alternatives --display cuda

このコマンドは、各候補の詳細なパス、優先度、現在のモード(auto/manual)を表示します。

特定のバージョンをコマンドラインで直接指定して切り替え

sudo update-alternatives --set cuda /usr/local/cuda-11.8

インタラクティブなメニューを出さずに、直接バージョンを指定したい場合に便利です。

登録解除(アンインストール)の方法

sudo update-alternatives --remove cuda /usr/local/cuda-11.8

古いCUDAバージョンをシステムから削除した後、update-alternativesの登録情報からも削除するために使用します。

環境変数の設定(~/.bashrcへの追記)

update-alternativesでリンクを切り替えても、シェルの環境変数が古いパスをキャッシュしている場合があります。確実にするために、~/.bashrcまたは~/.zshrcに以下を追加しましょう。

export PATH=/usr/local/cuda/bin:${PATH}
export LD_LIBRARY_PATH=/usr/local/cuda/lib64:${LD_LIBRARY_PATH}
# または、より堅牢な方法として
export LD_LIBRARY_PATH=/usr/local/cuda/lib64:/usr/lib64/nvidia:${LD_LIBRARY_PATH}

変更を反映させるには、シェルを再起動するか、source ~/.bashrcを実行します。

まとめ・補足情報

update-alternativesを活用したCUDAバージョン管理は、システム全体のデフォルトバージョンを一貫して、かつ簡単に切り替えることを可能にします。これにより、「ライブラリが見つからない」エラーや、ツール間のバージョン不一致に起因するトラブルを大幅に軽減できます。

重要な補足点:

  • フレームワークとの連携: PyTorchやTensorFlowのようなディープラーニングフレームワークは、pipやcondaでインストールする際に特定のCUDAバージョンに紐づいたバイナリをダウンロードします。update-alternativesでシステムのCUDAを切り替えても、既にインストールされたPyTorchのバイナリ自体の互換性は変わりません。プロジェクトごとに仮想環境(venv, conda)を使い、その中でフレームワークとCUDAバージョンを揃えてインストールするのがベストプラクティスです。システムのCUDAは、その環境下でコンパイルが必要なカスタムCUDAカーネルやツールに対して主に影響します。
  • NVIDIAドライバーとの関係: CUDAツールキットのバージョンは、インストールされているNVIDIA GPUドライバーのバージョンによってサポートされる上限が決まります。nvidia-smiコマンドで表示される右上の「CUDA Version」は、ドライバーがサポートする最大のCUDAランタイムバージョンです。それ以下のCUDAツールキットは通常問題なく動作します。
  • コンテナ環境: DockerやSingularityなどのコンテナ技術を使用する場合、コンテナイメージ内に完全なCUDA環境がパッケージ化されるため、ホスト側のupdate-alternatives設定の影響を受けません。開発環境と本番環境の再現性を高めるために、コンテナの利用も強く推奨されます。

この方法を身につけることで、様々なCUDAバージョンを要求する研究プロジェクトやライブラリの開発を、一つのマシン上でスムーズに進められるようになるでしょう。

この記事は役に立ちましたか?