使用HMM实现简单拼音输入法

592 查看

之前写过一篇使用语言模型进行中文分词的博客,本篇在之前写的语言模型的基础上,通过隐马尔科夫模型实现简单的拼音输入法,即输入一组拼音,我们把它转换成中文。

一、隐马尔科夫模型

首先我们来说一下什么是马尔科夫链,简单的说,任何一组我们可以观察到的连续序列,比如连续一个星期的天气状况,都可以称为马尔科夫链。

马尔科夫链的最主要特性是,假设当前节点的状态(比如今天的天气),只与之前N个连续状态相关(比如之前一个星期的天气状况),通过这个性质和大量的统计,我们就可以根据最近几天的天气预测未来一天的天气了。

那么什么是隐马尔科夫模型呢?

比如你有一个朋友在美国,他会每天告诉你他今天做了什么(打球、跑步或呆在家里),你要通过他的这些活动推测过去一周内他们那边的天气。这里你朋友的活动对你来说是可以观察到的,即观察序列,而过去一周的天气是隐藏序列,那么这个通过观察序列推测隐藏序列的模型,就是隐马尔科夫模型。

隐马尔科夫模型的“隐”就体现在“隐藏序列”这个概念里。

二、通过拼音推测汉字

很明显,我们的拼音输入法的观察序列就是用户的输入拼音,比如”wo shi zhong guo ren”,我们要推测出用户想要输入的是“我 是 中 国 人”,这是个很典型的隐马尔科夫模型:

hmm1

如上图所示,我们根据给定的观察对象O,获得一个概率最大的序列S*。我们所知道的数据有:

1, 所有观察对象的值

2, 隐藏序列的马尔科夫模型概率,这是通过统计获得的

3, 隐藏状态到观察状态的概率,比如 “晴天”(隐藏状态) 到 “出去玩”(观察状态)的概率

我们要求的是S*各个状态的连续概率最大的那个序列。

三、前向概率Viterbi算法

我们把隐藏序列中的一个节点的每一种可能取值都画出来的话,我们会发现这其实是一个有向图寻找最优路径的问题:

viterbi

H、O、S都是当前节点可能的取值(比如hao拼音可能有好、号、耗等汉字)。而对于这种寻找最优路径的问题,我们可以通过动态规划的思想去考虑,假设σt(k)表示第t个位置对应的汉字是k,s表示隐藏序列,o表示观察序列,M表示当前隐藏节点的可能取值,那么:

viterbi2

上式中的表示从隐藏节点k到观察序列t+1的发射概率,α_{l,k}表示l到k的马尔科夫状态转移概率。

写出了递归式,这个动态规划程序就容易写了。

四、实现

既然我们是一个有向图,那么闲来构造图中的所有节点:


核心的viterbi算法为:


由于完整代码牵扯的东西太多,包括语言模型、汉字拼音映射表,这里就不在全部贴出来了,不过有了上面两部分代码,其实其他的也很容易谢了,就是加载进去而已。如有兴趣可以联系我索取相关完整代码。

输出效果:


第一组输入的有一个错字,主要是因为语料库不够完善,可能“入法”两个字的概率小于“入发”两个字了,不是大问题。

由于找我发邮件要代码的人太多…我觉得还是直接放在 这里 让大家下载吧,不过代码都是demo性质的,只为实现效果,切勿放到真实环境运行。