💭

Segformerとmmcvを使いたかった

に公開

https://github.com/NVlabs/SegFormer
SegformerとMMCVのインストールに異常にハマったのでメモ
MMCVには複数のインストール方法が用意されているがどれも一筋縄では行かない。

環境

  • ubuntu 20.04
  • python 3.9
  • pytorch 2.0
  • cuda 11.8
  • GPU(driver) 440

pipを使ったインストール

dockerを使わず直接関連モジュールをインストールする方法は

pip install torchvision==0.8.2
pip install timm==0.3.2
pip install mmcv-full==1.2.7
pip install opencv-python==4.5.1.48
cd SegFormer && pip install -e . --user

らしいがmmcv-fullのインストールでコンパイルが行われ

      In file included from /tmp/pip-install-g_bzchrp/mmcv-full_f09835954d744c919e19d1d3afc2c437/mmcv/ops/csrc/common/pytorch_cuda_helper.hpp:5,
                       from /tmp/pip-install-g_bzchrp/mmcv-full_f09835954d744c919e19d1d3afc2c437/mmcv/ops/csrc/common/cuda/active_rotated_filter_cuda_kernel.cuh:10,
                       from ./mmcv/ops/csrc/pytorch/cuda/active_rotated_filter_cuda.cu:4:
      /home/xiangze/.local/lib/python3.8/site-packages/torch/include/ATen/cuda/CUDAContext.h:10:10: fatal error: cusolverDn.h: そのようなファイルやディレクトリはありません
         10 | #include <cusolverDn.h>
            |          ^~~~~~~~~~~~~~
      compilation terminated.
      error: command '/usr/local/cuda/bin/nvcc' failed with exit code 1

とエラーが出てきた。Google&ChatGPT先生に聞きまず

find /usr/local/cuda-12.3/ -name cusolverDn.h

で得られたpathを環境変数PATHに追加したが結果は変わらず
(成功例 https://medium.com/@jackychen924/cannot-found-cusolverdn-h-775bc8741274)

で2GBほどの容量を費やし解決したが次は

      ./mmcv/ops/csrc/pytorch/cc_attention_cuda.cu:4:10: fatal error: THC/THC.h: そのようなファイルやディレクトリはありません
          4 | #include <THC/THC.h>
            |          ^~~~~~~~~~~
      compilation terminated.
      error: command '/usr/local/cuda/bin/nvcc' failed with exit code 1

というエラーが出る。これは
https://github.com/open-mmlab/mmdetection3d/issues/1332
によれば依存しているPytorch 1.11 からTHC/THC.hが削除されたためでPytorchをダウングレードするか、ソースを修正してコンパイルする必要がある。
(https://github.com/open-mmlab/OpenPCDet/issues/1014 も同様)
https://www.kaggle.com/code/ipolas/fcos-object-detection

mmcvのソースからのインストール

git clone https://github.com/open-mmlab/mmcv.git

でソースを落として上記のような修正を施しコンパイルする。やや大変そう

mimを使ったインストール(推奨)

https://qiita.com/tkm0707/items/624e1e234dc904fed610
ではここでも上げたMMCVインストールの3つの方法

自動運転系のライブラリUniAD,VADなどもmim, MMCVに依存している。
そもそも
https://mmcv.readthedocs.io/en/latest/get_started/installation.html#install-with-pip
にOS, cuda, mmcv, pytorchのバージョン別のpipダウンロードコマンドが書かれていて親切。

だがやはりコンパイルが必要で冒頭のものと同じエラーが出てしまった。pytorch2.0以降を使っている限りエラーからは逃れられない。

dockerを使う方法

まずmmcvのdockerを試みる

git clone https://github.com/open-mmlab/mmcv.git && cd mmcv
docker build -t mmcv -f docker/release/Dockerfile .

nvidia dockerより大きく、build時間もかかる。(Ubuntu Disk fullで起動できなくなった時の対処法)

別の環境では

ERROR: failed to solve: pytorch/pytorch:1.8.1-cuda10.2-cudnn7-devel: failed to resolve source metadata for docker.io/pytorch/pytorch:1.8.1-cuda10.2-cudnn7-devel: failed to do request: Head "https://registry-1.docker.io/v2/pytorch/pytorch/manifests/1.8.1-cuda10.2-cudnn7-devel": Forbidden

というエラーが発生した。

参考nvidia dockerからの作成

pytorch,CUDAのバージョンを合わせるために
https://zenn.dev/ihpolyphe/articles/b0ba1143dab0f1
を参考にdockerを使った方法を試みる。
https://qiita.com/dandelion1124/items/31a3452b05510097daa0
ではCUDA10.2を使っているそうだが、そうでなければCUDAをダウングレードするのではなく素直にdockerxをインストールすれば良さそう。

git clone https://gitlab.com/nvidia/container-images/cuda.git

でコンテナイメージをダウンロードしてbuildする。buildxも問題なくbuildが進むがしかし

docker buildx build --pull --load --platform linux/x86_64 -t nvidia/cuda:10.2-runtime-ubuntu18.04 --build-arg IMAGE_NAME=nvidia/cuda dist/10.2/ubuntu1804/runtime 

ERROR: failed to solve: nvidia/cuda:10.2-base-ubuntu18.04:

がでてしまった。dockerhubにも存在しない。
https://forums.developer.nvidia.com/t/18-04-cuda-docker-image-is-broken/212892/14
を見るとDockerfileにapt keyを追加するかRUN apt-key del 7fa2af80 をコメントアウトせよとある。

参考 NVIDIAのDockerコンテナとCUDAのバージョン

ChatGPTのまとめによるとNVIDIAのDockerコンテナはCUDAのバージョンごとにあり、

git clone https://gitlab.com/nvidia/container-images/cuda.git

で入手可能だが

[アプリ層]     PyTorch / TensorFlow など
[CUDAライブラリ層]  libcudart, cuBLAS, cuDNN など
[ドライバ層]    NVIDIA Driver (ホストOS側)
[ハードウェア層] GPU (実機)

といった階層構造をもちGPUハードウェアに対応したホストOSにインストールされたドライバ、に対応したコンテナを使わないとならず

#例
CTK_TAG="12.3.0 545.23.06"
FLAVOR="runtime" # or devel
BASE_OS="ubuntu20.04"

docker pull "nvidia/cuda:${CTK_TAG}-${FLAVOR}-${BASE_OS}"

と切り替えるらしい。
で入手可能
インストールされたGPUドライバ版のバージョンと互換ルールに従って“使える中で最も新しいCUDAタグ”を自動で選択してくれるスクリプト(ChatGPT5作成)

#!/usr/bin/env bash
set -euo pipefail

FLAVOR="${1:-}"
# 引数パース(超簡易)
BASE_OS="ubuntu22.04"
FLAVOR="runtime"
DRY_RUN=0
while [[ $# -gt 0 ]]; do
  case "$1" in
    --base) BASE_OS="$2"; shift 2;;
    --flavor) FLAVOR="$2"; shift 2;;
    --dry-run) DRY_RUN=1; shift;;
    -h|--help)
      cat <<'USAGE'
Usage: pick-cuda-container.sh [--base ubuntu22.04|ubuntu24.04|rockylinux9] [--flavor runtime|devel] [--dry-run]
Detect host NVIDIA driver version and pull the newest compatible nvidia/cuda:<ctk>-<flavor>-<base> image.

Examples:
  pick-cuda-container.sh
  pick-cuda-container.sh --flavor devel
  pick-cuda-container.sh --base ubuntu24.04
  pick-cuda-container.sh --dry-run
USAGE
      exit 0;;
    *) echo "Unknown option: $1" >&2; exit 1;;
  esac
done

# 必須チェック
command -v nvidia-smi >/dev/null 2>&1 || { echo "ERROR: nvidia-smi が見つかりません(NVIDIAドライバ未インストール?)" >&2; exit 1; }

DRV_RAW="$(nvidia-smi --query-gpu=driver_version --format=csv,noheader | head -n1)"
if [[ -z "${DRV_RAW}" ]]; then
  echo "ERROR: ドライバ版を取得できませんでした。" >&2; exit 1
fi

# 文字列 "XXX.YY.ZZ" → 比較しやすい整数へ (major*1e6 + minor*1e3 + patch)
ver_to_int() {
  local v="$1"
  IFS='.' read -r M m p <<<"$v"
  : "${M:=0}"; : "${m:=0}"; : "${p:=0}"
  printf '%d\n' "$((10#$M*1000000 + 10#$m*1000 + 10#$p))"
}

DRV_INT="$(ver_to_int "${DRV_RAW}")"

# --- 互換テーブル(NVIDIA公式の最小ドライバに基づく) ---
# 可能な限り新しいCUDA(CTK)を上から順に選ぶ
# 参考: CUDA Toolkit Release Notes の "CUDA Toolkit and Corresponding Driver Versions"
# 13.x系は r580+、12.x系は r525+、11.x系は r450+ でマイナ互換。細かいGA/Updateの最小値は下記。 
# 出典: https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/ (表2・表3) など
CTK_LIST=(
  # CTK_VERSION   MIN_DRIVER
  "13.0.2 580.95.05"
  "13.0.1 580.82.07"
  "13.0.0 580.65.06"
  "12.9.1 575.57.08"
  "12.9.0 575.51.03"
  "12.8.1 570.124.06"
  "12.8.0 570.26"
  "12.6.0 560.28.03"
  "12.5.0 555.42.02"
  "12.4.0 550.54.14"
  "12.3.0 545.23.06"
  "12.2.0 535.54.03"
  "12.1.0 530.30.02"
  "12.0.0 525.60.13"
  "11.8.0 520.61.05"
  "11.7.0 515.43.04"
  "11.6.0 510.39.01"
  "11.5.0 495.29.05"
  "11.4.0 470.42.01"
  "11.3.0 465.19.01"
  "11.2.0 460.27.03"
  "11.1.0 455.23"
  "11.0.2 450.51.05"
)

pick_ctk=""
for entry in "${CTK_LIST[@]}"; do
  CTK_VER="${entry%% *}"
  MIN_DRV="${entry##* }"
  if (( DRV_INT >= $(ver_to_int "${MIN_DRV}") )); then
    pick_ctk="${CTK_VER}"
    break
  fi
done

if [[ -z "${pick_ctk}" ]]; then
  echo "ERROR: ドライバ ${DRV_RAW} に対応するCUDAバージョンが見つかりません(ドライバが古すぎる可能性)。" >&2
  echo "NVIDIAドライバ更新をご検討ください。" >&2
  exit 1
fi

# nvidia/cuda のタグは通常 "major.minor[.patch]-<flavor>-<base>" 形式。
# 13.0.2 → 13.0 (Dockerタグはパッチを含まないことが多い) に丸める
CTK_TAG="${pick_ctk%.*}"   # 13.0.2 -> 13.0, 12.6.0 -> 12.6
IMAGE="nvidia/cuda:${CTK_TAG}-${FLAVOR}-${BASE_OS}"

echo "Detected NVIDIA Driver: ${DRV_RAW}"
echo "Recommended CUDA Toolkit: ${pick_ctk}  (Docker tag uses: ${CTK_TAG})"
echo "Container image candidate: ${IMAGE}"

if [[ ${DRY_RUN} -eq 1 ]]; then
  echo "[dry-run] docker pull は実行しません。"
  exit 0
fi

# 前提: NVIDIA Container Toolkit が導入済み(必要なら公式手順で導入)
# https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html
if ! docker --version >/dev/null 2>&1; then
  echo "ERROR: docker が見つかりません。Docker を先にインストールしてください。" >&2
  exit 1
fi

echo "Pulling ${IMAGE} ..."
docker pull "${IMAGE}"

cat <<NOTE

Done.

次のように起動できます:
  docker run --rm --gpus all ${IMAGE} nvidia-smi

備考:
- このスクリプトは NVIDIA公式の最小ドライバ表に準拠して「使える中で最も新しいCUDA」を選択します。
- 13.x は原則 r580 以上、12.x は r525 以上のドライバで動作します(マイナ互換)。詳細は公式互換ガイドをご参照ください。
NOTE

その後

ディスクオーバーからの復活によるファイル削除によってNvidia driverが飛んだのでnvidia-driver-535とCUDA 12.1を再インストールした結果MMCV pipで提供しているVersionの組の中のものを使えるようになった。
https://mmcv.readthedocs.io/en/latest/get_started/installation.html#install-with-pip

pip install mmcv==2.2.0 -f https://download.openmmlab.com/mmcv/dist/cu121/torch2.1/index.html

感想

GPU driver, cuda, pytorch, mmcvの依存関係が組み合わさって極めて煩雑、特にPytorch2.0以降に対応していないのが引っかかってしまった。dockerも使えるがdockerxに関わる変更も過去の手法が使えない要因となり混乱してしまった。

参考

https://qiita.com/fakefurcoronet/items/b168cad7c2706f42c146

https://note.com/dr_syuna/n/na62ea78a4450

成功例

https://qiita.com/tkm0707/items/624e1e234dc904fed610#:~:text=ViTPoseとは,姿勢推定,推定に用いたモデル.

その3:githubからリポジトリをクローンしてからインストールする
私は唯一この方法を使ってバージョン指定でインストール成功しました.

git clone https://github.com/open-mmlab/mmcv.git

cd mmcv
git checkout v1.7.2
MMCV_WITH_OPS=1 pip install -e .

追記: uvを使った場合で失敗

uv を使って

curl -LsSf https://astral.sh/uv/install.sh | sh #インストール一回のみ

古いNvidiaドライバにCUDA11.8用のpytorchをいれて

uv venv .venv
source .venv/bin/activate

uv pip install "torch==2.1.0" "torchvision==0.16.0" --index-url https://download.pytorch.org/whl/cu118
uv pip install -U openmim
uv run mim install "mmcv==2.1.0"
uv pip install "mmsegmentation>=1.0.

みたものの

ModuleNotFoundError: No module named 'mmcv._ext'

と出てしまった。CUDA Driver上げるしかないのか
https://chatgpt.com/share/691b1258-2124-8008-8932-a06f87af4b93

朗報 UniAD2.0

https://github.com/OpenDriveLab/UniAD
UniADがmmdet3d 1.x & torch 2.x系に対応

Discussion