登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  人工智能

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 当成通用可运行值;不同模型的加载方式、设备和对话模板可能不同。

输入提示词、已生成 token、候选 token 分数与输出文本之间的静态关系图
图1:输入提示词、已生成 token、候选分数和输出文本的关系说明图;它用于理解参数作用,不是运行截图或推理结果。

从 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 会改变候选分布。如果你正在定位重复原因,第一轮不要同时大幅修改这些值。

repetition_penalty、no_repeat_ngram_size、采样参数和输出长度的职责边界图
图2:生成配置的职责边界说明图,区分重复倾向、连续 n-gram 限制、随机性和长度上限;这是原创静态结构图,不是软件界面截图。

它与 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 纳入比较。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>