1. 程式人生 > >系統學習機器學習之隨機場(一)--HMM

系統學習機器學習之隨機場(一)--HMM

HMM(隱馬爾科夫模型)是自然語言處理中的一個基本模型,用途比較廣泛,如漢語分詞、詞性標註及語音識別等,在NLP中佔有很重要的地位。網上關於HMM的介紹講解文件很多,我自己當時開始看的時候也有點稀裡糊塗。後來看到wiki上舉得一個關於HMM的例子才如醍醐灌頂,忽然間明白HMM的三大問題是怎麼回事了。例子我藉助中文wiki重新翻譯了一下,並對三大基本問題進行說明,希望對讀者朋友有所幫助:

  Alice 和Bob是好朋友,但是他們離得比較遠,每天都是通過電話瞭解對方那天作了什麼.Bob僅僅對三種活動感興趣:公園散步,購物以及清理房間.他選擇做什麼事情只憑當天天氣.Alice對於Bob所住的地方的天氣情況並不瞭解,但是知道總的趨勢.在Bob告訴Alice每天所做的事情基礎上,Alice想要猜測Bob所在地的天氣情況

.
  Alice認為天氣的執行就像一個馬爾可夫鏈. 其有兩個狀態 “雨”和”晴”,但是無法直接觀察它們,也就是說,它們對於Alice是隱藏的.每天,Bob有一定的概率進行下列活動:”散步”, “購物”, 或 “清理”. 因為Bob會告訴Alice他的活動,所以這些活動就是Alice的觀察資料.這整個系統就是一個
隱馬爾可夫模型HMM.
  Alice知道這個地區的總的天氣趨勢,並且平時知道Bob會做的事情.也就是說這個隱馬爾可夫模型的引數是已知的.可以用程式語言(Python)寫下來
:
   // 狀態數目,兩個狀態:雨或晴

states = (‘Rainy’, ‘Sunny’)
   // 每個狀態下可能的觀察值

   observations = (‘walk’, ’shop’, ‘clean’)            
   //初始狀態空間的概率分佈
start_probability = {‘Rainy’: 0.6, ‘Sunny’: 0.4}
   // 與時間無關的狀態轉移概率矩陣

transition_probability = {
   
’Rainy’ : {‘Rainy’: 0.7, ‘Sunny’: 0.3},
   
’Sunny’ : {‘Rainy’: 0.4, ‘Sunny’: 0.6},
   
}
   //給定狀態下,觀察值概率分佈,發射概率

emission_probability = {
   
’Rainy’ : {‘walk’: 0.1, ’shop’: 0.4, ‘clean’: 0.5},
   
’Sunny’ : {‘walk’: 0.6, ’shop’: 0.3, ‘clean’: 0.1},
   
}
  在這些程式碼中,start_probability代表了Alice對於Bob第一次給她打電話時的天氣情況的不確定性(Alice知道的只是那個地方平均起來下雨多些).在這裡,這個特定的概率分佈並非平衡的,平衡概率應該接近(在給定變遷概率的情況下){‘Rainy’: 0.571, ‘Sunny’: 0.429}。 transition_probability 表示馬爾可夫鏈下的天氣變遷情況,在這個例子中,如果今天下雨,那麼明天天晴的概率只有30%.程式碼emission_probability 表示了Bob每天作某件事的概率.如果下雨,有 50% 的概率他在清理房間;如果天晴,則有60%的概率他在外頭散步。

  Alice和Bob通了三天電話後發現第一天Bob去散步了,第二天他去購物了,第三天他清理房間了。Alice現在有兩個問題:這個觀察序列“散步、購物、清理”的總的概率是多少?(注:這個問題對應於HMM的基本問題之一:已知HMM模型λ及觀察序列O,如何計算P(O|λ)?) 最能解釋這個觀察序列的狀態序列(晴/雨)又是什麼?(注:這個問題對應HMM基本問題之二:給定觀察序列O=O1,O2,…OT以及模型λ,如何選擇一個對應的狀態序列S = q1,q2,…qT,使得S能夠最為合理的解釋觀察序列O?)
  至於HMM的基本問題之三:如何調整模型引數, 使得P(O|λ)最大?這個問題事實上就是給出很多個觀察序列值,來訓練以上幾個引數的問題。

C語言版:
1、 HTK(Hidden Markov Model Toolkit):
  HTK是英國劍橋大學開發的一套基於C語言的隱馬爾科夫模型工具箱,主要應用於語音識別、語音合成的研究,也被用在其他領域,如字元識別和DNA排序等。HTK是重量級的HMM版本。
  HTK主頁:http://htk.eng.cam.ac.uk/
2、 GHMM Library:
The General Hidden Markov Model library (GHMM) is a freely available LGPL-ed C library implementing efficient data structures and algorithms for basic and extended HMMs.
  GHMM主頁:
http://www.ghmm.org/
3、 UMDHMM(Hidden Markov Model Toolkit):
Hidden Markov Model (HMM) Software: Implementation of Forward-Backward, Viterbi, and Baum-Welch algorithms.
  這款屬於輕量級的HMM版本。

  UMDHMM主頁:http://www.kanungo.com/software/software.html

Java版:
4、 Jahmm Java Library (general-purpose Java library):
Jahmm (pronounced “jam”), is a Java implementation of Hidden Markov Model (HMM) related algorithms. It’s been designed to be easy to use (e.g. simple things are simple to program) and general purpose.
  Jahmm主頁:
http://code.google.com/p/jahmm/

Malab版:
5、 Hidden Markov Model (HMM) Toolbox for Matlab:
This toolbox supports inference and learning for HMMs with discrete outputs (dhmm’s), Gaussian outputs (ghmm’s), or mixtures of Gaussians output (mhmm’s).
  Matlab-HMM主頁:
http://www.cs.ubc.ca/~murphyk/Software/HMM/hmm.html

Common Lisp版:
6、CL-HMM Library (HMM Library for Common Lisp):
Simple Hidden Markov Model library for ANSI Common Lisp. Main structures and basic algorithms implemented. Performance speed comparable to C code. It’s licensed under LGPL.
  CL-HMM主頁:
http://www.ashrentum.net/jmcejuela/programs/cl-hmm/

Haskell版:
7、The hmm package (A Haskell library for working with Hidden Markov Models):
A simple library for working with Hidden Markov Models. Should be usable even by people who are not familiar with HMMs. Includes implementations of Viterbi’s algorithm and the forward algorithm.
  Haskell-HMM主頁:
http://hackage.haskell.org/cgi-bin/hackage-scripts/package/hmm
  注:Haskell是一種純函數語言程式設計語言,它的命名源自美國數學家Haskell Brooks Curry,他在數學邏輯方面上的工作使得函數語言程式設計語言有了廣泛的基礎。

  是否還有C++版、Perl版或者Python版呢?歡迎補充!

介紹(Introduction)
  我們通常都習慣尋找一個事物在一段時間裡的變化模式(規律)。這些模式發生在很多領域,比如計算機中的指令序列,句子中的詞語順序和口語單詞中的音素序列等等,事實上任何領域中的一系列事件都有可能產生有用的模式。
  考慮一個簡單的例子,有人試圖通過一片海藻推斷天氣——民間傳說告訴我們‘溼透的’海藻意味著潮溼陰雨,而‘乾燥的’海藻則意味著陽光燦爛。如果它處於一箇中間狀態(‘有溼氣’),我們就無法確定天氣如何。然而,天氣的狀態並沒有受限於海藻的狀態,所以我們可以在觀察的基礎上預測天氣是雨天或晴天的可能性。另一個有用的線索是前一天的天氣狀態(或者,至少是它的可能狀態)——通過綜合昨天的天氣及相應觀察到的海藻狀態,我們有可能更好的預測今天的天氣。
  這是本教程中我們將考慮的一個典型的系統型別。
  首先,我們將介紹產生概率模式的系統,如晴天及雨天間的天氣波動。
  然後,我們將會看到這樣一個系統,我們希望預測的狀態並不是觀察到的——其底層系統是隱藏的。在上面的例子中,觀察到的序列將是海藻而隱藏的系統將是實際的天氣。
  最後,我們會利用已經建立的模型解決一些實際的問題。對於上述例子,我們想知道:
  1. 給出一個星期每天的海藻觀察狀態,之後的天氣將會是什麼?
  2. 給定一個海藻的觀察狀態序列,預測一下此時是冬季還是夏季?直觀地,如果一段時間內海藻都是乾燥的,那麼這段時間很可能是夏季,反之,如果一段時間內海藻都是潮溼的,那麼這段時間可能是冬季。

生成模式(Generating Patterns)

1、確定性模式(Deterministic Patterns)

考慮下面交通燈的例子,一個序列可能是紅-紅/橙-綠-橙-紅。這個序列可以畫成一個狀態機,不同的狀態按照這個狀態機互相交替,每一個狀態都只依賴於前一個狀態,如果當前的是綠燈,那麼接下來就是橙燈,這是一個確定性系統,因此更容易理解和分析,只要這些狀態轉移都是已知的。但是在實際當中還存在許多不確定性系統。

2、非確定性模式(Non-deterministic patterns)

在日常生活當中,我們總是希望根據當前天氣的情況來預測未來天氣情況,和上面的交通燈的例子不同,我們不能依靠現有知識確定天氣情況的轉移,但是我們還是希望能得到一個天氣的模式。一種辦法就是假設這個模型的每個狀態都只依賴於前一個的狀態,這個假設被稱為馬爾科夫假設,這個假設可以極大簡化這個問題。顯然,這個假設也是一個非常糟糕的假設,導致很多重要的資訊都丟失了。

當涉及到天氣的時候,馬爾科夫假設描述為,假設如果我們知道之前一些天的天氣資訊,那麼我們就能預測今天的天氣。當然,這個例子也是有些不合實際的。但是,這樣一個簡化的系統可以有利於我們的分析,所以我們通常接受這樣的假設,因為我們知道這樣的系統能讓我們獲得一些有用的資訊,儘管不是十分準確的。

談到 HMM,首先簡單介紹一下馬爾可夫過程 (Markov Process),它因俄羅斯數學家安德烈·馬爾可夫而得名,代表數學中具有馬爾可夫性質的離散隨機過程。該過程中,每個狀態的轉移只依賴於之前的 n 個狀態,這個過程被稱為1個 n 階的模型,其中 n 是影響轉移狀態的數目。最簡單的馬爾科夫過程就是一階過程,每一個狀態的轉移只依賴於其之前的那一個狀態。注意這和確定性系統不一樣,因為這種轉移是有概率的,而不是確定性的。

馬爾可夫鏈是隨機變數X1, … , Xn 的一個數列。這些變數的範圍,即他們所有可能取值的集合,被稱為“狀態空間”,而 Xn  的值則是在時間 的狀態。如果Xn+1對於過去狀態的條件概率分佈僅是 X的一個函式,則

這裡 為過程中的某個狀態。上面這個恆等式可以被看作是馬爾可夫性質

  馬爾可夫鏈的在很多應用中發揮了重要作用,例如,谷歌所使用的網頁排序演算法(PageRank)就是由馬爾可夫鏈定義的。

下圖展示了天氣這個例子中所有可能的一階轉移:

注意一個含有 N 個狀態的一階過程有 N個狀態轉移。每一個轉移的概率叫做狀態轉移概率(state transition probability),就是從一個狀態轉移到另一個狀態的概率。這所有的 N個概率可以用一個狀態轉移矩陣來表示,其表示形式如下:

對該矩陣有如下約束條件:

下面就是海藻例子的狀態轉移矩陣

這個矩陣表示,如果昨天是晴天,那麼今天有50%的可能是晴天,37.5%的概率是陰天,12.5%的概率會下雨,很明顯,矩陣中每一行的和都是1。

為了初始化這樣一個系統,我們需要一個初始的概率向量:

這個向量表示第一天是晴天。

到這裡,我們就為上面的一階馬爾科夫過程定義了以下三個部分:

  狀態:晴天、陰天和下雨

  初始向量:定義系統在時間為0的時候的狀態的概率

  狀態轉移矩陣:每種天氣轉換的概率

所有的能被這樣描述的系統都是一個馬爾科夫過程

然而,當馬爾科夫過程不夠強大的時候,我們又該怎麼辦呢?在某些情況下,馬爾科夫過程不足以描述我們希望發現的模式。

例如,一個隱居的人可能不能直觀的觀察到天氣的情況,但是民間傳說告訴我們海藻的狀態在某種概率上是和天氣的情況相關的。在這種情況下我們有兩個狀態集合,一個可以觀察到的狀態集合(海藻的狀態)和一個隱藏的狀態(天氣狀況)。我們希望能找到一個演算法可以根據海藻的狀況和馬爾科夫假設來預測天氣的狀況。

一個更現實的例子是語音識別,我們聽到的聲音是聲帶、喉嚨和一起其他的發音器官共同作用的結果。這些因素相互作用,共同決定了每一個單詞的聲音,而一個語音識別系統檢測的聲音(可以觀察的狀態)是人體內部各種物理變化(隱藏的狀態、引申一個人真正想表達的意思)產生的。

某些語音識別裝置把內部的發音機制作為一個隱藏的狀態序列,把最後的聲音看成是一個和隱藏的狀態序列十分相似的可以觀察到的狀態的序列。在這兩個例子中,一個非常重要的地方是隱藏狀態的數目和可以觀察到的狀態的數目可能是不一樣的。在一個有3種狀態的天氣系統(sunny、cloudy、rainy)中,也許可以觀察到4種潮溼程度的海藻(dry、dryish、damp、soggy)。在語音識別中,一個簡單的發言也許只需要80個語素來描述,但是一個內部的發音機制可以產生不到80或者超過80種不同的聲音。

在上面的這些情況下,可以觀察到的狀態序列和隱藏的狀態序列是概率相關的。於是我們可以將這種型別的過程建模為有一個隱藏的馬爾科夫過程和一個與這個隱藏馬爾科夫過程概率相關的並且可以觀察到的狀態集合。這就是本文重點介紹的隱馬爾可夫模型。

  隱馬爾可夫模型 (Hidden Markov Model) 是一種統計模型,用來描述一個含有隱含未知引數的馬爾可夫過程。其難點是從可觀察的引數中確定該過程的隱含引數,然後利用這些引數來作進一步的分析。下圖是一個三個狀態的隱馬爾可夫模型狀態轉移圖,其中x 表示隱含狀態,y 表示可觀察的輸出,a 表示狀態轉換概率,b 表示輸出概率。

下圖顯示了天氣的例子中隱藏的狀態和可以觀察到的狀態之間的關係。我們假設隱藏的狀態是一個簡單的一階馬爾科夫過程,並且他們兩兩之間都可以相互轉換。

  對 HMM 來說,有如下三個重要假設,儘管這些假設是不現實的。

  假設1:馬爾可夫假設(狀態構成一階馬爾可夫鏈)

  假設2:不動性假設(狀態與具體時間無關)

  假設3:輸出獨立性假設(輸出僅與當前狀態有關)

  隱藏的狀態和可觀察到的狀態之間有一種概率上的關係,也就是說某種隱藏狀態 H 被認為是某個可以觀察的狀態 O1 是有概率的,假設為 P(O1 | H)。如果可以觀察的狀態有3種,那麼很顯然 P(O1 | H)+P(O2 | H)+ P(O3 | H) = 1

這樣,我們也可以得到一個另一個矩陣,稱為混淆矩陣(confusion matrix)。這個矩陣的內容是某個隱藏的狀態被分別觀察成幾種不同的可以觀察的狀態的概率,在天氣的例子中,這個矩陣如下圖:

上邊的圖示都強調了 HMM 的狀態變遷。而下圖則明確的表示出模型的演化,其中綠色的圓圈表示隱藏狀態,紫色圓圈表示可觀察到狀態,箭頭表示狀態之間的依存概率,一個 HMM 可用一個5元組 { N, M, π,A,B } 表示,其中 N 表示隱藏狀態的數量,我們要麼知道確切的值,要麼猜測該值,M 表示可觀測狀態的數量,可以通過訓練集獲得, π={πi} 為初始狀態概率,A={aij} 為隱藏狀態的轉移矩陣 Pr(xt(i) | xt-1(j)),B={bik} 表示某個時刻因隱藏狀態而可觀察的狀態的概率,即混淆矩陣,Pr(ot(i) | xt(j))。在狀態轉移矩陣和混淆矩陣中的每個概率都是時間無關的,即當系統演化時,這些矩陣並不隨時間改變。對於一個 N 和 M 固定的 HMM 來說,用 λ={ π, A, B} 表示 HMM 引數。

在正常的馬爾可夫模型中,狀態對於觀察者來說是直接可見的。這樣狀態的轉換概率便是全部的引數。而在隱馬爾可夫模型中,狀態並不是直接可見的,但受狀態影響的某些變數則是可見的。每一個狀態在可能輸出的符號上都有一概率分佈。因此輸出符號的序列能夠透露出狀態序列的一些資訊。

HMM 中有三個典型問題:

  (一) 已知模型引數,計算某一給定可觀察狀態序列的概率

假設我們已經有一個特定的隱馬爾科夫模型 λ 和一個可觀察狀態序列集。我們也許想知道在所有可能的隱藏狀態序列下,給定的可觀察狀態序列的概率。當給定如下一個隱藏狀態序列:

  那麼在 HMM 和這個隱藏狀態序列的條件下,可觀察狀態序列的概率為:

  而隱藏狀態序列在HMM條件下的概率為:

  因此,隱藏狀態序列和可觀察狀態序列的聯合概率為:

  那麼所有可能的隱藏狀態序列上,可觀察狀態序列的概率為:

  例如,我們也許有一個海藻的“Summer”模型和一個“Winter”模型,因為海藻在夏天和冬天的狀態應該是不同的,我們希望根據一個可觀察狀態(海藻的潮溼與否)序列來判斷現在是夏天還是冬天。

我們可以使用前向演算法來計算在某個特定的HMM 下一個可觀察狀態序列的概率,然後據此找到最可能的模型。

這種型別的應用通常出現在語音設別中,通常我們會使用很多 HMM,每一個針對一個特別的單詞。一個可觀察狀態的序列是從一個可以聽到的單詞向前得到的,然後這個單詞就可以通過找到滿足這個可觀察狀態序列的最大概率的HMM 來識別。

下面介紹一下前向演算法(Forward Algorithm)

 如何計算一個可觀察序列的概率?

  1. 窮舉搜尋

給定一個 HMM,我們想計算出某個可觀察序列的概率。考慮天氣的例子,我們知道一個描述天氣和海藻狀態的 HMM,而且我們還有一個海藻狀態的序列。假設這個狀態中的某三天是(dry,damp,soggy),在這三天中的每一天,天氣都可能是晴朗,多雲或者下雨,我們可以用下圖來描述觀察序列和隱藏序列:

在這個圖中的每一列表示天氣的狀態可能,並且每個狀態都指向相鄰的列的每個狀態,每個狀態轉換在狀態轉移矩陣中都有一個概率。每一列的下面是當天的可觀察的海藻的狀態,在每種狀態下出現這種可觀察狀態的概率是由混淆矩陣給出的。

一個可能的計算可觀察概率的方法是找到每一個可能的隱藏狀態的序列,這裡有3= 27種,這個時候的可觀察序列的概率就是 Pr(dry, damp, soggy | HMM)=Pr(dry, damp, soggy | sunny, sunny, sunny) + . . . . + Pr(dry, damp, soggy | rainy, rainy, rainy)。

很顯然,這種計算的效率非常低,尤其是當模型中的狀態非常多或者序列很長的時候。事實上,我們可以利用概率不隨時間變化這個假設來降低時間的開銷。

  2. 使用遞迴來降低複雜度

我們可以考慮給定 HMM 的情況下,遞迴的計算一個可觀察序列的概率。我們可以首先定義一個部分概率,表示達到某個中間狀態的概率。接下來我們將看到這些部分概率是如何 在time=1 和 time = n (n > 1) 的時候計算的。

假設一個T時間段的可觀察序列是:

  1) 部分概率

下面這張圖表示了一個觀察序列(dry,damp,soggy)的一階轉移

我們可以通過計算到達某個狀態的所有路徑的概率和來計算到達某個中間狀態的概率。比如說,t=2時刻,cloudy的概率用三條路徑的概率之和來表示:

我們用 αt(j) 來表示在 t 時刻是狀態 j 的概率,αt(j)=Pr(觀察狀態 | 隱藏狀態 j ) x Pr(t 時刻到達狀態 j 的所有路徑)。

最後一個觀察狀態的部分概率就表示了整個序列最後達到某個狀態的所有可能的路徑的概率和,比如說在這個例子中,最後一列的部分狀態是通過下列路徑計算得到的:

因為最後一列的部分概率是所有可能的路徑的概率和,所以就是這個觀察序列在給定 HMM 下的概率了。

  2) 計算 t=1時候的部分概率

當 t=1 的時候,沒有路徑到某個狀態,所以這裡是初始概率,Pr(狀態 j | t=0) = π(狀態 j ),這樣我們就可以計算 t=1 時候的部分概率為:

因為在初始的時候,狀態 j 的概率不僅和這個狀態本身相關,還和觀察狀態有關,所以這裡用到了混淆矩陣的值,k1 表示第一個觀察狀態,bjk1 表示隱藏狀態是 j,但是觀察成 k1 的概率。

  3) 計算 t>1 時候的部分概率

還是看計算部分概率的公式是:αt(j) = Pr(觀察狀態 | 隱藏狀態 j) x Pr(t 時刻到達狀態 j 的所有路徑)。 這個公式的左邊是從混淆矩陣中已知的,我只需要計算右邊部分,很顯然右邊是所有路徑的和:

需要計算的路徑數是和觀察序列的長度的平方相關的,但是 t 時刻的部分概率已經計算過了之前的所有路徑,所以在 t+1 時刻只需要根據 t 時刻的概率來計算就可以了:

這裡簡單解釋下,bjk(t+1) 就是在 t+1 時刻的第 j 個隱藏狀態被認為是當前的觀察狀態的概率,後面一部分是所有t時刻的隱藏狀態到 t+1 時候的隱藏狀態j的轉移的概率的和。這樣我們每一步的計算都可以利用上一步的結果,節省了很多時間。

  4) 公式推導

  5) 降低計算複雜度

我們可以比較窮舉和遞迴演算法的複雜度。假設有一個 HMM,其中有 n 個隱藏狀態,我們有一個長度為 T 的觀察序列。

窮舉演算法的需要計算所有可能的隱藏序列:

需要計算:

很顯然窮舉演算法的時間開銷是和 T 指數相關的,即 NT,而如果採用遞迴演算法,由於我們每一步都可以利用上一步的結果,所以是和 T 線性相關的,即複雜度是 N2T。

這裡我們的目的是在某個給定的 HMM 下,計算出某個可觀察序列的概率。我們通過先計算部分概率的方式遞迴的計算整個序列的所有路徑的概率,大大節省了時間。在 t=1 的時候,使用了初始概率和混淆矩陣的概率,而在t時刻的概率則可以利用 t-1 時刻的結果。

這樣我們就可以用遞迴的方式來計算所有可能的路徑的概率和,最後,所有的部分概率的計算公式為