HMM中文分词

1.模型的五元组

  • StatusSet: 状态值集合
  • ObservedSet: 观察值集合
  • TransProbMatrix: 转移概率矩阵
  • EmitProbMatrix: 发射概率矩阵
  • InitStatus: 初始状态分布

2.模型可以用来解决三种问题:

  1. 参数(StatusSet, TransProbMatrix, EmitRobMatrix, InitStatus)已知的情况下,求解观察值序列。(Forward-backward算法)
  2. 参数(ObservedSet, TransProbMatrix, EmitRobMatrix, InitStatus)已知的情况下,求解状态值序列。(viterbi算法)
  3. 参数(ObservedSet)已知的情况下,求解(TransProbMatrix, EmitRobMatrix, InitStatus)。(Baum-Welch算法)

其中,第三种问题最玄乎也最不常用,第二种问题最常用,【中文分词】,【语音识别】, 【新词发现】, 【词性标注】 都有它的一席之地。所以本文主要介绍第二种问题,即【viterbi算法求解状态值序列】的方法。

3.五元组参数在中文分词中的具体含义

  StatusSet & ObservedSet

  状态值集合为(B, M, E, S): {B:begin, M:middle, E:end, S:single}。分别代表每个状态代表的是该字在词语中的位置,B代表该字是词语中的起始字,M代表是词语中的中  间字,E代表是词语中的结束字,S则代表是单字成词。

  观察值集合为就是所有汉字(东南西北你我他…),甚至包括标点符号所组成的集合。

  状态值也就是我们要求的值,在HMM模型中文分词中,我们的输入是一个句子(也就是观察值序列),输出是这个句子中每个字的状态值。

  B后面只可能接(M or E),不可能接(B or S)。而M后面也只可能接(M or E),不可能接(B, S)。 

  EmitProbMatrix

  这里的发射概率(EmitProb)其实也是一个条件概率而已,根据HMM模型三个基本假设(哪三个请看文末备注)里的【观察值独立性假设】,观察值只取决于当前状态值,也就是:

  P(Observed[i], Status[j]) = P(Status[j]) * P(Observed[i]|Status[j])

  其中P(Observed[i]|Status[j])这个值就是从EmitProbMatrix中获取。

  这五元的关系是通过一个叫Viterbi的算法串接起来, ObservedSet序列值是Viterbi的输入, 而StatusSet序列值是Viterbi的输出, 输入和输出之间Viterbi算法还需要借助三个模型参数, 分别是InitStatus, TransProbMatrix, EmitProbMatrix

  InitStatus

  初始状态概率分布是最好理解的,可以示例如下:

  #B
  -0.26268660809250016
  #E
  -3.14e+100
  #M
  -3.14e+100
  #S
  -1.4652633398537678
4.Viterbi算法

定义变量

二维数组 weight[4][15],4是状态数(0:B,1:E,2:M,3:S),15是输入句子的字数。比如 weight[0][2] 代表 状态B的条件下,出现'硕'这个字的可能性。

二维数组 path[4][15],4是状态数(0:B,1:E,2:M,3:S),15是输入句子的字数。比如 path[0][2] 代表 weight[0][2]取到最大时,前一个字的状态,比如 path[0][2] = 1, 则代表 weight[0][2]取到最大时,前一个字(也就是)的状态是E。记录前一个字的状态是为了使用viterbi算法计算完整个 weight[4][15] 之后,能对输入句子从右向左地回溯回来,找出对应的状态序列。

使用InitStatus对weight二维数组进行初始化

已知InitStatus如下:

#B
-0.26268660809250016
#E
-3.14e+100
#M
-3.14e+100
#S
-1.4652633398537678

且由EmitProbMatrix可以得出

Status(B) -> Observed(小)  :  -5.79545
Status(E) -> Observed(小)  :  -7.36797
Status(M) -> Observed(小)  :  -5.09518
Status(S) -> Observed(小)  :  -6.2475

所以可以初始化 weight[i][0] 的值如下:

weight[0][0] = -0.26268660809250016 + -5.79545 = -6.05814
weight[1][0] = -3.14e+100 + -7.36797 = -3.14e+100
weight[2][0] = -3.14e+100 + -5.09518 = -3.14e+100
weight[3][0] = -1.4652633398537678 + -6.2475 = -7.71276

注意上式计算的时候是相加而不是相乘,因为之前取过对数的原因。

遍历句子计算整个weight二维数组

//遍历句子,下标i从1开始是因为刚才初始化的时候已经对0初始化结束了
for(size_t i = 1; i < 15; i++)
{
    // 遍历可能的状态
    for(size_t j = 0; j < 4; j++) 
    {
        weight[j][i] = MIN_DOUBLE;
        path[j][i] = -1;
        //遍历前一个字可能的状态
        for(size_t k = 0; k < 4; k++)
        {
            double tmp = weight[k][i-1] + _transProb[k][j] + _emitProb[j][sentence[i]];
            if(tmp > weight[j][i]) // 找出最大的weight[j][i]值
            {
                weight[j][i] = tmp;
                path[j][i] = k;
            }
        }
    }
}

如此遍历下来,weight[4][15]path[4][15] 就都计算完毕。

确定边界条件和路径回溯

边界条件如下:

对于每个句子,最后一个字的状态只可能是 E 或者 S,不可能是 M 或者 B。

所以在本文的例子中我们只需要比较 weight[1(E)][14]weight[3(S)][14] 的大小即可。

在本例中:

weight[1][14] = -102.492;
weight[3][14] = -101.632;

所以 S > E,也就是对于路径回溯的起点是 path[3][14]

回溯的路径是:

SEBEMBEBEMBEBEB

倒序一下就是:

BE/BE/BME/BE/BME/BE/S

所以切词结果就是:

小明/硕士/毕业于/中国/科学院/计算/所

5.HMM模型的三个基本假设
  • 有限历史性假设:
P(Status[i]|Status[i-1],Status[i-2],... Status[1]) = P(Status[i]|Status[i-1])
  • 齐次性假设(状态和当前时刻无关):
P(Status[i]|Status[i-1]) = P(Status[j]|Status[j-1])
  • 观察值独立性假设(观察值只取决于当前状态值):
P(Observed[i]|Status[i],Status[i-1],...,Status[1]) = P(Observed[i]|Status[i])


posted @ 2016-09-08 13:54  mingsun  阅读(1285)  评论(0)    收藏  举报