陳鍾誠

Version 1.0

Metropolis-Hasting 演算法

「Metropolis-Hasting 演算法」(以下簡稱 MH 算法) 的設計,是建構在「馬可夫系統的細緻平衡條件」之上的,因此在說明「MH 算法」之前,必須先理解上述的「細緻平衡條件」,也就是對於圖中的每一條連線都必須達到「流入=流出」的均衡狀態。換句話說,就是符合下列條件。

P(x) Q(x  \to  y) = P(y) Q(y  \to  x)

Metropolis-Hasting 演算法 (MH 程序) 是一個不斷調整 Q(x→y) 的演算法,該算法所關注的焦點在於 (x, y) 通道上。

假如目前 x 的機率過高,而且從 x 流向 y 的粒子較多,那麼就應當讓粒子全部從 x 流向 y,也就是 Q(x→y) 的流量均可順利流出。但是如果從 y 流向 x 的粒子較多時,那麼我們就讓某些粒子卡住,不要流入 x。

但是究竟要流出多少粒子,卡住多少粒子呢?MH 方法利用下列的 A(x→y) 比例進行調節,以便能透過堵塞通道 Q(y→x) 的方法,讓系統趨向平衡。

A(x \to y) = \frac{P(x) Q(x \to y)}{P(y) Q(y \to x)}

因此,Metropolis 設計出了下列通道流量的調整公式,以便用疊代的方式調整狀態轉移機率矩陣 P(x \to y)。

Q_{t+1}(x \to y) = \begin{cases} Q_t(x \to y) & \;\;\; \text{if x} \neq y  , A(x \to y) \geq 1;\\Q_t(x \to y) A(x \to y) & \;\;\;\text{if x} \neq y , A(x \to y) < 1;\\ Q_t(x \to y) + \sum_{z:A(x \to z) < 1} Q_t(x \to z) (1 - A(x \to z)) & \;\;\;\text{if x = y.} \end{cases}

Metropolis-Hasting 算法

在理解了平衡條件與 MH 程序的想法後,我們就可以正式撰寫出 Metropolis-Hasting 程序的演算法。

Algorithm Metropolis-Hasting(P(S)) output Q(S→S)
  foreach (x,y) in (S, S)
    Q(x→y) = 1/|S|
 while not converge
   foreach (x,y) in (S, S) // 計算 A 矩陣
     A(x→y) = (P(y) Q(y→x)) / (P(x) Q(x→y))

   foreach (x,y) in (S, S) // 計算下一代的轉移矩陣 Q
     if x = y
       Q'(x→y) = Q(x→y) + \sum_{z:A(x \to z) < 1} Q_t(x \to z) (1 - A(x \to z))
     else
       if A(x→y) >= 1
        Q'(x→y) = Q(x→y)
       else
        Q'(x→y) = Q(x→y) A(x→y)
   Q = Q'
 end while
End Algorithm

MH 算法的進一步簡化

在上述的 MH 程序中,算式 \sum_{z:A(x \to z) < 1} Q_t(x \to z) (1 - A(x \to z)) 是 $\sum_{z:A(x \to z) < 1} Q_t(x \to z) (1 - A(x \to z))$ 的 tex 數學式,該式的計算較為複雜,事實上,這個值就是為了讓 $Q(x \to y)$ 能夠『歸一化』的條件,也就是讓 $\sum_y Q(x \to y)=1$ 的差額補償值。因此我們也可以將上述演算法改寫如下。

Algorithm Metropolis-Hasting(P(S)) output Q(S,S)
  foreach (x,y) in (S, S)
    Q(x→y) = 1/|S|
 while not converge
   foreach (x,y) in (S, S) // 計算 A 矩陣
     Q'(x→y) = Q(x→y)
     A(x→y) = (P(y) Q(y→x)) / (P(x) Q(x→y))

   foreach (x,y) in (S, S) // 計算下一代的轉移矩陣 Q
     if A(x,y) < 1
       Q'(x→y) = Q(x→y) A(x→y)
       Q'(x→x) = Q(x→x) + Q(x→y) (1-A(x→y))

   Q = Q';
 end while
End Algorithm

MH 算法的程式範例

檔案:metropolis.js

// Metropolis Hasting 的範例
// 問題:機率式有限狀態機,P(s0)=0.3, P(s1)=0.5
// 目標:尋找「轉移矩陣」的穩態,也就是 Q(x→y)=? 時系統會達到平衡。

function rand(a, b) {
  return (b-a)*Math.random() + a;
}

function MetropolisHasting() {
  var P = [ 5.0/8, 3.0/8 ]; // 初始機率分佈,隨意設定。
  var Q = [ [0.5, 0.5], [0.5, 0.5] ]; // 初始機率分佈,隨意設定。
  var A = [ [0, 0], [0, 0]];
  do {
	console.log("Q = %j", Q);
    var Qn= [ [0,0], [0,0]];
	for (var x in Q) // 計算 A 矩陣
	  for (var y in Q[x]) {
	    Qn[x][y] = Q[x][y];
	    A[x][y] = (P[y]*Q[y][x]) / (P[x]*Q[x][y]); // 入出比 = 流入/流出
	  }
	
	console.log("A = %j", A);
	var diff = 0;
	for (var x in Q) 
	  for (var y in Q[x]) { // 計算下一代 Qn 矩陣
	    if (A[x][y] < 1) {  // 入出比 < 1 ,代表流入太少,流出太多
		  Qn[x][y] = Q[x][y] * A[x][y]; // 降低流出量
		  Qn[x][x] = Qn[x][x]+Q[x][y]*(1-A[x][y]); // 『規一化』調整
		  diff += Math.abs(Qn[x][y]-Q[x][y]); // 計算新舊矩陣差異
		}
	  }
	Q = Qn;
	console.log("diff = %d", diff);
  } while (diff > 0.001);  // 假如差異夠小的時候,就可以停止了。
}

MetropolisHasting();

執行結果

D:\Dropbox\Public\web\ml\code\Gibbs>node metropolis.js
Q = [[0.5,0.5],[0.5,0.5]]
A = [[1,0.6],[1.6666666666666667,1]]
diff = 0.2
Q = [[0.7,0.3],[0.5,0.5]]
A = [[1,1],[1,1]]
diff = 0

Metropolis-Hasting 程序可以用來學習具有『細緻平衡』特性的狀態轉移機率 Q(x→y),一但取得了狀態轉移機率,整個系統的機率行為就確定下來了,透過這樣的程序,我們可以學習到一個馬可夫模型,然後再利用這個模型進行『預測』,以便讓程式的行為模擬該馬可夫系統的行為。Metropolis-Hasting 程序對這些可用隨機系統描述的行為而言,是一個重要的學習程序,因此被廣泛應用在機器翻譯、文件分類、分群或貝氏網路的學習等領域上,這是數學領域在電腦上應用的一個優良方法。

結語

在本章中我們看到了兩種「馬可夫模型」的學習方法,Gibbs Algorithm 可以在已知「狀態轉移矩陣」 P(x→y) 的情況下,學習每個狀態的機率 P(x)。

而 Metropolis-Hasting 程序則可以在已知每個狀態的機率 P(x) 的情況下,學習「狀態轉移矩陣」 P(x→y) 的機率值。

當然、這是在沒有隱變數情況下的學習,如果有隱變數的時候,我們就必須採用「隱馬可夫模型」的學習方法才行。