天天看點

HMM 模型

馬爾可夫鍊

一個系統有N個狀态 S1,S2,···,Sn,随着時間推移,系統從某一狀态轉移到另一狀态,設qt為時間t的狀态,系統在時間t處于狀态Sj 的機率取決于其在時間 1 ,2,···,t-1 的狀态,該機率為:

HMM 模型

如果系統在t時間的狀态隻與其在時間 t -1的狀态相關,則該系統構成一個離散的一階馬爾可夫鍊(馬爾可夫過程):

HMM 模型

馬爾可夫模型

如果隻考慮獨立于時間t的随機過程:

HMM 模型

其中狀态轉移機率 aij 必須滿足 aij>=0 , 且

HMM 模型

,則該随機過程稱為馬爾可夫模型。

假定一段時間的氣象可由一個三狀态的馬爾可夫模型M描述,S1:雨,S2:多雲,S3:晴,狀态轉移機率矩陣為:

HMM 模型

如果第一天為晴天,根據這一模型,在今後七天中天氣為O=“晴晴雨雨晴雲晴”的機率為:

HMM 模型

隐馬爾可夫模型

對于一個随機事件,有一觀察值序列: O=O1,O2,…OT

該事件隐含着一個狀态序列: Q = q1,q2,…qT。

假設:馬爾可夫性假設(狀态構成一階馬爾可夫鍊)           
        P(qi|qi-…q1) = P(qi|qi-)
假設:不動性假設(狀态與具體時間無關)
        P(qi+|qi) = P(qj+|qj),對任意i,j成立
假設:輸出獨立性假設(輸出僅與目前狀态有關)          
        p(O1,...,OT | q1,...,qT) = Πp(Ot | qt) 
           

HMM定義

一個隐馬爾可夫模型 (HMM) 是由一個五元組描述的:

λ =( N,M ,A,B, π )

其中:

N = {q1,…qN}:狀态的有限集合

M = {v1,…,vM}:觀察值的有限集合

A = {aij},aij = P(qt = Sj |qt-1 = Si):狀态轉移機率矩陣

B = {bjk}, bjk = P(Ot = vk | qt = Sj):觀察值機率分布矩陣

π = {πi},πi = P(q1 = Si):初始狀态機率分布

觀察狀态是已知的,隐狀态是未知的。

三個基本問題

令 λ = {π,A,B} 為給定HMM的參數,

令 O = O1,…,OT 為觀察值序列,則有關于

隐馬爾可夫模型(HMM)的三個基本問題:

1.評估問題:對于給定模型,求某個觀察值序列的機率P(O|λ) ;

• 計算骰子點數序列的确由“作弊”模型生成的可能性

2.解碼問題:對于給定模型和觀察值序列,求可能性最大的狀态序列maxQ{P(Q|O,λ)};

• 在骰子點數序列中, 判斷哪些點數是用骰子B擲出的

3.學習問題:對于給定的一個觀察值序列O,調整參數λ,使得觀察值出現的機率P(O|λ)最大。

• 如何從大量的點數序列樣本中學習得出“作弊模型”的參數

三個基本問題解法

評估問題:前向算法

定義前向變量

采用動态規劃算法,複雜度O(N2T)

解碼問題:韋特比(Viterbi)算法

采用動态規劃算法,複雜度O(N2T)

學習問題:向前向後算法

EM算法的一個特例,帶隐變量的最大似然估計

HMM将兩個序列相聯系起來:

  1. 由離散隐狀态組成的狀态序列(路徑),Q = (q1,…,qT), 每個qt∈S均是一個狀态,由初始狀态機率及狀态轉移機率(π, A)所決定
  2. 由明字元組成的觀察序列,O = (o1,…,oT), 每個ot∈V均為一個離散明字元,由狀态序列及各狀态的明字元生成機率(Q,B)所決定。
package org.digdata.hmm;

/**
 * HMM對象類
 */
public class HMM implements Cloneable {

    /**
     * 隐藏狀态數目
     */
    public int N;

    /**
     * 觀察狀态數目
     */
    public int M;

    /**
     * 狀态轉移矩陣 一個隐狀态到另一個隐狀态的機率
     */
    public double[][] A;

    /**
     * 混淆矩陣 一個隐狀态到觀察狀态的機率
     */
    public double[][] B;

    /**
     * 初始向量
     */
    public double[] pi;

    @Override
    public Object clone() {
        HMM hmm = null;
        try {
            hmm = (HMM) super.clone();
            hmm.A = A.clone();
            for (int i = ; i < A.length; i++) {
                hmm.A[i] = A[i].clone();
            }
            hmm.B = B.clone();
            for (int i = ; i < B.length; i++) {
                hmm.B[i] = B[i].clone();
            }
            hmm.pi = pi.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }

        return hmm;
    }

    public HMM() {
        super();
    }

    /**
     * @param n
     *            隐藏狀态數目
     * @param m
     *            觀察狀态數目
     * @param a
     *            狀态轉移矩陣
     * @param b
     *            混淆矩陣
     * @param pi
     *            初始向量
     */
    public HMM(int n, int m, double[][] a, double[][] b, double[] pi) {
        super();
        N = n;
        M = m;
        A = a.clone();
        for (int i = ; i < a.length; i++) {
            A[i] = a[i].clone();
        }
        B = b.clone();
        for (int i = ; i < b.length; i++) {
            B[i] = b[i].clone();
        }
        this.pi = pi.clone();
    }

    /**
     * 用于參數估計
     * 
     * @param n
     *            隐藏狀态數目
     * @param m
     *            觀察狀态數目
     */
    public HMM(int n, int m) {
        super();
        N = n;
        M = m;
        A = new double[N][N];
        B = new double[N][M];
        pi = new double[N];
    }

    /**
     * 用于測試已知模型
     * 
     * @param a
     *            狀态轉移矩陣
     * @param b
     *            符号輸出矩陣
     * @param pi
     *            初始向量
     */
    public HMM(double[][] a, double[][] b, double[] pi) {
        super();
        N = a.length;
        M = b[].length;
        A = a.clone();
        for (int i = ; i < a.length; i++) {
            A[i] = a[i].clone();
        }
        B = b;
        for (int i = ; i < b.length; i++) {
            B[i] = b[i].clone();
        }
        this.pi = pi.clone();
    }

}
           

HMM 實際問題:

數值計算中的防溢出處理

在前向算法、Viterbi算法以及Baum-Welch算法中,機率值的連續乘法運算很容易導緻下溢現象。

解決辦法:

1.前向算法中:每一個時間步的運算中都乘以一 個比例因子

2.Viterbi算法中:對機率值取對數後計算