基本要素

  • 状态 \(N\)个

  • 状态序列 \(S = s_1,s_2,...\)

  • 观测序列 \(O=O_1,O_2,...\)

  • \(\lambda(A,B,\pi)\)

    • 状态转移概率 \(A = \{a_{ij}\}\)
    • 发射概率 \(B = \{b_{ik}\}\)
    • 初始概率分布 \(\pi = \{\pi_i\}\)
  • 观测序列生成过程

    • 初始状态
    • 选择观测
    • 状态转移
    • 返回step2

HMM三大问题

  • 概率计算问题(评估问题)

给定观测序列 \(O=O_1O_2...O_T\),模型 \(\lambda (A,B,\pi)\),计算 \(P(O|\lambda)\),即计算观测序列的概率

  • 解码问题

给定观测序列 \(O=O_1O_2...O_T\),模型 \(\lambda (A,B,\pi)\),找到对应的状态序列 \(S\)

  • 学习问题

给定观测序列 \(O=O_1O_2...O_T\),找到模型参数 \(\lambda (A,B,\pi)\),以最大化 \(P(O|\lambda)\),

概率计算问题

给定模型 \(\lambda\) 和观测序列 \(O\),如何计算\(P(O| \lambda)\)?

暴力枚举每一个可能的状态序列 \(S\)

  • 对每一个给定的状态序列

    \[P(O|S,\lambda) = \prod^T_{t=1} P(O_t|s_t,\lambda) =\prod^T_{t=1} b_{s_tO_t}
    \]

  • 一个状态序列的产生概率

    \[P(S|\lambda) = P(s_1)\prod^T_{t=2}P(s_t|s_{t-1})=\pi_1\prod^T_{t=2}a_{s_{t-1}s_t}
    \]

  • 联合概率

    \[P(O,S|\lambda) = P(S|\lambda)P(O|S,\lambda) =\pi_1\prod^T_{t=2}a_{s_{t-1}s_t}\prod^T_{t=1} b_{s_tO_t}
    \]

  • 考虑所有的状态序列

    \[P(O|\lambda)=\sum_S\pi_1b_{s_1O_1}\prod^T_{t=2}a_{s_{t-1}s_t}b_{s_tO_t}
    \]

\(O\) 可能由任意一个状态得到,所以需要将每个状态的可能性相加。

这样做什么问题?时间复杂度高达 \(O(2TN^T)\)。每个序列需要计算 \(2T\) 次,一共 \(N^T\) 个序列。

前向算法

在时刻 \(t\),状态为 \(i\) 时,前面的时刻观测到 \(O_1,O_2, ..., O_t\) 的概率,记为 \(\alpha _i(t)\) :

\[\alpha_{i}(t)=P\left(O_{1}, O_{2}, \ldots O_{t}, s_{t}=i | \lambda\right)
\]

当 \(t=1\) 时,输出为 \(O_1\),假设有三个状态,\(O_1\) 可能是任意一个状态发出,即

\[P(O_1|\lambda) = \pi_1b_1(O_1)+\pi_2b_2(O_1)+\pi_2b_3(O_1) = \alpha_1(1)+\alpha_2(1)+\alpha_3(1)
\]

当 \(t=2\) 时,输出为 \(O_1O_2\) ,\(O_2\) 可能由任一个状态发出,同时产生 \(O_2\) 对应的状态可以由 \(t=1\) 时刻任意一个状态转移得到。假设 \(O_2\) 由状态 1 发出,如下图

\[P(O_1O_2,s_2=q_1|\lambda) = \pi_1b_1(O_1)a_{11}b_1(O_2)+\pi_2b_2(O_1)a_{21}b_1(O_2)+\pi_2b_3(O_1)a_{31}b_1(O_2) \\
=\bold{\alpha_1(1)}a_{11}b_1(O_2)+\bold{\alpha_2(1)}a_{21}b_1(O_2)+\bold{\alpha_3(1)}a_{31}b_1(O_2) = \bold{\alpha_1(2)}
\]

同理可得 \(\alpha_2(2),\alpha_3(2)\)

\[\bold{\alpha_2(2)} = P(O_1O_2,s_2=q_2|\lambda)
=\bold{\alpha_1(1)}a_{12}b_2(O_2)+\bold{\alpha_2(1)}a_{22}b_2(O_2)+\bold{\alpha_3(1)}a_{32}b_2(O_2)
\\
\bold{\alpha_3(2)} = P(O_1O_2,s_2=q_3|\lambda)
=\bold{\alpha_1(1)}a_{13}b_3(O_2)+\bold{\alpha_2(1)}a_{23}b_3(O_2)+\bold{\alpha_3(1)}a_{33}b_3(O_2)
\]

所以

\[P(O_1O_2|\lambda) =P(O_1O_2,s_2=q_1|\lambda)+ P(O_1O_2,s_2=q_2|\lambda) +P(O_1O_2,s_2=q_3|\lambda)\\
= \alpha_1(2)+\alpha_2(2)+\alpha_3(2)
\]

所以前向算法过程如下:

​ step1:初始化 \(\alpha_i(1)= \pi_i*b_i(O_1)\)

​ step2:计算 \(\alpha_i(t) = (\sum^{N}_{j=1} \alpha_j(t-1)a_{ji})b_i(O_{t})\)

​ step3:\(P(O|\lambda) = \sum^N_{i=1}\alpha_i(T)\)

相比暴力法,时间复杂度降低了吗?

当前时刻有 \(N\) 个状态,每个状态可能由前一时刻 \(N\) 个状态中的任意一个转移得到,所以单个时刻的时间复杂度为 \(O(N^2)\),总时间复杂度为 \(O(TN^2)\)

代码实现

例子:

假设从三个 袋子 {1,2,3}中 取出 4 个球 O={red,white,red,white},模型参数\(\lambda = (A,B,\pi)\) 如下,计算序列O出现的概率

#状态 1 2 3
A = [[0.5,0.2,0.3],
	 [0.3,0.5,0.2],
	 [0.2,0.3,0.5]]

pi = [0.2,0.4,0.4]

# red white
B = [[0.5,0.5],
	 [0.4,0.6],
	 [0.7,0.3]]

​ step1:初始化 \(\alpha_i(1)= \pi_i*b_i(O_1)\)

​ step2:计算 \(\alpha_i(t) = (\sum^{N}_{j=1} \alpha_j(t-1)a_{ji})b_i(O_{t})\)

​ step3:\(P(O|\lambda) = \sum^N_{i=1}\alpha_i( T)\)

#前向算法
def hmm_forward(A,B,pi,O):
    T = len(O)
    N = len(A[0])
    #step1 初始化
    alpha = [[0]*T for _ in range(N)]
    for i in range(N):
        alpha[i][0] = pi[i]*B[i][O[0]]

    #step2 计算alpha(t)
    for t in range(1,T):
        for i in range(N):
            temp = 0
            for j in range(N):
                temp += alpha[j][t-1]*A[j][i]
            alpha[i][t] = temp*B[i][O[t]]

    #step3
    proba = 0
    for i in range(N):
        proba += alpha[i][-1]
    return proba,alpha

A = [[0.5,0.2,0.3],[0.3,0.5,0.2],[0.2,0.3,0.5]]
B = [[0.5,0.5],[0.4,0.6],[0.7,0.3]]
pi = [0.2,0.4,0.4]
O = [0,1,0,1]
hmm_forward(A,B,pi,O)  #结果为 0.06009

结果

后向算法

在时刻 \(t\),状态为 \(i\) 时,观测到 \(O_{t+1},O_{t+2}, ..., O_T\) 的概率,记为 \(\beta _i(t)\) :

\[\beta_{i}(t)=P\left(O_{t+1},O_{t+2}, ..., O_T | s_{t}=i, \lambda\right)
\]

当 \(t=T\) 时,由于 \(T\) 时刻之后为空,没有观测,所以 \(\beta_i(t)=1\)

当 \(t = T-1\) 时,观测 \(O_T\) ,\(O_T\) 可能由任意一个状态产生

\[\beta_i(T-1) = P(O_T|s_{t}=i,\lambda) = a_{i1}b_1(O_T)\beta_1(T)+a_{i2}b_2(O_T)\beta_2(T)+a_{i3}b_3(O_T)\beta_3(T)
\]

当 \(t=1\) 时,观测为 \(O_{2},O_{3}, ..., O_T\)

\[\begin{aligned}
\beta_1(1)
&= P(O_{2},O_{3}, ..., O_T|s_1=1,\lambda)\\
&=a_{11}b_1(O_2)\beta_1(2)+a_{12}b_2(O_2)\beta_2(2)+a_{13}b_3(O_2)\beta_3(2)
\\
\quad
\\
\beta_2(1)
&= P(O_{2},O_{3}, ..., O_T|s_1=2,\lambda)\\
&=a_{21}b_1(O_2)\beta_1(2)+a_{22}b_2(O_2)\beta_2(2)+a_{23}b_3(O_2)\beta_3(2)
\\
\quad
\\
\beta_3(1)
&=P(O_{2},O_{3}, ..., O_T|s_1=3,\lambda)\\
&=a_{31}b_1(O_2)\beta_1(2)+a_{32}b_2(O_2)\beta_2(2)+a_{33}b_3(O_2)\beta_3(2)
\end{aligned}
\]

所以

\[P(O_{2},O_{3}, ..., O_T|\lambda) = \beta_1(1)+\beta_2(1)+\beta_3(1)
\]

后向算法过程如下:

​ step1:初始化 \(\beta_i(T)=1\)

​ step2:计算 \(\beta_i(t) = \sum^N_{j=1}a_{ij}b_j(O_{t+1})\beta_j(t+1)\)

​ step3:\(P(O|\lambda) = \sum^N_{i=1}\pi_ib_i(O_1)\beta_i(1)\)

  • 时间复杂度 \(O(N^2T)\)

代码实现

还是上面的例子

#后向算法
def hmm_backward(A,B,pi,O):
    T = len(O)
    N = len(A[0])
    #step1 初始化
    beta = [[0]*T for _ in range(N)]
    for i in range(N):
        beta[i][-1] = 1

    #step2 计算beta(t)
    for t in reversed(range(T-1)):
        for i in range(N):
            for j in range(N):
                beta[i][t]  += A[i][j]*B[j][O[t+1]]*beta[j][t+1]

    #step3
    proba = 0
    for i in range(N):
        proba += pi[i]*B[i][O[0]]*beta[i][0]
    return proba,beta

A = [[0.5,0.2,0.3],[0.3,0.5,0.2],[0.2,0.3,0.5]]
B = [[0.5,0.5],[0.4,0.6],[0.7,0.3]]
pi = [0.2,0.4,0.4]
O = [0,1,0,1]
hmm_backward(A,B,pi,O)  #结果为 0.06009

结果

前向-后向算法

回顾前向、后向变量:

  • \(a_i(t)\) 时刻 \(t\),状态为 \(i\) ,观测序列为 \(O_1,O_2, ..., O_t\) 的概率
  • \(\beta_i(t)\) 时刻 \(t\),状态为 \(i\) ,观测序列为 \(O_{t+1},O_{t+2}, ..., O_T\) 的概率

\[\begin{aligned}
P(O,s_t=i|\lambda)
&= P(O_1,O_2, ..., O_T,s_t=i|\lambda)\\
&= P(O_1,O_2, ..., O_t,s_t=i,O_{t+1},O_{t+2}, ..., O_T|\lambda)\\
&= P(O_1,O_2, ..., O_t,s_t=i|\lambda)*P(O_{t+1},O_{t+2}, ..., O_T|O_1,O_2, ..., O_t,s_t=i,\lambda) \\
&= P(O_1,O_2, ..., O_t,s_t=i|\lambda)*P(O_{t+1},O_{t+2}, ..., O_T,s_t=i|\lambda)\\
&= a_i(t)*\beta_i(t)
\end{aligned}
\]

即在给定的状态序列中,\(t\) 时刻状态为 \(i\) 的概率。

使用前后向算法可以计算隐状态,记 \(\gamma_i(t) = P(s_t=i|O,\lambda)\) 表示时刻 \(t\) 位于隐状态 \(i\) 的概率

\[P\left(s_{t}=i, O | \lambda\right)=\alpha_{i}(t) \beta_{i}(t)
\]

\[\begin{aligned}
\gamma_{i}(t)
&=P\left(s_{t}={i} | O, \lambda\right)=\frac{P\left(s_{t}={i}, O | \lambda\right)}{P(O | \lambda)} \\
&=\frac{\alpha_{i}(t) \beta_{i}(t)}{P(O | \lambda)}=\frac{\alpha_{i}(t) \beta_{i}(t)}{\sum_{i=1}^{N} \alpha_{i}(t) \beta_{i}(t)}
\end{aligned}
\]

references:

[1] https://www.cs.sjsu.edu/~stamp/RUA/HMM.pdf

[2]https://www.cnblogs.com/fulcra/p/11065474.html

[3] https://www.cnblogs.com/sjjsxl/p/6285629.html

[4] https://blog.csdn.net/xueyingxue001/article/details/52396494

HMM-前向后向算法与实现的更多相关文章

  1. HMM 前向后向算法(转)

    最近研究NLP颇感兴趣,但由于比较懒,所以只好找来网上别人的比较好的博客,备份一下,也方便自己以后方便查找(其实,一般是不会再回过头来看的,嘿嘿 -_-!!) 代码自己重新写了一遍,所以就不把原文代码 ...

  2. HMM 自学教程(七)前向后向算法

    本系列文章摘自 52nlp(我爱自然语言处理: http://www.52nlp.cn/),原文链接在 HMM 学习最佳范例,这是针对 国外网站上一个 HMM 教程 的翻译,作者功底很深,翻译得很精彩 ...

  3. 隐马尔科夫模型HMM(二)前向后向算法评估观察序列概率

    隐马尔科夫模型HMM(一)HMM模型 隐马尔科夫模型HMM(二)前向后向算法评估观察序列概率 隐马尔科夫模型HMM(三)鲍姆-韦尔奇算法求解HMM参数(TODO) 隐马尔科夫模型HMM(四)维特比算法 ...

  4. 条件随机场CRF(二) 前向后向算法评估标记序列概率

    条件随机场CRF(一)从随机场到线性链条件随机场 条件随机场CRF(二) 前向后向算法评估标记序列概率 条件随机场CRF(三) 模型学习与维特比算法解码 在条件随机场CRF(一)中我们总结了CRF的模 ...

  5. 《统计学习方法》P179页10.22前向后向算法公式推导

  6. 隐马尔可夫(HMM)、前/后向算法、Viterbi算法

    HMM的模型  图1 如上图所示,白色那一行描述由一个隐藏的马尔科夫链生成不可观测的状态随机序列,蓝紫色那一行是各个状态生成可观测的随机序列 话说,上面也是个贝叶斯网络,而贝叶斯网络中有这么一种,如下 ...

  7. 隐马尔可夫模型HMM与维特比Veterbi算法(一)

    隐马尔可夫模型HMM与维特比Veterbi算法(一) 主要内容: 1.一个简单的例子 2.生成模式(Generating Patterns) 3.隐藏模式(Hidden Patterns) 4.隐马尔 ...

  8. HMM-前向后向算法

    基本要素 状态 \(N\)个 状态序列 \(S = s_1,s_2,...\) 观测序列 \(O=O_1,O_2,...\) \(\lambda(A,B,\pi)\) 状态转移概率 \(A = \{a ...

  9. HMM-前向后向算法(附python实现)

    基本要素 状态 \(N\)个 状态序列 \(S = s_1,s_2,...\) 观测序列 \(O=O_1,O_2,...\) \(\lambda(A,B,\pi)\) 状态转移概率 \(A = \{a ...

  10. HMM-前向后向算法(附代码)

    目录 基本要素 HMM三大问题 概率计算问题 前向算法 后向算法 前向-后向算法 基本要素 状态 \(N\)个 状态序列 \(S = s_1,s_2,...\) 观测序列 \(O=O_1,O_2,.. ...

随机推荐

  1. 如何可视化深度学习网络中Attention层

    前言 在训练深度学习模型时,常想一窥网络结构中的attention层权重分布,观察序列输入的哪些词或者词组合是网络比较care的.在小论文中主要研究了关于词性POS对输入序列的注意力机制.同时对比实验 ...

  2. 好用的mitmproxy代理抓包

    安装证书 浏览器输入 `mitm.it` 下载证书有时候打不开,可能是起的服务卡死了,回车下命令行,再再网页刷新下载证书就可以了. mitmweb Chrome浏览器代理设置 打开的话,记得保存点一下 ...

  3. Say goodbye

    Since September 28th 2015 Scriptogram officially closed. We considered every option before making th ...

  4. Python 中取代 Printf 大法的工具

    「printf 大法」大概是最早期学到的 debug 方式?不同语言有不同的指令,在 Python 里对应的是 print指令 (加上%或是.format). 刚刚看到「 cool-RR/pysnoo ...

  5. 改善 Python 程序的 91 个建议

    1.引论 建议1:理解Pythonic概念—-详见Python中的<Python之禅> 建议2:编写Pythonic代码 避免不规范代码,比如只用大小写区分变量.使用容易混淆的变量名.害怕 ...

  6. windows下部署.netcore+docker系列三 (unbuntu 18.4 下安装ftp)

    // 先更新下系统sudo apt-get update//安装ftpsudo apt-get install vsftpd// 启动 服务sudo service vsftpd start//ftp ...

  7. Java同步方法:synchronized到底锁住了谁?

    目录 前言 同步方法 类的成员方法 类的静态方法 同步代码块 总结 其他同步方法 参考资料 前言 相信不少同学在上完Java课后,对于线程同步部分的实战,都会感到不知其然. 比如上课做实验的时候,按着 ...

  8. 五分钟学会Python装饰器,看完面试不再慌

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是Python专题的第12篇文章,我们来看看Python装饰器. 一段囧事 差不多五年前面试的时候,我就领教过它的重要性.那时候我Pyt ...

  9. PHP如何实现判断提交的是什么方式

    function get_request_method() { // $_SERVER包含了诸多头信息.路径.以及脚本位置等等信息的数组,这个数组中的项目有web服务器创建. if (isset($_ ...

  10. Python logging 模块打印异常 exception

    logger.exception(sys.exc_info())