Markov Chain Monte Carlo

김당찬·2022년 9월 11일

Markov Chain Monte Carlo

MCMC라고도 하는 Markov Chain Monte Carlo 기법은 확률분포에서 샘플을 추출하는 여러 종류의 알고리즘을 일컫는다. 다양한 머신러닝 이론들이 등장하며, 기존 통계학에서 다룰 수 없을 정도의 수만-수백만 개의 변수 및 파라미터를 사용하는 모델들 역시 등장했고, 특히 신경망과 같은 모델들은 너무나도 널리 사용되고 있다. 하지만 그러한 고차원 모델들에 대해 샘플링을 수행하거나, 기댓값 등 적분값을 구하는 과정은 기존의 다중적분으로는 불가능하다. 이를 해결하기 위해 몬테카를로 방법, 그중에서도 마코프 체인을 이용한 MCMC가 사용되며 이는 근래 통계학 및 머신러닝 분야에서 매우 중요한 부분을 차지한다.

Markov Chain

Markov Chain은 시간(tt)에 따라 변화하는 시스템(계)의 상태를 설명하기 위한 개념이다. 어떤 시스템의 상태가 A에서 B로, B에서 C로 시간(t=0,1,2,t=0,1,2,\dots)에 따라 변화하는 과정이 각각 확률로 주어지는 것을 의미한다. 만일 시간 tt에서의 상태를 모두 포함하는 충분통계량 xtx_t가 존재하며, 모든 과거의 상태가 이에 포함된다면 이를 markov property라고 한다. 즉, 다음을 의미한다.

p(xt+τxt,x1:t1)=p(xt+τxt)p(x_{t+\tau}|x_t,x_{1:t-1}) = p(x_{t+\tau}|x_t)

Markov property가 만족될 경우 유한한 확률과정열을 다음과 같이 쓸 수 있는데,

p(x1:T)=p(x1)t=2Tp(xtxt1)p(x_{1:T}) = p(x_1)\prod_{t=2}^Tp(x_t|x_{t-1})

이를 Markov Chain 이라고 한다.

Stationary Markov Chain

다음과 같이 time-shift가 이루어져도 joint distribution이 일치하는 markov chain을 stationary markov chain이라고 한다.(stationary : 정상성)

Pr(x0=z0,x1=z1,,xk=zk)=Pr(xn=z0,,xk+n=zk)\Pr(x_0 = z_0, x_1=z_1,\ldots,x_k = z_k)=\Pr(x_n=z_0,\ldots,x_{k+n}=z_k)

또한 stationary markov chain에서의 marginal distribution, 즉 Pr(x0=x)\Pr(x_0=x)을 해당 마코프 체인의 stationary distribution이라고 한다.

Monte Carlo Integration

몬테카를로 적분은 확률변수의 기댓값, 즉 적분값을 random sampling으로 근사하는 방법이다.

E[f(x)]=f(x)p(x)dx\mathrm E[f(x)] = \int f(x)p(x)dx

확률변수 XRnX\in\mathbb R^n 와 target distribution p(X)p(X)에 대해 기댓값을 구하기 위해서는 위와 같은 적분을 계산해야 한다. 그러나, 때로는 적분의 closed form을 구하기 어렵거나 데이터가 고차원인 경우 계산 과정이 매우 복잡하여 computation cost 문제가 발생할 수 있다. 이를 극복하기 위해 다음과 같이 적분값을 근사하는 방법을 Monte Carlo integration이라고 한다.

E[f(x)]1nsn=1nsf(xn)\mathrm E[f(x)]\approx {1\over n_s}\sum_{n=1}^{n_s} f(x_n)

MCMC

Markov Chin Monte Carlo(이하 MCMC)는 몬테카를로 방법 중에서 가장 널리 사용되는 기법 중 하나이다. MCMC의 기본적인 아이디어는 상태공간 X\mathcal X에서 target density p(x)p^*(x)를 stationary distribution으로 하는 마코프 체인을 구성하는 것이다. 이는 상태공간에서 각 상태 xx에 머문 시간(tt)의 비율이 p(x)p^*(x)에 비례하도록 random walk를 진행하는 것을 의미한다.

이러한 random walk로부터 샘플 x0,x1,x_0,x_1,\ldots를 추출하여 확률측도 pp^*에 대해 몬테카를로 적분을 실행할 수 있다. 이때 중요한 것은, random walk의 초기 과정은 sample의 개수가 적기 때문에 이때에는 정상성(stationarity)이 보장되지 않는다. 따라서 정상성에 이르는 시간동안의 샘플은 제거하는 것이 맞으며, 정상성에 이르기까지의 시간을 burn-in time이라고도 한다.

MH(Metropolis Hastings) Algorithm

MCMC 알고리즘의 가장 대표적인 것 중 하나인 MH 알고리즘에 대해 살펴보도록 하자. 앞서 MCMC의 기본 원리는 상태간 이동이 정상분포(pp^*)에 근거해 이루어진다고 설명한 바 있다. MH 알고리즘에서는 xxx\to x'의 상태이동이 확률 q(x  x)q(x'|\;x) 로 이동하는데, qqproposal distribution 이라고 한다(새로운 상태 xx'로 움직일 것을 제안받는다는 의미로 proposal이라고 하는 것 같다😃).

알고리즘에서 xxx\to x'로의 상태 이동을 제안받으면, 그 제안을 accept 할 것인지 결정하는 과정이 존재한다. Accept가 이루어지면 xx'를 새로운 샘플로 사용하고, 그렇지 않으면 기존 샘플을 반복해서 추출한다. 전체 알고리즘은 다음과 같다.

Metropolis Hastings Algorithm

  1. Initialize x0x^0

  2. 각 단계 s=0,1,2s=0,1,2\ldots 에 대해 다음 과정을 반복한다:

    1. x=xsx=x^s
    2. xq(xx)x'\sim q(x'|x) 으로부터 새로운 샘플을 추출한다.
    3. Acceptance probability를 계산한다.
    α=p~(x)q(xx)p~(x)q(xx)A=min(1,α)\alpha=\frac{\tilde p(x')q(x|x')}{\tilde p(x)q(x'|x)}\\ A=\min(1,\alpha)
    1. uU(0,1)u\sim U(0,1) 으로부터 샘플을 추출한다.
    2. 새로운 샘플 xs+1x^{s+1}을 다음과 같이 정의한다.
    xs+1={x    :  if  uA    (accept)xs    :  if  u>A    (reject)x^{s+1}=\begin{cases}x'\;\;:\;\mathrm{if} \; u\leq A\;\;(\mathrm{accept}) \\ x^s\;\;:\;\mathrm{if}\; u>A\;\;(\mathrm{reject}) \end{cases}

여기서 p(x)=p~(x)/Zp^*(x) = \tilde p(x)/Zp~\tilde p는 정규화되지 않은 분포를, pp^*는 정규화상수를 이용하여 정규화된 분포를 각각 나타낸다.

MH 알고리즘이 실제로 정상확률분포 pp^*로부터 샘플을 생성한다는 것을 증명하는 자세한 과정은 참고 교재를 살펴보면 좋을 것 같다. 아래는 실제로 MH 알고리즘을 이용한 sample generating을 코딩해보도록 하겠다.

Code

앞서 살펴본 MH 알고리즘에서, proposal distribution을 simple normal distribution N(0,1)N(0,1) 로 하는 코드를 구현해보도록 하자. 필요한 패키지들은 다음과 같다.

import numpy as np
import scipy.stats as ss
import matplotlib.pyplot as plt

샘플링하고자 할 타겟 분포를 이번에는 평균이 5, 표준편차가 10인 정규분포로 하고, 다음과 같이 random variable을 scipy.stats 으로 설정했다.

# Parameter
MU = 10.0
SIGMA = 5.0
target = ss.norm(loc=MU, scale=SIGMA) # target distribution

MH 알고리즘은 아래와 같은 코드로 진행시켰다. 총 반복횟수는 10000회로 둔 뒤 초기값은 임의로 설정했고(3.0, random으로 생성해도 된다) 각 반복문의 단계에서 이전 state에 proposal distribution을 더한 값 x_proposed으로 AA 값을 계산하여, uniform distribution에서 추출한 uu와 비교한 뒤 새 단계의 state를 업데이트 하는 방식이다.

# Rep count = 10000
x = np.zeros(shape=10000)

# initialize x_0
x[0] = 3.0

for i in range(1,10000):
    x_t = x[i-1]
    x_proposed = x_t + np.random.standard_normal(1)[0] # Proposal Distribution
    A = min(1, target.pdf(x_proposed) / target.pdf(x_t)) # Since q is symmetric

    u = np.random.uniform(size=1)[0] # u from Uniform dist

    if u <= A : # Accept
        x[i] = x_proposed
    else:
        x[i] = x_t

Plotting한 결과는 다음과 같다.

References

profile
블로그 이사했습니다 https://ddangchani.github.io

0개의 댓글