Transformers 怎样用 repetition_penalty 缓解重复输出
来源:17golang原创
时间:2026-11-14 21:04:54 124浏览 收藏
我在调本地文本生成时,最容易误判的一类问题就是“模型一直重复”。有时是生成长度没有设好,有时是停止条件不匹配,也有时确实需要给已经出现过的 token 增加一点惩罚。Transformers 的 repetition_penalty 正是控制这一倾向的参数,但它不是“禁止重复”的开关。
官方地址:https://huggingface.co/docs/transformers/
比较稳妥的做法是先把 max_new_tokens 固定,再从 1.0 逐步往上试。官方文档说明,1.0 表示不施加惩罚,数值越大,惩罚越强;因此它更适合缓解明显的复读,而不是替代提示词、停止条件或模型本身的修正。
先把“重复”与“输出太长”分开
如果每次生成的上限都不同,就很难判断重复是参数造成的,还是模型只是获得了更长的续写空间。第一轮比较时,固定提示词、模型、输入格式和 max_new_tokens,只改变 repetition_penalty。
from transformers import AutoModelForCausalLM, AutoTokenizer
# 这里只准备一次输入,比较时不要同时更换模型或提示词。
model_name = "your-model-id"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name)
# 固定生成上限,避免把“更长所以更容易重复”误当成惩罚失效。
inputs = tokenizer("请用三点说明如何记录接口变更。", return_tensors="pt")
# 先用 1.0 建立没有 repetition penalty 的对照组。
output_ids = model.generate(
**inputs,
max_new_tokens=128,
repetition_penalty=1.0,
)
print(tokenizer.decode(output_ids[0], skip_special_tokens=True))
这里的 max_new_tokens 只控制最多新增多少 token,不包括输入提示词。把它固定后,才有资格比较“相同长度预算下,重复程度有没有变化”。不要把示例中的模型 ID 当成通用可运行值;不同模型的加载方式、设备和对话模板可能不同。

从 1.0 开始逐步提高惩罚值
我通常把 1.0 当作基线,然后只增加一个小幅度,观察三件事:重复短语是否减少、关键术语是否仍然保留、回答是否变得突兀或过早转向。以小步长比较,比直接把数值调得很大更容易找到模型与任务的平衡点。
penalties = [1.0, 1.05, 1.1, 1.15]
for penalty in penalties:
# 只改变 repetition_penalty,其余生成条件保持不变。
output_ids = model.generate(
**inputs,
max_new_tokens=128,
repetition_penalty=penalty,
)
text = tokenizer.decode(output_ids[0], skip_special_tokens=True)
print(f"penalty={penalty}: {text}")
这些数值是调参起点,不是官方保证的最佳区间。若 1.05 到 1.15 仍然复读,可以继续小步增加;一旦出现专有名词被替换、句子不完整或文本变得生硬,就应回退,而不是继续加大惩罚。repetition_penalty 影响的是生成倾向,并不承诺输出一定符合事实或格式。
把配置保存下来,避免比较时漏改参数
当同一个模型要在多个任务中使用时,把生成参数集中到 GenerationConfig 会更清楚。官方文档也建议通过它统一保存生成配置;直接传给 generate() 的同名参数则会覆盖配置中的值。
from transformers import GenerationConfig
# 用一份配置保存可复现的生成边界,便于之后只替换 penalty。
generation_config = GenerationConfig(
max_new_tokens=128,
repetition_penalty=1.1,
do_sample=True,
temperature=0.7,
top_p=0.9,
)
# 生成调用显式接收配置,便于在日志中记录本轮参数。
output_ids = model.generate(
**inputs,
generation_config=generation_config,
)
result = tokenizer.decode(output_ids[0], skip_special_tokens=True)
print(result)
这里把采样参数一并写出,是为了让实验条件完整;它们和 repetition_penalty 不是同一职责。do_sample=True 会启用采样,temperature 和 top_p 会改变候选分布。如果你正在定位重复原因,第一轮不要同时大幅修改这些值。

它与 no_repeat_ngram_size 有什么区别
两者都能处理重复,但强度和语义不同:
| 参数 | 作用 | 更适合的场景 | 主要副作用 |
|---|---|---|---|
repetition_penalty | 调低已出现 token 的生成倾向 | 重复明显但仍希望保留自然表达 | 过高会让关键词和常用词变得难以再次出现 |
no_repeat_ngram_size | 限制同尺寸 n-gram 再次出现 | 需要明确禁止连续片段复现 | 固定术语、代码或模板句可能被误伤 |
max_new_tokens | 限制新增 token 数量 | 控制回答长度和成本 | 过小会截断正常答案,不能单独解决复读 |
如果需求是“同一段连续短语绝不能再次出现”,可以考虑 no_repeat_ngram_size;如果只是希望模型别围绕同一词打转,先试较小的 repetition_penalty。两者叠加前,先确认任务确实需要这么强的限制。
重复仍然存在时,检查这三个边界
一是提示词和对话模板
聊天模型通常依赖特定的角色格式或 chat template。输入格式不符合模型预期时,输出可能异常重复;这不是把惩罚值加大就能稳定修好的问题。
二是停止条件和长度预算
没有合适的结束 token,或者 max_new_tokens 设得过大,都会给重复留下更多空间。先确认模型的 eos_token_id、输入 padding 方式和长度设置,再判断是否需要惩罚。
三是解码策略的组合
Transformers 支持贪心、采样和 beam search 等生成方式。重复现象可能来自解码策略、温度、top-p、提示词和模型能力的组合。一次只改一个变量,并记录完整配置,才能知道是哪项改变产生了效果。
我的调参记录方式
不要只看“读起来好不好”,至少记录下面四列:惩罚值、重复片段、关键术语是否保留、答案是否提前结束。对摘要、代码解释、结构化输出分别准备固定提示词,因为不同任务对重复的容忍度不同。
experiment = {
"prompt_id": "api-change-01", # 用固定编号绑定同一条测试提示词。
"max_new_tokens": 128, # 每轮比较保持同一长度上限。
"repetition_penalty": 1.1, # 只记录本轮真正变化的惩罚值。
"keep_terms": ["HTTP", "JSON"], # 检查专有名词是否被错误回避。
}
# 这里的字典只是记录实验条件,不代表已经得到某个模型的质量结论。
print(experiment)
如果较高惩罚值减少了重复,却让答案遗漏关键术语,那么这轮结果不能算成功。对面向用户的回答,完整、可读和术语准确通常比“绝不重复”更重要。
常见问题
repetition_penalty 设置为 1.0 会怎样?
官方文档将 1.0 定义为不施加重复惩罚,适合当作对照组。
是不是数值越大越好?
不是。数值越大代表更强的惩罚,但可能损伤关键词复用、固定格式和自然语句,应按任务逐步比较。
它能解决模型事实错误吗?
不能。它只改变生成过程中的候选倾向,不会补充知识,也不能替代检索、提示词设计或输出校验。
为什么我加了惩罚还是重复?
优先检查提示模板、停止 token、长度上限和解码策略,再确认你比较的确实是同一输入与同一模型。必要时才考虑 n-gram 限制或更换模型。
一句话总结:先用固定的 max_new_tokens 建立基线,再小步提高 repetition_penalty,同时观察重复减少和关键信息保留是否平衡;只有当任务需要硬限制连续片段时,才把 no_repeat_ngram_size 纳入比较。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
268 收藏
-
261 收藏
-
212 收藏
-
科技周边 · 人工智能 | 44分钟前 | python · 人工智能 · 并行处理 index Hugging Face Datasets Datasets shard num_shards contiguous417 收藏
-
280 收藏
-
科技周边 · 人工智能 | 47分钟前 | python · Transformers TextIteratorStreamer 流式生成 AsyncTextIteratorStreamer StoppingCriteria198 收藏
-
279 收藏
-
161 收藏
-
453 收藏
-
科技周边 · 人工智能 | 54分钟前 | 人工智能 · padding Transformers tokenizer max_length attention_mask truncation return_tensors352 收藏
-
科技周边 · 人工智能 | 58分钟前 | 人工智能 · 文本分类 softmax Transformers AutoModelForSequenceClassification logits id2label172 收藏
-
243 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习