Tokenizer 左填充和右填充应该怎么选
来源:17golang原创
时间:2026-09-28 07:32:01 399浏览 收藏
Tokenizer 左填充还是右填充,不能只看模型名字:decoder-only 模型做批量文本生成时通常选左填充;因果语言模型训练、encoder-only 和多数 encoder-decoder 数据整理流程通常使用右填充,并优先遵循模型默认值、模型卡和 DataCollator 的约定。单条输入没有发生 padding 时,方向不会产生实际差异。
官方文档:https://huggingface.co/docs/transformers/main_classes/tokenizer
- decoder-only 批量
generate():优先padding_side="left"。 - decoder-only 训练:多数数据管线使用右填充,并把 PAD 对应标签设为
-100。 - encoder-only 分类、抽取任务:通常保持 tokenizer 默认右填充,并正确传入 attention_mask。
- encoder-decoder:源序列和目标标签交给模型配套 tokenizer/DataCollator 管理,通常不要自行改方向。
padding_side 控制的到底是什么
批次里的文本长度不同,无法直接组成矩形张量。padding=True 会把较短序列补到批次最长长度,padding="max_length" 则补到指定或模型允许的最大长度;padding_side 决定 PAD 放在有效 token 左边还是右边。官方 Tokenizer API 只允许 "left" 或 "right",未显式设置时采用对应 tokenizer 类的默认值。
方向本身并不能让模型忽略 PAD。真正告诉模型哪些位置无效的是 attention_mask。如果还在训练,损失函数还需要通过标签中的 -100 忽略 PAD 位置;只改 padding_side 而漏掉这两个掩码,结果仍可能异常。
为什么 decoder-only 批量生成优先左填充
自回归生成要从每条提示词的最后一个有效 token 继续预测。右填充时,短提示词的批次末端是 PAD;许多生成流程从张量最后一个位置取得下一 token 的 logits,即使 attention_mask 屏蔽了注意力,末端位置仍不是短提示词真正的结尾。Hugging Face 的 LLM 生成教程因此明确建议 decoder-only 批量生成使用左填充。

许多 decoder-only LLM 没有独立 pad_token。推理时常见做法是临时把 EOS 作为 PAD,并始终传入 attention_mask。这样不是说 PAD 变成了“真正的句尾”,而是利用掩码让补齐位置不参与有效上下文。
from transformers import AutoModelForCausalLM, AutoTokenizer
model_id = "your-decoder-only-model"
# 批量生成让有效提示词末端位于同一列,避免从右侧 PAD 位置续写。
tokenizer = AutoTokenizer.from_pretrained(model_id, padding_side="left")
model = AutoModelForCausalLM.from_pretrained(model_id)
if tokenizer.pad_token_id is None:
# 推理时可复用 EOS 作为 PAD,但必须保留 attention_mask。
tokenizer.pad_token = tokenizer.eos_token
batch = tokenizer(
["用一句话解释缓存", "列出三个 HTTP 状态码并说明用途"],
padding=True,
return_tensors="pt",
)
# 把 input_ids 和 attention_mask 一起传入生成接口。
generated = model.generate(**batch, max_new_tokens=32)
texts = tokenizer.batch_decode(generated, skip_special_tokens=True)
按模型与任务选择填充方向

| 模型与任务 | 常见选择 | 主要理由 |
|---|---|---|
| decoder-only 批量生成 | 左填充 | 让批次末端对应每条提示词的最后一个有效 token |
| decoder-only 因果 LM 训练 | 右填充 | 常见数据整理器和标签移位流程按右填充组织 |
| encoder-only 分类/抽取 | 通常右填充 | 双向注意力配合 attention_mask,遵循预训练与 tokenizer 默认 |
| encoder-decoder | 通常右填充 | 源序列、目标标签和 DataCollator 有各自约定 |
| 单条且不补齐 | 无实际差异 | 输入中没有 PAD 位置 |
“通常”不是绝对规则。某些模型会自行构造 position_ids,某些模型卡会明确要求方向,远程推理服务也可能在内部重新组批。可靠做法是先保持 tokenizer 默认,再只为明确的生成或训练问题调整,并把配置写进推理或训练入口,避免同一个 tokenizer 在不同阶段被隐式修改。
训练时不要误伤真实 EOS
因果语言模型训练通常右填充,让每条样本从索引 0 开始放置有效 token。创建 labels 后,应根据 attention_mask 把 PAD 位置设为 -100。如果 pad_token 与 eos_token 共用同一个 ID,不要按“token ID 等于 EOS”批量屏蔽,否则可能连样本中真实的 EOS 也从损失中去掉。
batch = tokenizer(
texts,
padding=True,
truncation=True,
return_tensors="pt",
)
# labels 从 input_ids 复制,不能直接修改模型输入张量。
labels = batch["input_ids"].clone()
# 按 attention_mask 屏蔽补齐位置,保留正文里的真实 EOS 标签。
labels[batch["attention_mask"] == 0] = -100
batch["labels"] = labels
若使用 Transformers 提供的 DataCollator,应先查看它对 pad_token、label_pad_token_id 和左右填充的处理,不要在外层再重复改 labels。对于 token classification,还要同步对齐 word_ids 与标签;对 seq2seq,目标端的 label padding 由专用 collator 处理更稳妥。
快速检查配置是否真的生效
不要只打印 tokenizer.padding_side。取两条长度明显不同的文本组成批次,同时检查 input_ids 与 attention_mask:左填充时,短序列开头应出现 PAD 且 mask 为 0;右填充时,PAD 和 0 应出现在末尾。
sample = tokenizer(
["短句", "这是一条明显更长的输入文本"],
padding=True,
return_tensors="pt",
)
# 同时观察 token 与掩码,确认 PAD 一侧和无效位置一致。
print("padding_side:", tokenizer.padding_side)
print("input_ids:\n", sample["input_ids"])
print("attention_mask:\n", sample["attention_mask"])
decoder-only 生成还应做一组 A/B:同样的两条提示词分别左填充和右填充,固定解码参数,比较短提示词的输出是否异常;训练则比较有效 token 数、被屏蔽标签数和 loss 是否包含 PAD。这样得到的是任务级证据,而不是对 padding_side 的泛化猜测。
常见误区
- 把左填充当成 LLM 的全局配置:生成和训练可能需要不同方向,应分开创建或显式设置 tokenizer。
- 只传 input_ids:批量补齐后必须传 attention_mask,否则模型可能把 PAD 当成上下文。
- 把 pad_token_id 和 eos_token_id 相同理解为完全等价:它们的数值可以复用,但语义要由 attention_mask 和 labels 区分。
- 忽略 position_ids:自定义模型或手写 forward 时,左填充可能改变位置编号;优先调用模型官方生成接口。
- 混淆 padding_side 与 truncation_side:前者决定补齐位置,后者决定超长序列从哪端截断,两者要分别设置。
相关问题
单条推理也必须左填充吗?
如果单条输入没有补齐,左右方向不会改变张量。只有单条也使用 padding="max_length" 时,方向才会实际出现。
attention_mask 正确,右填充生成就一定没问题吗?
不一定。decoder-only 批量生成通常还会从批次最后一个位置取得下一 token logits,右填充会让短序列末端落在 PAD 上,因此官方 LLM 教程仍建议左填充。
可以永久修改 tokenizer.padding_side 吗?
可以,但更推荐在训练和生成入口显式设置并记录,因为同一模型的两个阶段可能采用不同方向。保存 tokenizer 时也要确认配置是否随制品一起交付。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
258 收藏
-
360 收藏
-
100 收藏
-
468 收藏
-
268 收藏
-
206 收藏
-
458 收藏
-
478 收藏
-
477 收藏
-
113 收藏
-
438 收藏
-
412 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习