【中文分词】隐马尔可夫模型HMM

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

【中⽂分词】隐马尔可夫模型HMM
Nianwen Xue 在《Chinese Word Segmentation as Character Tagging 》中将中⽂分词视作为序列标注问题(sequence tagging problem ),由此引⼊监督学习算法来解决分词问题。

1. HMM
⾸先,我们将简要地介绍HMM (主要参考了李航⽼师的《统计学习⽅法》)。

HMM 包含如下的五元组:状态值集合Q ={q 1,q 2,⋯,q N },其中N 为可能的状态数;
观测值集合V ={v 1,v 2,⋯,v M },其中M 为可能的观测数;
转移概率矩阵A =a ij ,其中a ij 表⽰从状态i 转移到状态j 的概率;
发射概率矩阵(在[2]中称之为观测概率矩阵)B =b j (k ),其中b j (k )表⽰在状态j 的条件下⽣成观测v k 的概率;初始状态分布π.
⼀般地,将HMM 表⽰为模型λ=(A ,B ,π),状态序列为I ,对应测观测序列为O 。

对于这三个基本参数,HMM 有三个基本问题:
概率计算问题,在模型λ下观测序列O 出现的概率;
学习问题,已知观测序列O ,估计模型λ的参数,使得在该模型下观测序列P (O |λ)最⼤;
解码(decoding )问题,已知模型λ与观测序列O ,求解条件概率P (I |O )最⼤的状态序列I 。

2. 中⽂分词
将状态值集合Q 置为{B ,E ,M ,S },分别表⽰词的开始、结束、中间(begin 、end 、middle )及字符独⽴成词(single );观测序列即为中⽂句⼦。

⽐如,“今天天⽓不错”通过HMM 求解得到状态序列“B E B E B E”,则分词结果为“今天/天⽓/不错”。

通过上⾯例⼦,我们发现中⽂分词的任务对应于解码问题:对于字符串C ={c 1,⋯,c n },求解最⼤条件概率
max P (t 1,⋯,t n |c 1,⋯,c n )
其中,t i 表⽰字符c i 对应的状态。

应如何求解状态序列呢?解决的办法便是Viterbi 算法;其实,Viterbi 算法本质上是⼀个动态规划算法,利⽤到了状态序列的最优路径满⾜这样⼀个特性:最优路径的⼦路径也⼀定是最优的。

定义在时刻t 状态为i 的概率最⼤值为δt (i ),则有递推公式:
δt +1(i )=max [δt (j )a ji ]b i (o t +1)
其中,o t +1即为字符c t +1。

3. 开源实现
以下的源码分析基于Jieba 0.36版本。

Jieba 的实现HMM 中⽂分词。

prob_start.py 定义初始状态分布π:P={'B': -0.26268660809250016, 'E': -3.14e+100,
'M': -3.14e+100,
'S': -1.4652633398537678}
转移概率矩阵A :
P={'B': {'E': -0.510825623765990, 'M': -0.916290731874155},
'E': {'B': -0.5897149736854513, 'S': -0.8085250474669937},
[][]
'M': {'E': -0.33344856811948514, 'M': -1.2603623820268226},
'S': {'B': -0.7211965654669841, 'S': -0.6658631448798212}}
定义了发射概率矩阵B,⽐如,表⽰状态为M的情况下出现“和”这个字的概率;
P={'B': {'⼀': -3.6544978750449433,
'丁': -8.125041941842026,
'七': -7.817392401429855,
...}
'S': {':': -15.828865*********,
'⼀': -4.92368982120877,
...}
...}
关于训练模型的⽣成,作者在有解释,来源主要有两个:标准的切分语料 + ICTCLAS切分的txt⼩说。

还有⼀个⼤家可能会疑惑的问题,为什么Jieba中的概率矩阵中出现了负数?不急,我们先来看看Viterbi算法的实现——函数:
PrevStatus = {
'B': 'ES',
'M': 'MB',
'S': 'SE',
'E': 'BM'
}
def viterbi(obs, states, start_p, trans_p, emit_p):
V = [{}] # tabular
path = {}
for y in states: # init
V[0][y] = start_p[y] + emit_p[y].get(obs[0], MIN_FLOAT)
path[y] = [y]
for t in xrange(1, len(obs)):
V.append({})
newpath = {}
for y in states:
em_p = emit_p[y].get(obs[t], MIN_FLOAT)
(prob, state) = max(
[(V[t - 1][y0] + trans_p[y0].get(y, MIN_FLOAT) + em_p, y0) for y0 in PrevStatus[y]])
V[t][y] = prob
newpath[y] = path[state] + [y]
path = newpath
(prob, state) = max((V[len(obs) - 1][y], y) for y in 'ES')
return (prob, path[state])
为了适配中⽂分词任务,Jieba对Viterbi算法做了如下的修改:
状态转移时应满⾜PrevStatus条件,即状态B的前⼀状态只能是E或者S,...
最后⼀个状态只能是E或者S,表⽰词的结尾。

与此同时,Jieba在实现公式(1)时,对其求对数,将相乘转化成了相加:
lnδt+1(i)=max{lnδt(j)+ln a ji+ln b i(o t+1)}
这就回答了上⾯的问题——为什么概率矩阵中出现了负数,是因为对其求了对数。

Jieba的HMM分词:
from jieba.finalseg import cut
sentence = "⼩明硕⼠毕业于中国科学院计算所,后在⽇本京都⼤学深造"
print('/'.join(cut(sentence)))
分词结果为“⼩明/硕⼠/毕业于/中国/科学院/计算/所/,/后/在/⽇/本京/都/⼤学/深造”,我们发现:关于“⽇本京都”出现分词错误的情况。

这是因为最⼤条件概率P(I|O)对应的状态序列不⼀定是分词正确的标注序列。

此外,HMM做了两个基本假设:
齐次Markov性假设,即任意时刻t的状态仅与前⼀时刻状态相关,与其他时刻的状态、时刻t均⽆关;
观测独⽴性假设,任意时刻t的观测仅依赖于该时刻HMM的状态,与其他的观测及状态均⽆关。

HMM受限于这两个假设(字符c t仅与前⼀字符c t−1相关),⽽不能学习到更多的特征,泛化能⼒有限。

4. 参考资料
[1] Xue, Nianwen. "Chinese word segmentation as character tagging." Computational Linguistics and Chinese Language Processing 8.1 (2003): 29-48.
[2] 李航. "统计学习⽅法." 清华⼤学出版社, 北京 (2012).
[3] Itenyh, .
[4] Django梦之队, .(源链接挂了,为转载链接)
Loading [MathJax]/jax/output/HTML-CSS/jax.js。

相关文档
最新文档