More Related Content Similar to Cmdstanr入門とreduce_sum()解説
Similar to Cmdstanr入門とreduce_sum()解説 (12) More from Hiroshi Shimizu
More from Hiroshi Shimizu (20) Cmdstanr入門とreduce_sum()解説8. rstanとcmdstanrの違い
• rstanのメリット
• 豊富な関数
• 出力や、結果を要約するための関数を揃えている
• 他のパッケージとの連携
• bridgesamplingとか、stanfitを入れたらそのまま動くパッ
ケージが多い
• cmdstanrのメリット
• 速い・軽い
• 安定している(爆発しにくい)
• 依存パッケージが少なく、インストールしやすい
• cmdstanのバージョンアップにすぐ対応できる
10. rstanは重い
• 最近よく爆発するようになった
• あぼーん
• Rのrcppで動かしてることが原因?
• stopボタンを押しても止まってくれない
• 結果、あぼーん
• とくにVBだとほぼ確実に止まらない
• cmdstanr
• R内部ではなく、cmdstanをR外部で動かしている
• R自体は重くならない
• stopボタンをおしたら確実にcmdstanを殺す
• VBでもしっかり殺す
15. インストールの仕方
• まずはインストール
• コンパイル環境の確認
• cmdstanをインストール
install.packages("cmdstanr", repos = c("https://mc-stan.org/r-packages/",
getOption("repos")))
check_cmdstan_toolchain()
library(cmdstanr)
install_cmdstan(cores = 2)
バージョンを指定したい場合
install_cmdstan(cores = 2,version = "2.26.1")
20. サンプルデータ生成
set.seed(123)
N <- 10000
P <- 2
alpha <- -3
beta <- rep(1,P)
X1 <- rnorm(N, 5, 2)
X2 <- rnorm(N, 3, 4)
mu <- alpha + beta[1]*X1 + beta[2]*X2
logistic <- function(x){
1/(1+exp(-x))
}
Y <- rbinom(N,1,logistic(mu))
X <- data.frame(X1,X2)
Y %>% hist
glm(Y ~ X1 + X2,family=binomial) %>% summary
21. 今回使うStanコード
data{
int N;
int P;
int Y[N];
matrix[N,P] X;
}
parameters{
real alpha;
vector[P] beta;
}
model{
Y ~ bernoulli_logit(alpha + X*beta);
alpha ~ normal(0, 10^2);
beta ~ normal(0, 10^2);
}
generated quantities{
vector[100] mu = alpha + X[1:100,]*beta;
}
22. サンプリング
• rstanとちょっと癖が違う
• fit <- model$sample(data = “datastan”)
• モデルオブジェクトにメソッドがある
• sample():MCMCを行う
• variational():VBを行う
• オプションが違う
• iter_warmup:ウォームアップ期間のサイズ
• iter_sampling:ウォームアップ後のサイズ
• chains:マルコフ連鎖の数
• parallel_chains:並列コアの数
23. サンプリング
datastan <- list(N=N, P=P, Y=Y, X=X)
model <- cmdstan_model(“logistic.stan")
fit <- model$sample(datastan,
iter_warmup = 1000,
iter_sampling = 1000,
chains = 4,
parallel_chains = 4,
refresh = 200)
26. 僕が使ってる感じ
map <- function(z){
density(z)$x[which.max(density(z)$y)]
}
quantile95 <- function(x){
quantile(x, probs = c(0.025, 0.975), names = TRUE)
}
ess_tail95 <- function(x){
min(posterior::ess_quantile(x, probs = c(0.025, 0.975), names = TRUE))
}
r_hat <- posterior::rhat
pd_out <- c("mean","sd","map","quantile95","ess_bulk","ess_tail95", "r_hat")
fit$print(c("alpha","beta"),pd_out,max_rows = 30)
貼り付け可能なテキストは
こちら
42. cmdstanrの欠点
• bridgesamplingパッケージと連携しない
• 2021年9月現在
• 一度、rstanfitオブジェクトに変換する必要がある
• どうやらcmdstan単体ではモデル全体の対数確率を
出力する機能がないので対応厳しいらしい
• ちょい面倒
• rstanfitオブジェクトを作って、iter=0でもう一度か
らのrstanfitオブジェクトを作る
fit.sf <- rstan::read_stan_csv(fit$output_files())
path <- model$stan_file()
sf <- rstan::stan(path,data=data,iter=0)
bs <- bridge_sampler(fit.sf, stanfit_model = sf)
43. 関数を作ったよ
• cmdstanr_bs()
cmdstanr_bs <- function(fit,model,data){
require(rstan)
require(bridgesampling)
path <- model$stan_file()
fit.sf <- rstan::read_stan_csv(fit$output_files())
sf <- rstan::stan(path,data=data,iter=0)
bs <- bridge_sampler(fit.sf, stanfit_model = sf)
return(bs)
}
bs <- cmdstanr_bs(fit,model,datastan)
MCMCのサンプルが入ったfitオブジェ
クト、モデル、データの順に入れる
47. partial_sum_lpmfのコード
• こんな感じ
• 関数内で、bernoulli_logit_lumf()にモデルを入れる
• slice_Yは適当につけた名前で、特に決まってない。別にYで
も走る。
• 目的変数はそのまま入れればいいけど、説明変数などは
start:endで配列を指定する必要あり
• 内部システム的に、startとendには分割された配列の範囲が割
り振られる
real partial_sum_lpmf(int[] slice_Y, int start, int end, real alpha, vector beta, matrix X){
return bernoulli_logit_lupmf(slice_Y | alpha + X[start:end,]*beta);
}
50. テキストバージョン
functions{
real partial_sum_lpmf(int[] slice_Y, int start, int end, real alpha, vector beta, matrix X){
return bernoulli_logit_lupmf(slice_Y | alpha + X[start:end,]*beta);
}
}
data{
int N;
int P;
int Y[N];
matrix[N,P] X;
}
transformed data{
int grainsize = 1;
}
parameters{
real alpha;
vector[P] beta;
}
model{
target += reduce_sum(partial_sum_lpmf, Y, grainsize, alpha, beta, X);
alpha ~ normal(0, 10^2);
beta ~ normal(0, 10^2);
}
51. コンパイル時の注意
• Rstudioのコンパイルチェック機能
• rstanのバージョンに合わせている
• reduce_sum()は2.23で追加したものなので、コンパ
イルエラーがでる
• そんな関数ねぇよ
• 気にせずコンパイルする
• 並列化のためのコンパイルをやる必要がある
• cpp_options = list(stan_threads = TRUE)
model.rs <- cmdstan_model("logistic_rs.stan", cpp_options = list(stan_threads = TRUE))
52. サンプリングのやり方
• threads_per_chainを指定
• PCのコアが32個あるなら、4×8まで可能
• ただコアの数が多くなると計算結果の統合に時間がか
かってしまって余計効率が悪いこともある
• モデルの複雑さやサンプルサイズなどでうまく調整する
• 2~4で十分な気がする
fit.rs <- model.rs$sample(datastan,
iter_warmup = 1000,
iter_sampling = 1000,
chains = 4,
parallel_chains = 4,
threads_per_chain = 2,
refresh = 200)
54. まとめ
• cmdstanrを使おう!
• rstanは重くて遅くて爆発する
• cmdstanrは軽くてバージョンを選べて速い
• reduce_sum()も使おう!
• もしコアが多いPCをお持ちならオススメ
• rstanで普通に推定するよりも、cmdstanrを使って、
かつ、reduce_sum()を活用したら、断然スピードが
違う!
• rstanで13.5秒→cmdstanで最速4.5秒