「正月にMetropolis Procedural Modelingを基礎から理解してみる」その2。 Gauche:MetropolisProceduralModeling:MCMC-1Dの続き。
前回の問題を2次元に拡張してみる。 コードはmcmc2.scm。
今回のターゲット分布はこんな感じ。
(define (p x y) (+ (* 0.3 (exp (+ (* -0.2 (expt (- x 0) 2)) (* -0.2 (expt (- y 5) 2))))) (* 0.2 (exp (+ (* -0.2 (expt (- x 15) 2)) (* -0.2 (expt (- y 10) 2))))) (* 0.5 (exp (+ (* -0.1 (expt (- x 10) 2)) (* -0.1 (expt (- y 0) 2)))))))
マルコフ過程は現在位置から正規分布を使って動かす。
;; Pick a sample (x* y*) by proposal distribution (define (pick1 x y) (values (dpick x 10 -10 20 1) (dpick y 10 -10 20 1)))
Metropolis-Hastingsは1次元のものの素直な拡張。
;; Posteriori probability q([x*,y*]|[x,y]) (define (q x* y* x y) (* (/ (φ (/ (- x* x) 10.)) 10.) (/ (φ (/ (- y* y) 10.)) 10.))) ;; Single MH step (define (step x y) (let1 u (random-real) (receive (x* y*) (pick1 x y) (if (< u (min 1 (/ (* (p x* y*) (q x* y* x y)) (* (p x y) (q x y x* y*))))) (values x* y*) (values x y)))))
次元が増えた分、探索範囲がうんと広がるので、デフォルトのサンプル数も増やした。
(define (run x0 y0 N) (rlet1 results (make-hash-table 'equal?) (let loop ([i 0] [x x0] [y y0]) (unless (= i N) (receive (x y) (step x y) (hash-table-update! results (cons x y) (cut + 1 <>) 0) (loop (+ i 1) x y)))))) (define (mcmc2 :optional (samples 200000) (file "mcmc2.dat")) (with-output-to-file file (^[] (let1 result (run 0 0 samples) (do-ec (: y -10 20 1) (: x -10 20 1) (begin (when (= x -10) (newline)) (let1 z (hash-table-get result (cons x y) 0) (format #t "~a\t~a\t~a\n" x y (/. z samples)))))))))
実行。
gosh> (mcmc2) #<undef> gosh> (plot'result) #<undef>
次元数が増えると多少有難味が感じられるけど、 ターゲットp(x)が解析的に与えられてるんじゃまだあんまり面白くない。 次はちょっと違った問題にMCMCを適用してみる。 → Gauche:MetropolisProceduralModeling:MCMC-fit