nltk 3.8.1
我正在使用KneserNeyInterpolated对语料库中的句子进行训练和测试。
看起来nltk实现的这个平滑算法在处理词汇表之外的单词时不知道该如何处理,因为在测试过程中,模型在这些单词上的困惑度是无穷大。但这个问题只出现在特定的情况下,更多的情况如下。
训练:
train_input, train_vocab = padded_everygram_pipeline(order=2, text=train_tokens)
lm = KneserNeyInterpolated(order=2)
lm.fit(train_input, train_vocab)
然后我在bigram上测试它(根据#3065的一些建议)
from nltk.util import bigrams
from nltk.lm.preprocessing import pad_both_ends
grams = list(bigrams(pad_both_ends('a motorcycle sits parked across from a herd of livestock'.split(), n=2)))
print(grams)
print(lm.entropy(grams))
print(lm.perplexity(grams))
结果是
[('<s>', 'a'), ('a', 'motorcycle'), ('motorcycle', 'sits'), ('sits', 'parked'), ('parked', 'across'), ('across', 'from'), ('from', 'a'), ('a', 'herd'), ('herd', 'of'), ('of', 'livestock'), ('livestock', '</s>')]
inf
inf
我查看了模型在这些bigram上的困惑度,发现对于('of', 'livestock')
,困惑度是无穷大,但对于('livestock', '</s>')
,困惑度是一个数字,不是无穷大。问题词(我怀疑是“livestock”)在训练期间没有出现过:lm.vocab['livestock']
是0。
我测试了另一个OOV词('radiator'),观察到了完全相同的情况:当'radiator'是bigram中的第二个词(第一个词可以是任何词)时,困惑度是无穷大,但当'radiator'是第一个词时,忽略第二个词是什么,困惑度是一个数字。为什么会发生这样的行为?
MLE和Laplace工作正常,问题并不存在。
出了什么问题?
7条答案
按热度按时间wlwcrazw1#
我会调查这个问题。我也遇到了同样的错误。
f0brbegy2#
我尝试了一些事情,这是结果。第二组数字是MLE
无上下文
1.3831080559223603
0.4679138720730883
inf
inf
第一个二元组位置无上下文
1.7481417052901929
0.8058221352008101
inf
inf
第二个二元组位置无上下文
inf
inf
inf
inf
全部无上下文
#inf
#inf
#inf
#inf
我不确定无上下文的词是否有特定的处理方式。你能做更多的测试来确定这是否是数学问题还是其他问题吗?也许提供预期和实际结果。从我所了解的,KneserNey插值法很难判断OOV的预期功能是什么。
axzmvihb3#
这也可能与问题$x_{1e0f1}x$有关。
rdlzhqv94#
你好,我遇到了同样的问题。我通过降级NLTK到3.6.1版本解决了这个问题。看起来在3.8.1版本中存在一些bug,因为相同的代码在3.6.1版本中可以正常工作。
ntjbwcob5#
我确认在使用nltk 3.6.1时,这个错误不会出现。3.6.1和3.8.1之间的区别在于KneserNey的实现:在3.8.1中,实现已经将折扣与计数延续一起实现,这很重要,因为n-grams的顺序不同(较低或较高),例如在3.38中的
P_continuation
和Jurafsky and Martin。我认为这是Kneser-Ney算法的一个改进,因此将其作为uni-/和bi-grams与更高阶的n-grams具有不同的折扣因子是有意义的。3.6.1中的代码没有实现这种直觉:它为所有n-grams设置了一个固定的折扣因子。
这是否意味着问题出在延续计数的实现上?如果是这样的话,那么3.6.1中的代码执行的是绝对折扣而不是Kneser-Ney折扣,因此使用来自nltk==3.6.1的代码并将其视为Kneser-Ney方法是不正确的,因为它是不完整的。3.8.1中的代码看起来更完整,但在计算延续计数方面显然存在错误。
tkclm6bt6#
我收回一些话:nltk 3.8.1似乎正确地实现了带有折扣的Kneser-Ney算法。这些部分是算法实现中的
alpha
和gamma
,它们对应于Jurafsky等人原始公式。然而,在测试过程中,它似乎无法处理OOV(词汇表外)单词——这就是问题所在。在Jurafsky的文章中,他们讨论了这个问题以及可能的解决方案,见方程式3.42。
有人能指出代码中实现这一点的部分吗?
sqougxex7#
Can someone point to part in the code which implements that?
I'm not super familiar with this, but it looks to me like the part of the code that implements the unknown word handling as described by Jurafsky was captured by the 3.6.1 fixed discount factor of 1.0/vocab_length in unigram_score, whereas now, unigram_score doesn't include that term any longer, and so unknown words which of course have a continuation count of 0 get a score of 0.
I think it might be that it should, in addition to dividing continuation count by total count, also add the lambda(E)*1/V term as seen in Jurafsky 3.41? That way unknown unigrams wouldn't be zero, just close to it, and all other unigrams would have their score very slightly increased by the uniform distribution?