根據(jù)此訓(xùn)練得出隱馬爾科夫模型,用維特比算法實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的拼音輸入法。
原理簡(jiǎn)介
隱馬爾科夫模型
抄一段網(wǎng)上的定義:
隱馬爾可夫模型 (Hidden Markov Model) 是一種統(tǒng)計(jì)模型,用來描述一個(gè)含有隱含未知參數(shù)的馬爾可夫過程。其難點(diǎn)是從可觀察的參數(shù)中確定該過程的隱含參數(shù),然后利用這些參數(shù)來作進(jìn)一步的分析。
拼音輸入法中可觀察的參數(shù)就是拼音,隱含的參數(shù)就是對(duì)應(yīng)的漢字。
viterbi算法
維特比算法,思想是動(dòng)態(tài)規(guī)劃,代碼比較簡(jiǎn)單就不贅述。
代碼解釋
model定義
代碼見model/table.py文件,針對(duì)隱馬爾科夫的三個(gè)概率矩陣,分別設(shè)計(jì)了三個(gè)數(shù)據(jù)表存儲(chǔ)。這樣的好處很明顯,漢字的轉(zhuǎn)移概率矩陣是一個(gè)非常大的稀疏矩陣,直接文件存儲(chǔ)占用空間很大,并且加載的時(shí)候也只能一次性讀入內(nèi)存,不僅內(nèi)存占用高而且加載速度慢。此外數(shù)據(jù)庫的join操作非常方便viterbi算法中的概率計(jì)算。
數(shù)據(jù)表定義如下:
classTransition(BaseModel):
__tablename__='transition'
id=Column(Integer,primary_key=True)
previous=Column(String(1),nullable=False)
behind=Column(String(1),nullable=False)
probability=Column(Float,nullable=False)
classEmission(BaseModel):
__tablename__='emission'
id=Column(Integer,primary_key=True)
character=Column(String(1),nullable=False)
pinyin=Column(String(7),nullable=False)
probability=Column(Float,nullable=False)
classStarting(BaseModel):
__tablename__='starting'
id=Column(Integer,primary_key=True)
character=Column(String(1),nullable=False)
probability=Column(Float,nullable=False)
模型生成
代碼見train/main.py文件,里面的initstarting,initemission,init_transition分別對(duì)應(yīng)于生成隱馬爾科夫模型中的初始概率矩陣,發(fā)射概率矩陣,轉(zhuǎn)移概率矩陣,并把生成的結(jié)果寫入sqlite文件中。訓(xùn)練用到的數(shù)據(jù)集是結(jié)巴分詞里的詞庫,因?yàn)闆]有訓(xùn)練長(zhǎng)句子,最后運(yùn)行的結(jié)果也證明只能適用于短句輸入。
初始概率矩陣
統(tǒng)計(jì)初始化概率矩陣,就是找出所有出現(xiàn)在詞首的漢字,并統(tǒng)計(jì)它們出現(xiàn)在詞首的次數(shù),最后根據(jù)上述數(shù)據(jù)算出這些漢字出現(xiàn)在詞首的概率,沒統(tǒng)計(jì)的漢字就認(rèn)為出現(xiàn)在詞首的概率是0,不寫入數(shù)據(jù)庫。有一點(diǎn)注意的是為了防止概率計(jì)算的時(shí)候因?yàn)樵剿阍叫?dǎo)致計(jì)算機(jī)無法比較,所有的概率都進(jìn)行了自然對(duì)數(shù)運(yùn)算。統(tǒng)計(jì)的結(jié)果如下:
轉(zhuǎn)移概率矩陣
此處用到的是最簡(jiǎn)單的一階隱馬爾科夫模型,即認(rèn)為在一個(gè)句子里,每個(gè)漢字的出現(xiàn)只和它前面的的一個(gè)漢字有關(guān),雖然簡(jiǎn)單粗暴,但已經(jīng)可以滿足大部分情況。統(tǒng)計(jì)的過程就是找出字典中每個(gè)漢字后面出現(xiàn)的漢字集合,并統(tǒng)計(jì)概率。因?yàn)檫@個(gè)概率矩陣非常的大,逐條數(shù)據(jù)寫入數(shù)據(jù)庫過慢,后續(xù)可以優(yōu)化為批量寫入,提高訓(xùn)練效率。結(jié)果如下:
上圖展示的一后面出現(xiàn)概率最高的十個(gè)字,也挺符合日常習(xí)慣。
發(fā)射概率矩陣
通俗點(diǎn)就是統(tǒng)計(jì)每個(gè)漢字對(duì)應(yīng)的拼音以及在日常情況下的使用概率,已暴舉例,它有兩個(gè)讀音:bao和pu,難點(diǎn)就是找bao和pu出現(xiàn)的概率。此處統(tǒng)計(jì)用到了pypinyin模塊,把字典中的短語轉(zhuǎn)換為拼音后進(jìn)行概率統(tǒng)計(jì),但是某些地方讀音也不完全正確,最后運(yùn)行的輸入法會(huì)出現(xiàn)和拼音不匹配的結(jié)果。統(tǒng)計(jì)結(jié)果如下:
viterbi實(shí)現(xiàn)
代碼建input_method/viterbi.py文件,此處會(huì)找到最多十個(gè)局部最優(yōu)解,注意是十個(gè)局部最優(yōu)解而不是十個(gè)全局最優(yōu)解,但是這十個(gè)解中最優(yōu)的那個(gè)是全局最優(yōu)解,代碼如下:
def viterbi(pinyin_list):
"""
viterbi算法實(shí)現(xiàn)輸入法
Aargs:
pinyin_list (list): 拼音列表
"""
start_char=Emission.join_starting(pinyin_list[0])
V={char:probforchar,probinstart_char}
foriinrange(1,len(pinyin_list)):
pinyin=pinyin_list[i]
prob_map={}
forphrase,probinV.iteritems():
character=phrase[-1]
result=Transition.join_emission(pinyin,character)
ifnotresult:
continue
state,new_prob=result
prob_map[phrase+state]=new_prob+prob
ifprob_map:
V=prob_map
else:
returnV
returnV
結(jié)果展示
運(yùn)行input_method/viterbi.py文件,簡(jiǎn)單的展示一下運(yùn)行結(jié)果:
問題統(tǒng)計(jì):
統(tǒng)計(jì)字典生成轉(zhuǎn)移矩陣寫入數(shù)據(jù)庫的速度太慢,運(yùn)行一次要將近十分鐘。
發(fā)射概率矩陣數(shù)據(jù)不準(zhǔn)確,總有一些漢字的拼音不匹配。
訓(xùn)練集太小,實(shí)現(xiàn)的輸入法不適用于長(zhǎng)句子。
-
python
+關(guān)注
關(guān)注
56文章
4797瀏覽量
84694 -
隱馬爾科夫模型
+關(guān)注
關(guān)注
0文章
4瀏覽量
1340
原文標(biāo)題:隱馬爾科夫模型 python 實(shí)現(xiàn)簡(jiǎn)單拼音輸入法
文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論