この記事では,cythonを用いたMCMCの実装を行う.
なぜcythonを使うかと言われれば,ただでさえ時間のかかるMCMCをpythonで実装したところで,収束まで時間が掛かりすぎてしまう.そこで,cythonを使ってMCMCを実装しようという流れになった.
cythonのコードを外部からimportする方法 を先に読むとcython独特の記法が把握出来る.
コードは,git clone https://github.com/akitoshiblog/blogsite
でmcmc_cythonの下にある.
*2020年1月19日に大幅に書き換えました.
使い方
メインのコードは.myMCMC.pyx/myMCMC.pxdとmyStats.pxd/myStast.pyxである.図示に関しては cythonを使ってMCMCを実装 | 図示編 を参照のこと.
動作はjupyter notebook上を想定するので, cythonのセルマジックを使えるように,%load_ext Cython
を回す.
次に,myMCMCからクラスを引き継いで次の三点を行う.
1. super().__init__
でmcmcのアウトプットの保存用のパスと変数名,ランダムウォーク用の標準偏差の値を渡す.
2. パラメータを受け渡しするための,setParametersとsetInitialを定義する.
3. 評価関数用のlogLikelihoodを定義する.
Rosenbrock’s banana functionを尤度関数として用いてパラメータを a=1,b=100の下で,(x,y)=(1,1)という大域最小解が得られるか確かめる.
モデルのためのcythonのコードは以下のようにする.MCMCは関数を最大にしようとするので,返り値は負の値にしておく.
jupyter notebook
%%cython -a cimport cython # custom function cimport myStats as ms cimport myMCMC cdef class model(myMCMC.MCMC): ''' Log-Likelihood function is defined. ''' cdef public double x cdef public double y def __init__(self,path,parName,sdRandomWalk): super().__init__(path,parName,sdRandomWalk) cpdef int setParameters(self): self.x = self.par[0] self.y = self.par[1] cpdef int setInitial(self): self.par[0] = self.x self.par[1] = self.y ########## Data setting part ################## cdef public double a cdef public double b def setInitParams(self): self.a = 1 self.b = 100 self.x = 2 self.y = 2 ############# calculate log likelihood ############### @cython.cdivision(True) cpdef double logLikelihood(self): cdef double v cdef double lv v = ms.pow(self.a - self.x,2) + self.b*ms.pow(self.y - self.x*self.x,2) + 1e-5 lv = ms.log(v) return(- lv)
大事なのは,logLikelihoodの関数がきっちりc言語としてコンパイルされること.それ以外の部分はMCMCの最中には呼ばれないので,大量のパラメーター推定の際には,名前や初期値はforやlist,dictを用いて設定することもできる.
modelを定義したら,必要なパラメータを与えてrunさせる.
parName = ["x","y"] sdRandomWalk = [0.5,0.5] mcmc = model(path ="output/result", parName = parName, sdRandomWalk = sdRandomWalk) # set initial values for each parameter mcmc.setInitParams() mcmc.nSim = 1000000 mcmc.nThin = 1000 print(mcmc.path2Save) mcmc.run()
これでMCMCのアウトプットが得られる.
ソースコードの準備の仕方
myMCMC.pyx/myMCMC.pxdにmcmcのアーキテクチャーが,myStats.pxd/myStast.pyxに基本的なc言語の関数と正規分布に関する定義を記してある.
一度,これらのファイルをいじったら再度cythonを用いてコンパイルする必要がある.その場合は,python setup.py build_ext --inplace
を用いて実行すること.
setup.py のコードは以下の通りである.
from distutils.core import setup from distutils.extension import Extension from Cython.Build import cythonize import numpy as np # if you run this code, type tye following code # >>> python setup.py build_ext --inplace ext_modules = [ Extension("myStats", ["myStats.pyx"]), Extension("myMCMC", ["myMCMC.pyx"]), ] setup( name = "Myproject", ext_modules = cythonize(ext_modules,annotate=True), include_dirs=[np.get_include()] )
コメント
[…] この記事は cythonを使ってMCMCを実装 | サンプリング編 の続きです.前回の記事でoutputされたデータを図示する. […]