隐马尔科夫模型 (HMM) 算法介绍及代码实现

HMM 基本问题的公式推导及 Java 实现(二) 后向概率公式及推导过程 1.后向概率定义 给定 λ,定义到时刻 t ,部分观测序列为 q1,q2,…,qt 且状态为 si 的概率为前向概率。 记作: αt(i) = P(q1,q2,…qt,st=si | λ)。 2.后向概率的初始条件 根据定义,第一个时刻的前向概率是 α1(i)=P(q1,s1=si| λ) ,给定观察模型下,第一个时刻的状态为 Si 且观测结果为 q1 。这个值很容易用 H... 阅读详情

Table of Contents

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

Back to TOC

两种问题特征:

  • 基于序列的,比如时间序列,或者状态序列
  • 两类数据,一类序列数据是可以观测到的,即观测序列;而另一类数据是不能观察到的,即隐藏状态序列,简称状态序列

定义

Back to TOC

假设 N N N是可能的隐藏状态数, M M M是可能的观测状态数,定义
Q = { q 1 , q 2 , … , q N } , V = { v 1 , v 2 , … , v M } \mathcal{Q}=\{q_1,q_2,\dots,q_N\},\mathcal{V}=\{v_1,v_2,\dots,v_M\} Q={q1​,q2​,…,qN​},V={v1​,v2​,…,vM​}
分别为所有可能的隐藏状态和所有可能的观测状态的集合
同时,对于一个长度为 T T T的序列 I I I,和对应的观测序列 O O O
I = { s 1 , s 2 , … , s T } , O = { o 1 , o 2 , … , o T } \mathcal{I}=\{s_1,s_2,\dots,s_T\},\mathcal{O}=\{o_1,o_2,\dots,o_T\} I={s1​,s2​,…,sT​},O={o1​,o2​,…,oT​}
HMM做了两个很重要的假设:

  • 齐次马尔科夫链假设。任意时刻隐藏状态只依赖于它前一个隐藏状态
    定义状态转移概率 A i j A_{ij} Aij​为从当前时刻 t t t的状态 s i s_i si​转移到下一时刻 t + 1 t+1 t+1的状态 s j s_j sj​的概率,即
    A i j = P ( s t + 1 = q j ∣ s t = q i ) A_{ij}=P(s_{t+1}=q_j|s_t=q_i) Aij​=P(st+1​=qj​∣st​=qi​)
    从而定义状态转移矩阵 A ∈ R N × N A\in \mathbb{R}^{N\times N} A∈RN×N
  • 观测独立性假设即任意时刻的观测状态只仅仅依赖于当前时刻的隐藏状态。定义生成概率 B i j B_{ij} Bij​为由隐藏状态 s i s_i si​生成观测状态 q j q_j qj​的概率,即
    B i j = P ( o t = v i ∣ s t = q j ) B_{ij}=P(o_t=v_i|s_t=q_j) Bij​=P(ot​=vi​∣st​=qj​)
    从而定义生成概率矩阵(发射矩阵) B ∈ R N × M B\in \mathbb{R}^{N\times M} B∈RN×M
    最后,定义在 t t t时刻的隐藏状态分布 Π t = [ π t ( k ) ] \Pi_t=[\pi_t (k)] Πt​=[πt​(k)],其中 π t ( k ) = P ( s t = q k ) \pi_t (k)=P(s_t=q_k) πt​(k)=P(st​=qk​)
    因此一个HMM模型主要由三个参数表示:
    λ = ( A , B , Π ) \lambda=(A,B,\Pi) λ=(A,B,Π)

基本问题

Back to TOC

    1. 评估观察序列概率。给定模型 λ \lambda λ和观测序列 O \mathcal{O} O,计算在模型 λ \lambda λ下该观测序列 O \mathcal{O} O出现的概率 P ( O ∣ λ ) P(\mathcal{O}|\lambda) P(O∣λ)。求解方法:前向后向算法
    1. 预测问题。给定观测序列 O = { o 1 , o 2 , … , o T } \mathcal{O}=\{o_1,o_2,\dots,o_T\} O={o1​,o2​,…,oT​}和模型参数 λ = ( A , B , Π ) \lambda=(A,B,\Pi) λ=(A,B,Π),求解最有可能出现的隐藏状态序列。求解方法:Viterbi算法
    1. 模型参数学习问题。给定观测序列 O = { o 1 , o 2 , … , o T } \mathcal{O}=\{o_1,o_2,\dots,o_T\} O={o1​,o2​,…,oT​},求解模型参数 λ = ( A , B , Π ) \lambda=(A,B,\Pi) λ=(A,B,Π)使得 P ( O ∣ λ ) P(\mathcal{O}|\lambda) P(O∣λ)最大。求解方法:Baum-Walch算法(EM算法)

前向算法

Back to TOC
在这里插入图片描述

算法流程

输入:观测序列 O = { o 1 , o 2 , … , o T } \mathcal{O}=\{o_1,o_2,\dots,o_T\} O={o1​,o2​,…,oT​},模型参数 λ = ( A , B , Π ) \lambda=(A,B,\Pi) λ=(A,B,Π)
输出:观测序列 P ( O ∣ λ ) P(O|\lambda) P(O∣λ)
步骤:

  • 计算时刻1各个隐藏状态 s i s_i si​的前向概率
    α 1 ( i ) = π ( i ) B i , o 1 , i = 1 , 2 , … , N \alpha_1(i)=\pi(i)B_{i,o_1},i=1,2,\dots,N α1​(i)=π(i)Bi,o1​​,i=1,2,…,N
  • 递推 2 , 3 , … , T 2,3,\dots,T 2,3,…,T时刻的前向概率
    α t + 1 ( i ) = [ ∑ j = 1 N α t ( j ) A j i ] B i , o t + 1 , i = 1 , 2 , … , N \alpha_{t+1}(i)=[\sum_{j=1}^{N}\alpha_{t}(j)A_{ji}]B_{i,o_{t+1}},i=1,2,\dots,N αt+1​(i)=[j=1∑N​αt​(j)Aji​]Bi,ot+1​​,i=1,2,…,N
  • 最终结果
    P ( O ∣ λ ) = ∑ i N α T ( i ) P(\mathcal{O}|\lambda)=\sum_i^N\alpha_T(i) P(O∣λ)=i∑N​αT​(i)

实现代码

def HMMfwd(pi, a, b, obs):
    '''
    pi:初始概率分布
    a:状态转移矩阵
    b:发射矩阵
    obs:观测序列
    '''

    nStates = np.shape(b)[0]
    T = np.shape(obs)[0]

    alpha = np.zeros((nStates,T))
    '''alpha[i,t]表示上述公式的 alpha_t(i)'''
    alpha[:,0] = pi*b[:,obs[0]]

    for t in range(1,T):
        for s in range(nStates):
            alpha[s,t] = b[s,obs[t]] * np.sum(alpha[:,t-1] * a[:,s])

    return alpha

最后计算 P ( O ∣ λ ) P(\mathcal{O}|\lambda) P(O∣λ)

np.sum(alpha[:,-1])

后向算法

Back to TOC
在这里插入图片描述

算法流程

输入:观测序列 O = { o 1 , o 2 , … , o T } \mathcal{O}=\{o_1,o_2,\dots,o_T\} O={o1​,o2​,…,oT​},模型参数 λ = ( A , B , Π ) \lambda=(A,B,\Pi) λ=(A,B,Π)
输出:观测序列 P ( O ∣ λ ) P(O|\lambda) P(O∣λ)
步骤:

  • 初始化时刻 T T T各个隐藏状态 s i s_i si​的前向概率
    β T ( i ) = 1 , i = 1 , 2 , … , N \beta_T(i)=1, i=1,2,\dots,N βT​(i)=1,i=1,2,…,N
  • 递推 T − 1 , T − 2 , … , 1 T-1,T-2,\dots,1 T−1,T−2,…,1时刻的后向概率
    β t ( i ) = ∑ i = 1 N A i j B j , o t + 1 β t + 1 ( j ) , i = 1 , 2 , … , N \beta_{t}(i)=\sum_{i=1}^{N}A_{ij}B_{j,o_{t+1}}\beta_{t+1}(j),i=1,2,\dots,N βt​(i)=i=1∑N​Aij​Bj,ot+1​​βt+1​(j),i=1,2,…,N
  • 最终结果
    P ( O ∣ λ ) = ∑ i N π i B i , o 1 β 1 ( i ) P(\mathcal{O}|\lambda)=\sum_i^N\pi_iB_{i,o_1}\beta_1(i) P(O∣λ)=i∑N​πi​Bi,o1​​β1​(i)

实现代码

def HMMbwd(a, b, obs):
    '''
    a:状态转移矩阵
    b:发射矩阵
    obs:观测序列
    '''

    nStates = np.shape(b)[0]
    T = np.shape(obs)[0]
    '''beta[i,t]表示上述公式的 beta_t(i)'''
    beta = np.zeros((nStates,T))

    beta[:,-1] = 1.0 

    for t in range(T-2,-1,-1):
        for s in range(nStates):
            beta[s,t] = np.sum(a[s,:] * b[:,obs[t+1]] * beta[:,t+1] )

    return beta

最后计算 P ( O ∣ λ ) P(\mathcal{O}|\lambda) P(O∣λ)

np.sum(pi*b[:,obs[0]]*beta[:,0])

Viterbi算法

Back to TOC

算法流程

输入:观测序列 O = { o 1 , o 2 , … , o T } \mathcal{O}=\{o_1,o_2,\dots,o_T\} O={o1​,o2​,…,oT​},模型参数 λ = ( A , B , Π ) \lambda=(A,B,\Pi) λ=(A,B,Π)
输出:最有可能的有隐状态序列 I ∗ = { i 1 ∗ , i 2 ∗ , … , i T ∗ } \mathcal{I}^*=\{i^{*}_1,i^{*}_2,\dots,i^{*}_T\} I∗={i1∗​,i2∗​,…,iT∗​}
步骤:

  • 初始化局部状态
    δ 1 ( i ) = π i B i , o 1 , Φ 1 ( i ) = 0 , i = 1 , 2 , … , N \delta_1(i)=\pi_iB_{i,o_1},\quad \Phi_1(i)=0,\quad i=1,2,\dots,N δ1​(i)=πi​Bi,o1​​,Φ1​(i)=0,i=1,2,…,N
  • 进行动态规划递推时刻 t = 2 , 3 , … , T t=2,3,\dots,T t=2,3,…,T的局部状态
    δ t ( i ) = max ⁡ 1 ≤ j ≤ N [ δ t − 1 ( j ) A j , i ] B i , o t , i = 1 , 2 , … , N Φ t ( i ) = arg ⁡ max ⁡ 1 ≤ j ≤ N [ δ t − 1 ( j ) A j , i ] , i = 1 , 2 , … , N \begin{array}{c} {\delta_t(i)=\max_{1\leq j\leq N}[\delta_{t-1}(j)A_{j,i}]B_{i,o_t},\quad i=1,2,\dots,N} \\ \\ {\Phi_t(i)=\arg \max_{1\leq j\leq N}[\delta_{t-1}(j)A_{j,i}],\quad i=1,2,\dots,N} \end{array} δt​(i)=max1≤j≤N​[δt−1​(j)Aj,i​]Bi,ot​​,i=1,2,…,NΦt​(i)=argmax1≤j≤N​[δt−1​(j)Aj,i​],i=1,2,…,N​
  • 计算时刻 T T T最大的 δ T ( i ) \delta_T(i) δT​(i)即为最可能隐藏状态序列出现的概率,计算时刻 T T T最大的 Φ T ( i ) \Phi_T(i) ΦT​(i),即为最可能的隐藏状态
    i T ∗ = arg ⁡ max ⁡ 1 ≤ j ≤ N δ T ( i ) i^*_T=\arg \max_{1\leq j\leq N}\delta_{T}(i) iT∗​=arg1≤j≤Nmax​δT​(i)
  • 利用局部状态 Φ ( i ) \Phi(i) Φ(i)开始回溯,对于时刻 t = T − 1 , T − 2 , … , 1 t=T-1,T-2,\dots,1 t=T−1,T−2,…,1:
    i t ∗ = Φ t + 1 ( i t + 1 ∗ ) i^*_t=\Phi_{t+1}(i^*_{t+1}) it∗​=Φt+1​(it+1∗​)
  • 最终得到最有可能的隐藏状态序列 I ∗ = { i 1 ∗ , i 2 ∗ , … , i T ∗ } \mathcal{I}^*=\{i^{*}_1,i^{*}_2,\dots,i^{*}_T\} I∗={i1∗​,i2∗​,…,iT∗​}

实现代码

def Viterbi(pi, a, b, obs):
    '''
    pi:初始概率分布
    a:状态转移矩阵
    b:发射矩阵
    obs:观测序列
    '''

     nStates = np.shape(b)[0]
    T = np.shape(obs)[0]

    path = np.zeros(T, dtype=np.int32)
    delta = np.zeros((nStates,T))
    phi = np.zeros((nStates,T))

    delta[:,0] = pi * b[:,obs[0]]
    phi[:,0] = 0

    for t in range(1,T):
        for s in range(nStates):
            delta[s,t] = np.max(delta[:,t-1]*a[:,s])*b[s,obs[t]]
            phi[s,t] = np.argmax(delta[:,t-1]*a[:,s])

    path[-1] = np.argmax(delta[:,-1])
    for t in range(T-2,-1,-1):
        path[t] = phi[path[t+1],t+1]

    return path

最后解码得到的序列即为path

Baum-Welch 算法

Back to TOC

单观测序列

输入: 1 1 1个观测序列样本 O = { o 1 , o 2 , … , o T } \mathcal{O}=\{o_1,o_2,\dots,o_T\} O={o1​,o2​,…,oT​}
输出:模型参数 λ = ( A , B , Π ) \lambda=(A,B,\Pi) λ=(A,B,Π)
步骤:

  • 随机初始化或手动初始化 A , B , Π A,B,\Pi A,B,Π
  • E 步,求解两个中间变量 γ t ( i ) , ξ t ( i , j ) \gamma_{t}(i), \xi_{t}(i, j) γt​(i),ξt​(i,j),两者含义如下
    • γ t ( i ) \gamma_{t}(i) γt​(i):给定模型 λ \lambda λ和观测序列 O \mathcal{O} O,在时刻 t t t的隐含状态为 q i q_i qi​的概率,即 γ t ( i ) = P ( s t = q i ∣ O , λ ) \gamma_{t}(i)=P(s_{t}=q_{i} | O, \lambda) γt​(i)=P(st​=qi​∣O,λ)
    • ξ t ( i , j ) \xi_{t}(i, j) ξt​(i,j):给定模型 λ \lambda λ和观测序列 O \mathcal{O} O,在时刻 t t t的隐含状态为 q i q_i qi​,时刻 t + 1 t+1 t+1的隐含状态为 q j q_j qj​的概率,即 ξ t ( i , j ) = P ( s t = q i , s t + 1 = q j ∣ O , λ ) \xi_{t}(i, j)=P(s_{t}=q_{i}, s_{t+1}=q_{j} | O, \lambda) ξt​(i,j)=P(st​=qi​,st+1​=qj​∣O,λ)
      结合前面的前向概率和后向概率的定义,计算这两个中间变量的公式如下:
      γ t ( i ) = α t ( i ) β t ( i ) ∑ j = 1 N α t ( j ) β t ( j ) ξ t ( i , j ) = α t ( i ) A i j B j , o t + 1 β t + 1 ( j ) ∑ p = 1 N ∑ q = 1 N α t ( p ) A p q B q , o t + 1 β t + 1 ( q ) \begin{array}{c}{\gamma_{t}(i)=\frac{\alpha_{t}(i) \beta_{t}(i)}{\sum_{j=1}^{N} \alpha_{t}(j) \beta_{t}(j)}} \\ \\ {\xi_{t}(i, j)=\frac{\alpha_{t}(i) A_{i j} B_{j,o_{t+1}} \beta_{t+1}(j)}{\sum_{p=1}^{N} \sum_{q=1}^{N} \alpha_{t}(p) A_{pq} B_{q,o_{t+1}} \beta_{t+1}(q)}}\end{array} γt​(i)=∑j=1N​αt​(j)βt​(j)αt​(i)βt​(i)​ξt​(i,j)=∑p=1N​∑q=1N​αt​(p)Apq​Bq,ot+1​​βt+1​(q)αt​(i)Aij​Bj,ot+1​​βt+1​(j)​​
  • M 步,通过 E 步求解出的两个中间变量来求解模型参数,求解公式如下:
    A i j = ∑ t = 1 T − 1 ξ t ( i , j ) ∑ t = 1 T − 1 γ t ( i ) B i j = ∑ t = 1 T γ t ( i ) I ( o t = v j ) ∑ t = 1 T γ t ( i ) π i = γ 1 ( i ) \begin{array}{c} {A_{i j}=\frac{\sum_{t=1}^{T-1} \xi_{t}(i, j)}{\sum_{t=1}^{T-1} \gamma_{t}(i)}} \\ \\ {B_{ij}=\frac{\sum_{t=1}^{T} \gamma_{t}(i) I\left(o_{t}=v_{j}\right)}{\sum_{t=1}^{T} \gamma_{t}(i)}} \\ \\ {\pi_{i}=\gamma_{1}(i)} \end{array} Aij​=∑t=1T−1​γt​(i)∑t=1T−1​ξt​(i,j)​Bij​=∑t=1T​γt​(i)∑t=1T​γt​(i)I(ot​=vj​)​πi​=γ1​(i)​
    上式中的 I ( o t = v j ) I(o_{t}=v_{j}) I(ot​=vj​)表示当时刻 t t t观测状态为 v k v_k vk​ 时, I ( o t = v j ) = 1 I(o_{t}=v_{j})=1 I(ot​=vj​)=1,否则 I ( o t = v j ) = 0 I(o_{t} = v_{j})=0 I(ot​=vj​)=0

多观测序列

输入: D D D个观测序列样本 { O 1 , O 2 , … , O D } \{\mathcal{O}_1,\mathcal{O}_2,\dots,\mathcal{O}_D\} {O1​,O2​,…,OD​},其中 O d = { o 1 , o 2 , … , o T } , d = 1 , 2 , … , D \mathcal{O}_d=\{o_1,o_2,\dots,o_T\},d=1,2,\dots,D Od​={o1​,o2​,…,oT​},d=1,2,…,D
输出:模型参数 λ = ( A , B , Π ) \lambda =(A,B,\Pi) λ=(A,B,Π)
步骤:

  • 随机初始化或手动初始化 A , B , Π A,B,\Pi A,B,Π
  • E 步,为每个序列求解两个中间变量 γ t ( d ) ( i ) , ξ t ( d ) ( i , j ) \gamma^{(d)}_{t}(i), \xi^{(d)}_{t}(i, j) γt(d)​(i),ξt(d)​(i,j)
    类似单观测序列,只不过每个序列各自用前向后向算法求出各自的 α ( d ) \alpha^{(d)} α(d)和 β ( d ) \beta^{(d)} β(d),求解公式如下:
    γ t ( d ) ( i ) = α t ( d ) ( i ) β t ( d ) ( i ) ∑ j = 1 N α t ( d ) ( j ) β t ( d ) ( j ) ξ t ( d ) ( i , j ) = α t ( d ) ( i ) A i j B j , o t + 1 β t + 1 ( d ) ( j ) ∑ p = 1 N ∑ q = 1 N α t ( d ) ( p ) A p q B q , o t + 1 β t + 1 ( d ) ( q ) \begin{array}{c}{\gamma^{(d)}_{t}(i)=\frac{\alpha^{(d)}_{t}(i) \beta^{(d)}_{t}(i)}{\sum_{j=1}^{N} \alpha^{(d)}_{t}(j) \beta^{(d)}_{t}(j)}} \\ \\ {\xi^{(d)}_{t}(i, j)=\frac{\alpha^{(d)}_{t}(i) A_{i j} B_{j,o_{t+1}} \beta^{(d)}_{t+1}(j)}{\sum_{p=1}^{N} \sum_{q=1}^{N} \alpha^{(d)}_{t}(p) A_{pq} B_{q,o_{t+1}} \beta^{(d)}_{t+1}(q)}}\end{array} γt(d)​(i)=∑j=1N​αt(d)​(j)βt(d)​(j)αt(d)​(i)βt(d)​(i)​ξt(d)​(i,j)=∑p=1N​∑q=1N​αt(d)​(p)Apq​Bq,ot+1​​βt+1(d)​(q)αt(d)​(i)Aij​Bj,ot+1​​βt+1(d)​(j)​​
  • M 步,通过 E 步求解出的两个中间变量来求解模型参数,同样类似单观测序列,只不过更新参数时需要考虑所有序列(即外层加上一个求和复方蒿),求解公式如下:
    A i j = ∑ d = 1 D ∑ t = 1 T − 1 ξ t ( d ) ( i , j ) ∑ d = 1 D ∑ t = 1 T − 1 γ t ( d ) ( i ) B i j = ∑ d = 1 D ∑ t = 1 T γ t ( d ) ( i ) I ( o t = v j ) ∑ d = 1 D ∑ t = 1 T γ t ( d ) ( i ) π i = ∑ d = 1 D γ 1 ( d ) ( i ) D \begin{array}{c} {A_{i j}=\frac{\sum_{d=1}^D \sum_{t=1}^{T-1} \xi^{(d)}_{t}(i, j)}{\sum_{d=1}^D \sum_{t=1}^{T-1} \gamma^{(d)}_{t}(i)}} \\ \\ {B_{ij}=\frac{\sum_{d=1}^D \sum_{t=1}^{T} \gamma^{(d)}_{t}(i) I\left(o_{t}=v_{j}\right)}{\sum_{d=1}^D \sum_{t=1}^{T} \gamma^{(d)}_{t}(i)}} \\ \\ {\pi_{i}=\frac{\sum_{d=1}^D \gamma^{(d)}_{1}(i)}{D}} \end{array} Aij​=∑d=1D​∑t=1T−1​γt(d)​(i)∑d=1D​∑t=1T−1​ξt(d)​(i,j)​Bij​=∑d=1D​∑t=1T​γt(d)​(i)∑d=1D​∑t=1T​γt(d)​(i)I(ot​=vj​)​πi​=D∑d=1D​γ1(d)​(i)​​
    同样的,上式中的 I ( o t = v j ) I(o_{t}=v_{j}) I(ot​=vj​)表示当时刻 t t t观测状态为 v k v_k vk​ 时, I ( o t = v j ) = 1 I(o_{t}=v_{j})=1 I(ot​=vj​)=1,否则 I ( o t = v j ) = 0 I(o_{t} = v_{j})=0 I(ot​=vj​)=0

实现代码(单观测序列)

def BaumWelch(obs, n_states, n_obs, pi=None, a=None, b=None, tol=1e-2, n_iter=10):
    T = np.shape(obs)[0]
    # initialize
    if not pi:
        pi = np.ones((n_states))/n_states
    if not a:
        a = np.random.rand(n_states, n_states)
    if not b:
        b = np.random.rand(n_states, n_obs)
    xi = np.zeros((n_states, n_states, T))
    
    nits = 0
    while True:
        nits += 1
        old_a = a.copy()
        old_b = b.copy()
        alpha = HMMfwd(pi, a, b, obs)
        beta = HMMbwd(a, b, obs)
        gamma = alpha*beta
        gamma /= gamma.sum(0)
        
        # E-step
        for t in range(T-1):
            for i in range(n_states):
                for j in range(n_states):
                    xi[i, j, t] = alpha[i,t]*beta[j,t+1]*a[i,j]*b[j,obs[t+1]]
            xi[:,:,t] /= xi[:,:,t].sum()
            
        # The last step has no b, beta in
        for i in range(n_states):
            for j in range(n_states):
                xi[i,j,-1] = alpha[i,-1]*a[i,j]
        xi[:,:,-1] /= xi[:,:,-1].sum()
        
        # M-step
        for i in range(n_states):
            for j in range(n_states):
                a[i,j] = xi[i,j,:-1].sum()/gamma[i,:-1].sum()
                
        a /= a.sum(1, keepdims=True)
        
        for i in range(n_states):
            for j in range(n_obs):
                found = (obs==j).nonzero()[0]
                b[i,j] = gamma[i,found].sum()/gamma[i].sum()
                
        b /= b.sum(1, keepdims=True)
        
        pi = gamma[:, 0]

        if np.linalg.norm(a - old_a) < tol and np.linalg.norm(b - old_b)< tol or nits > n_iter:
            break
            
    return pi, a, b

符号总结

Back to TOC

符号解释符号解释
N N N可能的隐藏状态数 M M M可能的观测状态数
Q = { q 1 , q 2 , … , q N } \mathcal{Q}=\{q_1,q_2,\dots,q_N\} Q={q1​,q2​,…,qN​}所有可能的隐藏状态集合 V = { v 1 , v 2 , … , v M } \mathcal{V}=\{v_1,v_2,\dots,v_M\} V={v1​,v2​,…,vM​}所有可能的观测状态的集合
I = { s 1 , s 2 , … , s T } \mathcal{I}=\{s_1,s_2,\dots,s_T\} I={s1​,s2​,…,sT​}真实隐藏状态 O = { o 1 , o 2 , … , o T } \mathcal{O}=\{o_1,o_2,\dots,o_T\} O={o1​,o2​,…,oT​}真实观测序列
A i j A_{ij} Aij​从当前时刻 t t t的状态 s i s_i si​转移到下一时刻 t + 1 t+1 t+1的状态 s j s_j sj​的概率 B i j B_{ij} Bij​由隐藏状态 s i s_i si​生成观测状态 q j q_j qj​的概率
Π t = [ π t ( k ) ] \Pi_t=[\pi_t (k)] Πt​=[πt​(k)] π t ( k ) = P ( s t = q k ) \pi_t (k)=P(s_t=q_k) πt​(k)=P(st​=qk​)代表 t t t时刻的隐藏状态为 q k q_k qk​的概率,一般忽略时刻 t t t简写为 π k \pi_k πk​ λ \lambda λ λ = ( A , B , Π ) \lambda=(A,B,\Pi) λ=(A,B,Π)为模型参数
δ t ( i ) \delta_t(i) δt​(i)表示 t t t时刻隐状态的取值 s t = q i s_t=q_i st​=qi​,观测状态为 o t o_t ot​的最大概率 Φ t ( i ) \Phi_t(i) Φt​(i)表示 t t t时刻隐藏状态为 q i q_i qi​,观测状态为 o t o_t ot​的最大概率,是由上一时刻哪一个隐藏状态转移而来的
α t ( i ) \alpha_t(i) αt​(i) t t t时刻隐藏状态为 q i q_i qi​且 1 1 1时刻到 t t t时刻的观测序列为 o 1 , o 2 , … , o t o_{1},o_{2},\dots,o_{t} o1​,o2​,…,ot​的前向概率 β t ( i ) \beta_t(i) βt​(i) t t t时刻隐藏状态为 q i q_i qi​且 t + 1 t+1 t+1时刻到 T T T时刻的观测序列为 o t + 1 , o t + 2 , … , o T o_{t+1},o_{t+2},\dots,o_{T} ot+1​,ot+2​,…,oT​的后向概率
γ t ( i ) \gamma_{t}(i) γt​(i)给定模型 λ \lambda λ和观测序列 O \mathcal{O} O,在时刻 t t t的隐含状态为 q i q_i qi​的概率,即 γ t ( i ) = P ( s t = q i ∥ O , λ ) \gamma_{t}(i)=P(s_{t}=q_{i} \| O, \lambda) γt​(i)=P(st​=qi​∥O,λ) ξ t ( i , j ) \xi_{t}(i, j) ξt​(i,j)给定模型 λ \lambda λ和观测序列 O \mathcal{O} O,在时刻 t t t的隐含状态为 q i q_i qi​,时刻 t + 1 t+1 t+1的隐含状态为 q j q_j qj​的概率,即 ξ t ( i , j ) = P ( s t = q i , s t + 1 = q j ∥ O , λ ) \xi_{t}(i, j)=P(s_{t}=q_{i}, s_{t+1}=q_{j} \| O, \lambda) ξt​(i,j)=P(st​=qi​,st+1​=qj​∥O,λ)
I ( o t = v j ) I(o_{t}=v_{j}) I(ot​=vj​)当时刻 t t t观测状态为 v k v_k vk​ 时, I ( o t = v j ) = 1 I(o_{t}=v_{j})=1 I(ot​=vj​)=1,否则 I ( o t = v j ) = 0 I(o_{t} = v_{j})=0 I(ot​=vj​)=0

hmmlearn

Back to TOC

hmmlearn 是一个用于隐马尔可夫模型无监督学习和推理的算法库,其提供了易于使用的类似于sklearn的API。

安装

pip install hmmlearn

注意:前提是要有gcc编译器,因为部分源代码由C编译而成。
当前版本:V 0.2.2

使用

这里只介绍通用的离散HMM模型的使用(序列是离散的)

  • 建立一个HMM模型
from  hmmlearn import hmm

model = hmm.MultinomialHMM(n_components=n_states, tol=1e-2, n_iter=10, init_params='')
model.startprob_ = init_pi
model.transmat_ = init_T
model.emissionprob_ = init_E

如果是自己初始化的话,init_params='',否则模型随机初始化(默认)init_params='ste'代表初始化三个参数,并且需要手动设定model.n_features = n_obs

  • hmm.MultinomialHMM 相关参数

    • n_components : int
      Number of states. (隐状态数)

    • startprob_prior : array, shape (n_components, ), optional
      Parameters of the Dirichlet prior distribution for
      :attr:startprob_.

    • transmat_prior : array, shape (n_components, n_components), optional
      Parameters of the Dirichlet prior distribution for each row
      of the transition probabilities :attr:transmat_.

    • algorithm : string, optional
      Decoder algorithm. Must be one of “viterbi” or “map”.
      Defaults to “viterbi”.

    • random_state: RandomState or an int seed, optional
      A random number generator instance.

    • n_iter : int, optional
      Maximum number of iterations to perform.

    • tol : float, optional
      Convergence threshold. EM will stop if the gain in log-likelihood
      is below this value.

    • verbose : bool, optional
      When True per-iteration convergence reports are printed
      to :data:sys.stderr. You can diagnose convergence via the
      :attr:monitor_ attribute.

    • params : string, optional
      Controls which parameters are updated in the training
      process. Can contain any combination of ‘s’ for startprob,
      ‘t’ for transmat, ‘e’ for emissionprob.
      Defaults to all parameters.

    • init_params : string, optional
      Controls which parameters are initialized prior to
      training. Can contain any combination of ‘s’ for
      startprob, ‘t’ for transmat, ‘e’ for emissionprob.
      Defaults to all parameters.

  • 计算 P ( O ∣ λ ) P(\mathcal{O}|\lambda) P(O∣λ)(问题1)

model.score(obs.T)
  • Viterbi 算法解码(问题2)
model.decode(obs.T)
  • Baum-Welch 算法训练(问题3)
model.fit(obs.T)

常见错误

  • Expected 2D array, got 1D array instead
    输入的obs序列需要是一个[n_sample,n_obs]的二维数组,如果只有一个观测序列,需要将其扩展为二维,使用 np.atleast_2d(obs)
  • Buffer dtype mismatch, expected ‘dtype_t’ but got 'float’
    由于hmmlearn库在前向传播的时候调用的是C编译的代码,因此如果传入的变量类型不为float64则会报如上错误。解决办法:将传入的初始化变量类型改为np.float64。
  • arrays used as indices must be of integer (or boolean) type
    传入的obs序列需要为整型
  • expected a sample from a Multinomial distribution.
    源码的解释是: X should be an array of non-negative integers from range [min(X), max(X)], such that each integer from the range occurs in X at least once. For example [0, 0, 2, 1, 3, 1, 1] is a valid sample from a Multinomial distribution, while [0, 0, 3, 5, 10] is not.
    也就是说传入的序列需要每个obs都至少出现一次,但这在大多数情况下不太可能,官方GitHub的解决办法是:
>>> from sklearn.preprocessing import LabelEncoder
>>> LabelEncoder().fit_transform([0, 1, 5, 10])
array([0, 1, 2, 3])

但是这样重新编码不就是失去了一些状态?因此我的解决办法是,注释掉hmm.py第407行左右的self._check_input_symbols(X)语句,不让它对输入进行检查,然后对于第436行可能出错的代码进行一点小改进

def _compute_log_likelihood(self, X):
        return np.log(self.emissionprob_)[:, np.concatenate(X)].T

增加一个微小常数,改为

def _compute_log_likelihood(self, X):
        return np.log(self.emissionprob_ + 1e-10)[:, np.concatenate(X)].T

GitHub

Back to TOC

源代码GitHub传送门

参考资料

Back to TOC

隐马尔可夫模型(Hidden Markov Model,HMM)及其实现 隐马尔可夫模型是一种用于建模时序数据的强大工具,可以解决评估、解码和学习等问题。通过使用Python代码实现,我们可以更好地理解隐马尔可夫模型的工作原理和应用。隐马尔可夫模型(Hidden Markov Model,HMM)是一种用于建模时序数据的统计模型。本文将详细介绍隐马尔可夫模型的原理和实现,并提供相应的源代码。在示例中,我们使用了一个简单的隐马尔可夫模型,包含两个隐藏状态和三个观测。下面通过Python代码实现隐马尔可夫模型,为了简化问题,我们假设已知模型参数。二、隐马尔可夫模型的实现。 阅读详情

相关推荐

MATLAB实现隐马尔科夫模型全解_HMM学习与应用

隐马尔科夫模型(Hidden Markov Model,HMM)是一种统计模型,用于描述一个含有隐含未知参数的马尔科夫过程。HMM是马尔科夫链和统计模型相结合的产物,广泛应用于语音识别、生物信息学、自然语言处理等领域。在HMM中,系统被认为是一个马尔科夫过程,但状态并不直接可见,而是通过观测序列间接地表现出来。马尔科夫链是随机过程的一种,其核心特征是具有无记忆性,即未来的状态只与当前状态有关,而与过去的状态无关。数学上,这个性质可以表述为:假定有一个随机过程 {X_n},它取值于状态空间 S。

weixin_32661831的博客 993

一文读懂NLP之隐马尔科夫模型(HMM)详解加python实现

一文读懂NLP之隐马尔科夫模型(HMM)详解加python实现1 隐马尔科夫模型1.1 HMM解决的问题1.2 HMM模型的定义1.2.1HMM的两个假设1.2.2 HMM模型1.3 HMM模型的三个问题概率估计功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定...

Elenstone的博客 1万+

隐马尔科夫模型Python实现

机器学习中的隐马尔科夫模型的Python实现,包括参考资料链接等

隐马尔科夫模型模型:原理、实现

文章目录引入盒子模型与盒子问题(urn problem)随机过程索引集状态空间采样函数增量马尔可夫链与马尔可夫过程隐马尔科夫模型定义示例——帮助理解精灵、盒子与球天气估计原理描述推断问题估算观测序列出现的概率计算隐藏变量的概率过滤问题平滑问题最可能解释问题模型训练 引入 为了更方便地理解隐马尔可夫模型,我们需要引入以下概念。 盒子模型与盒子问题(urn problem) 所谓盒子问题,就是将感兴趣的实体视为一系列的,带有颜色的球。之后,人们从盒子中取出一个或多个的球,再根据这些球,估算某些概率或概率分布。比

zhuo木鸟的博客 2894

5-DOF机械臂课程设计(一)之正逆运动学

文章目录基本要求基本概念关节坐标系的建立正运动学求解DH参数表的建立逆运动学求解多解下解的选取源码下载后续 基本要求 ​ 开发上位机程序,要求有良好的界面,能提供关节空间下和笛卡尔坐 标下表示的目标位姿点和中间若干经过点的输入功能,进行轨迹规划, 并控制机械臂沿轨迹运动,最终完成目标抓取的任务。 基本概念 连杆长度 :2个相邻关节轴线之间的距离 连杆扭角 :2个相邻关节轴线之间的角度 连杆偏距 :2个关节坐标系的X轴之间的距离 关节角度 :关节变量 计算时需要加初始角度偏移 关节坐标系的建立 ​ 根据《机

Rosen的博客 5858

Data+AI新玩法:Text2SQL让数据查询变得如此简单!

你是不是也遇到过这种情况?明明手头有海量数据,却因为SQL这道“门槛”,让分析和决策变得复杂和拖沓。你可能想着:“要是我能直接用自然语言和数据库对话,那该多好!你不是一个人在这样想,Text2SQL技术正是为了帮你摆脱这一困境而诞生的。

Ase5gqe的博客 865

HMM隐马尔可夫模型最详细讲解与代码实现

首先就要说到中文分词 现阶段的分词手法一般有三大流派1.基于规则: 前后向最大匹配2.基于统计:HMM, CRF3.基于深度学习:Bilstm+crf 那么我们今天重点要讲的就是其中之一HMM隐马尔可夫模型 再说一下为什么要进行分词?1.更好的理解语义(能够提高模型性能)2.为了更重要的任务 如(命名实体识别、情感分析、文本分类 、语义识别等等)3.应用场景的需要 (淘宝、百度)搜索算法对于分词的要求就非常高But 并非所有中文任务都需要进行分词! 比如说 Bert (NSP)然后绕不开的一个点就是语料

m0_53292725的博客 3115

5GCPE与4G物联网卡兼容实战:通过AT指令修改IMEI实现设备迁移

本文详细介绍了如何通过AT指令修改5GCPE设备的IMEI,实现4G物联网卡的设备迁移。从硬件准备、驱动安装到串口工具配置,再到具体的AT指令操作步骤,提供了全面的实战指南。文章还包含信号优化、APN设置等实用技巧,帮助用户顺利完成设备迁移并提升网络性能。

weixin_28684757的博客 633

隐马尔科夫模型HMM之前后向算法Python代码实现,包括2个优化版本

利用python实现隐马尔科夫模型HMM中前向算法和后向算法实战

尚拙的博客 1687

基于ESP32与PCM5102的WiFi无损音频传输系统设计与实现

本文详细介绍基于ESP32与PCM5102的WiFi无损音频传输系统设计与实现。通过I2S接口直接传输PCM数据,避免SRC重采样,实现真正的HIFI级音质。涵盖硬件连接、软件架构、网络传输优化及实际音质对比,为音频爱好者提供高性价比的无损无线音频解决方案。

rnn9storyteller的博客 948

VS2019 C# 连接IBM DB2数据库并查询数据表

操作系统:win10 64位 C#:VS2019 数据库:IBM DB2v11.1_win64_expc 其他工具:IBM Data Studio ibm_ds4130_win 步骤一:使用命令行或是IBM DB2工具:Data Studio,创建一个数据库。这里名称为:Student CREATE DATABASE "Student" AUTOMATIC STORAGE YES ...

坚韧与专注 3796

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

wiki上有定义:隐马尔可夫模型(Hidden Markov Model,HMM)是统计模型,它用来描述一个含有隐含未知参数的马尔可夫过程。其难点是从可观察的参数中确定该过程的隐含参数。然后利用这些参数来作进一步的分析,例如模式识别。

狮子座明仔知识集散场 1万+

低代码部署与管理——OpenClaw智能助手的应用部署与运维(2026技术版)

OpenClaw智能助手的低代码部署与管理平台采用分层架构设计,包含部署工具、环境管理、版本控制等核心模块,支持从开发到生产的全流程自动化部署。该系统通过Docker、Kubernetes等技术实现应用构建和部署,利用Terraform等工具管理多环境配置,并提供完善的监控运维能力。平台针对开发、测试、预生产和生产环境提供差异化配置,确保部署效率和运行可靠性。这种架构设计遵循自动化、可扩展性和安全性原则,显著提升了智能助手应用的部署效率和运维质量。

一键难忘的博客 319

HMM详细讲解与代码的实现

#写在前面 老习惯,正文之前瞎扯一通。HMM学了很久,最初是在《统计学自然语言处理》里面就学到了相关内容,并且知道HMM CRF一直都是NLP比较底层比较基础且较为有效的算法模型(虽然感觉还是挺难的),之前仅仅局限在了解前向算法和维特比算法上。也没有去写代码,只知道个大概思路。最近从52nlpHMM系列讲解再次入手,结合多篇博客、github项目以及李航的《统计学习方法》比较全面的对HMM做了一次学习,要求对自己强制输出,所以在整体公式推导没有什么大问题之后,昨天花了一天完善了代码,今天来做一个全面的讲解,

caohailan666的博客 2193

【AI智能体】QClaw 对接GitHub处理自动化任务实战操作详解

QClaw 对接GitHub处理自动化任务实战操作详解

congge 4869

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

【大道至简】机器学习算法之隐马尔科夫模型(Hidden Markov Model, HMM)详解(2)---计算问题:前向算法和后向算法原理详解公式推导及Python实现

对于后向算法的理解,从定义出发非常重要。我看网上包括很多教学视频,对这部分内容的讲解几乎是一笔带过,基本上都是说:和前向算法类似,只不过这边是反过来计算而已,这里不再多说了,大家自己看书。我觉得这么说是很不负责任的,因为对于大多数数学天赋没那么好的人真的仔细理解后向算法,还是需要花点时间的,如果没有人指点,可能真的就需要费很大劲(我就是)。为了让大伙不再走太多弯路,我接下来尽最大可能把自己已经搞明白的知识给大家分享。

尚拙的博客 3994

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

【机器学习】隐马尔科夫模型(下)——学习算法和预测算法

HMM的学习问题和预测问题

HerosOfEarth的博客 9851

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

HMM原理介绍 示例 python代码实现

下面使用李航博士书上的例子说明:

liugallup的专栏 5139

python实现李航第十章HMM算法的前向、后向、维特比算法

python实现李航第十章HMM算法的前向、后向、维特比算法前向算法后向算法维特比算法 前向算法 理论部分参考链接:前向算法 问题:给出 λ\lambdaλ,求P(O∣λ)P(O|\lambda)P(O∣λ) 以下只给结论,不给具体推导: 首先假设一个α\alphaα αt(i)=P(o1...,ot,it=qi∣λ)\alpha{_t}{(i)}=P(o{_1}...,o{_t},i{_t...

qq_36782366的博客 875

基于特定语料的HMM模型计算和Viterbi算法的实现

HMM,它用来描述一个含有隐含未知参数的马尔可夫过程。其难点是从可观察的参数中确定该过程的隐含参数(后面要讨论到的Viterbi算法)。然后利用这些参数来作进一步的分析,例如模式识别。在中文信息处理方面,它主要用于词性标注,计算机并不知道一句话中某个词的具体词性,需要通过相应的模型和算法来使计算机能够识别出一句话中具体某个词的词性,那么模型就是某个HMM,算法就是在此模型上的Viterbi算法。 我的工作是以北大1998年1月份的语料为基础,求出此HMM,然后在这个HMM的基础之上设计Vi

bingby的专栏 1210

HMM隐马尔科夫模型

对于这些模型的介绍我打算从以下几个部分来写: 1:模型的基本概念 2:模型是如何应用于nlp当中的 3:相关论文 4:代码实现 HMM是隐马尔科夫模型的简称,这个模型的结构可以直接由下面的图来表示:其中蓝色方块表示的是状态序列,它是不可以被观测到的;红色圆圈表示观测序列,是可以直接观测到。而两个箭头都表示概率,黑色称为转换概率,红色称为发射概率。 因为我们只直到观测序列,那么就可以引出以下四个问题...

qq_20739243的博客 483

隐马尔科夫模型C#语言算法实现

开发工具: Visual Studio v2010 .NET Framework 4 Client Profile 版本历史: V1.1 2011年06月09日 修正UMDHMM在Baum-Welch算法中存在的模型参数调整错误。   V1.0 2011年06月08日 将C语言实现的隐马尔科夫模型算法(UMDHMM)改为C#语言实现。 功能描述:

xiaotianlan的专栏 2921

HMM之后向算法

HMM的后向算法那原理及简单实现

小黑的专栏 1046

【NLP】HMM原理---维特比算法实现

HMM原理 参考博客: https://www.cnblogs.com/pinard/p/6945257.html https://www.cnblogs.com/pinard/p/6991852.html 代码实现 将述博客中的例子代码实现 def hmm_viterbi(A,B,pi,O): δ = np.zeros((len(O),len(A))) #第一个局部 Ψ = np.zeros((len(O),len(A))) #第二个局部 # 1、初始化t=1时刻维特比的两

qq_44866428的博客 3804

Python隐形马尔科夫实战_python实现隐马尔科夫模型HMM

一份完全按照李航<>介绍的HMM代码,供大家参考,具体内容如下#coding=utf8'''''Created on 2017-8-5里面的代码许多地方可以精简,但为了百分百还原公式,就没有精简了。@author: adzhua'''import numpy as npclass HMM(object):def __init__(self, A, B, pi):'''''A: 状态转移...

weixin_33428129的博客 377
上一篇: Python画高斯分布图 (2D, 3D)
下一篇: GraphGallery,一个基于TensorFlow 2.x与 PyTorch 的GNN benchmark 框架
EdisonLeejt
博客等级 码龄9年 70粉丝 25原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值