Transformers 预训练模型微调实战:从 Trainer 到原生 PyTorch 训练循环
2026/9/10 8:27:17 网站建设 项目流程

Transformers 预训练模型微调实战:从 Trainer 到原生 PyTorch 训练循环

【免费下载链接】transformers🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.项目地址: https://gitcode.com/GitHub_Trending/tra/transformers

导读

本文基于 🤗 Transformers 官方日语文档 docs/source/ja/training.md 编写,系统讲解如何对预训练模型进行微调(Fine-tuning):先走一遍使用Trainer的高层训练流程,再深入原生 PyTorch 手写训练循环的底层实现。读完本文,你将掌握从数据集加载与分词、训练超参数配置、评估指标接入,到优化器与学习率调度器创建、完整训练循环与评估的全链路能力,并能将这些技能直接复用到文本分类、生成、序列标注等各类任务上。


为什么需要微调

使用预训练模型可以显著降低计算成本与碳排放,无需从零开始训练即可获得 SOTA 模型。🤗 Transformers 提供了数千个面向不同任务的预训练模型,而将预训练模型迁移到自己的特定任务数据集上继续训练,这一过程称为微调(Fine-tuning)——它是当今 NLP 领域最强大的训练技术之一。

微调的本质是:模型不再从随机权重起步,而是在一个已经学到大语言规律的权重基础上,用较小的领域数据继续优化。因此它所需的算力、数据和时间都远小于从零预训练。在动手之前,请确保已按官方安装指南准备好环境,并安装了datasetsevaluateaccelerate等配套库。

准备数据集(Prepare a dataset)

微调的第一步是下载并预处理数据集。本教程使用 Yelp Reviews 数据集(包含 5 个情感标签的评论数据)进行序列分类任务的演示。

加载数据集

通过datasets库的load_dataset一行代码即可加载:

>>> from datasets import load_dataset >>> dataset = load_dataset("yelp_review_full") >>> dataset["train"][100] {'label': 0, 'text': 'My expectations for McDonalds are t rarely high. ...'}

每个样本包含两个字段:text(评论文本)与label(情感标签 0~4),共 5 个类别。

分词与批处理

分词器负责把文本转换为模型可理解的 token id,同时处理可变序列长度问题(padding 与 truncation)。利用datasetsmap方法,可以将预处理函数一次性应用到整个数据集:

>>> from transformers import AutoTokenizer >>> tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-cased") >>> def tokenize_function(examples): ... return tokenizer(examples["text"], padding="max_length", truncation=True) >>> tokenized_datasets = dataset.map(tokenize_function, batched=True)
  • padding="max_length"将每条样本填充到固定最大长度,便于组成 batch;
  • truncation=True截断超长序列;
  • batched=True让预处理函数对一批样本(而非单条)批量执行,充分利用 GPU/CPU 向量化能力,显著缩短预处理时间。

构建小子集加速实验

为缩短运行时间,可以创建完整数据集的小型子集用于快速验证流程:

>>> small_train_dataset = tokenized_datasets["train"].shuffle(seed=42).select(range(1000)) >>> small_eval_dataset = tokenized_datasets["test"].shuffle(seed=42).select(range(1000))

固定seed=42保证每次实验数据划分一致、结果可复现。

使用 PyTorch Trainer 微调

🤗 Transformers 的Trainer类专门针对 Transformers 模型训练做了优化,免去手动编写训练循环的繁琐,同时支持日志记录、梯度累积、混合精度等一系列训练选项与特性(对应实现见 src/transformers/trainer.py)。

加载模型并指定标签数

>>> from transformers import AutoModelForSequenceClassification >>> model = AutoModelForSequenceClassification.from_pretrained("google-bert/bert-base-cased", num_labels=5)

关于"部分权重未使用"警告:加载时你可能会看到"某些预训练权重未被使用、某些权重被随机初始化"的警告,这完全正常。BERT 预训练的分类头会被丢弃,替换为随机初始化的新分类头;微调的过程正是让这个新分类头在序列分类任务上学习,同时把预训练模型学到的知识迁移过来。

配置训练超参数(TrainingArguments)

TrainingArguments类承载所有训练选项与可调超参数。其字段定义可在 src/transformers/training_args.py 中查看,这里仅指定输出目录即可开始:

>>> from transformers import TrainingArguments >>> training_args = TrainingArguments(output_dir="test_trainer")

常用超参数及其源码默认值一览(均为TrainingArguments的默认配置):

参数默认值说明
output_dirNone(必填)模型预测与 checkpoint 的输出目录
per_device_train_batch_size8每张设备(GPU/TPU core/CPU)上的训练 batch 大小
num_train_epochs3.0总训练轮数
max_steps-1若为正数则覆盖num_train_epochs,适用于流式数据集
learning_rate5e-5优化器初始学习率
lr_scheduler_type"linear"学习率调度器类型,见SchedulerType枚举
warmup_steps0从 0 线性预热到learning_rate的步数
optim"adamw_torch"(PyTorch 2.8+ 为"adamw_torch_fused"优化器类型
weight_decay0.0权重衰减系数(自动排除 bias 与 LayerNorm 参数)
gradient_accumulation_steps1梯度累积步数,有效 batch =per_device_train_batch_size × 设备数 × 累积步数
max_grad_norm1.0梯度裁剪范数,设 0 关闭
bf16/fp16False混合精度开关,硬件支持时优先bf16
eval_strategy"no"何时评估:"no"/"steps"/"epoch"
eval_stepsNoneeval_strategy="steps"时的评估间隔,默认回退到logging_steps
save_strategy"steps"何时保存 checkpoint
load_best_model_at_endFalse训练结束时加载最优 checkpoint(需设置eval_strategy
logging_steps500日志输出间隔

接入评估指标(Evaluate)

Trainer在训练过程中不会自动评估模型性能,需要你把计算指标的函数传给它。evaluate库提供了简洁的accuracy指标加载方式:

>>> import numpy as np >>> import evaluate >>> metric = evaluate.load("accuracy")

由于所有 🤗 Transformers 模型返回的是logits,在调用metric.compute前必须先用argmax把 logits 转换为预测类别:

>>> def compute_metrics(eval_pred): ... logits, labels = eval_pred ... predictions = np.argmax(logits, axis=-1) ... return metric.compute(predictions=predictions, references=labels)

若希望在微调过程中监控指标,可在训练参数中通过eval_strategy指定评估时机——例如每个 epoch 结束时报告一次:

>>> from transformers import TrainingArguments, Trainer >>> training_args = TrainingArguments(output_dir="test_trainer", eval_strategy="epoch")

组装 Trainer 并开始训练

把模型、训练参数、训练/测试数据集与评估函数组装为Trainer对象,随后调用train()

>>> trainer = Trainer( ... model=model, ... args=training_args, ... train_dataset=small_train_dataset, ... eval_dataset=small_eval_dataset, ... compute_metrics=compute_metrics, ... )
>>> trainer.train()

Trainer内部会自动完成:optimizer 与 scheduler 的创建(见 src/transformers/trainer.py 的create_optimizer/create_scheduler)、梯度累积、梯度裁剪、混合精度、日志记录与 checkpoint 保存。训练结束后还可调用trainer.save_model()保存微调后的模型与分词器。

使用原生 PyTorch 微调

Trainer一行代码即可完成微调;但如果你想完全掌控训练过程,也可以使用原生 PyTorch 手写训练循环。此部分对应文档中的 "Train in native Pytorch" 章节。

环境清理与数据格式调整

若此前已运行过Trainer流程,建议释放显存:

>>> del model >>> del trainer >>> torch.cuda.empty_cache()

随后调整数据集格式,使其适配模型输入:

# 1. 模型不接受原始文本输入,删除 text 列 >>> tokenized_datasets = tokenized_datasets.remove_columns(["text"]) # 2. 将 label 列重命名为 labels(模型期望的参数名) >>> tokenized_datasets = tokenized_datasets.rename_column("label", "labels") # 3. 设置数据集格式为 PyTorch 张量 >>> tokenized_datasets.set_format("torch")

同样构建小子集加速验证:

>>> small_train_dataset = tokenized_datasets["train"].shuffle(seed=42).select(range(1000)) >>> small_eval_dataset = tokenized_datasets["test"].shuffle(seed=42).select(range(1000))

创建 DataLoader

用 PyTorch 的DataLoader包装数据集以迭代 batch:

>>> from torch.utils.data import DataLoader >>> train_dataloader = DataLoader(small_train_dataset, shuffle=True, batch_size=8) >>> eval_dataloader = DataLoader(small_eval_dataset, batch_size=8)

加载序列分类模型(同样指定 5 个标签):

>>> from transformers import AutoModelForSequenceClassification >>> model = AutoModelForSequenceClassification.from_pretrained("google-bert/bert-base-cased", num_labels=5)

优化器与学习率调度器

使用 PyTorch 的AdamW优化器:

>>> from torch.optim import AdamW >>> optimizer = AdamW(model.parameters(), lr=5e-5)

学习率调度器可以使用transformersget_scheduler统一创建,其实现位于 src/transformers/optimization.py。该函数通过TYPE_TO_SCHEDULER_FUNCTION映射表(见同文件 L944-L957)把调度器名称解析为具体实现:

>>> from transformers import get_scheduler >>> num_epochs = 3 >>> num_training_steps = num_epochs * len(train_dataloader) >>> lr_scheduler = get_scheduler( ... name="linear", optimizer=optimizer, num_warmup_steps=0, num_training_steps=num_training_steps ... )

get_scheduler支持的name取值(即SchedulerType枚举)包括:linearcosinecosine_with_restartspolynomialconstantconstant_with_warmupinverse_sqrtreduce_on_plateaucosine_with_min_lrcosine_warmup_with_min_lrwarmup_stable_decaygreedy。注意:除constant等少数类型外,大多数调度器要求提供num_warmup_steps,否则会抛出ValueError

指定运行设备

尽可能使用 GPU,否则 CPU 上训练可能耗时数小时:

>>> import torch >>> device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu") >>> model.to(device)

如果没有云 GPU,可以使用 Colaboratory 或 SageMaker StudioLab 等托管笔记本免费获得 GPU 资源。

手写训练循环

使用tqdm显示训练进度,标准的三轮循环如下:

>>> from tqdm.auto import tqdm >>> progress_bar = tqdm(range(num_training_steps)) >>> model.train() >>> for epoch in range(num_epochs): ... for batch in train_dataloader: ... batch = {k: v.to(device) for k, v in batch.items()} ... outputs = model(**batch) ... loss = outputs.loss ... loss.backward() ... optimizer.step() ... lr_scheduler.step() ... optimizer.zero_grad() ... progress_bar.update(1)

训练循环的关键步骤:

  1. 将每个 batch 的张量搬运到device
  2. 前向传播得到loss,调用loss.backward()计算梯度;
  3. optimizer.step()更新权重;
  4. lr_scheduler.step()推进学习率调度;
  5. optimizer.zero_grad()清零梯度,避免累积。

手写评估循环

Trainercompute_metrics不同,原生循环中我们用evaluate.add_batch累积所有 batch 的预测,最后统一计算指标:

>>> import evaluate >>> metric = evaluate.load("accuracy") >>> model.eval() >>> for batch in eval_dataloader: ... batch = {k: v.to(device) for k, v in batch.items()} ... with torch.no_grad(): ... outputs = model(**batch) ... logits = outputs.logits ... predictions = torch.argmax(logits, dim=-1) ... metric.add_batch(predictions=predictions, references=batch["labels"]) >>> metric.compute()

评估时务必:

  • 调用model.eval()切换为推理模式(关闭 dropout 等);
  • 使用torch.no_grad()禁用梯度计算,节省显存与时间;
  • 对 logits 取argmax得到类别预测后送入metric.add_batch累积。

从源码看 Trainer 的底层实现

为进一步理解Trainer做了什么,可以对照源码确认关键环节:

  • 优化器与调度器Trainer.create_optimizer()(src/transformers/trainer.py#L1227)根据TrainingArguments.optim创建优化器;create_scheduler()(src/transformers/trainer.py#L1303)内部同样调用get_schedulerlr_scheduler_type生成调度器——与原生 PyTorch 路径完全一致;
  • 训练主循环Trainer.train()(src/transformers/trainer.py#L1406)封装了数据迭代、梯度累积、梯度裁剪、混合精度、日志与 checkpoint 逻辑;
  • 评估Trainer.evaluate()(src/transformers/trainer.py#L2635)负责在eval_strategy指定的时机执行评估并调用compute_metrics

TrainingArguments的字段校验逻辑(src/transformers/training_args.py#L1526-L1550)还做了若干约束:例如设置eval_strategy="steps"时必须提供eval_stepslogging_stepsload_best_model_at_end=Truesave_strategyeval_strategy必须匹配(除非save_strategy="best")。了解这些约束可避免运行时参数报错。

进阶参考与示例脚本

  • 仓库的 examples/pytorch/text-classification 目录提供了可直接运行的文本分类微调脚本:run_glue.py(基于Trainer的 GLUE 基准微调)、run_glue_no_trainer.py(基于Accelerate与原生训练循环)、run_classification.pyrun_xnli.py,可作为实战模板;
  • 仓库 notebooks 目录收录了针对不同任务微调模型的各类 notebook;
  • 更多Trainer特性(自定义损失函数、内存高效评估、checkpoint 等)与回调机制可参阅 docs/source/en/trainer_recipes.md、docs/source/en/trainer_callbacks.md 等英文文档。

总结

本文完整复现了官方日语教程的核心脉络:从 Yelp Reviews 数据集的加载与分词预处理,到Trainer高层 API 的微调(含TrainingArguments超参数、compute_metrics评估接入、eval_strategy评估时机),再到原生 PyTorch 手写训练循环(含DataLoaderAdamWget_scheduler调度器、完整训练与评估代码),并结合仓库源码说明了Trainer内部与原生路径的一致性。无论你偏好开箱即用的Trainer,还是希望完全掌控每一步的原生 PyTorch,本文给出的代码均可直接复制运行,帮助你快速上手预训练模型的微调实践。

【免费下载链接】transformers🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.项目地址: https://gitcode.com/GitHub_Trending/tra/transformers

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询