第八週作業報告

馬爾科夫鏈模型

介紹


馬爾科夫模型是一個用於預測的統計模型,在人口,股票等問題上有很多應用。
馬爾科夫過程是一個離散隨機過程,在這個過程中,過去的信息對於預測將來是無關的。即只與當前狀態有關。(一階模型,也有N階馬爾科夫模型,表示當前狀態僅與之前的N個狀態有關,跟再前面的無關。)
時間和狀態都是離散的馬爾科夫過程,稱爲馬爾科夫鏈,記爲:這裏寫圖片描述
這樣,我們根據上面介紹的,可以得出:馬爾科夫性質

對於有N個狀態的一階馬爾科夫模型,每個狀態可以轉移到另一個狀態(包括自己),則共有N^2次狀態轉移,可以用狀態轉移矩陣表示。

Pij = P(Xn + 1 = i | Xn = j),其中Pij表示系統在時刻t處於狀態j,在下一時刻t+l處於狀態i的概率。


例如:一段文字中名詞、動詞、形容詞出現的情況可以用有3個狀態的y一階馬爾科夫模型M表示。狀態s1:名詞,狀態s2:動詞,狀態s3:形容詞。已知狀態轉移矩陣A,則狀態序列O=“名動形名”
馬爾科夫過程定義了以下三個部分:狀態,初始向量,狀態轉移矩陣。

隱形馬爾科夫模型


隱形馬爾科夫模型(HMM)是一個用來描述含有隱含未知參數的馬爾可夫過程的統計模型。其難點是從可觀察的參數中確定該過程的隱含參數。然後利用這些參數來作進一步的分析。

隱性馬爾科夫模型由初始概率分佈,狀態轉移概率分佈以及觀測概率分佈確定。

隱性馬爾科夫模型作了兩個基本假設
1 齊次馬爾科夫假設,即假設因此的馬爾科夫鏈在任意時刻t的狀態只依賴於其前一時刻的狀態,與其他時刻的狀態以及觀測無關。
2 觀測獨立性假設,即假設任意時刻的觀測只依賴於該時刻的馬爾科夫鏈的狀態,與其他觀測以及狀態無關。

HMM是馬爾科夫鏈中的一種,只是它的狀態不能直接被觀察到,但是可以通過觀察向量間接的反映出來,即每一個觀察向量由一個具有相應概率密度分佈的狀態序列產生,又由於每一個狀態也是隨機分佈的,所以HMM是一個雙重隨機過程。


某地只有兩種天氣:雨天和晴天。某人只做3件事:散步,購物,打掃衛生。
做什麼事,跟天氣很有關係。
你知道這個地區的總的天氣趨勢,並且平時知道某人會做的事情。就是說這個隱馬爾可夫模型的參數是已知的.

    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},
      }<br>
     emission_probability = {
          Rainy : {walk: 0.1, shop: 0.4, clean: 0.5},
          Sunny : {walk: 0.6, shop: 0.3, clean: 0.1},
      }

可以觀察到的狀態序列和隱藏的狀態序列是概率相關的。隱藏的狀態和可觀察到的狀態之間有一種概率上的關係,也就是說某種隱藏狀態 H 被認爲是某個可以觀察的狀態 O1 是有概率的,假設爲 P(O1 | H)。如果可以觀察的狀態有3種,那麼很顯然 P(O1 | H)+P(O2 | H)+ P(O3 | H) = 1。
HMM是語音識別,人體行爲識別,文字識別等領域應用非常廣泛。

HMM的3個基本問題
1 概率計算問題:根據模型計算制定序列O出現的概率。
2 學習問題:根據已知觀測序列,估計模型的參數,使得在該模型觀測序列概率最大。
3 預測問題:根據給定觀測序列,求最有可能的對應的狀態序列。
之前在交大做的情感計算就是上面第3個問題。


已知模型參數,計算某一特定輸出序列的概率.通常使用forward算法解決.
已知模型參數,尋找最可能的能產生某一特定輸出序列的隱含狀態的序列.通常使用Viterbi算法解決.
已知輸出序列,尋找最可能的狀態轉移以及輸出概率.通常使用Baum-Welch算法以及Reversed Viterbi算法解決.

預測算法
1 近似算法:在每個t時刻,選擇最有可能出現的狀態i,從而得到一個狀態序列,將它作爲預測的結果。
這樣做的缺點就是不能保證序列整體是最有可能的狀態序列。

2 維特比算法:實際上是動態規劃來解決預測模型。
根據動態規劃原理,最優路徑具有這樣的特性:若是最優路徑在時刻t通過節點i(t),那麼這一路徑從節點i(t)到終點i(T)的部分路徑,對於所有節點i(t)到終點i(T)的路徑必須是最優的。
從終點i(T)開始,由後向前逐步求得節點,得到最優路徑。這就是維特比算法。

算法實踐,實現單詞聯想

思路

  1. 對於給定訓練文本,用分詞器將每句話分爲一個列表W={w1,w2,.........wn}
  2. 對於連續的兩個wi 以及wi+1 ,將前一個wi 作爲字典的key,字典的value作爲一個list(因爲要存儲一定數量的後續word)
  3. 對於聯想,隨機產生前綴單詞,然後在字典中查找該單詞的value(這裏爲list),然後隨機產生一個序號作爲後一個詞語或文字。

    ps:這裏想法很簡單,並沒有去統計頻率。可以從以下方面去改進:

    • 對於每句話的文字列表,將前一個詞語wi 與後一個詞語wi+1 寫成w_i w_i+1 1,處理完之後再來統計w_i w_i+1的頻率(類似於mapreduce
    • 考慮P(wn|wn+1)

實現及運行

參考https://www.shiyanlou.com/courses/678/labs/2204/document

訓練文本: 最近的新聞
運行結果:

這裏寫圖片描述

Viterbi算法

前面簡單介紹了一下該算法,這裏就不多贅述了。

輸入

  • 觀測空間O={o1,o2.....,on}
  • 狀態序列S={S1,S2.....,Sk}
  • 初始狀態Π={π1,π2.....,πk}
  • 觀察序列Y={y1,y2.....,yT}
  • 狀態轉移矩陣A (K*K),Aij 存儲狀態從sisj 的概率
  • 矩陣B,存儲觀察的概率從Si到Oj。

輸出

  • 最可能的隱藏狀態X={x1,x2,.......,xN}

示例

參考https://en.wikipedia.org/wiki/Viterbi_algorithm
由於wiki中已經用Python實現了該算法,下面用java試着去實現以下

1.輸入數據

//觀測狀態
int [] obs = new int[]{Feel.Normal.ordinal(),
        Feel.Cold.ordinal(),
        Feel.Dizzy.ordinal()};
//隱藏的狀態
int [] states = new int[]{BodyState.Healthy.ordinal(),
        BodyState.Fever.ordinal()};
//初始概率
double[] start_p = new double[]{0.6,0.4};
//狀態轉換矩陣
double[][] trans_p = {{0.7,0.3},{0.4,0.6}};
//每種狀態對應的各種觀測概率
double[][] emit_p = {{0.5,0.4,0.1},{0.1,0.3,0.6}};

2.狀態轉換圖
這裏寫圖片描述

3.僞代碼
這裏寫圖片描述

4.算法實現

 protected int[] getViterbiPath()
  {
      double[][] V = new double[obs.length][states.length];
      int[][] path = new int[states.length][obs.length];

      for (int y : states)
      {
          V[0][y] = start_p[y] * emit_p[y][obs[0]];
          path[y][0] = y;
      }

      for (int t = 1; t < obs.length; ++t)
      {
          int[][] newpath = new int[states.length][obs.length];

          for (int y : states)
          {
              double prob = -1;
              int state;
              for (int y0 : states)
              {
                  double nprob = V[t - 1][y0] * trans_p[y0][y] * emit_p[y][obs[t]];
                  if (nprob > prob)
                  {
                      prob = nprob;
                      state = y0;
                      // 記錄最大概率
                      V[t][y] = prob;
                      // 記錄路徑
                      System.arraycopy(path[state], 0, newpath[y], 0, t);
                      newpath[y][t] = y;
                  }
              }
          }

          path = newpath;
      }

      double prob = -1;
      int state = 0;
      for (int y : states)
      {
          if (V[obs.length - 1][y] > prob)
          {
              prob = V[obs.length - 1][y];
              state = y;
          }
      }

      return path[state];
  }

5.運行結果
對於給定的觀察序列: normal cold dizzy
運行結果爲:
這裏寫圖片描述

參考:

隱馬爾可夫模型(HMM)攻略
MangoLiu
wiki
github Viterbi java

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