本文将讲述怎样利用HMM进行拼音转汉字。
准备阶段
python 2.7;
安装 python 工具包 ChineseTone,直接使用 pip install 安装;
运行程序的过程中,可能还会用到其他工具包,自行使用 pip install 安装即可;
下载拼音转汉字程序,https://github.com/letiantian/Pinyin2Hanzi;
原理讲述
HMM涉及三个问题,拼音转汉字程序是以下问题的应用:
在给定模型
μ=(A,B,π)
μ
=
(
A
,
B
,
π
)
和观察序列
O=O1,O2,⋯,OT
O
=
O
1
,
O
2
,
⋯
,
O
T
情况下,如何选择在一定意义下“最优”的状态序列
Q=q1q2⋯qT
Q
=
q
1
q
2
⋯
q
T
,使得该状态序列“最好地解释”观察序列?
对应到拼音转汉字程序:
状态序列:汉字序列
观察序列:拼音序列
A:状态转移概率矩阵,汉字转汉字的概率矩阵;
B:从某个状态观察到特定符号的概率分布矩阵,由某个汉字得到某个拼音的概率分布矩阵;
π
π
:初始状态概率分布,汉字的概率分布;
实验步骤
从 github 上下载的程序分别根据 HMM 和 DAG 实现了拼音转汉字的功能,这里我们只讲述 HMM 的实现步骤。
主要用到了 train 和 Pinyin2Hanzi 这两个文件夹中的内容:
train:根据外部语料,统计计算得到 HMM 的模型
μ=(A,B,π)
μ
=
(
A
,
B
,
π
)
,其实就是两个矩阵和一个向量;
Pinyin2Hanzi:根据模型
μ=(A,B,π)
μ
=
(
A
,
B
,
π
)
和 观察序列(输入的拼音序列),使用 Viterbi 算法,计算得到状态序列(输出的汉字序列,可以有多个);
步骤1:删除以下文件夹中的内容,以便更好的观察程序的输出:
Pinyin2Hanzi-master\Pinyin2Hanzi-master\train\hmm\result;
Pinyin2Hanzi-master\Pinyin2Hanzi-master\Pinyin2Hanzi\data;
步骤2:运行 process_article.py
功能:将 train\hmm\article 中的语料转换为句子;
输入:train\hmm\article 中的所有文件;
输出:train\hmm\result\sentence.txt;
错误:UnicodeDecodeError: ‘utf8’ codec can’t decode byte 0xc4 in position 1: invalid continuation byte;
解决方法:因为 train\hmm\article 中的文件名字含有中文,将其更名为0-6.txt;
步骤3:运行 process_hzpy.py
功能:统计 hanzipinyin.txt 中出现的所有汉字、拼音、每个拼音对应的所有汉字;
输入:train\hmm\hanzipinyin.txt;
输出:
train\hmm\result\all_states.txt;
train\hmm\result\all_observations.txt;
train\hmm\result\pinyin2hanzi.txt;
步骤4:运行 gen_base.py
功能:根据sentence.txt、word.txt、hanzipinyin.txt,统计计算得到三个文件;
输入:sentence.txt、word.txt、hanzipinyin.txt;
输出:
result/base_start.json,一个汉字出现在序列(sentence or word)开头的次数,为了计算初始状态概率分布;
result/base_emission.json,一个汉字对应的各种拼音(多音字)在语料 (sentence.txt、word.txt)中出现的次数,为了计算从某个状态观察到特定符号的概率分布矩阵;
result/base_transition.json,一个汉字后面出现某个汉字的次数,为了计算状态转移矩阵;
步骤5:运行 process_finally.py
功能:根据 pinyin2hanzi.txt 和步骤四输出的三个文件,统计计算得到模型对应的两个矩阵和一个向量,以及某个拼音(符号)对应的所有汉字(状态);
输入:pinyin2hanzi.txt、base_start.json、base_emission.json、base_transition.json;
输出:
Pinyin2Hanzi/data/hmm_py2hz.json,将 pinyin2hanzi.txt 中的无效行去掉;
Pinyin2Hanzi/data/hmm_start.json,将 base_start.json 中的次数转换为频率;
Pinyin2Hanzi/data/hmm_emission.json,将 base_emission.json 中的次数转换为频率;
Pinyin2Hanzi/data/hmm_transition.json,将 base_transition.json 中的次数转换为频率;
至此,我们已经根据 article 文件夹中的语料以及 word.txt、hanzipinyin.txt 统计计算得到了模型对应两个矩阵和一个向量
步骤6:有了模型和输入状态序列(拼音序列),我们就可以根据 viterbi 算法计算得到候选的符号序列(汉字序列),主要代码见 Pinyin2Hanzi\implement.py 和 Pinyin2Hanzi\viterbi.py
示例代码:
#coding:utf-8
from Pinyin2Hanzi import DefaultHmmParams
from Pinyin2Hanzi import viterbi
hmmparams = DefaultHmmParams()
## 2个候选
result = viterbi(hmm_params=hmmparams, observations=('ni', 'zhi', 'bu', 'zhi', 'dao'), path_num = 2)
for item in result:
print(item.score, item.path)
'''输出
1.3155294593897203e-08 ['你', '知', '不', '知', '道']
3.6677865125992192e-09 ['你', '只', '不', '知', '道']
'''
## 2个候选,使用对数打分
result = viterbi(hmm_params=hmmparams, observations=('ni', 'zhi', 'bu', 'zhi', 'dao'), path_num = 2, log = True)
for item in result:
print(item.score, item.path)
'''输出
-18.14644152864202 ['你', '知', '不', '知', '道']
-19.423677486918002 ['你', '只', '不', '知', '道']
'''
## 2个候选,使用对数打分
result = viterbi(hmm_params=hmmparams, observations=('ni', 'zhii', 'bu', 'zhi', 'dao'), path_num = 2, log = True)
for item in result:
print(item.score, item.path)
# 发生KeyError,`zhii`不规范
请将以上代码放到目录 Pinyin2Hanzi-master\Pinyin2Hanzi-master 中运行。