维特比算法解决隐马尔可夫模型解码问题(中文句法标注)

作者:白宁超

2016年7月12日14:08:28

摘要:最早接触马尔可夫模型的定义源于吴军先生《数学之美》一书,起初觉得深奥难懂且无什么用场。直到学习自然语言处理时,才真正使用到隐马尔可夫模型,并体会到此模型的妙用之处。马尔可夫模型在处理序列分类时具体强大的功能,诸如解决:词类标注、语音识别、句子切分、字素音位转换、局部句法剖析、语块分析、命名实体识别、信息抽取等。另外广泛应用于自然科学、工程技术、生物科技、公用事业、信道编码等多个领域。本文写作思路如下:第一篇对马尔可夫个人简介和马尔科夫链的介绍;第二篇介绍马尔可夫链(显马尔可夫模型)和隐马尔可夫模型以及隐马尔可夫模型的三大问题(似然度、编码、参数学习);第三至五篇逐一介绍三大问题相关算法:(向前算法、维特比算法、向前向后算法);最后非常得益于冯志伟先生自然语言处理教程一书,冯老研究自然语言几十余载,在此领域别有建树。本文原创,转载注明出处维特比算法解决隐马尔可夫模型解码问题(中文句法标注)  )

目录


【自然语言处理:马尔可夫模型(一)】:初识马尔可夫和马尔可夫链

【自然语言处理:马尔可夫模型(二)】:马尔可夫模型与隐马尔可夫模型

【自然语言处理:马尔可夫模型(三)】:向前算法解决隐马尔可夫模型似然度问题

【自然语言处理:马尔可夫模型(四)】:维特比算法解决隐马尔可夫模型解码问题(中文句法标注)

【自然语言处理:马尔可夫模型(五)】:向前向后算法解决隐马尔可夫模型机器学习问题

马尔可夫个人简介


安德烈·马尔可夫,俄罗斯人,物理-数学博士,圣彼得堡科学院院士,彼得堡数学学派的代表人物,以数论和概率论方面的工作著称,他的主要著作有《概率演算》等。1878年,荣获金质奖章,1905年被授予功勋教授称号。马尔可夫是彼得堡数学学派的代表人物。以数论和概率论方面的工作著称。他的主要著作有《概率演算》等。在数论方面,他研究了连分数和二次不定式理论 ,解决了许多难题 。在概率论中,他发展了矩阵法,扩大了大数律和中心极限定理的应用范围。马尔可夫最重要的工作是在1906~1912年间,提出并研究了一种能用数学分析方法研究自然过程的一般图式——马尔可夫链。同时开创了对一种无后效性的随机过程——马尔可夫过程的研究。马尔可夫经多次观察试验发现,一个系统的状态转换过程中第n次转换获得的状态常取决于前一次(第(n-1)次)试验的结果。马尔可夫进行深入研究后指出:对于一个系统,由一个状态转至另一个状态的转换过程中,存在着转移概率,并且这种转移概率可以依据其紧接的前一种状态推算出来,与该系统的原始状态和此次转移前的马尔可夫过程无关。马尔可夫链理论与方法在现代已经被广泛应用于自然科学、工程技术和公用事业中。

1 算法原理描述


维特比算法解决:问题2(解码问题):给定一个观察序列O和一个HMM λ=(A,B),找出最好的隐藏状态序列Q。

解码:使HMM这种包含隐藏变量的模型中,确定隐藏在某个观察序列后面变量序列的工作,叫做解码。

形式化描述:给定一个HMMλ=(A,B)和一个观察序列 作为输入,找出概率最大的状态序列就是解码。

思想:使用前面算法找到隐藏在观察序列之后最好的状态序列,对于每个可能的隐藏状态序列,运用向前算法选出观察序列对隐藏序列的最大似然度的隐藏状态序列,从而完成解码工作,算法复杂度,当状态序列很大时,指数级增长,计算量过大,由此采用一种动态规划算法降低算法复杂度:维特比算法。

2 维特比算法实例分析


例子:通过吃冰淇淋数量(观察序列状态)计算隐藏状态空间的最佳路径(维特比网格)如下:

其中:

  1. 圆圈:隐藏状态 方框:观察状态
  2. 虚线圆圈:非法转移 虚线:计算路径
  3. q:隐藏空间状态 o:观察时间序列状态

 :在时间步t的观察状态下,隐藏状态j的概率。

Viterbi算法思想:按照观察序列由左向右顺序,每个表示自动机λ,HMM在看了头t个观察并通过了概率最大的状态序列 之后,在状态j的概率,每个 的值递归计算,并找出最大路径。

Viterbi算法形式化描述:每一个单元表示如下概率:

V的计算公式如下:

在时刻t-1的时候使用扩充前面路径的方法计算维特比概率,计算时,把下面3个因素相乘:

案例分析

给定一个HMMλ=(A,B),HMM把最大似然度指派给观察序列,算法返回状态路径,从而找到最优的隐藏状态序列。上图是小明夏天吃冰淇淋‘3 1 3’,据此使用Viterbi算法推断最可能出现的天气状态(天气的热|冷)。

1)计算时间步1的维特比概率

计算时间步t=1和状态1的概率:

路径:start--C

计算时间步t=1和状态2的概率:

路径:start—H  较大

2)计算时间步2的维特比概率,在(1) 基础计算

计算时间步t=2和状态1的概率:

路径:start—H—C   较大

计算时间步t=2和状态2的概率:

路径:start—H--H

3)计算时间步3的维特比概率,在(2) 基础计算

计算时间步t=3和状态1的概率:

路径:start—H—C —C

计算时间步t=3和状态2的概率:

路径:start—H—C—H  较大

4)维特比反向追踪路径

路径为:start—H—C---H

综上所述可知:利用Viterbi算法我们知道小明夏天某天吃冰淇淋的观察值(3 1 3)推断出天气为(热 冷 热)。这也符合事实,天热吃3根,天冷吃一根。

维特比算法与向前算法的区别

(1)    维特比算法要在前面路径的概率中选择最大值,而向前算法则计算其总和,除此之外,维特比算法和向前算法一样。

(2)    维特比算法有反向指针,寻找隐藏状态路径,而向前算法没有反向指针。

3 HMM和维特比算法解决随机词类标注问题


上面例子根据小明吃冰淇淋成功推断出天气事件,但是读者不免意犹未尽,那么下面利用同样方法进行词类标注。在随机词类标注算法中,单词是观察序列,相当于冰淇淋的数量。词类标记是隐藏状态,相当于天气的热冷。因此可以进行随机词类标注如下:

对于一个给定的句子或者单词序列,我们使用HMM词类标注算法来选择使用下面公式为最大值标记序列:

在进行词类标注时,句子“Secretariat is expected to race tomorrow”中的race是一个动词VB或者名词NN,它可以标注VB也可以标注NN,我们利用Viterbi算法解决:

根据HMM标注算法的公式可知,选择概率比较大的一个作为race的标记。P(VB|TO)*P(race|VB)  和P(NN|TO)*P(race|NN) 两者最大值即race的标记。

假设转移概率已知为:

P(NN|TO)=0.021

P(VB|TO)=0.34

假设词汇的发射概率即似然度也是知道的:

P(race|NN)=0.00041

P(race|VB)=0.00003

我们把标记序列概率和词汇发射概率相乘得到以下结果:

P(VB|TO)*P(race|VB) = 0.034*0.00003=0.00001

P(NN|TO)*P(race|NN) =0.021*0.00041=0.000007

因此,我们把race的标记确定为VB,这就是正确的词类标记结果,本质上采用统计模型的方法。当然真正使用时,我们根据需求对整个句子或者整段话以至于整篇文章进行标注,原理是一样的。

4 维特比算法描述


Viterbi算法定义:

5 利用Viterbi算法的中文句法标注


1 对文本数据清洗的预处理操作。代码略

2 对清洗后的文本,采用有监督方法对古文献BIO标记(B表示句子开始I表示句子中间O表示句子结尾)代码略

3 统计文本的转移矩阵B。 代码略

4 统计文本的发射矩阵A。 代码略

5 维特比解码算法找出观察序列O的最后的隐藏状态序列Q

5.1 隐马尔可夫模型中维特比解码算法序列标注

  1. String observationStr="病有发热恶寒者;发于阳也,无热恶寒者;发于阴也。";//观察序列
  2. String[] states={"B","I","O"};//状态序列
  3. double start_probability=0.3333;//初始状态概率
  4. String str="书名:伤寒论。作者:张仲景。朝代:东汉。";
  5. String stateStr=MethodUilt.Vitrerbi(str, start_probability, Amatrixpath, Bmatrixpath);//隐藏状态序列,即隐含马尔科夫模型的词类标注
  6. System.out.println("观察序列:\t"+str.replaceAll("", "\t")+"\n标注序列:\t\t"+stateStr);

5.2 针对马尔科夫模型中第二个问题,采用维特比算法进行句子标注,其中主要还是动态规划思想

  1. /**
  2. * 针对马尔科夫模型中第二个问题,采用维特比算法进行句子标注,其中主要还是动态规划思想
  3. * @param observationStr 观察序列
  4. * @param states 状态序列
  5. * @param start_probability 初始化状态,即π
  6. * @param Amatrixpath 发射矩阵路径
  7. * @param Bmatrixpath 转移矩阵路径
  8. * start_probability, transititon_probability, emission_probability
  9. * @return
  10. */
  11. public static String Vitrerbi(String observationStr,double start_probability,String Amatrixpath,String Bmatrixpath){
  12. //将观察序列切词存储在数组里面
  13. String[] ObserArr=observationStr.split("");
  14. //将发射矩阵放入数组中
  15. String[] emissionArrs=HeplerUilt.readStrFile(Amatrixpath, "\n").split("\n");//文本中发射矩阵逐次切割放于一位数组中
  16. Map<String,BIOEntity> countMap=new HashMap<String,BIOEntity>();//实例化map,存储:词+实体(二维数组)
  17. for(int i=0;i<emissionArrs.length;i++){
  18. String[] rowdata = emissionArrs[i].split("\t");
  19. countMap.put(rowdata[0], new BIOEntity(rowdata[0],Double.parseDouble(rowdata[1]), Double.parseDouble(rowdata[2]), Double.parseDouble(rowdata[3])));
  20. }
  21. //转移概率矩阵放入数组中
  22. String[] transititonArr=HeplerUilt.readStrFile(Bmatrixpath, "\t").split("\t");
  23. double[][] transArr=new double[3][3];//存放转移矩阵
  24. int k=0;
  25. for(int i=0;i<transArr.length;i++){
  26. for(int j=0;j<transArr[i].length;j++){
  27. transArr[i][j]=Double.parseDouble(transititonArr[k]);
  28. k++;
  29. }
  30. }
  31. //隐含的标注序列
  32. String stateStr="";
  33. double V=0;//每步V*P(q_i|q_i-1)*P(w|q_i)
  34. List list = new LinkedList();//存放路径
  35. //初始状态V的值
  36. String tarWord=ObserArr[1];//首个字母
  37. for(Map.Entry<String, BIOEntity> entry : countMap.entrySet()){
  38. if(entry.getKey().equals(tarWord)){
  39. double emission_probability=HeplerUilt.getMax(entry.getValue().getXb(), entry.getValue().getXi(), entry.getValue().getXo());
  40. String prior=HeplerUilt.compareMark(entry.getValue().getXb(), entry.getValue().getXi(), entry.getValue().getXo());
  41. list.add(prior);
  42. V=start_probability*emission_probability;
  43. //System.out.println(tarWord+":"+start_probability+":"+emission_probability+":"+prior+":"+HeplerUilt.DecFormat(4,V));
  44. }
  45. }
  46. //观察序列O,第二个状态到结束
  47. for(int i=2;i<ObserArr.length;i++){//由初始状态生成V,接着后面遍历观察序列进行
  48. for(Map.Entry<String, BIOEntity> entry : countMap.entrySet()){
  49. String q=list.get(list.size()-1).toString();//获取前一个标注
  50. if(entry.getKey().equals(ObserArr[i])){ //获取观察序列的发射概率
  51. double max_probability=HeplerUilt.getMax(entry.getValue().getXb(), entry.getValue().getXi(), entry.getValue().getXo());//得到最大发射概率值
  52. double transititon_probability=HeplerUilt.getMaxTrans(q,transArr); //获取最大的转移概率
  53. String prior=HeplerUilt.compareMark(entry.getValue().getXb(), entry.getValue().getXi(), entry.getValue().getXo());//得到最大发射概率的标注
  54. list.add(prior);//将最大发射概率进行保存
  55. V=V*max_probability*transititon_probability;//得到下一步的V值
  56. //测试数据
  57. //System.out.println(ObserArr[i]+":"+max_probability+":"+transititon_probability+":"+prior+":"+HeplerUilt.DecFormat(4,V));
  58. }
  59. }
  60. }
  61. //System.out.println(observationStr.length()+":"+list.size());
  62. for(int i=0;i<list.size();i++){
  63. stateStr+=list.get(i)+"\t";//记录路径
  64. }
  65. return stateStr;
  66. }
  67. //单元测试
  68. public static void main(String[] args) {
  69. //维特比解码算法找出观察序列O的最后的隐藏状态序列Q
  70. System.out.println("***************************隐马尔可夫模型中维特比解码算法序列标注****************************");
  71. String observationStr="病有发热恶寒者;发于阳也,无热恶寒者;发于阴也。";//观察序列
  72. String str="书名:伤寒论。作者:张仲景。朝代:东汉。";
  73. String stateStr=MethodUilt.Vitrerbi(str, 0.3333, "./targetFile/Amatrix.txt", "./targetFile/Bmatrix.txt");//隐藏状态序列,即隐含马尔科夫模型的词类标注
  74. System.out.println("观察序列:\t"+str.replaceAll("", "\t")+"\n标注序列:\t\t"+stateStr);
  75. }

6 实验结果:

3 参考文献


【1】统计自然语言处理基础  Christopher.Manning等 著    宛春法等 译

【2】自然语言处理简明教程  冯志伟 著

【3】数学之美  吴军 著

【4】Viterbi算法分析文章  王亚强

声明:关于此文各个篇章,本人采取梳理扼要,顺畅通明的写作手法。一则参照相关资料二则根据自己理解进行梳理。避免冗杂不清,每篇文章读者可理清核心知识,再找相关文献系统阅读。另外,要学会举一反三,不要死盯着定义或者某个例子不放。诸如:此文章例子冰淇淋数量(观察值)与天气冷热(隐藏值)例子,读者不免问道此有何用?我们将冰淇淋数量换成中文文本或者语音(观察序列),将天气冷热换成英文文本或者语音文字(隐藏序列)。把这个问题解决了不就是解决了文本翻译、语音识别、自然语言理解等等。解决了自然语言的识别和理解,再应用到现在机器人或者其他设备中,不就达到实用和联系现实生活的目的了?本文原创,转载注明出处维特比算法解决隐马尔可夫模型解码问题(中文句法标注)

【NLP】揭秘马尔可夫模型神秘面纱系列文章(四)的更多相关文章

  1. 【NLP】揭秘马尔可夫模型神秘面纱系列文章(一)

    初识马尔可夫和马尔可夫链 作者:白宁超 2016年7月10日20:34:20 摘要:最早接触马尔可夫模型的定义源于吴军先生<数学之美>一书,起初觉得深奥难懂且无什么用场.直到学习自然语言处 ...

  2. 【NLP】揭秘马尔可夫模型神秘面纱系列文章(二)

    马尔可夫模型与隐马尔可夫模型 作者:白宁超 2016年7月11日15:31:11 摘要:最早接触马尔可夫模型的定义源于吴军先生<数学之美>一书,起初觉得深奥难懂且无什么用场.直到学习自然语 ...

  3. 【NLP】揭秘马尔可夫模型神秘面纱系列文章(三)

    向前算法解决隐马尔可夫模型似然度问题 作者:白宁超 2016年7月11日22:54:57 摘要:最早接触马尔可夫模型的定义源于吴军先生<数学之美>一书,起初觉得深奥难懂且无什么用场.直到学 ...

  4. 【NLP】揭秘马尔可夫模型神秘面纱系列文章(五)

    向前向后算法解决隐马尔可夫模型机器学习问题 作者:白宁超 2016年7月12日14:28:10 摘要:最早接触马尔可夫模型的定义源于吴军先生<数学之美>一书,起初觉得深奥难懂且无什么用场. ...

  5. 【NLP学习其二】什么是隐马尔可夫模型HMM?

    概念 隐马尔可夫模型描述的是两个时序序列联合分布p(x,y)的概率模型,其中包含了两个序列: x序列外界可见(外界指的是观测者),称为观测序列(obsevation seuence) y序列外界不可见 ...

  6. NLP | 自然语言处理 - 标注问题与隐马尔科夫模型(Tagging Problems, and Hidden Markov Models)

    什么是标注? 在自然语言处理中有一个常见的任务,即标注.常见的有:1)词性标注(Part-Of-Speech Tagging),将句子中的每一个词标注词性,比如名词.动词等:2)实体标注(Name E ...

  7. NLP —— 图模型(一)隐马尔可夫模型(Hidden Markov model,HMM)

    本文简单整理了以下内容: (一)贝叶斯网(Bayesian networks,有向图模型)简单回顾 (二)隐马尔可夫模型(Hidden Markov model,HMM) 写着写着还是写成了很规整的样 ...

  8. HMM:隐马尔可夫模型HMM

    http://blog.csdn.net/pipisorry/article/details/50722178 隐马尔可夫模型 隐马尔可夫模型(Hidden Markov Model,HMM)是统计模 ...

  9. 猪猪的机器学习笔记(十七)隐马尔科夫模型HMM

    隐马尔科夫模型HMM 作者:樱花猪 摘要: 本文为七月算法(julyedu.com)12月机器学习第十七次课在线笔记.隐马尔可夫模型(Hidden Markov Model,HMM)是统计模型,它用来 ...

随机推荐

  1. 从直播编程到直播教育:LiveEdu.tv开启多元化的在线学习直播时代

    2015年9月,一个叫Livecoding.tv的网站在互联网上引起了编程界的注意.缘于Pingwest品玩的一位编辑在上网时无意中发现了这个网站,并写了一篇文章<一个比直播睡觉更奇怪的网站:直 ...

  2. Javascript生成二维码(QR)

    网络上已经有非常多的二维码编码和解码工具和代码,很多都是服务器端的,也就是说需要一台服务器才能提供二维码的生成.本着对服务器性能的考虑,这种小事情都让服务器去做,感觉对不住服务器,尤其是对于大流量的网 ...

  3. Docker笔记一:基于Docker容器构建并运行 nginx + php + mysql ( mariadb ) 服务环境

    首先为什么要自己编写Dockerfile来构建 nginx.php.mariadb这三个镜像呢?一是希望更深入了解Dockerfile的使用,也就能初步了解docker镜像是如何被构建的:二是希望将来 ...

  4. hibernate多对一双向关联

    关联是类(类的实例)之间的关系,表示有意义和值得关注的连接. 本系列将介绍Hibernate中主要的几种关联映射 Hibernate一对一主键单向关联Hibernate一对一主键双向关联Hiberna ...

  5. BootStrap_02之全局样式及组件

    1.BootStrap指定的四种屏幕尺寸: ①超大PC屏幕--lg(large):w>=1200px: ②中等PC屏幕--md(medium):1200px>w>=992px: ③P ...

  6. 探索ASP.NET MVC5系列之~~~4.模型篇---包含模型常用特性和过度提交防御

    其实任何资料里面的任何知识点都无所谓,都是不重要的,重要的是学习方法,自行摸索的过程(不妥之处欢迎指正) 汇总:http://www.cnblogs.com/dunitian/p/4822808.ht ...

  7. JavaScript特性(attribute)、属性(property)和样式(style)

    最近在研读一本巨著<JavaScript忍者秘籍>,里面有一篇文章提到了这3个概念. 书中的源码可以在此下载.我将源码放到了线上,如果不想下载,可以直接访问在线网址,修改页面名就能访问到相 ...

  8. 开源免费且稳定实用的.NET PDF打印组件itextSharp(.NET组件介绍之八)

    在这个.NET组件的介绍系列中,受到了很多园友的支持,一些园友(如:数据之巅. [秦时明月]等等这些大神 )也给我提出了对应的建议,我正在努力去改正,有不足之处还望大家多多包涵.在传播一些简单的知识的 ...

  9. C语言中如何判断文件是否存在

    方法一:access函数判断文件夹或者文件是否存在 函数原型: int access(const char *filename, int mode); 所属头文件:io.h filename:可以填写 ...

  10. 使用po模式读取豆瓣读书最受关注的书籍,取出标题、评分、评论、题材 按评分从小到大排序并输出到txt文件中

    #coding=utf-8from time import sleepimport unittestfrom selenium import webdriverfrom selenium.webdri ...