LoginSignup
4
2

More than 3 years have passed since last update.

メモ : CmdStanPyの環境をdockerで用意する

Posted at

StanとRでベイズ統計モデリング」を読むために、CmdStanPy環境をdockerで用意しました。CmdStanPyの環境構築については日本語の資料はほとんどなさそうだったので、もしかしたら誰かの役に立つかもしれないと思い、メモに残しておきます。

はじめに

公式documentにもある通り、PyStanを既にインストールした環境を使っている方はご注意ください。

Note for PyStan users: PyStan and CmdStanPy should be installed in separate environments. If you already have PyStan installed, you should take care to install CmdStanPy in its own virtual environment.

他にも依存性の問題などでもろもろ面倒になりそうなので、筆者はdockerで環境を用意しました1

CmdStanPyとは

PythonによるCmdStanの軽量wrapper

なぜCmdStanPyか?

PythonからStanを使いたい場合、一般的にはPyStanを利用することが多いかと思います2。ではなぜCmdStanPyを使うことにしたかというと、PyStanより(現状では)速く動くからです。

詳しい経緯は以下の通りです :

筆者も最初はPyStan環境を用意したのですが、Eight schoolsという簡単な例(PyStanのdocumentのこの部分参照)でのモデルのコンパイルに1分以上かかってしまいました。

筆者のインストール方法が悪かったのか、はたまたこれが普通なのか調べたところ、StanのCommunityでのこちらのやりとりを見つけました。曰く、

Stan compilation speedup was introduced in Stan 2.20, but Rstan is only up to Stan 2.19.2.

right now we have lightweight wrappers CmdStanPy 11 (still in beta) and CmdStanR 18 (almost to beta release) which use the latest CmdStan (now at 2.21, 2.22 coming soon) - or any version of CmdStan that you’d like.

このやりとり自体は2年前だったのですが、筆者のPyStan環境のPyStanのversionを確認すると2.19.1.1で、speedup導入前のもののようでした3。また、こちらのStackoverflowの書き込みでも、CmdStanPyにすることで3倍以上コンパイルが速くなったとの記述がありました。

そこで、CmdStanPyを試してみることにしました。

環境

  • OS : macOS Mojave 10.14.6
  • docker : 19.03.12

Dockerでの環境構築

Dockerfile
FROM ubuntu:20.04

RUN apt-get -y update
RUN apt-get -y install python3
RUN apt-get -y install python3-pip
RUN pip3 install --upgrade pip
RUN pip3 install cmdstanpy[all]
RUN python3 -c 'import cmdstanpy; cmdstanpy.install_cmdstan()'

WORKDIR /workdir

このDockerfile4があるdirectoryで次のようにbuildし(YOUR_TAGは適当なTAG名に変えてください)、

docker image build -t YOUR_TAG .

起動します(localのソースコードを利用したいので、カレントディレクトリを/workdirにマウントしています。)


docker container run -it --rm --net=host  \
        --mount type=bind,src=`pwd`,dst=/workdir \
        YOUR_TAG \
        bash

実行

dockerコンテナを起動したディレクトリに

  • stan file(8schools.stan5)
  • データ(8schools.data.json)
  • python script(run-cmdstanpy.py)

を用意しておきます。

8schools.stan
data {
    int<lower=0> J; // number of schools
    vector[J] y; // estimated treatment effects
    vector<lower=0>[J] sigma; // s.e. of effect estimates
}
parameters {
    real mu;
    real<lower=0> tau;
    vector[J] eta;
}
transformed parameters {
    vector[J] theta;
    theta = mu + tau * eta;
}
model {
    eta ~ normal(0, 1);
    y ~ normal(theta, sigma);
}
8schools.data.json
{
    "J": 8,
    "y": [28,  8, -3,  7, -1,  1, 18, 12],
    "sigma": [15, 10, 16, 11,  9, 11, 10, 18]
}
run-cmdstanpy.py
from cmdstanpy import CmdStanModel


print("Compile started")
model = CmdStanModel(stan_file="8schools.stan")
print("Compile finished")
print(model)
print("========================================")
data = "8schools.data.json"
print("Sampling started")
fit = model.sample(data=data)
print("Sampling finished")
print(fit)

「Dockerでの環境構築」の節で起動したコンテナ内の/workdirpython3 run-cmdstanpy.pyを実行して以下のような結果が出ればひとまず成功です。

Compile started
INFO:cmdstanpy:compiling stan program, exe file: /workdir/8schools
INFO:cmdstanpy:compiler options: stanc_options=None, cpp_options=None
INFO:cmdstanpy:compiled model file: /workdir/8schools
Compile finished
CmdStanModel: name=8schools
     stan_file=/workdir/8schools.stan
     exe_file=/workdir/8schools
     compiler_optons=stanc_options=None, cpp_options=None
========================================
Sampling started
INFO:cmdstanpy:start chain 1
INFO:cmdstanpy:start chain 2
INFO:cmdstanpy:start chain 3
INFO:cmdstanpy:start chain 4
INFO:cmdstanpy:finish chain 3
INFO:cmdstanpy:finish chain 1
INFO:cmdstanpy:finish chain 4
INFO:cmdstanpy:finish chain 2
Sampling finished
CmdStanMCMC: model=8schools chains=4['method=sample', 'algorithm=hmc', 'adapt', 'engaged=1']
 csv_files:
    /tmp/tmpd0ii4fo_/8schools-202009110125-1-0qknvwdc.csv
    /tmp/tmpd0ii4fo_/8schools-202009110125-2-qfoj4mom.csv
    /tmp/tmpd0ii4fo_/8schools-202009110125-3-cbn8wxph.csv
    /tmp/tmpd0ii4fo_/8schools-202009110125-4-h_5980t6.csv
 output_files:
    /tmp/tmpd0ii4fo_/8schools-202009110125-1-0qknvwdc-stdout.txt
    /tmp/tmpd0ii4fo_/8schools-202009110125-2-qfoj4mom-stdout.txt
    /tmp/tmpd0ii4fo_/8schools-202009110125-3-cbn8wxph-stdout.txt
    /tmp/tmpd0ii4fo_/8schools-202009110125-4-h_5980t6-stdout.txt
deleting tmpfiles dir: /tmp/tmpd0ii4fo_
done

CmdStanPyの詳しい使い方などは公式document をご覧ください。

appendix : PyStanとの速度比較

PyStanとの速度比較についても軽く記録しておきます。stan fileはいずれも「実行」の節に書いた8schools.stanで共通です。

CmdStanPy

docker環境は「Dockerでの環境構築」に書いたとおりのものです。python fileは次のものを用いました:

test-cmdstanpy.py
from cmdstanpy import CmdStanModel
import time

print("Compile started")
t1 = time.time()
model = CmdStanModel(stan_file="8schools.stan")
t2 = time.time()

data = "8schools.data.json"
print("Sampling started")
t3 = time.time()
fit = model.sample(data=data)
t4 = time.time()

print("Compile time :", t2 - t1, "seconds")
print("Sampling time :", t4 - t3, "seconds")

PyStan

利用したDockerfileは次の通りです:

Dockerfile
FROM ubuntu:20.04

RUN apt-get -y update
RUN apt-get -y install python3
RUN apt-get -y install python3-pip
RUN pip3 install --upgrade pip
RUN pip3 install pystan

WORKDIR /workdir

「Dockerでの環境構築」と同様にbuild, 起動します。また、python fileは以下のものを利用しました。:

test-pystan.py
import pystan
import time

schools_dat = {'J': 8,
               'y': [28,  8, -3,  7, -1,  1, 18, 12],
               'sigma': [15, 10, 16, 11,  9, 11, 10, 18]}

print("Compile started")
t1 = time.time()
sm = pystan.StanModel(file='8schools.stan')
t2 = time.time()
print("Sampling started")
t3 = time.time()
fit = sm.sampling(data=schools_dat, iter=1000, chains=4)
t4 = time.time()

print("Compile time :", t2 - t1, "seconds")
print("Sampling time :", t4 - t3, "seconds")

結果

CmdStanPy

Compile time : 12.916020393371582 seconds
Sampling time : 0.16101527214050293 seconds

PyStan

Compile time : 98.87509870529175 seconds
Sampling time : 0.45189523696899414 seconds

何度か測ってみましたが、モデルのコンパイルについては、基本的にCmdStanPyがPyStanより7倍程度速いという結果になりました67


  1. ただし、筆者はdockerを雰囲気で使っているところがあるので、ここに書いたdocker環境の構築法は最善のものでない可能性があります。 

  2. 「Python Stan」でGoogle検索して真っ先に出てきたのはPyStanのdocumentgithubのpageでした。 

  3. PyStanのversionの数字がStanのversionの数字と対応しているという認識であっているのでしょうか...? 

  4. CmdStanPyのインストールを行う部分の詳細は https://cmdstanpy.readthedocs.io/en/latest/getting_started.html#installation を参照。 

  5. PyStanのgetting started のページからダウンロードしました。 https://pystan.readthedocs.io/en/latest/getting_started.html 

  6. CmdStanPyの場合は「exe fileとstan fileの更新時刻を比べて、後者が前者より新しい場合はコンパイルをしない」という気の利いた機能がついているので、繰り返し測る場合はご注意ください。 

  7. PyStanのbase imageをubuntu:16.04にしたときはPyStanも50秒程度で済んだのですが、原因は調べていません。 

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2