覚え書き: cmdstanr+OpenCLでGPUをうまく使えたり使えなかったり (WSL2-Ubuntu-NVIDEA編)

 cmdstanrパッケージでOpenCLを経由してGPUを使う方法についての試行錯誤の記録、その第三弾。こんどは、Windows上のWSL(Windows Subsystem for Linux)の上でLinuxを動かし、そこでcmdstanからGPUを使ってみようという試みである。
 なんだか遠回りな話だが、一概にばかばかしいとはいえない。下のCase 21でわかるように、GPUを使わない場合、Windows上でcmdstanを使うより、おなじPCのWindows上のWSL上のLinux仮想マシン上でcmdstanを使ったほうが、計算速度が速かったりするのである。

目次

Case 21-22の準備

 本件、ここ数日にわたってあれこれ試しすぎて頭が混乱してきたので、すべてを消して一からやりなおすことにする。

 まずはWSL上で動くUbuntu仮想マシンの準備から。

  • Windows 10 Home (22H2)
  • WSLってなんだかいろいろあるらしいんだけど、ここではMicrosoft StoreからダウンロードしたWSL2を使ってます。
  • 既存のdistroを削除。Windowsのコマンドラインから
    wsl --unregistor

    ついでにWindowsの「機能とアプリ」から、既存のdistroの項目をすべて削除。

  • 念のため、wslそのものの更新を試みておく。
    wsl --update
    wsl --version

    WSLバージョンは 1.2.5.0 であった。

  • どのdistroをいれようか考える。ちょっと楽しいですね。
    wsl --list --online
  • 無難にUtuntuをいれることにして…
    wsl --install Ubuntu

    ここでユーザ名とパスワードの設定を求められるはず。

  • 今後のため、Windows Terminal上にUbuntu用の設定をつくっておく。これ、なんとなく自動で設定されるような気がしていたよ。私これまでどうしていたのだろうか?
    • 名前: Ubuntu
    • コマンドライン: wsl.exe -d Ubuntu
    • 開始ディレクトリ: %USERPROFILE%
    • アイコン: https://assets.ubuntu.com/v1/49a1a858-favicon-32×32.png
    • 外観-テキスト-フォントサイズ: 11
    • 外観-テキスト-見分けがつかないテキストの明るさを自動的に調整する: 常時

    Windows TerminalでUbuntuのターミナル画面を開けることを確認。

  • Ubuntuのリリースを確認する。Ubuntuのターミナルから
    lsb_release -a

    あいたたた、単にUbuntuと指定すると、Ubuntu 22.04.2 LTSとなるようだ。20.04がよかったんだけど… まあいいか…

  • システムを更新しておく。Ubuntuのターミナルから
    sudo apt update
    sudo apt upgrade
  • R 4.3.1をインストール。CRANの指示に従い、
    wget -qO- https://cloud.r-project.org/bin/linux/ubuntu/marutter_pubkey.asc | sudo tee -a /etc/apt/trusted.gpg.d/cran_ubuntu_key.asc
    sudo add-apt-repository "deb https://cloud.r-project.org/bin/linux/ubuntu $(lsb_release -cs)-cran40/"
    sudo apt install --no-install-recommends r-base
  • RStudio Server 2023.06.1 Build 524 のインストール。posit様の指示に従い、
    sudo apt-get install gdebi-core
    wget https://download2.rstudio.org/server/jammy/amd64/rstudio-server-2023.06.1-524-amd64.deb
    sudo gdebi rstudio-server-2023.06.1-524-amd64.deb

    RStudio Serverがスタートしたようなので、Windows上のブラウザから localhost:8787 にアクセスし、ログインできることを確認。

こんどはOpenCLの設定。

  • このPCにはGPUとしてNVIDIA GeForce GTX 660が載っています。ドライババージョンは474.44。
  • まず、OpenCL実行環境について調べるためにclinfoをインストールしておく。Ubuntuのターミナルから
    sudo apt install clinfo

    さっそくclinfoと実行してみると、Number of platforms: 0と表示される。まだOpenCLが設定できていないわけである。

  • ここで肝心なのは、NVIDIAのドライバ類を一切インストールしないこと。単にCUDA ToolkitのWSL-Ubuntu版をインストールすればよいのである。
     CUDA Toolkitのリリースノートを参照し、グラフィック・ドライバと整合する適切なバージョンを選び、CUDA Toolkitの配布ページを参照して、インストール用のコマンドを教えてもらう。
     …というのは簡単だが、正直なところ、バージョンの選び方がわからない。リリースノートの説明が良く理解できないのだ。私の場合は11.7.1を選んでうまくいかず、すべてアンインストールして、11.4.4で再挑戦した。
     dev(local)を選んだ場合のコマンドは以下の通り。

    wget https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/cuda-wsl-ubuntu.pin
    sudo mv cuda-wsl-ubuntu.pin /etc/apt/preferences.d/cuda-repository-pin-600
    wget https://developer.download.nvidia.com/compute/cuda/11.4.4/local_installers/cuda-repo-wsl-ubuntu-11-4-local_11.4.4-1_amd64.deb
    sudo dpkg -i cuda-repo-wsl-ubuntu-11-4-local_11.4.4-1_amd64.deb
    sudo apt-key add /var/cuda-repo-wsl-ubuntu-11-4-local/7fa2af80.pub
    sudo apt-get update
    sudo apt-get -y install cuda

    最後の行は、liburcu6がないというエラーになった。以下を実行してから改めて実行した。

    sudo add-apt-repository ppa:cloudhan/liburcu6
    sudo apt update
    sudo apt install liburcu6
  • 無事インストールは終わったが、clinfoは依然としてNumber of platforms: 0と返してくる。こちらの投稿によれば、さらにOpenCL開発パッケージとランタイムが必要になる(とChatGPTが教えてくれたのだそうだ。ははは)。
    sudo apt-get install ocl-icd-opencl-dev
    sudo apt-get install pocl-opencl-icd
  • 再度clinfoを動かしてみると… おお!なんか出てきた!
    Number of platforms                               1
      Platform Name                                   Portable Computing Language
      Platform Vendor                                 The pocl project
      Platform Version                                OpenCL 2.0 pocl 1.8  Linux, None+Asserts, RELOC, LLVM 11.1.0, SLEEF, DISTRO, POCL_DEBUG
      Platform Profile                                FULL_PROFILE
      Platform Extensions                             cl_khr_icd cl_pocl_content_size
      Platform Extensions function suffix             POCL
    
      Platform Name                                   Portable Computing Language
    Number of devices                                 1
      Device Name                                     pthread-Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz
      Device Vendor                                   GenuineIntel
      Device Vendor ID                                0x6c636f70
      Device Version                                  OpenCL 1.2 pocl HSTR: pthread-x86_64-pc-linux-gnu-ivybridge
      Driver Version                                  1.8
      Device OpenCL C Version                         OpenCL C 1.2 pocl
    (後略)

    しかし、Device NameのところにCPUが出てくるのが不安だなあ…

  • NVIDEAのシステム管理ツールnvidia-smiの出力もおかしい。
    +-----------------------------------------------------------------------------+
    | NVIDIA-SMI 470.199.01   Driver Version: 474.44       CUDA Version: 11.4     |
    |-------------------------------+----------------------+----------------------+
    | GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
    | Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
    |                               |                      |               MIG M. |
    |===============================+======================+======================|
    |   0  NVIDIA GeForce ...  Off  | 00000000:01:00.0 N/A |                  N/A |
    |ERR!    0C    P8    N/A /  N/A |    420MiB /  1536MiB |     N/A      Default |
    |                               |                      |                  N/A |
    +-------------------------------+----------------------+----------------------+
    
    +-----------------------------------------------------------------------------+
    | Processes:                                                                  |
    |  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
    |        ID   ID                                                   Usage      |
    |=============================================================================|
    |  No running processes found                                                 |
    +-----------------------------------------------------------------------------+
  • いっぽう、/usr/local/cuda/extras/demo_suite/deviceQueryというツールによれば、GPUはちゃんと認識されている。
    ./deviceQuery Starting...
    
     CUDA Device Query (Runtime API) version (CUDART static linking)
    
    Detected 1 CUDA Capable device(s)
    
    Device 0: "NVIDIA GeForce GTX 660"
      CUDA Driver Version / Runtime Version          11.4 / 11.4
      CUDA Capability Major/Minor version number:    3.0
    (後略)

    よくわかんないけど、ちゃんとOpenCLに対応しているのだろうか。不安になってきた。

Case 21. Win10, WLS-Ubuntu 22.04, R4.3.1, Rtools 4.3, cmdstan2.32.2, OpenCLなし, 成功

お待たせしました、cmdstanrの登場です。まずはOpenCLを使わないベンチマーク。

  • cmdstanr 0.5.3開発版をインストール。
    install.packages("remotes")
    remotes::install_github("stan-dev/cmdstanr")
  • cmdstan2.32.2をインストール。
    cmdstanr::install_cmdstan(cores = 4, overwrite = TRUE)
  • コンパイル。前々回記事で作ったstantest.stanを使います。
    mod <- cmdstan_model("./stantest.stan", force_recompile = TRUE)
  • サンプリング。
    n <- 250000
    k <- 20
    X <- matrix(rnorm(n * k), ncol = k)
    y <- rbinom(n, size = 1, prob = plogis(3 * X[,1] - 2 * X[,2] + 1))
    mdata <- list(k = k, n = n, y = y, X = X)
    fit <- mod$sample(data = mdata, chains = 4, parallel_chains = 4, refresh = 100)

    無事終了。所要時間は504秒であった。同じマシンのWindows上の所要時間が584秒だから、こっちのほうが少し早いわけだ。

Case 22. Win10, WLS-Ubuntu22.04, R4.3.1, Rtools4.3, cmdstan2.32.2, OpenCL(NVIDIA CUDA11.4.4), 失敗

いよいよOpenCLの登場。

  • cmdstanr 0.5.3開発版をインストール。
  • cmdstan2.32.2をインストール。
    cmdstanr::install_cmdstan(cores = 4, overwrite = TRUE, cpp_options = list(STAN_OPENCL=TRUE))
  • コンパイル。
    mod <- cmdstan_model(
      "./stantest.stan", 
      force_recompile = TRUE, 
      cpp_options = list(stan_opencl = TRUE)
    )
  • サンプリング。
    n <- 250000
    k <- 20
    X <- matrix(rnorm(n * k), ncol = k)
    y <- rbinom(n, size = 1, prob = plogis(3 * X[,1] - 2 * X[,2] + 1))
    mdata <- list(k = k, n = n, y = y, X = X)
    fit <- mod$sample(data = mdata, chains = 4, parallel_chains = 4, opencl_ids = c(0, 0), refresh = 100)

    無事終了したが、所要時間はなんと970秒。それもそのはず、タスクマネージャを確認すると、GPUを全然使っていないのである。やっぱり、OpenCLが設定できていないようだ。

 NVIDIAのCUDA on WSL User Guideによれば、公式にサポートしているGPUはPascal世代以降。その前のMaxwell世代のGPUはサポート外だがたぶん動く、とのこと。わがマシーンのGTX 660はさらにその前、Kepler世代ってやつだもんな。ダメか... がっくり。

Case 23-24の準備

[2023/10/11 追記] 新PCをお迎えしたので再挑戦。以下はその記録です。

 まずはWSL2-Ubuntu環境の用意。

  • Windows 11 Pro (22H2)
  • Microsoft StoreからWSL2をインストール。
  • 念のため、wslそのものの更新を試みたが(上述)、更新不要だった模様。WSLバージョンは 1.2.5.0。
  • Utuntuのインストール。
    wsl --install Ubuntu-22.04

    ここでユーザ名とパスワードの設定を求められた。

  • 今回は、Windows Terminal上にUbuntu用の設定が勝手に作られた。
  • システムを更新しておく。上述。
  • R 4.3.1をインストール。上述。
  • RStudio Server 2023.09.0 Build 463 のインストール。posit様の指示に従い、
    sudo apt-get install gdebi-core
    wget https://download2.rstudio.org/server/jammy/amd64/rstudio-server-2023.09.0-463-amd64.deb
    sudo gdebi rstudio-server-2023.09.0-463-amd64.deb

    Windows上のブラウザから localhost:8787 にアクセスし、ログインできることを確認。

おつぎはOpenCLの設定。

  • このPCにはGPUとしてNVIDIA GeForce GTX 4070が載っています(貧乏性の私としては結構張り込みました)。ドライババージョンは537.58。
  • clinfoのインストール。上述。
  • CUDA ToolkitのWSL-Ubuntu版をインストール。おそらく最新版で大丈夫だろうと踏んで、こちらで [Linux] - [x86_64] - [WSL-Ubuntu] - [2.0] - [dev(network)] を選んだところ、以下の神託がくだされた。
    wget https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/cuda-keyring_1.1-1_all.deb
    sudo dpkg -i cuda-keyring_1.1-1_all.deb
    sudo apt-get update
    sudo apt-get -y install cuda

    最後までエラーなしで実行できました。なお、後述するnvidia-smiの出力によれば、インストールされたのはCUDA 12.2らしい。

  • clinfoは依然としてNumber of platforms: 0と返してくる。
  • OpenCL開発パッケージとランタイムをインストール。
    sudo apt-get install ocl-icd-opencl-dev
    sudo apt-get install pocl-opencl-icd
  • 再度clinfoを動かしてみると...
    Number of platforms                               1
      Platform Name                                   Portable Computing Language
      Platform Vendor                                 The pocl project
      Platform Version                                OpenCL 2.0 pocl 1.8  Linux, None+Asserts, RELOC, LLVM 11.1.0, SLEEF, DISTRO, POCL_DEBUG
      Platform Profile                                FULL_PROFILE
      Platform Extensions                             cl_khr_icd cl_pocl_content_size
      Platform Extensions function suffix             POCL
    
      Platform Name                                   Portable Computing Language
    Number of devices                                 1
      Device Name                                     pthread-13th Gen Intel(R) Core(TM) i5-13400F
      Device Vendor                                   GenuineIntel
      Device Vendor ID                                0x6c636f70
      Device Version                                  OpenCL 1.2 pocl HSTR: pthread-x86_64-pc-linux-gnu-goldmont
      Driver Version                                  1.8
      Device OpenCL C Version                         OpenCL C 1.2 pocl
    (後略)

    今回も、Device NameのところにCPUが出てきている... 不安だ...

  • NVIDEAのシステム管理ツールnvidia-smiの出力は以下のとおり。こちらはGPUが表示されている。
    +---------------------------------------------------------------------------------------+
    | NVIDIA-SMI 535.112                Driver Version: 537.42       CUDA Version: 12.2     |
    |-----------------------------------------+----------------------+----------------------+
    | GPU  Name                 Persistence-M | Bus-Id        Disp.A | Volatile Uncorr. ECC |
    | Fan  Temp   Perf          Pwr:Usage/Cap |         Memory-Usage | GPU-Util  Compute M. |
    |                                         |                      |               MIG M. |
    |=========================================+======================+======================|
    |   0  NVIDIA GeForce RTX 4070        On  | 00000000:01:00.0  On |                  N/A |
    |  0%   52C    P8              12W / 200W |    908MiB / 12282MiB |      2%      Default |
    |                                         |                      |                  N/A |
    +-----------------------------------------+----------------------+----------------------+
    
    +---------------------------------------------------------------------------------------+
    | Processes:                                                                            |
    |  GPU   GI   CI        PID   Type   Process name                            GPU Memory |
    |        ID   ID                                                             Usage      |
    |=======================================================================================|
    |    0   N/A  N/A        26      G   /Xwayland                                 N/A      |
    +---------------------------------------------------------------------------------------+
  • /usr/local/cuda/extras/demo_suite/deviceQueryというツールによれば、GPUはちゃんと認識されている。
    /usr/local/cuda/extras/demo_suite/deviceQuery Starting...
    
     CUDA Device Query (Runtime API) version (CUDART static linking)
    
    Detected 1 CUDA Capable device(s)
    
    Device 0: "NVIDIA GeForce RTX 4070"
      CUDA Driver Version / Runtime Version          12.2 / 12.2
      CUDA Capability Major/Minor version number:    8.9
    (後略)

では、準備はできたということにして、いよいよテストです。

Case 23. Win11, WLS-Ubuntu22.04, R4.3.1, Rtools 4.3, cmdstan2.33.1, OpenCLなし, 成功

まずはOpenCLを使わないベンチマーク。

  • cmdstanr 0.6.1をインストール。
    install.packages("cmdstanr", repos = c("https://mc-stan.org/r-packages/", getOption ("repos")))
  • cmdstan2.33.1をインストール。
    cmdstanr::install_cmdstan(cores = 4, overwrite = TRUE)
  • コンパイル。前々回記事で作ったstantest2.stanを使います。
    mod <- cmdstan_model("./stantest.stan", force_recompile = TRUE)
  • サンプリング。
    n <- 250000
    k <- 20
    X <- matrix(rnorm(n * k), ncol = k)
    y <- rbinom(n, size = 1, prob = plogis(3 * X[,1] - 2 * X[,2] + 1))
    mdata <- list(k = k, n = n, y = y, X = X)
    fit <- mod$sample(data = mdata, chains = 4, parallel_chains = 4, refresh = 100)

    無事終了。所要時間は203秒であった。

Case 24. Win11, WLS-Ubuntu 22.04, R4.3.1, Rtools 4.3, cmdstan2.33.1, OpenCL(NVIDIA CUDA12.2), 失敗

いよいよOpenCLの登場。

  • cmdstanr 0.6.1をインストール。
  • cmdstan2.33.1をインストール。
    cmdstanr::install_cmdstan(cores = 4, overwrite = TRUE, cpp_options = list(STAN_OPENCL=TRUE))
  • コンパイル。
    mod <- cmdstan_model(
      "./stantest2.stan", 
      force_recompile = TRUE, 
      cpp_options = list(stan_opencl = TRUE)
    )
  • サンプリング。
    n <- 250000
    k <- 20
    X <- matrix(rnorm(n * k), ncol = k)
    y <- rbinom(n, size = 1, prob = plogis(3 * X[,1] - 2 * X[,2] + 1))
    mdata <- list(k = k, n = n, y = y, X = X)
    fit <- mod$sample(data = mdata, chains = 4, parallel_chains = 4, opencl_ids = c(0, 0), refresh = 100)

    固唾をのんでタスクマネージャを見守ったが、期待に反し、GPUではなくCPUが猛烈に動き出した。無事終了したが、所要時間は400秒。

  • opencl_idsの設定がいかんのかなと思い、試しにc(0,1), c(1,0), c(1,1)を試したが、いずれもエラーになった。
  • ためしに
    sudo apt-get purge ocl-icd-opencl-dev
    sudo apt-get purge pocl-opencl-icd

    として再挑戦したが、事態は改善しないどころか、Stanのコンパイルがエラーとなった。

巷の情報をみるに、WSL2上でNVIDIAのGPUを使うことはできる、しかしOpenCLを経由して使えるわけではない... ということなのかもしれない。話が複雑すぎてよくわからないんだけど。

というわけで、「WSLの上のLinuxの上でcmdstanからGPUを使う」作戦はいまだ成功をみていない。がっくり。