GPT2微调时attention mask与pad token id警告及生成异常问题
解决GPT2微调Wikitext-2时推理输出混乱的问题
核心原因
你遇到的训练警告和推理异常直接相关:GPT2原生设计没有pad token,即便你在tokenizer里指定了pad_token,模型配置(config)里的pad_token_id仍未同步设置,导致训练时attention mask没有正确屏蔽pad token的位置,模型在训练过程中学习到了无效的pad token上下文信息,最终干扰了推理时的文本生成逻辑。
具体修复步骤
1. 同步模型与Tokenizer的pad_token_id
GPT2模型本身不会自动继承Tokenizer的pad_token设置,必须手动同步:
from transformers import GPT2Tokenizer, GPT2LMHeadModel # 初始化Tokenizer并指定特殊token tokenizer = GPT2Tokenizer.from_pretrained("gpt2") tokenizer.bos_token = "<|startoftext|>" tokenizer.eos_token = "<|endoftext|>" # 推荐用eos_token作为pad_token,避免额外新增未训练的token tokenizer.pad_token = tokenizer.eos_token # 初始化模型并同步pad_token_id model = GPT2LMHeadModel.from_pretrained("gpt2") model.config.pad_token_id = tokenizer.pad_token_id
2. 数据集处理时显式生成attention mask
在tokenize阶段必须返回attention mask,让模型知道哪些位置是需要忽略的pad内容:
def tokenize_function(examples): return tokenizer( examples["text"], truncation=True, padding="max_length", max_length=512, return_attention_mask=True # 关键:显式返回attention mask ) tokenized_datasets = raw_datasets.map(tokenize_function, batched=True)
3. 训练时确保传入attention mask
如果用Trainer API,只要数据集包含attention_mask字段,Trainer会自动处理;如果手动写训练循环,要把所有输入字段传入模型:
# 手动训练循环示例 for batch in train_dataloader: inputs = {k: v.to(device) for k, v in batch.items()} outputs = model(**inputs) loss = outputs.loss loss.backward() optimizer.step() optimizer.zero_grad()
4. 推理时规范生成参数
推理时必须显式指定pad_token_id,避免模型生成pad token或提前终止:
prompt = "<|startoftext|>你的输入文本内容" inputs = tokenizer(prompt, return_tensors="pt").to(device) outputs = model.generate( **inputs, max_new_tokens=100, pad_token_id=tokenizer.pad_token_id, eos_token_id=tokenizer.eos_token_id, do_sample=True, temperature=0.7 ) print(tokenizer.decode(outputs[0], skip_special_tokens=True))
补充说明
你手动添加的<|startoftext|>和<|endoftext|>标记是正确的,确保了文本边界一致性,但必须和Tokenizer指定的bos/eos token完全匹配。训练时loss下降只能说明模型在拟合训练数据,但如果attention mask未正确设置,模型会把pad token当成有效文本学习,最终导致推理逻辑混乱。
内容的提问来源于stack exchange,提问作者Toakley
相关产品推荐
相关产品推荐

