CmdStanRのコンパイルが速すぎたお話
こんにちは。
今朝、TwitterのStan好きTLを騒がせていた、
Holy shitballs CmdStanR is so fucking fast! https://t.co/stM9JnqoE0
— Dan Simpson (@dan_p_simpson) October 31, 2019
Help to test development version of CmdStanR, which is a lightweight interface to Stan for R usershttps://t.co/G3SOrxKF4O. CmdStanR misses some useful features of RStan, but has the benefit of getting more recent features faster. One example is the much faster model compilation. https://t.co/gOWVWFlm2Q
— Stan (@mcmc_stan) October 31, 2019
こちらについて簡単に検証してみました。
まだ、開発が始まったばかり程度なので、今後どうなるかわかりませんが、とても期待できそうであることがわかりました。
結果から書くと、
に記載のモデル(bernoulli.stan)では、
CmdStanRによるコンパイル時間
Time difference of 1.574471 secs
rstanによるコンパイル時間
Time difference of 44.28613 secs
という結果でした。本当にso fucking fast! で笑いました。
ということで、もう少し詳しく見ていこうと思います。
基本的には、上のGetting startedを見て、導入、実践してもらえればと思います。
まず、私の環境ですが、OSが Windows 10 Proです。
そして、このおかげ?で、Windowsにうまくcmdstanを導入することが出来ませんでした。
というのも、
devtools::install_github("stan-dev/cmdstanr")
library(cmdstanr)
ここまではうまくいくのですが、
install_cmdstan()
これがうまくいきませんでした。
Running bash "C:/Users/hogehoge/Documents/R/win-library/3.6/cmdstanr/make_cmdstan.sh" \ -j2 -w
Error in rethrow_call(c_processx_exec, command, c(command, args), stdin, :
Command not found @win/processx.c:977
という感じのエラーがはかれます。
恐らく、実行に際し、make_cmdstan.shというファイルを実行して、cmdstanをインストールするようなのですが、そこでこけてしまっています。
.shファイルは、bashと呼ばれる、linuxとかで開く前提の拡張子らしいので?(あっている?)そもそも、windowsで開けないっぽい。
windowsで.shファイルを開く方法をググったらできそうな感じはありましたが、それを実行するのが面倒だったので window subsystem for linux (ubuntu LTS 18.04) を使って環境を構築しました。なので、環境は、仮想linux(ubuntu)です。
もちろん、通常?のlinuxやAWS,AWS,GCP等のlinux環境でも普通に実行できると思いますが。
また、Rからではなく、自力でcmdstanを導入することもできると思いますが、今回は行いませんでした(面倒だった)。
まずは、仮想linuxにRやRstudio Serverを構築しました(ここはCmdStanR関係ないので省きます)。
調べればたくさん出てきますので、そちらを参考にしてください。
そしたら、Rで(僕は、Rstudio Serverでやりました。)
devtools::install_github("stan-dev/cmdstanr")
library(cmdstanr)install_cmdstan()
先ほど同様のコードを走らせます。
すると、cmdstanがインストールされます。
その後、cmdstanのpathを指定します(動作環境によって以下でうまくいかないようですが、その際は公式( https://mc-stan.org/cmdstanr/articles/cmdstanr.html )を見てください)。
set_cmdstan_path()
続いて、.stanモデルを指定します。
今回は、パッケージインストールと同時に導入される例題モデルをコンパイルしてみます。
## .stanファイルのpathを指定する。
file <- file.path(cmdstan_path(), "examples", "bernoulli", "bernoulli.stan")
start <- Sys.time()
mod <- cmdstan_model(file) ##モデルのコンパイル
end <- Sys.time()
print(end-start)
上記を実行させれば、モデルがコンパイルされます。
僕の環境では、
Time difference of 1.574471 secs
でした。
ちなみに、コンパイルされた例題モデルは
mod$print()
で確認することが出来ます。
上記では、
data {
int<lower=0> N;
int<lower=0,upper=1> y[N];
}
parameters {
real<lower=0,upper=1> theta;
}
model {
theta ~ beta(1,1); // uniform prior on interval 0,1
y ~ bernoulli(theta);
}
が、出力されると思います。
あとは、
data_list <- list(N = 10, y =c(0,1,0,0,0,0,0,0,0,1))
fit <- mod$sample(data = data_list, seed = 123, num_chains = 2)
を実行すれば、MCMCのサンプリングを行ってくれます。
VBも出来るそうですが、今回は実行しませんでした(内容の本質ではありませんので)。
結果オブジェクトは、rstanの結果オブジェクトとは異なります。
class(fit)
[1] "CmdStanMCMC" "R6"
という形式で保存されています。
そのため、結果の取り出し方も少し違います。
## 要約統計量
fit$summary()
## MCMCの診断
fit$diagnose()## MCMC samples (rstanのextract関数)
fit$draws()
ここらへん、少し不便かなと思ったのですが、以下のように実行してあげると、rstanの結果オブジェクトと同様に扱ってあげることができます。
stanfit <- rstan::read_stan_csv(fit$output_files())
print(stanfit)
やっていることとしては、
cmdstanrの結果オブジェクトは、.csvファイルで保存されている(される?)ようなので、
これらをrstanに標準装備されているread_stan_csv()関数で読み込んであげれば、結果オブジェクトを復元することができます。
あとは、いつものようにrstanの結果オブジェクトと同様に扱うことが可能です。
ここらへんは、今後改善されるてきなことが公式にも記載されていたような気がします。
それでは、少し話しを戻して、cmdstanrでコンパイル時間を計算できたので、比較してみましょう。
先ほどのモデルコードを事前にbernoulli.stanのようにどこかに保存しておいてください。
比較するので、念のため、僕はRを再起動しました。
library(rstan)
options(mc.cores = parallel::detectCores())
rstan_options(auto_write = TRUE)start <- Sys.time()
mod <- stan_model("Documents/R/model/bernoulli.stan")
end <- Sys.time()
print(end-start)
あとは、こんな感じで書いてあげれば、コンパイル時間を計測することが出来るかと思います。
Time difference of 44.28613 secs
という結果でした。
比較してみると、
cmdstanRによるコンパイル時間
Time difference of 1.574471 secs
rstanによるコンパイル時間
Time difference of 44.28613 secs
so fucking fast! でした(言いたいだけ)。
経験上、モデルの違いでコンパイル時間は大きく変化しない気がするので(主にCPUのスペックだと思います)、他のモデルでも早いのではないでしょうか。
ちなみに、なぜこんなに早いのかについても公式で言及されています。
The RStan interface (rstan package) is an in-memory interface to Stan and relies on R packages like Rcpp and inline call C++ code from R. On the other hand, the CmdStanR interface does not directly call any C++ code from R, instead relying on CmdStan for compilation, running algorithms, and writing results to output files.
https://mc-stan.org/cmdstanr/articles/cmdstanr.html
Rcppを一切介さず諸々をやるので速いようです。
実際に計算しているのも、CmdStanくんが頑張っているようです。
速いっていいですね。
今回は、サクッと比較したので、記事に誤字、脱字多いかもしれません。すみません。
あと、Windowsで簡単に出来る方法(CmdStanをインストールさえしてしまえばという感じですが)をご存じの方は教えていただけると嬉しいです。
Enjoy!!