Python从零搭建文本生成预测模型:改进后效果下降问题咨询
问题分析与优化方案
核心结论
参考多个前文词的上下文做文本预测是非常成熟合理的方案(本质就是经典的n元语法模型),你遇到的效果退化问题是建模逻辑设计缺陷+代码实现疏漏共同导致的,和多上下文这个思路本身无关。
现有方案的核心问题
建模逻辑底层错误
你目前的实现没有遵循多上下文文本预测的基本逻辑:高阶n元语法的统计对象是连续的词序列,而非不同位置的单个词的加权计数。
举个例子,你想参考前2个词预测下一个,统计的应该是「连续2个词共同出现后,下一个词的频率」,而不是把第一个词后面第2位的词频、第二个词后面第1位的词频随便加权相加。这种跨位置的词频相加没有任何语言统计依据,相当于把不相关的搭配权重混在一起,自然会生成"to at"这类完全不符合搭配逻辑的结果。
你举的示例里的语义合并逻辑就是典型错误:cat后第二位的to和jumps后第一位的to完全是两个维度的统计值,直接相加得到的7没有任何实际意义,不能作为预测权重。
代码实现层面的疏漏
你提供的伪代码本身逻辑就存在多处矛盾:
- 数据结构定义前后不一致,一会儿是
dict[0]['foo']这种双层字典结构,一会儿又用dict['cat']存数组,运行时必然存在取值错误 semantics=semantics/2这个权重折半操作没有任何统计依据,人为压低了合理搭配的权重,反而提高了低频错误搭配的选中概率- 上下文窗口的维护逻辑混乱,
remember变量的取值、删除、追加操作完全不符合多上下文的窗口滑动要求
可直接落地的优化方案
你可以基于原来的字典实现思路,直接改成标准的n元语法模型即可,不需要复杂改动:
- 先确定你要使用的上下文长度n,比如n=2就是参考前面2个词预测下一个(二阶模型),n越大语义连贯性越好,但对训练语料量的要求也越高
- 构建统计字典的时候,键直接存连续n个词的元组,值还是后续词的频率字典,示例如下:
# 二阶模型的字典结构示例 ngram_dict = { ('cat', 'jumps'): {'to': 5, 'over': 2}, ('jumps', 'to'): {'the': 6, 'a': 3}, ('jumps', 'over'): {'the': 4, 'a': 1} }
- 生成文本的时候维护一个长度为n的滑动窗口:
# 初始窗口取文本开头的n个词 window = ('cat', 'jumps') output = list(window) while output[-1] != '///ending///': # 用当前窗口查后续词频率 next_words = ngram_dict.get(window, {}) if not next_words: # 遇到未见过的窗口可以退化成n-1阶平滑处理,比如只取最后1个词查一阶字典 next_words = one_gram_dict.get(window[-1], {}) # 按权重选下一个词 next_word = random.choices(list(next_words.keys()), weights=next_words.values())[0] output.append(next_word) # 滑动窗口:去掉最前面的词,加入新词 window = window[1:] + (next_word,)
这个方案实现简单,效果会远好于你现在的自定义加权逻辑,也比一阶模型的语义连贯性强很多。
内容的提问来源于stack exchange,提问作者Aguaraguazu
相关产品推荐
相关产品推荐

