在基于Sampling解码的文本生成任务里,模型按照概率分布逐个挑词,容易陷入把刚说过的短语一遍遍吐出来的窘境。这种现象在开放域对话、故事续写和机器翻译中都很常见,轻则显得啰嗦,重则整段废话循环。要从根本上缓解,工程上主要依赖两类手段:一类是概率层面的Repetition Penalty,另一类是序列层面的No Repeat N-gram约束。

Repetition Penalty到底是什么
Repetition Penalty直译是重复惩罚,核心想法非常直观:当一个词已经在前面生成过,我们就人为把它在下一步选词时的概率调低,让模型更倾向说点新的东西。具体实现通常是在softmax之前,把出现过的词的logit除以一个大于1的系数,或者没出现过的乘以小于1的系数,从而拉开新旧词的差距。
这个系数一般取1.1到1.5之间。设得太小比如1.01几乎没效果,设得太大例如2.0以上,模型为了躲重复会硬凑生僻词,语句通顺度反而崩盘。很多开源推理框架像Hugging Face Transformers里都直接带了这个参数,叫做repetition_penalty,调起来不需要自己写代码。
需要注意的是,它只看词粒度的命中,不关心词之间的距离。如果一段话很长,早期出现过的词到后面依旧会被压概率,这可能误伤本来就该重复的功能词,比如中文里的“的”或者英文的“the”。因此光靠它不够,还要配合别的机制。
No Repeat N-gram约束的工作方式
No Repeat N-gram是一种硬性规则,要求生成过程中任意连续的n个词组成的片段,在全文中不能出现第二次。比如no_repeat_ngram_size设为3,那么模型刚吐出“今天天气真好”,后面就不能再原样接出这三个词连在一起的串。
实现上,解码器每生成一个新词,就把末尾n-1个词加上新词组成候选ngram,去历史里查重,命中就直接把该词概率置为负无穷,从根本上剔掉这个选项。它比Repetition Penalty更狠,属于不让选就不让选,不会因为系数温和就漏网。
不过ngram尺寸要选好。size=2只能防“的的”这种相邻重复,size=4以上又容易把正常修辞也禁掉,一般对话场景设3就够用。另外它依赖准确的分词,英文按空格切还行,中文必须用同一套tokenizer,否则拦不住。
两者如何搭配使用
实际项目里,单用Repetition Penalty容易留漏洞,单用No Repeat N-gram又太死板。推荐做法是先开ngram拦截明显复读,再叠加温和的penalty处理更远处的词频偏移。这样既能保住句式多样,也不至于语句变形。
下面给出一个常见参数组合参考:
| 参数 | 推荐值 | 作用说明 |
|---|---|---|
| temperature | 0.8 | 控制随机性,太高更乱更低更死 |
| repetition_penalty | 1.2 | 软性打压已出词概率 |
| no_repeat_ngram_size | 3 | 禁止三词片段重复出现 |
在聊天机器人项目里,这样设完后用户明显感觉机器人少了很多“好的好的好的”式应答。摘要系统也能避免把原文句子抄两遍。如果还重复,可以再微调penalty到1.3,或把ngram_size提到4试试。
常见误区与排查思路
有人以为penalty越大越好,结果模型满嘴生造词,这是典型误区。重复的本质是模型没学到长程依赖,不是光靠罚就能教会。另一误区是ngram_size乱设,导致正常排比句被砍,读起来像结巴。
排查时建议先关掉所有约束看原始输出,确认是局部复读还是全局啰嗦。局部就加ngram,全局飘忽再上penalty。也可以打印出被禁掉的候选词,确认没有误伤关键术语。多跑几组样本对比,才能定出适合自己业务的数值。
重复控制不是消灭所有重复,而是让重复出现在该出现的地方,比如强调和固定搭配,而不是无意义的循环。
小结
Repetition Penalty与No Repeat N-gram约束分别从概率和规则两端入手,是解决Sampling生成重复的黄金组合。理解它们各自边界,按场景调参,就能用较低成本大幅改善生成质量。后续也可探索配合top-k、top-p进一步稳定输出。
repetition_penaltyno_repeat_ngram文本生成去重修改时间:2026-08-11 01:57:27