蒙特卡洛馬爾可夫鏈學習小結

目錄

MCMC背景

關於採樣的理解

什麼是採樣

爲什麼要採樣

什麼是好的樣本

採樣爲什麼是困難的(the curse of high dimensionality)

蒙特卡洛採樣方法

基於概率分佈的採樣Inverse Transform Sampling

接受-拒絕採樣Rejection Sampling

重要性採樣

MCMC 蒙特卡洛馬爾可夫鏈

什麼是馬爾可夫鏈

平穩分佈定義及目的

馬氏鏈收斂到平穩分佈的條件

MH算法方法案例

MCMC的問題

可逆馬爾科夫鏈蒙特卡洛RJMCMC簡介


MCMC背景

    在統計學中,經常會遇到高維積分的計算,用傳統的數值方法往往很難解決高維積分計算問題。不過,通過隨機模擬的方法爲解決這些高維積分問題提供了一個思路。所謂隨機模擬方法,是使通過隨機變量函數的概率模擬或隨機抽樣求解工程技術問題的近似數值解的概率統計方法。

    馬爾可夫鏈蒙特卡洛MCMC,就是其中一種應用廣泛的模擬方法,使得統計學領域中極大似然估計、非參數估計、貝葉斯統計學等方向上的很多問題得到了解決。

    本次學習筆記參考了網絡很多資源,就不列舉了,這裏推薦下,B站的機器學習白板推導系列

 

關於採樣的理解

什麼是採樣

    所謂採樣,簡單來說就是按照某個概率分佈(概率密度函數),生成一批樣本。比如下面按照均勻分佈進行離散採樣。假設離散變量r有3個取值,a1,a2,a3,概率分佈如下圖所示:

    所有取值概率之和爲1。此時我們可以從 Uniform[0,1) 生成一個隨機數 b,若 0≤b<0.6,則選擇出 a1;若 0.6≤b<0.7,則選擇出 a2;若 0.7≤b<1,則選擇出 a3。

爲什麼要採樣

    採樣的動機通常有兩種:

  • 機器學習中,如果你已經通過訓練學習出來一個模型,可能是個很複雜的概率分佈函數。在推理階段,需要從訓練的概率分佈中,產生一些樣本。比如VAE、GAN生成模型中,輸入一張圖片到模型裏,會生成一張新的圖片,這個新生成的圖片就是從概率分佈中採樣得到的。
  • 簡化對於複雜函數求和或求積分的運算,近似求解,比如蒙特卡洛積分。如果我們要計算上圖中f(x)在[a, b]區域的面積。

我們可以產生N個服從均勻分佈的樣本。然後統計處於函數f(x)曲線之下樣本點的數量。這裏就是採樣的動機。

因此最終的面積爲,

什麼是好的樣本

如果我們從P(x)分佈中採集了N個樣本,如何讓這些樣本點充分地表達P(x)?

  如上圖所示,這些樣本點應該大部分集中在高概率區域,概率越低的地方,樣本點越稀疏。如果大部分樣本點在低概率區域,那麼這種採樣就是失敗的,無法表達當前分佈。

  如果上圖表達了某國公民的財富的分佈,雖說大部分人都是韭菜或者綿羊,但是從客觀統計財富分佈的情況,樣本之間還是要有一定限制的,它們應該是相互獨立的。比如,即使是收集了10個碼農的存款數據,那麼這10個碼農也不要在同一家公司裏,不然重複統計,相關性太強的樣本,沒有意義。

因此,好樣本應該是,

(1)樣本點趨向高概率區域,同時兼顧低概率區域。

(2)樣本點之間相互獨立

採樣爲什麼是困難的(the curse of high dimensionality)

    假設變量x是p維的,且每個維度有k種取值,即,那麼總的狀態空間複雜度維,且每個狀態有自己的概率。爲了使樣本趨於高概率區域,不可能遍歷每個狀態的概率值,看看哪個高,哪個低。

蒙特卡洛採樣方法

     許多科學問題的基本部分都是計算下面形式的積分

     這裏f(x)是感興趣的目標函數,D通常是高維空間種的一個區域。通常情況下,如果問題稍微複雜一點,這個積分就難以計算。但是根據數學期望的定理,我們可以另闢蹊徑。

     若隨機變量Y符合函數爲概率密度函數,且絕對收斂,則有:

    根據上述定理,如果f(x)可以被分解成一個函數g(x)與一個概率密度函數f(x)的乘積,那麼上述f(x)積分可以看作是g(x)在密度下的期望。另外,我們求E(Y)時不需要算出Y的概率分佈,只要利用X的概率密度即可。

    這樣,如果我們能得到的獨立樣本,就能獲得I的近似值

    由大數定理有,

    這就是Monte Carlo積分,接下來我們關心從已知分佈中怎麼採樣。目前的統計模擬方法從抽樣分佈是否改變角度可以分爲靜態蒙特卡洛與動態蒙特卡洛方法。靜態蒙特卡洛方法是對獨立同分布隨機變量模擬抽樣,包括逆變換法(Inverse Transform Sampling)和拒絕採樣(Rejection Sampling)。動態蒙特卡洛本文此次講解MCMC中最常見的Metropolis-Hasting法。

基於概率分佈的採樣Inverse Transform Sampling

   該方法就是基於累計分佈函數的逆函數進行採樣。給定目標密度函數後,通過求累計密度函數的逆函數能夠將任何形式的隨機變量轉化爲均勻分佈隨機變量,也就是用均勻分佈的隨機變量帶入逆函數中來模擬目標分佈。

   下面是示例,從離散的一維的累計分佈中採樣,即從數字1到N抽樣,使得樣本逼近當前的概率分佈。

   累積分佈函數爲,

  累積分佈函數的逆函數爲,

    在計算了累計概率分佈後,每次採樣,從[0,1]中按照均勻分佈生成隨機數字u。然後根據u查詢累計概率分佈函數,得到採樣樣本j,如下圖所示

舉例:

    假設現在希望從指數分佈密度函數λ=1中抽樣:

    相應的累積概率密度爲:

    接下來,通過F的反函數將一個0到1的均勻分佈的隨機數轉換成了符合指數分佈的隨機數。由於x小於0的地方概率爲0,因此對於x小於0的地方不用採樣。這樣,累積概率密度反函數如下:

    代碼仿真:

import matplotlib.pyplot as plt 

def sampleExp(Lambda = 2,maxCnt = 50000):
    ys = []
    standardXaxis = []
    standardExp = []
    for i in range(maxCnt):
        u = np.random.random()
        y = -1/Lambda*np.log(1-u) #F-1(X)
        ys.append(y)
    
    for i in range(20):
        t = Lambda * np.exp(-Lambda*i)
        standardXaxis.append(i)
        standardExp.append(t)
    plt.plot(standardXaxis,standardExp,'r')
    
    plt.hist(ys,1000,normed=True)
    plt.show()

sampleExp(1,50000)

從上圖中可以發現採樣點與原始分佈非常吻合。

接受-拒絕採樣Rejection Sampling

    假設已知概率密度函數P(x),想要進行採樣,但是其累積概率密度函數可能很難通過積分計算得到,或者它的反函數也不容易計算。這時可以考慮拒絕採樣。我們首先構造提議分佈Q(x),這個函數相對容易採樣。然後我們找一個常數c,將其與Q(x)相乘之後,即c*Q(x)將P(x)完全罩住。如下圖所示,相當於cQ(x)給P(x)劃定了上界。

    在cQ(x)的範圍內,按照[0, 1]均勻分佈採樣:

    如果採樣點落在函數P(x)的曲線下方,則接收這個採樣,否則拒絕。

    樣本生成步驟:

  • 從備選分佈q(x)中抽樣,得到樣本xi
  • 從均勻分佈U[0,1]中抽樣,得到樣本u
  • 如果存在,則接受樣本xi,否則拒絕

    下圖是對拒絕採樣很好的總結。

    這種方法非常依賴於提議分佈Q(x)的形式,如果M*Q(x)與P(x)越接近,則接受率越高,採樣效率也就越高。但是往往提議分佈和常數M,很難設計。對於極端複雜的P(x),如果拒絕採樣設計不好,可以認爲無法採樣,因爲始終被拒絕。

代碼仿真:

import numpy as np
import scipy.stats as st
import seaborn as sns
import matplotlib.pyplot as plt

sns.set()

def p(x):
    return st.norm.pdf(x, loc=30, scale=10) + st.norm.pdf(x, loc=80, scale=20)

def q(x):
    return st.norm.pdf(x, loc=50, scale=30)

x = np.arange(-50, 151)
k = max(p(x) / q(x))

def rejection_sampling(iter=1000):
    samples = []

    for i in range(iter):
        z = np.random.normal(50, 30)
        u = np.random.uniform(0, k*q(z))

        if u <= p(z):
            samples.append(z)

    return np.array(samples)

plt.plot(x, p(x))
plt.plot(x, k*q(x))
plt.show()

s = rejection_sampling(iter=30000)
sns.distplot(s)

重要性採樣

    我們回到一開始談論蒙特卡洛方法的背景,我們想要通過求某個函數g(x)在密度函數分佈下的數學期望,達到求另一個函數f(x)的積分的目的。重要性採樣並不是用於生成樣本,它是用於估計函數f(x)的數學期望的方法。

    如果符合的分佈難以採樣,我們可以引入另一個分佈,可以很方便的生成樣本,使得

    其中,

    我們把w(x)成爲important weight。重要性採樣的一般流程:

  • 從提議分佈產生N個樣本xi
  • 構建重要性權重
  • 估計函數的數學期望

MCMC 蒙特卡洛馬爾可夫鏈

    蒙特卡洛方法的一個基本步驟是產生(僞)隨機數,使之服從目標概率分佈。當X是一維的情況時,很容易靠逆變換法、接受拒絕採樣做到。但是當我們需要從一個高維的密度函數非常複雜的分佈中抽樣時,我們既無法求出逆函數、也很難球場密度函數的支撐集與常數M。要解決這個問題,MCMC方法是比較常用的。MCMC方法本質上是一個蒙特卡洛綜合程序,它的隨機樣本產生與一條馬氏鏈有關。

什麼是馬爾可夫鏈

    接下來介紹下有關馬氏鏈的基本知識,假設{Xt: t≥0}是隨機序列,隨機序列所有可能取到的值組成的集合記爲S,稱爲狀態空間(馬氏鏈每個節點上採樣樣本)。如果對於及任意狀態si,sj,si0,……,sit-1都有,

    則稱{Xt: t≥0}爲馬氏鏈。直觀上看對於馬氏鏈(馬氏過程),要預測將來的唯一有用信息就是過程當前的狀態,而與以前的狀態無關。馬氏鏈的性質完全由它的轉移概率(轉移核)來決定,它是由狀態si到狀態sj的一步轉移概率,這裏用P(i,j)表示,即,

    用表示馬氏鏈在t時刻處於狀態sj的概率,用表示在t步狀態空間概率的行向量,初始向量用表示,通常中只有一個分量爲1,其餘全部是0,意味着馬氏鏈從一個特定的狀態開始,隨着時間的變化,概率值擴散到整個狀態空間。

   從t時刻到t+1時刻,馬氏鏈中狀態值si的概率計算如下(注意t+1時刻的狀態si之前可能是任意其他狀態)

   如果我們定義一個轉移概率矩陣P,P(i,j)就是從狀態i轉移到狀態j的概率。這意味着此矩陣每一行元素的和爲1。這樣從t時刻到t+1時刻,馬氏鏈中狀態值si的概率計算可以寫成更緊湊的形式,

   定義n步轉移概率,表示從狀態i出發經過n步到達狀態j的概率,即

   接下來,介紹兩個馬氏鏈重要性質:

  • 不可約

如果對所有的i,j都有正整數n,使得,則稱此馬氏鏈爲不可約的,也就是所有狀態互相之間是有聯繫的,從一個狀態總能轉移到另一個狀態(雖然可能不止一步)。

  • 非週期

     如果從狀態x到狀態y的步數都不是某個整數的倍數(即無公約數),就稱此鏈是非週期的。馬氏鏈不會在某些狀態之間以固定的長度陷入循環。

平穩分佈定義及目的

接下來是關於馬氏鏈的例子。下圖代表孩子心情轉變的概率關係,轉移概率矩陣爲:

   若假設初始的三個概率分別是[0.5,0.3,0.2],即t0時刻,小孩子有50%的概率是高興的,30%的概率是一般,20%的概率是難過。將此代入轉移概率,我們發現經過一個充分長的時間,期望的心情狀態與初始狀態無關了,比如觀察100步迭代

代碼仿真:

transfer_matrix = np.array([[0.6,0.2,0.2],[0.3,0.4,0.3],[0,0.3,0.7]],dtype='float32')
start_matrix = np.array([[0.5,0.3,0.2]],dtype='float32')

value1 = []
value2 = []
value3 = []
for i in range(30):
    start_matrix = np.dot(start_matrix,transfer_matrix)
    value1.append(start_matrix[0][0])
    value2.append(start_matrix[0][1])
    value3.append(start_matrix[0][2])
print(start_matrix)

x = np.arange(30)
plt.plot(x,value1,label='cheerful')
plt.plot(x,value2,label='so-so')
plt.plot(x,value3,label='sad')
plt.legend()
plt.show()

 

輸出結果:
[[0.23076935 0.30769244 0.46153864]]

    可以發現,從10輪左右開始,我們的狀態概率分佈就不變了,一直保持在[0.23076934,0.30769244,0.4615386]。換一個初始概率分佈試一試[0.2,0.3,0.5]

    最終狀態的概率分佈趨於同一個穩定的概率分佈[0.23076934,0.30769244,0.4615386],也就是說,經過k步後,我們的馬爾科夫鏈模型的狀態轉移矩陣收斂到的穩定概率值與初始狀態概率值無關,馬氏鏈達到了一個平穩分佈,平穩分佈的數學表達。

   如果存在一個分佈,

   使得下式成立,xàx*代表的是條件概率P(x*|x)

   也即

   則稱它是平穩分佈。下面圖示表示,經過k步後的t時刻,馬氏鏈收斂於平穩分佈。X爲狀態,不同的狀態都有對應自己的概率分佈。

   另外注意,平穩分佈的條件是馬氏鏈是不可約、非週期的。在馬氏鏈中,不同時刻的狀態有自己的概率分佈。當馬氏鏈達到平穩分佈後,每個時刻對應的概率分佈都相同了。

   那爲什麼MCMC引入平穩分佈呢?有何用?

   我們是要對目標概率分佈進行採樣。我們利用馬氏鏈收斂於平穩分佈的性質,構造馬氏鏈(包括狀態隨機變量及狀態轉移矩陣),經過若干次迭代達到平穩分佈,使得平穩分佈逼近目標分佈,此時平穩分佈對應的隨機變量樣本即爲採樣結果。也就是說,如果我們得到了這個穩定概率分佈對應的馬爾科夫鏈模型的狀態轉移矩陣,則我們可以用任意的概率分佈樣本開始,帶入馬爾科夫鏈模型的狀態轉移矩陣,這樣經過一些序列的轉換,最終就可以得到符合對應穩定概率分佈(目標概率分佈)的樣本,採樣方法給定當前時刻狀態樣本及下一時刻狀態轉移矩陣,參考本文最初的離散採樣方法,得到下一時刻的狀態樣本。

    如何讓平穩分佈逼近目標分佈呢?見後續MH算法中證明。

馬氏鏈收斂到平穩分佈的條件

    接下來,我們需要回答什麼樣的馬氏鏈才能收斂到平穩分佈呢?它的充要條件是什麼?

    假如一個分佈滿足細緻平衡條件(detailed balance),則這個分佈是平穩分佈。反之不成立,僅僅是充分非必要條件。所謂細緻平衡,對任意狀態x和x*都有

簡單證明:

如果細緻平衡條件滿足的話,則

由於狀態轉移矩陣的行向量和爲1,即,因此滿足細緻平衡條件的分佈,一定是平穩分佈。

MH算法方法案例

   我們知道了馬氏鏈收斂到平穩分佈的條件,那麼如何構造馬氏鏈,使之收斂到平穩分佈?這個狀態轉移矩陣該如何構造呢?下面用不嚴謹的方式,推導Metroplis-Hasting算法。

   對於馬氏鏈中的兩個狀態x和x*,其對應的分佈用p(x)和p(x*)表示(也就是前面提到的),給定初始提議分佈Q作爲狀態轉移矩陣,通常下式不成立,

    爲了讓上式成立,兩邊乘以一個因子,

     我們這麼理解上式,

    我們把稱爲接受率,根據接受率來決定是否轉移。比如馬氏鏈在時刻t處於狀態x,以概率α(x,x*)接受x*作爲馬氏鏈在下一個時刻的狀態值,以概率1-α(x,x*)拒絕轉移到x*,從而在下一個時刻仍處於狀態x。那怎麼構造這個因子呢?

    再次申明,Q表示的是條件概率。因此有

    上面證明了如果引入接受率,對於任意的提議分佈,都能滿足細緻平衡條件

下面給出MH算法的完整流程:

  1. 給定初始狀態x
  2. 從提議分佈Q(x(i+1)|xi)中生成樣本x*,提議分佈必須是對稱分佈(聯想下二元高斯、二元均勻分佈)
  3. 計算接受率,
  4. 從均勻分佈[0,1]中,生成閾值u
  5. 如果u<α,則接受提議,馬氏鏈的下一時刻狀態爲x*,否則馬氏鏈維持當前狀態
  6. 返回第二部,直到滿足迭代上限

   由於每次迭代都會生成樣本點,我們取馬氏鏈達到平穩分佈後的樣本點,這樣就實現了採樣的目的。

   下面是利用MCMC算法,對一維雙峯的分佈進行採樣的示意圖。

    左圖展示了馬氏鏈在不同迭代次數中,其採樣對目標分佈的逼近程度。右圖中間震盪的曲線,表示馬氏鏈在不同時刻i,對應的狀態x的取值(一維分佈,所以x取值也是一維的)。理論上MCMC每個狀態對應的採樣可以看作對目標分佈的逼近,而右圖只顯示了MCMC迭代最後一次。

    下面是一則例子,希望採樣滿足,逆分佈,這裏假設n=5,a=4,應用Metroplis方法,假設我們用(0,.100)上的均勻分佈做提議分佈。取作爲初始值。   

    假設得到一個候選值來自於均勻分佈U(0,100),,再次強調初始樣本來自提議分佈。接下來計算接受率,

    接下來在(0, 1)上均勻地抽取一個u,如果u<a,則接受θ*(把他作爲下一次抽樣地初值,繼續以上運算),否則拒絕它。

    下面的代碼仿真是兩則對二元分佈的採樣,一個是圓形,一個是高斯

import numpy as np
import scipy.stats as st
import seaborn as sns


mus = np.array([5, 5])
sigmas = np.array([[1, .9], [.9, 1]])


def circle(x, y):
    return (x-1)**2 + (y-2)**2 - 3**2


def pgauss(x, y):
    return st.multivariate_normal.pdf([x, y], mean=mus, cov=sigmas)


def metropolis_hastings(p, iter=1000):
    x, y = 0., 0.
    samples = np.zeros((iter, 2))

    for i in range(iter):
        x_star, y_star = np.array([x, y]) + np.random.normal(size=2)
        if np.random.rand() < p(x_star, y_star) / p(x, y):
            x, y = x_star, y_star
        samples[i] = np.array([x, y])

    return samples


if __name__ == '__main__':
    samples = metropolis_hastings(circle, iter=10000)
    sns.jointplot(samples[:, 0], samples[:, 1])

    samples = metropolis_hastings(pgauss, iter=10000)
    sns.jointplot(samples[:, 0], samples[:, 1])

MCMC的問題

  • 無理論檢驗馬氏鏈何時收斂

   理論只保證收斂性(證明略),但無法直到何時收斂。缺乏明確的理論證明,馬氏鏈到達某一步後達到平穩分佈,所以何時收斂並不知道。只能隔一段時間做檢查、統計平均,看看是否達到平穩分佈。

  • 混合時間過長,或者無法收斂

    我們把馬氏鏈開始到收斂到平穩分佈中間的時間叫做burn in/mixing時間,也就是說馬氏鏈只有經過burn in時間後纔會收斂到平穩分佈。對於某些高維複雜分佈,並且維度之間相關性非常強,不是相互獨立的,無法分解,此時馬氏鏈無法收斂,而是發散的。

  •         MCMC採樣具有一定相關性

    由於MCMC基於馬爾可夫鏈,所以前後狀態之間的樣本一定具有相關性,因此從採樣角度來說不能具有很好的代表性。實際運用中,只能每隔幾步,取一個樣本。

可逆馬爾科夫鏈蒙特卡洛RJMCMC簡介

    關於可逆馬爾科夫鏈蒙特卡洛(reversible jump markov chain monte carlo)此處僅作簡單介紹,不展開。與MCMC相似,RJMCMC的目的也是爲了產生一個以平穩分佈的馬氏鏈。不同之處是MCMC適用於變量個數即參數空間的維度是確定的問題中,而對於參數空間維度不定的問題,只能用RJMCMC來解決。

    RJMCMC可以在不同參數空間中跳轉以產生樣本,一個可以應用RJMCMC的例子是,在一張圖片中,有k個物體,每個物體需要n個參數θ來描述。由於k是不確定的,所以參數空間的維度不確定,那麼就愮RJMCMC來進行推斷確定k的大小。

    爲了實現RJMCMC,需要有birth,death,update三種跳躍(也有人說是merge, split, birth, death四種)。Birth實現了低維空間到高維空間的跳轉,death實現了從高維空間到低維空間的跳轉,而update實現了同一參數空間中的狀態改變。對於目標跟蹤的例子,birth對應圖片中物體個數的增加,death對應圖片中物體個數的減少,update對應物體參數的更新。下圖就是一個birth的實例圖,爲了適配二維分佈,提議分佈從一維增加到二維。

    算法步驟如下:

   注意,k是狀態空間的維度,u表示狀態空間的採樣,不同跳轉方式有自己的概率。

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章