この記事はStan Advent Calendar 2020の15日目の記事です。
さて、このネタも若干使い古されたというか、同様の記事はすでにたくさんあります。北條さんの記事、うちの院生の柏原さんの記事、この記事などなど。
rstanパッケージが、どうもR4.0になってからイマイチうまく動かない事例が増えています。WindowsでもMacでも。僕はWinしか使わないのでそれ限定の話を書きますが、とりえあずRtoolsとの連携がうまくいかないなど、コンパイル環境でコケることが多いです。
またrstan側の問題で動かないこともあります。最近rstanがいろいろ機能が増えてきたのも合って、パッケージの依存関係で動かなかったり。あるいは、動くんだけど、cmdstanのバージョンアップに全然追いついてなくて、最新機能をrstanで使えなかったり。
※ついでにcmdstanというのは、cmdで動かせる、最も基本的なStanのプログラムのことです。rstanのコアですね。これがまず開発され、それに合わせて他のrstanやpystanなどが開発されていきます。
そういうのもあって、今から書くcmdstanrをWSL2で動かしたUbuntu上のRstudio Serverで走らせる、というところにメリットがでてきます。
cmdstanrをWSL2で動かしたUbuntu上のRstudio Serverで走らせるメリット
ちょっと専門用語が多いかもなので、順番に説明しましょう。
まず、cmdstanrについて。これは、rstanのようにRのパッケージの一つです。rstanとは別に、Stanを動かすことができるパッケージなんです。なぜそれが生まれたかといえば、上述のrstanの依存パッケージが増えたことの問題と、cmdstanのバージョンアップについていけなくなったことの問題があります。
そこでcmdstanをR上で動かすだけ、という非常にシンプルなパッケージが登場しました。cmdstanrは、cmdstanを別にインストールする形式を取るので、cmdstanがバージョンアップしたら、それに合わせて変更することができます。つまり、パッケージのバージョンアップをせずとも最新のStanを使うことができるのです。また、コンパイルにRcppを使わないので(内部で直接C++を動かしている)、rstanよりコンパイルが早いです。これも結構重要なメリットです。
次にWSL2について。WSLとはWindows Subsystem for Linuxの略で、Windows上でLinuxを動かすことができるシステムです。Linuxは、WindowsやMacとはまた違うOSのことで、オープンでフリーなOSです。いつでも誰でも使えます。WSLで動かせるLinuxのディストリビューションとしてUbuntuがあります(ややこしいのでLinuxと一緒と思えばいいです)。
さて、WSL2はWSLをさらにパワーアップさせたやつで、よりUbuntuとWindowsの連携を良くしてくれるやつです。WSL2を使ってなぜUbuntuを動かしたいかといえば、今から述べるように、Windowsよりもいろいろ安定しているからです。
まず、Ubuntuは商用のOSではないのでバージョンアップはWinほど頻繁に行われず、またどのバージョンでも好きな物を選んでインストールできます。また、Stanを動かすという意味で重要なのは、Ubuntuにははじめからコンパイラがはいっているので、StanコードのコンパイルにRtoolsを使いません。よって、コンパイル環境でコケる心配があまりありません。
もちろん、はじめからUbuntsを使って分析すればいいんですが、僕のようにWindowsしか使わない人のために、Windows上で、Ubuntuをあたかもアプリのように動かしてRを使いたいとき、WSLが活きてくるわけです。
そして、Ubuntuで起動したRstudioをWindowsから操作するために、Rstudio Serverが必要になります。でもこれは、Ubuntuにいれるだけですから、それほど大きな問題ではありません。強いて言えば、ブラウザ上で動かすことになるのでそのあたりに慣れがいるかもしれません。
あとUbuntu上で動くRstudio Serverはとても動作が安定しています。これはなぜなのかはわかりませんし、直感的なものも含まれていますが、僕的にかなり重要な点です。具体的に言えば、rstanで複雑なモデルを推定してlooパッケージのwaic関数を使うと高確率で爆発(Rstudioが落ちる)します。なので、わざわざ自作のWAIC計算用関数を使ったりするんですが、推定終わった直後に爆発する絶望感はすごいです。あと、変分ベイズ推論のvbを使っていても安定感が違います。vbは推定を途中で止めようと思っても内部の計算がrcppを使っているせいか、なかなか止まってくれません。無理に止めようとすると爆発します。しかし、cmdstanrはすぐ止まります。すごい。あと、単純にUbuntuのほうがWindowsよりも推定が早いです。
もう一つ、Windowsだと並列演算をしたときビューアーの更新をしないとMCMCの進捗がわかりませんが、Ubuntuだと勝手に進捗を教えてくれます。これも便利。
メリットをまとめますと、
- cmdstanrを使うと、cmdstanの最新バージョンがいつでも使える
- コンパイルが早い
- コンパイル環境でコケることがない
- 推定が早い
- Rstudioの挙動が安定する
などなど、いいことばかりです。
cmdstanrをWSL2で動かしたUbuntu上のRstudio Serverで走らせる環境を作ろう
さて、それでは環境の構築方法ですが、まずはWSL2が動く環境である必要があります。それについてはこの記事を見てください。この記事に書かれている通りに操作すれば、WindowsでWSL2上でUbuntuを起動するところまではいけるはずです。
まずはUbuntu20.04を起動します。そしたらユーザーネームとパスワードの設定が求められます。適当なものを設定しておきますが、この2つはあとで使うので、メモっておきましょう。
さて、ここから以下のコードをUbuntuで走らせてください。コードをコピーして、Ubuntuのコンソール上で右クリックすれば貼り付けられます。
以下のコードでアップデートしておきます。最初のコードを走らせるとパスワードが聞かれます。これはsudoという管理者権限でのコマンド実行をしているためです。最初に設定したパスワードを入力します(打っても何も入力されてない感じですが、大丈夫です、入力されてます)。
1 2 |
sudo apt update sudo apt upgrade |
続いて、Ubuntuのライブラリをインストールします。これはdevtools、rstanやtidyverseを動かすのにいりますので、走らせておきましょう。
1 |
sudo apt-get -y --no-install-recommends install libxml2-dev libcairo2-dev libgit2-dev default-libmysqlclient-dev libpq-dev libsasl2-dev libsqlite3-dev libssh2-1-dev unixodbc-dev libjpeg-dev libv8-dev clang make libcurl4-openssl-dev |
次にRをUbuntuにインストールします。以下、呪文だと思って黙々と走らせていきましょう。まずはインストールの準備。
1 2 |
gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys E298A3A825C0D65DFD57CBB651716619E084DAB9 gpg -a --export E298A3A825C0D65DFD57CBB651716619E084DAB9 | sudo apt-key add - |
続いて、R4.0をインストール。1行目の実行でエラーがでますが、それはパッケージをインストールする先のリポジトリが古いやつなので出るエラーらしく、Rをインストールするだけなら問題ないようです。
2行目を走らせるとRのインストールが始まります。そこそこ時間がかかります。
1 2 |
sudo add-apt-repository 'deb https://cloud.r-project.org/bin/linux/ubuntu focal-cran40/' sudo apt-get install r-base-dev |
次に、Rstudio Serverのインストール。これもそこそこかかります。
1 2 3 |
sudo apt install gdebi-core wget https://rstudio.org/download/latest/stable/server/bionic/rstudio-server-latest-amd64.deb sudo gdebi rstudio-server-latest-amd64.deb |
次にRstudio Serverを起動します。
1 |
sudo service rstudio-server start |
この時点では、何も起きません。しかし、Ubuntuの内部ではちゃんと起動できています。Ubuntu上のRstudio Serverにアクセスするためには、ブラウザからアクセスする必要があります。
適当なブラウザで、アドレスバーにlocalhost:8787と入力してエンターを押すと、RstudioServerに繋がります。ここでユーザーIDとパスが求められますが、Ubuntuを初めて起動したときに求められたIDとパスワードをここで入力します。そうすると、見慣れたRstudioの画面が表示されるはずです。
これはRを入れたばかりの状態ですので、いくつかパッケージを入れておく必要があります。cmdstanrを入れるためには、まずdetoolsパッケージを入れます。そして、devtoolsのinstall_github関数を使って、cmdstanrパッケージを入れます。cmdstanrを入れたら、次にcmdstanをインストールします。それぞれ、そこそこ時間かかります。このあたりでコーヒーを入れてもいいと思います。
1 2 3 4 5 6 7 8 |
install.packages("devtools") install.packages("rstan") devtools::install_github("stan-dev/cmdstanr") library(cmdstanr) install_cmdstan() set_cmdstan_path() |
ここで、うまくパッケージが入らないことがあります。エラーメッセージを見て、コケてるパッケージをダイレクトにいれてからもう一度走らせてみてください。結構心が折れそうになりますが、一つずつ確実に入れていけばいずれ全部入ります。
あと、cmdstanrの結果を見やすくするために、rstanパッケージも必要になりますので、入れておきましょう。
なお、Rstudio-Serverを終了したいときは、
1 |
sudo service rstudio-server stop |
とUbuntuに入力しましょう。
cmdstanrを走らせよう
cmdstanrは、rstanと走らせ方も引数も違うので、注意が必要です。
まずはどうでもいいStanコードを書いたStanファイルを保存します。prob.stanとします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
data{ int N; int Y[N]; int Trial; } parameters{ real<lower=0,upper=1> p; } model{ for(n in 1:N){ Y[n] ~ binomial(Trial,p); } } |
次に、モデルのコンパイルなのですが、Stanファイルのフルパスがいります。僕は面倒なので、getwd()でワーキングディレクトリのアドレスを取得します。あとはプロジェクト内のStanファイルの相対パスをつなげればOKです。具体的には、次のような感じです。
1 |
model_c <- cmdstan_model(paste0(getwd(),"/prob.stan")) |
あと、データリストも用意しておきます。これはrstanと同じです。適当なデータを乱数で作ります。
1 2 3 4 5 6 7 |
N <- 1000 Trial <- 30 prob <- 0.5 set.seed(42) Y <- rbinom(N,Trial,prob) stan_data <- list(N=N,Trial=Trial,Y=Y) |
さて、さっそくcmdstanrを走らせましょう。コードはrstanと少し違い、コンパイルしたモデルのオブジェクト内のsample関数を実行するという形を取ります。オブジェクト指向っぽい。
1 2 3 4 5 6 7 |
fit_c <- fit <- model_c$sample( data = stan_data, parallel_chains = 4, chains = 4, iter_warmup = 1000, iter_sampling = 1000 ) |
注意が必要なのは、iter_warmupがウォームアップ数、iter_samplingはウォームアップしたあとのMCMCサンプル数である点です。rstanのようにウォームアップとサンプルの合計を指定するわけではないので気をつけてください。
これで無事にcmdstanrが走ったと思います。
次に、結果を見たいときですが、rstanのread_stan_csv()を使います。そこに、fit_cの内部にある、output_files()を指定することで、cmdstanrの出力をrstan風に変えてくれます。次のコードをまるまる使えばOKです。
1 2 |
stanfit <- rstan::read_stan_csv(fit_c$output_files()) print(stanfit) |
すると
1 2 3 4 5 6 7 8 9 10 11 12 13 |
> print(stanfit) Inference for Stan model: prob-202012132046-1-649859. 4 chains, each with iter=2000; warmup=1000; thin=1; post-warmup draws per chain=1000, total post-warmup draws=4000. mean se_mean sd 2.5% 25% 50% 75% 97.5% n_eff Rhat p 0.50 0.00 0.00 0.49 0.49 0.5 0.5 0.5 1620 1 lp__ -20795.43 0.02 0.71 -20797.50 -20795.60 -20795.2 -20795.0 -20794.9 1546 1 Samples were drawn using NUTS(diag_e) at Sun Dec 13 20:46:38 2020. For each parameter, n_eff is a crude measure of effective sample size, and Rhat is the potential scale reduction factor on split chains (at convergence, Rhat=1). |
上のような出力が得られます。
基本的には、cmdstanrのドキュメントを見れば、使い方は書いてますので、そちらを見ていれば大体わかります。
WSL2からWindows上のプロジェクトにアクセスする方法
さて、Rstudio-Serverを使って分析ができたわけですが、Ubuntu上のRstudioなわけなので、ワーキングディレクトリはhome/ユーザー名という謎な空間がデフォルトとなっています。一見、Windows上のファイルにアクセスできないように見えます。
それもWSLなら問題なくアクセスできます。Rsutdio ServerのFilesから、Open Projectを選びます。そして、エクスプローラではなく、File name:のところに、/mnt/c/users/[Windowsでのユーザー名]/と入力してみましょう。たとえばWindowsのユーザー名がnorimuneならば、/mnt/c/users/norimune と入力します。そうすれば、Windows上のファイルが見れるようになるはずです。あとは、Rstudioのプロジェクトがあるディレクトリまで進んでいって、Rprojファイルを起動すれば、いつものプロジェクトが開けます。もちろん、Cドライブのルートにおいてるなら、/mnt/cと入力したらOKです。
せっかくなのでRstudio-Server専用のブラウザを用意してみる
僕はもはやデスクトップ版Rstudioは使っておらず、WSL2上のRstudio-ServerでしかRを動かしていません。そうすると、普段使ってるブラウザで動かしているといろいろ不満がでてきます。
まず、タブが多くなるとうざい、ブックマークとかあるとRstudioの画面が小さくなってうざい、なんとなくブラウザと分析は分けたい、などなど。
そこで、普段はChromeをブラウザにしている僕は、Firefoxをいれて、それをRstudio専用にしています。しかも、わざわざショートカットの画像もRstudioにしました。これで「分析するぞ!」っていう気分になります。なるんです。
ホームページもlocalhost:8787に設定し、タブバーもメニューバーもアドレスバーも消しました。
現状、下のような感じです。
これでほぼ、デスクトップ版Rstudioと変わらない使い勝手になりました。
というわけで、みなさんもWSL2でcmdstanr生活やってみてください。