![65d6978c02842a6e21b202b0039ee1e5.png](https://img-blog.csdnimg.cn/img_convert/65d6978c02842a6e21b202b0039ee1e5.png)
先声明,srilm-python中计算出来的平滑值,跟我们看到的加1平滑公式算出来的不一样,感觉上,srilm的平滑计算不管是程序说明,还是文档说明,都很乱,甚至有时候跟我们见到的公式算出来的不一样。这里我们直接给出加法平滑的调用代码,至于另外6个平滑,直接改参数就可以了。后边,我们试试不用srilm-python,而直接用srilm的ngram-count,n-gram,如果依然对不上,那只能看看kenlm了,如果kenlm也对不上,我们放弃吧^_^。
首先,列出加法平滑公式
![163d9393e8b85fc8d514fb255bf2d28a.png](https://img-blog.csdnimg.cn/img_convert/163d9393e8b85fc8d514fb255bf2d28a.png)
输入的文本zcq_text.txt如下
$ cat zcq_text.txt
brown read holy bible
mark read a text book
he read a book by david
这个训练集是选自宗的《统计自然语言处理》。
下边我们用这个代码来计算句子brown read a book的2-gram加1平滑概率
import srilm.vocab
import srilm.stats
import srilm.discount
import srilm.ngram
import numpy as np
vocab = srilm.vocab.Vocab()
lm = srilm.ngram.Lm(vocab, 2)
stats = srilm.stats.Stats(vocab, 2)
# 读取训练集,构建词汇表
fname = 'data/zcq_text.txt'
# 读取词汇表
with open(fname) as infile:
for line in infile:
line = line.strip()
if line:
for w in line.split():
vocab.add(w)
print("词汇表长度=", len(vocab))
# n-gram计数
stats.count_file(fname)
for index, cnt in stats:
print(vocab.string(index), cnt)
for index, cnt in stats.iter(1):
print(vocab.string(index), cnt)
# 设置平滑方法
for i in range(1, 3):
lm.set_discount(i, srilm.discount.Discount(method='additive'))
lm.debug_level = 2
# 训练语言模型
lm.train(stats)
ngram2_li = [['<s>', 'brown'],
['brown', 'read'],
['read', 'a'],
['a', 'book'],
['book', '</s>']]
for word_li in ngram2_li:
logprob = lm.prob_ngram(vocab.index(word_li))
prob = np.power(10,logprob)
print(logprob, prob, word_li)
我们列出n-gram统计结果,n-gram统计是正确的,大家可以按照这些值以及平滑公式算算,结果跟程序计算的不一样。
['<s>', 'brown'] 1
['<s>', 'mark'] 1
['<s>', 'he'] 1
['brown', 'read'] 1
['read', 'holy'] 1
['read', 'a'] 2
['holy', 'bible'] 1
['bible', '</s>'] 1
['mark', 'read'] 1
['a', 'text'] 1
['a', 'book'] 1
['text', 'book'] 1
['book', '</s>'] 1
['book', 'by'] 1
['he', 'read'] 1
['by', 'david'] 1
['david', '</s>'] 1
['<s>'] 3
['</s>'] 3
['brown'] 1
['read'] 3
['holy'] 1
['bible'] 1
['mark'] 1
['a'] 2
['text'] 1
['book'] 2
['he'] 1
['by'] 1
['david'] 1
最后,附上程序运行结果
-1.1903316974639893 0.064516129137182 ['<s>', 'brown']
-0.8893017172813416 0.12903225367473986 ['brown', 'read']
-1.0142403841018677 0.09677420580692216 ['read', 'a']
-1.0142403841018677 0.09677420580692216 ['a', 'book']
-0.8893017172813416 0.12903225367473986 ['book', '</s>']
鹅厂同学,你能给我解释一下为什么吗?。还有个问题,就是同一份代码多次运行,居然结果会出现特别特别小的概率值,这都是啥稳定性呀,太不靠谱,以前用srilm源码写程序时候,倒是没遇到过这种问题,大家慎用srilm-python的ngram模块吧。
至于其他平滑方法,只需要修改 lm.set_discount(i, srilm.discount.Discount(method='additive')) 的method参数为'kneser-ney', 'good-turing', 'witten-bell', 'chen-goodman', 'absolute', 'additive', 'natural'。
如果srilm-python就只能提供一个n-gram计数的话,那还不如直接用HanLP呢,根本不需要再用srilm了。