我一直在尝试实现Stupid Backoff语言模型(描述可用here,但我相信细节与问题无关)。
问题是,代码正在工作并产生预期的结果,但工作速度比我预期的要慢。我想出了减速的部分就在这里(而不是在训练部分):
def compute_score(self, sentence):
length = len(sentence)
assert length <= self.n
if length == 1:
word = tuple(sentence)
return float(self.ngrams[length][word]) / self.total_words
else:
words = tuple(sentence[::-1])
count = self.ngrams[length][words]
if count == 0:
return self.alpha * self.compute_score(sentence[1:])
else:
return float(count) / self.ngrams[length - 1][words[:-1]]
def score(self, sentence):
""" Takes a list of strings as argument and returns the log-probability of the
sentence using your language model. Use whatever data you computed in train() here.
"""
output = 0.0
length = len(sentence)
for idx in range(length):
if idx < self.n - 1:
current_score = self.compute_score(sentence[:idx+1])
else:
current_score = self.compute_score(sentence[idx-self.n+1:idx+1])
output += math.log(current_score)
return output
self.ngrams是一个嵌套字典,有n个条目。这些条目中的每一个都是形式字典(word_i,word_i-1,word_i-2 ...... word_i-n):这种组合的计数。
self.alpha是一个常数,定义了去n-1的惩罚。
self.n是程序在字典self.ngrams中查找的元组的最大长度。它设置为3(虽然设置为2或甚至1不是任何东西)。这很奇怪,因为Unigram和Bigram模型在几分之一秒内工作得很好。
我正在寻找的答案不是我自己的代码的重构版本,而是一个提示,其中一部分是计算上最昂贵的(因此我可以弄清楚自己如何重写它并获得最多教育从解决这个问题中获益)。
请耐心等待,我只是一个初学者(进入编程世界两个月)。感谢。
UPD: 我使用time.time():
使用相同的数据计算运行时间Unigram = 1.9
Bigram = 3.2
愚蠢的退避(n = 2)= 15.3
愚蠢的退避(n = 3)= 21.6
(由于time.time的精确度不高,它在一些比原来更大的数据上。)
答案 0 :(得分:0)
如果句子很长,那么实际运行的大部分代码都在这里:
def score(self, sentence):
for idx in range(len(sentence)): # should use xrange in Python 2!
self.compute_score(sentence[idx-self.n+1:idx+1])
def compute_score(self, sentence):
words = tuple(sentence[::-1])
count = self.ngrams[len(sentence)][words]
if count == 0:
self.compute_score(sentence[1:])
else:
self.ngrams[len(sentence) - 1][words[:-1]]
这并不意味着工作代码 - 它只是删除了不重要的部分。
关键路径中的流量因此是:
compute_score()
加上以下内容2.这会创建一个长度为3的新列表。您可以使用itertools.islice()
来避免这种情况。
-1
步骤参数来避免这种情况。self.ngrams
中查找,这是一个嵌套的dict,第一个键是一个数字(如果这个级别是一个列表可能会更快;反正只有三个键?),第二个是元组创建。(sentence[2], sentence[1])
,或self.ngrams
中执行另一次查找,隐式创建另一个新元组(words[:-1])
。总之,我认为你遇到的最大问题是列表和元组的重复和嵌套创建和销毁。