NLTK中的Ngram模型和困惑度

14

为了让我的问题有上下文,我想要训练和测试/比较几个(神经)语言模型。为了专注于模型而不是数据准备,我选择使用nltk中的Brown语料库,并使用nltk提供的Ngrams模型作为基准进行比较。

因此,我的第一个问题实际上是关于nltk的Ngram模型行为的可疑之处。由于代码相当简短,我在这里贴出了它:

import nltk

print "... build"
brown = nltk.corpus.brown
corpus = [word.lower() for word in brown.words()]

# Train on 95% f the corpus and test on the rest
spl = 95*len(corpus)/100
train = corpus[:spl]
test = corpus[spl:]

# Remove rare words from the corpus
fdist = nltk.FreqDist(w for w in train)
vocabulary = set(map(lambda x: x[0], filter(lambda x: x[1] >= 5, fdist.iteritems())))

train = map(lambda x: x if x in vocabulary else "*unknown*", train)
test = map(lambda x: x if x in vocabulary else "*unknown*", test)

print "... train"
from nltk.model import NgramModel
from nltk.probability import LidstoneProbDist

estimator = lambda fdist, bins: LidstoneProbDist(fdist, 0.2) 
lm = NgramModel(5, train, estimator=estimator)

print "len(corpus) = %s, len(vocabulary) = %s, len(train) = %s, len(test) = %s" % ( len(corpus), len(vocabulary), len(train), len(test) )
print "perplexity(test) =", lm.perplexity(test)

我觉得非常可疑的是我得到了以下结果:

... build
... train
len(corpus) = 1161192, len(vocabulary) = 13817, len(train) = 1103132, len(test) = 58060
perplexity(test) = 4.60298447026

在困惑度为4.6的情况下,Ngram建模在该语料库上表现非常出色。如果我的理解正确,那么该模型平均应该能够在大约5次尝试中猜对正确的单词(虽然有13817种可能性...)。如果您能分享一下您对这个困惑度的评估经验(我不是很相信它),那就太好了。我在网上没有找到任何关于nltk Ngram模型的投诉(但也许我操作不当)。您知道还有哪些好的替代方案可以用于Ngram模型和计算困惑度吗?

谢谢!


3
看起来NLTK中的ngrams实现有误。SRILM(http://www.speech.sri.com/projects/srilm/)给出了一个约为150的困惑度(更可靠)。尽管如此,考虑到NLTK的普及度,我很惊讶没有人早些发现这个问题... - zermelozf
1个回答

4
您之所以得到低困惑度,是因为您使用了五元模型。如果您使用二元模型,您的结果将在更正常的范围内,大约在50-1000之间(或者大约在5到10位之间)。
鉴于您的评论,您是否正在使用NLTK-3.0alpha?您不应该这样做,至少不用于语言模型:

https://github.com/nltk/nltk/issues?labels=model

实际上,在问题得到解决之前,整个model模块已经从NLTK-3.0a4预发布版中删除了。


然而,使用5元组在棕色语料库上得到4的困惑度根本不现实。有人能够复现这个结果吗?对我来说,n元组实现存在缺陷或者有些地方我没有理解。 - zermelozf
嗯,你是在使用NLTK2.0还是3.0?请看我上面的“额外”回答。 - fnl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接