【Hidden Markov Model】

隐马尔科夫模型(Hidden Markov Model)

与马尔科夫模型相比,隐马尔科夫模型有 隐藏状态观测状态。两者并非对应关系,即隐藏状态数 n n n和观测状态数 m m m无关。

  • 当前时刻隐藏状态 x t x_t xt只与上一时刻隐藏状态 x t − 1 x_{t-1} xt1有关:
    状态转移概率 a i j = P ( x t = i ∣ x t − 1 = j ) a_{ij}=P(x_t=i|x_{t-1}=j) aij=P(xt=ixt1=j)
  • 某个观测状态 o t o_t ot只和生成它的隐藏状态 x t x_t xt有关:
    观测状态概率 b j ( k ) = P ( o t = k ∣ x t = j ) b_j(k)=P(o_t=k|x_t=j) bj(k)=P(ot=kxt=j)
  • 初始隐藏状态:
    π i = P ( x 1 = i ) \pi_i=P(x_1=i) πi=P(x1=i)

在这里插入图片描述
总而言之,隐马尔科夫模型表示如下:
H M M = ( π , A , B ) HMM=(\pi,\mathcal{A},\mathcal{B}) HMM=(π,A,B)
其中 π \pi π为初始状态概率, A \mathcal{A} A为隐藏状态转移概率, B \mathcal{B} B为观测状态生成概率。

隐马尔可夫模型解决的问题

求解参数

已知观测状态序列 O = { o 1 , o 2 , . . . , o T } \mathbf{O} = \left \{ o_1,o_2,...,o_T \right \} O={o1,o2,...,oT}、隐藏状态序列 X = { x 1 , x 2 , . . . , x T } \mathbf{X} = \left \{ x_1,x_2,...,x_T \right \} X={x1,x2,...,xT},求解隐马尔科夫模型参数 π , A , B \pi,\mathcal{A},\mathcal{B} π,A,B

根据 π , A , B \pi,\mathcal{A},\mathcal{B} π,A,B定义,利用大数定律估计 π , A , B \pi,\mathcal{A},\mathcal{B} π,A,B即可。

滤波(filtering)

已知模型 λ = ( π , A , B ) \lambda =(\pi,\mathcal{A},\mathcal{B}) λ=(π,A,B)及观测序列 O = { o 1 , o 2 , . . . , o T } \mathbf{O} = \left \{ o_1,o_2,...,o_T \right \} O={o1,o2,...,oT},求取该观测序列出现的概率 P ( O ∣ λ ) P(\mathbf{O}|\lambda ) P(Oλ)

直接求解

为求给定模型下观测序列出现的概率,因观测状态只与其对应的隐藏状态有关,则通过所有可能的隐藏状态序列 X = { x 1 , x 2 , . . . , x T } \mathbf{X} = \left \{ x_1,x_2,...,x_T \right \} X={x1,x2,...,xT}即可求取 P ( O ∣ λ ) P(\mathbf{O}|\lambda ) P(Oλ)
P ( O ∣ λ ) = ∑ X P ( O , X ∣ λ ) = ∑ X P ( X ∣ λ ) P ( O ∣ X , λ ) (1) P(\mathbf{O}|\lambda)=\sum_{\mathbf{X}}P(\mathbf{O},\mathbf{X}|\lambda)=\sum_{\mathbf{X}}P(\mathbf{X}|\lambda)P(\mathbf{O}|\mathbf{X},\lambda)\tag{1} P(Oλ)=XP(O,Xλ)=XP(Xλ)P(OX,λ)(1)
利用 π , A \pi,\mathcal{A} π,A可求取:
P ( X ∣ λ ) = P ( x 1 ∣ λ ) P ( x 2 , . . . , x T ∣ x 1 , λ ) = π x 1 P ( x 2 ∣ x 1 , λ ) P ( x 2 , . . . , x T ∣ x 1 , x 2 , λ ) P(\mathbf{X}|\lambda)=P(x_1|\lambda)P(x_2,...,x_T|x_1,\lambda)=\pi_{x_1} P(x_2|x_1,\lambda)P(x_2,...,x_T|x_1,x_2,\lambda) P(Xλ)=P(x1λ)P(x2,...,xTx1,λ)=πx1P(x2x1,λ)P(x2,...,xTx1,x2,λ)
利用 B \mathcal{B} B可求取:
P ( O ∣ X , λ ) = ∏ k = 1 T P ( o k ∣ x k , λ ) P(\mathbf{O}|\mathbf{X},\lambda)=\prod_{k=1}^{T}P(o_k|x_k,\lambda) P(OX,λ)=k=1TP(okxk,λ)
则式 ( 1 ) (1) (1)为:
P ( O ∣ λ ) = ∑ X P ( O , X ∣ λ ) = ∑ x 1 , x 2 , . . . , x T π x 1 b x 1 ( o 1 ) a x 1 x 2 b x 2 ( o 2 ) a x 2 x 3 . . . a x T − 1 x T b x T ( o T ) (2) P(\mathbf{O}|\lambda)=\sum_{\mathbf{X}}P(\mathbf{O},\mathbf{X}|\lambda)=\sum_{x_1,x_2,...,x_T}\pi_{x_1}b_{x_1}(o_1)a_{x_1x_2}b_{x_2}(o_2)a_{x_2x_3}...a_{x_{T-1}x_T}b_{x_T}(o_T)\tag{2} P(Oλ)=XP(O,Xλ)=x1,x2,...,xTπx1bx1(o1)ax1x2bx2(o2)ax2x3...axT1xTbxT(oT)(2)
若隐藏状态数为 n n n,则式 ( 2 ) (2) (2)复杂度为 O ( T n T ) O(Tn^T) O(TnT)

前向算法

假设 t t t时刻隐藏状态 x t = i x_t=i xt=i,观测序列 O = { o 1 , o 2 , . . . , o t } \mathbf{O} = \left \{ o_1,o_2,...,o_t \right \} O={o1,o2,...,ot}的概率被称为前向概率:
α i ( t ) = P ( o 1 , o 2 , . . . , o t , x t = i ∣ λ ) (3) \alpha_i(t)=P( o_1,o_2,...,o_t,x_t=i|\lambda) \tag{3} αi(t)=P(o1,o2,...,ot,xt=iλ)(3)
t = T t=T t=T时,根据式 ( 3 ) (3) (3) α i ( T ) = P ( o 1 , o 2 , . . . , o T , x T = i ∣ λ ) \alpha_i(T)=P( o_1,o_2,...,o_T,x_T=i|\lambda) αi(T)=P(o1,o2,...,oT,xT=iλ),则此时可求取 P ( O ∣ λ ) P(\mathbf{O}|\lambda ) P(Oλ)
P ( O ∣ λ ) = ∑ i = 1 n α i ( T ) (4) P(\mathbf{O}|\lambda )=\sum_{i=1}^{n} \alpha_i(T)\tag{4} P(Oλ)=i=1nαi(T)(4)
利用 α i ( 1 ) = P ( o 1 , x t = i ∣ λ ) = π i b i ( o 1 ) \alpha_i(1)=P( o_1,x_t=i|\lambda)=\pi_ib_i(o_1) αi(1)=P(o1,xt=iλ)=πibi(o1) α i ( t + 1 ) = ( ∑ j = 1 n α j ( t ) a j i ) b i ( o t + 1 ) \alpha_i(t+1)=(\sum_{j=1}^{n}\alpha_j(t)a_{ji})b_i(o_{t+1}) αi(t+1)=(j=1nαj(t)aji)bi(ot+1)可求取式 ( 4 ) (4) (4),复杂度减少为 O ( T n 2 ) O(Tn^2) O(Tn2)

与之类似,后向算法:
β i ( t ) = P ( o t + 1 , o t + 2 , . . . , o T ∣ x t = i , λ ) (5) \beta_i(t)=P( o_{t+1},o_{t+2},...,o_T|x_t=i,\lambda) \tag{5} βi(t)=P(ot+1,ot+2,...,oTxt=i,λ)(5)

训练(training)

已知观测序列 O = { o 1 , o 2 , . . . , o T } \mathbf{O} = \left \{ o_1,o_2,...,o_T \right \} O={o1,o2,...,oT},求解模型参数 ( π , A , B ) (\pi,\mathcal{A},\mathcal{B}) (π,A,B)使得 P ( O ∣ λ ) P(\mathbf{O}|\lambda ) P(Oλ)最大

EM算法:Baum-Welch算法

期望最大化(Exoectation maximization, EM)算法可以用于含有隐变量的统计模型的参数最大似然估计,其的核心思想是:

  1. 初始时随机地给模型的参数赋值λ0,该赋值遵循模型对参数的限制;
  2. 根据λ0求得模型中隐变量的期望值;
  3. 由该期望值又可以重新得到模型参数的新估计值λ1;
  4. 循环进行该过程,直到参数收敛于最大似然估计值。

Baum-Welch算法或前向后向算法是EM算法的一种具体实现。

给定HMM的参数 λ = ( π , A , B ) \lambda=(\pi,\mathcal{A},\mathcal{B}) λ=(π,A,B)及观测状态序列 O = { o 1 , o 2 , . . . , o T } \mathbf{O} = \left \{ o_1,o_2,...,o_T \right \} O={o1,o2,...,oT}

时间 t t t时,隐藏状态 x t = i x_t=i xt=i的概率为:
γ i ( t ) = P ( i t = q i ∣ O , λ ) = P ( i t = q i , O ∣ λ ) P ( O ∣ λ ) = α i ( t ) β i ( t ) ∑ j = 1 n α j ( t ) β j ( t ) (6) \gamma_i(t)=P(i_t=q_i|\mathbf{O},\lambda)=\frac{P(i_t=q_i,\mathbf{O}|\lambda)}{P(\mathbf{O}|\lambda)}=\frac{\alpha_i(t)\beta_i(t)}{\sum_{j=1}^n\alpha_j(t)\beta_j(t)}\tag{6} γi(t)=P(it=qiO,λ)=P(Oλ)P(it=qi,Oλ)=j=1nαj(t)βj(t)αi(t)βi(t)(6)

时间 t t t时隐藏状态 x t = i x_t=i xt=i t + 1 t+1 t+1时隐藏状态 x t + 1 = j x_{t+1}=j xt+1=j的概率为:
ξ i j ( t ) = P ( x t = i , x t + 1 = j ∣ O , λ ) = P ( x t = i , x t + 1 = j , O ∣ λ ) P ( O ∣ λ ) = α i ( t ) a i j b j ( o t + 1 ) β j ( t + 1 ) P ( O ∣ λ ) = α i ( t ) a i j b j ( o t + 1 ) β j ( t + 1 ) ∑ i = 1 n ∑ j = 1 n α i ( t ) a i j b j ( o t + 1 ) β j ( t + 1 ) (7) \xi_{ij}(t)=P(x_t=i,x_{t+1}=j|\mathbf{O},\lambda)\\=\frac{P(x_t=i,x_{t+1}=j,\mathbf{O}|\lambda)}{P(\mathbf{O}|\lambda)}\\=\frac{\alpha_i(t)a_{ij}b_j(o_{t+1})\beta_j(t+1)}{P(\mathbf{O}|\lambda)}\\=\frac{\alpha_i(t)a_{ij}b_j(o_{t+1})\beta_j(t+1)}{\sum^{n}_{i=1}\sum^{n}_{j=1}\alpha_i(t)a_{ij}b_j(o_{t+1})\beta_j(t+1)}\tag{7} ξij(t)=P(xt=i,xt+1=jO,λ)=P(Oλ)P(xt=i,xt+1=j,Oλ)=P(Oλ)αi(t)aijbj(ot+1)βj(t+1)=i=1nj=1nαi(t)aijbj(ot+1)βj(t+1)αi(t)aijbj(ot+1)βj(t+1)(7)
根据式 ( 6 ) 、 ( 7 ) (6)、(7) (6)(7)可得参数估计:
{ π i ^ = γ i ( 1 ) a i j ^ = ∑ t = 1 T − 1 ξ i j ( t ) ∑ t = 1 T − 1 γ i ( t ) b j ( k ) ^ = ∑ t = 1 , o t = k T γ i ( t ) ∑ t = 1 T γ i ( t ) (8) {\LARGE \left\{\begin{matrix} \hat{\pi_i}=\gamma_i(1)\\ \hat{a_{ij}}=\frac{\sum^{T-1}_{t=1}\xi_{ij}(t)}{\sum^{T-1}_{t=1}\gamma_i(t)}\\ \hat{b_j(k)}=\frac{\sum^{T}_{t=1,o_t=k}\gamma_i(t)}{\sum^{T}_{t=1}\gamma_i(t)} \end{matrix}\right. \tag{8}} πi^=γi(1)aij^=t=1T1γi(t)t=1T1ξij(t)bj(k)^=t=1Tγi(t)t=1,ot=kTγi(t)(8)

解码(decodin)

已知模型 λ = ( π , A , B ) \lambda =(\pi,\mathcal{A},\mathcal{B}) λ=(π,A,B)及观测序列 O = { o 1 , o 2 , . . . , o T } \mathbf{O} = \left \{ o_1,o_2,...,o_T \right \} O={o1,o2,...,oT},求取最有可能的状态序列 X = { x 1 , x 2 , . . . , x T } \mathbf{X} = \left \{ x_1,x_2,...,x_T \right \} X={x1,x2,...,xT},即使 P ( X ∣ O , λ ) P(\mathbf{X}|\mathbf{O},\lambda) P(XO,λ)最大

Viterbi算法

对于时刻 t t t,隐藏状态 x t = i x_t=i xt=i,所有可能的情况中概率最大路径:
δ t ( i ) = max ⁡ x 1 , x 2 , . . . , x t − 1 P ( x t = i , x t − 1 , . . . , x 1 , o t , . . . , o 1 ∣ λ ) (9) \delta_t(i)=\max_{x_1,x_2,...,x_{t-1}}P(x_t=i,x_{t-1},...,x_1,o_t,...,o_1|\lambda)\tag{9} δt(i)=x1,x2,...,xt1maxP(xt=i,xt1,...,x1,ot,...,o1λ)(9)
由此可知:
δ t + 1 ( i ) = max ⁡ x 1 , x 2 , . . . , x t P ( x t + 1 = i , x t , . . . , x 1 , o t + 1 , . . . , o 1 ∣ λ ) = max ⁡ 1 ≤ j ≤ N [ δ t ( j ) a j i ] b i ( o t + 1 ) (10) \delta_{t+1}(i)=\max_{x_1,x_2,...,x_{t}}P(x_{t+1}=i,x_{t},...,x_1,o_{t+1},...,o_1|\lambda)\\ =\max_{1\le j\le N}[\delta_t(j)a_{ji}]b_i(o_{t+1})\tag{10} δt+1(i)=x1,x2,...,xtmaxP(xt+1=i,xt,...,x1,ot+1,...,o1λ)=1jNmax[δt(j)aji]bi(ot+1)(10)
概率最大的路径中 t − 1 t-1 t1时刻的隐藏状态:
Ψ t ( i ) = arg ⁡ max ⁡ 1 ≤ j ≤ n [ δ t − 1 ( j ) a j i ] (11) \Psi _t(i)=\arg \max _{1\le j\le n }[\delta_{t-1}(j)a_{ji}]\tag{11} Ψt(i)=arg1jnmax[δt1(j)aji](11)

  1. 根据式 ( 10 ) (10) (10)计算 T T T时刻所有隐藏状态对应的值,若 δ T ( i ) \delta_T(i) δT(i)为其中最大的一项,则 x T = i x_T=i xT=i
  2. T − 1 T-1 T1时刻隐藏状态 x T − 1 = Ψ T ( i ) = k x_{T-1}=\Psi _T(i)=k xT1=ΨT(i)=k T − 2 T-2 T2时刻时刻隐藏状态 x T − 2 = Ψ T − 1 ( k ) x_{T-2}=\Psi _{T-1}(k) xT2=ΨT1(k),以此类推。

算法实现

创建一个隐马尔科夫模型的类:

class HMM:
    """
    状态取值有N个,观测序列取值有M个
    """
    def __init__(self, A: np.ndarray, B: np.ndarray, pi):
        self.A = A  # 状态转移概率矩阵 [N, N]
        self.B = B  # 输出观测概率矩阵 [N, M]
        self.pi = pi  # 初设状态概率向量 [N]

        self.N = len(pi)
        self.M = self.A.shape[1]

        self.map_i = {}  # 存储状态取值对应的编码, key为编码,value为状态值
        self.map_o = {}  # 存储观测值对应的编码, key为观测值,value为编码

前向概率计算:

def forward(self, t, i, O):
    """
        前向算法
        :param t: 时刻t,以0为起点
        :param i: 状态值,[0, 1, ...., N-1]
        :param O: 观测序列
        :return:
        """
    if t == 0:
        return self.pi[i] * self.B[i][O[t]]

    return self.B[i][O[t]] * sum([self.forward(t - 1, j, O) * self.A[j][i] for j in range(self.N)])

后向概率计算:

def backward(self, t, i, O):
    """
        后向算法
        :param t: 时刻t,以0为起点
        :param i: 状态值,[0, 1, ...., N-1]
        :param O: 观测序列
        :return:
        """
    if t == len(O) - 1:
        return 1

    return sum([self.A[i][j] * self.B[j][O[t+1]] * self.backward(t+1, j, O) for j in range(self.N)])

前向后向算法
计算期望:

def gamma(self, t, i, O):
    """
    根据已知隐马尔科夫模型的参数和观测序列O,时刻t处于状态i的概率
    :param t: 时刻t,以0为起点
    :param i: 状态值,[0, 1, ...., N-1]
    :param O: 观测序列
    :return:
    """
    molecule = self.forward(t, i, O) * self.backward(t, i, O)
    denominator = sum([self.forward(t, j, O) * self.backward(t, j, O)] for j in range(self.N))
    return molecule / denominator

def xi(self, t, i, j, O):
    """
    根据已知隐马尔科夫模型的参数和观测序列O,时刻t处于状态i且时刻t+1处于状态j的概率
    :param t: 时刻t,以0为起点
    :param i: 状态值,[0, 1, ...., N-1]
    :param O: 观测序列
    :return:
    """
    molecule = self.forward(t, i, O) * self.A[i][j] * self.B[j][O[t+1]] * self.backward(t+1, j, O)
    denominator = 0
    for n in range(self.N):
        for m in range(self.N):
            denominator += self.forward(t, n, O) * self.A[n][m] * self.B[m][O[t+1]] * self.backward(t+1, m, O)

    return molecule / denominator

参数更新:

def train(self, O):
    """
    根据隐马尔科夫模型参数的估计值,极大化模型参数
    :param O:
    :return:
    """
    pi = self.pi.copy()
    A = self.A.copy()
    B = self.B.copy()

    for i in range(self.N):
        pi[i] = self.gamma(0, i, O)

        # 根据公式计算a(i,j)
        for j in range(self.N):
            A[i][j] = sum([self.xi(t, i, j, O) for t in range(len(O)-1)]
                          ) / sum([self.gamma(t, i, O) for t in range(len(O)-1)])

        # 根据公式计算b_i(k)
        B_denominator = sum([self.gamma(t, i, O) for t in range(len(O))])  # 公式中的分母
        # 求得观测序列的所有不同的取值,和对应的所有时刻。
        # 比如观测序列(1, 2, 1),第一个和最后一个时刻的取值为1,第二个时刻的取值为2
        Map = {}
        for t in range(len(O)):
            if O[t] in Map.keys():
                Map[O[t]].append(t)
            else:
                Map[O[t]] = [t]
        # 这里k对应观测序列中的一个不同的值
        for k, tl in Map.items():
            B[i][k] = sum([self.gamma(t, i, O) for t in tl]) / B_denominator

    # 更新模型参数
    self.pi = pi
    self.A = A
    self.B = B
   
def run(self, train_nums, O):
    """
    对训练样本进行训练
    :param train_nums: 训练轮数
    :param O: 所有训练样本,二维数组
    :return:
    """
    for i in range(train_nums):
        for o in O:
            # 将观测文本值映射为对应编码
            o = [self.map_o[m] for m in o]
            self.train(o)  # 对一个观测序列训练,进行参数更新

维特比算法

def viterbi(self, O):
    """
    维特比编码求最优路径
    :param O:
    :return:
    """
    pro = np.ones([len(O), self.N])  # 记录累计概率
    backpointers = np.ones([len(O), self.N], dtype=np.int32)  # 记录最优路径

    # 计算时刻t=1,各个状态下观测序列为o_1的概率
    pro[0] = [self.pi[i] * self.B[i][O[0]] for i in range(self.N)]
    # 时刻t=2,3,....,
    for t in range(1, len(O)):
        b = [self.B[i][O[t]] for i in range(self.N)]  # 计算各个状态下观测序列为o_t的概率
        v = np.expand_dims(pro[t - 1], 1) * self.A  # 计算前一个时刻状态为j,当前时刻状态为i的概率矩阵
        pro[t] = np.max(v, 0) * b  # 当前状态为i的最大概率 * 对应状态下观测序列为o_t的概率
        backpointers[t] = np.argmax(v, 0)  # 记录,当前状态为i的概率最大时,上个时刻的状态

    # 开始回溯
    viterbi = [np.argmax(pro[-1])]  # 最终累计概率最大时,最后一个时刻的状态
    # 根据当前状态从最优路径中挑选上个时刻的状态
    for bp in reversed(backpointers[1:]):
        viterbi.append(bp[viterbi[-1]])
    viterbi.reverse()

    # 将状态编码转化为对应的状态值
    viterbi = [self.map_i[v] for v in viterbi]

    viterbi_score = np.max(pro[-1])  # 最高的累计概率
    return viterbi, viterbi_score

应用举例

拼音输入/语音识别

在这里插入图片描述

  • 输入法把拼音看做是观察状态,需要得到的汉字为隐藏状态,这样,输入法的整句解码就变成了维特比解码,其转移概率即是二元语言模型,其输出概率即是多音字对应不同拼音的概率。
  • 将上图中的拼音换成语音,就成了语音识别问题,转移概率仍然是二元语言模型,其输出概率则是语音模型,即语音和汉字的对应模型。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值