T5模型微调实战:避开那些让你模型“跑偏”的五个深坑
如果你尝试过微调T5模型,大概率经历过这样的时刻:满怀期待地跑完训练脚本,看着损失曲线平稳下降,结果在验证集上的表现却一塌糊涂,或者模型干脆就“学废了”,输出一些不知所云的内容。这往往不是模型本身的问题,而是微调过程中的一些细节,像隐藏的陷阱,悄无声息地影响了最终结果。
微调,尤其是基于LoRA等参数高效方法的微调,看似流程标准化,实则处处是学问。它不仅仅是调用几行API,更是一场对数据、模型结构和训练动力学的精细调控。本文面向那些已经熟悉Hugging Face transformers 基础操作,但在实战中仍会碰壁的开发者。我们将深入五个最容易被忽视,却又至关重要的环节——从数据进入模型前的最后一道关卡,到LoRA超参数背后的数学逻辑——通过正反案例对比,帮你把模型“调教”到最佳状态,让每一次训练都有的放矢。
1. 数据预处理:不止于Tokenization,关键在于标签对齐
很多人认为数据预处理就是调用 tokenizer() 函数,设置一下 max_length 和 padding 就万事大吉。但对于T5这类Seq2Seq模型,预处理的一个核心陷阱在于标签(labels)的处理。错误的标签格式会直接导致模型无法学习到有效的映射关系。
1.1 标签掩码:-100的秘密
在序列到序列任务中(如文本分类、摘要生成),我们需要将目标序列(标签)也转换为token ids。一个常见的错误是,对标签序列进行tokenization后,直接将其 input_ids 作为 labels 输入模型。这忽略了损失函数计算时对填充符(pad token)的忽略机制。
注意:在计算交叉熵损失时,通常需要忽略掉填充部分,防止模型学习去预测填充符。在PyTorch中,通过将对应位置的标签值设置为
-100来实现。
错误示范:
# 这是一个会导致问题的预处理函数片段
def preprocess_function_wrong(examples):
inputs = tokenizer(examples["source_text"], truncation=True, padding="max_length")
labels = tokenizer(examples["target_text"], truncation=True, padding="max_length")
# 错误:直接将标签的input_ids赋给labels
inputs["labels"] = labels["input_ids"]
return inputs
这种方式下,填充符(假设pad_token_id=0)的标签值也是0,损失函数会计算这些位置的损失,干扰模型学习。
正确做法:
def preprocess_function_correct(examples):
# 编码输入
model_inputs = tokenizer(
examples["source_text"],
max_length=128,
padding="max_length",
truncation=True
)
# 编码标签
with tokenizer.as_target_tokenizer():
labels = tokenizer(
examples["target_text"],
max_length=32, # 标签序列通常较短
padding="max_length",
truncation=True
)
# 关键步骤:将标签中的pad_token_id替换为-100
labels["input_ids"] = [
[(l if l != tokenizer.pad_token_id else -100) for l in label]
for label in labels["input_ids"]
]
model_inputs["labels"] = labels["input_ids"]
return model_inputs
这里使用了 tokenizer.as_target_tokenizer() 上下文管理器,确保对标签使用可能不同的特殊规则(如前缀空格)。核心的一步是遍历 labels[“input_ids”],将所有的 pad_token_id 替换为 -100。
1.2 序列长度不匹配的隐患
另一个坑出现在输入和输出序列长度差异巨大的任务中。例如,在文本分类任务中,输入可能是一段长文本,而输出只是一个类别词(如“积极”、“消极”)。
- 问题:如果为输入和输出设置相同的


4666

被折叠的 条评论
为什么被折叠?



