Transformers 序列分类实战指南:用 DistilBERT 微调 IMDb 情感分类模型
2026/9/7 14:47:36 网站建设 项目流程

Transformers 序列分类实战指南:用 DistilBERT 微调 IMDb 情感分类模型

【免费下载链接】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 的序列分类(Text Classification)任务文档为核心,完整讲解如何基于 IMDb 电影评论数据集微调 DistilBERT 实现情感二分类:从数据加载、分词预处理、动态填充(Dynamic Padding)、精度指标计算,到使用Trainer训练、上传模型,以及通过pipeline与手动 forward 两种方式完成推理,并结合仓库源码剖析关键参数与底层实现。

一、任务概览

文本分类是最常见的 NLP 任务之一:为一段文本指派一个类别或标签。最典型的形态是情感分析——把一段文本标记为「正面(Positive)」「负面(Negative)」或「中性(Neutral)」。

本指南覆盖的完整链路:

  1. 在 IMDb 数据集(stanfordnlp/imdb)上微调 DistilBERT,判断电影评论是正面还是负面;
  2. 使用微调后的模型进行预测。

环境准备

开始前确认安装必要的依赖库:

pip install transformers datasets evaluate accelerate

建议登录 Hugging Face 账户,以便后续下载模型并把训练成果分享给社区:

>>> from huggingface_hub import notebook_login >>> notebook_login()

二、加载 IMDb 数据集

使用 🤗 Datasets 库加载数据集:

>>> from datasets import load_dataset >>> imdb = load_dataset("stanfordnlp/imdb")

查看一条样本:

>>> imdb["test"][0] { "label": 0, "text": "I love sci-fi and am willing to put up with a lot. Sci-fi movies/TV are usually underfunded, ...", }

该数据集只有两个字段:

  • text:电影评论文本;
  • label0表示负面评论,1表示正面评论。

三、数据预处理

3.1 加载分词器并编写预处理函数

加载 DistilBERT 的分词器,用于处理text字段:

>>> from transformers import AutoTokenizer >>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilbert-base-uncased")

编写预处理函数:完成编码,并通过truncation=True将超长文本截断到 DistilBERT 可接受的最大输入长度:

>>> def preprocess_function(examples): ... return tokenizer(examples["text"], truncation=True)

使用 🤗 Datasets 的Dataset.map把该函数应用到整个数据集。batched=True会按批处理数据,显著加速map

tokenized_imdb = imdb.map(preprocess_function, batched=True)

3.2 用DataCollatorWithPadding做动态填充

效率最高的做法是动态填充(dynamic padding):只把每个批次内的序列填充到该批最长序列,而不是把全部数据都填充到全局最大长度。创建数据收集器:

>>> from transformers import DataCollatorWithPadding >>> data_collator = DataCollatorWithPadding(tokenizer=tokenizer)

源码级解析DataCollatorWithPadding定义于 src/transformers/data/data_collator.py,其默认行为与可调参数值得注意:

  • padding:默认True(等价于'longest',填充到批内最长序列);也可设为'max_length'(填充到max_length或模型最大输入长度)或False/'do_not_pad'(不填充,序列长度可以不一致);
  • max_lengthNone时不限制长度;
  • pad_to_multiple_of:把序列填充为指定值的倍数,尤其在 NVIDIA Volta(计算能力 >= 7.0)及更高架构上对启用 Tensor Cores 有帮助;
  • return_tensors:默认返回"pt"(PyTorch 张量),也支持"np"
  • 一个实用细节:__call__会自动把批次中的label键重命名为labels(见 data_collator.py 第 233-238 行),而Trainer的 loss 计算正是读取labels键——这就是为什么 IMDb 数据集的label字段无需改名即可直接训练。

提示:Trainer在传入tokenizer时默认就使用动态填充,此时可以不显式指定data_collator

四、评估指标:accuracy

在训练过程中嵌入评估指标有助于监控模型表现。用 🤗 Evaluate 库加载准确率指标:

>>> import evaluate >>> accuracy = evaluate.load("accuracy")

然后编写compute_metrics函数:把预测 logits 与真实标签交给EvaluationModule.compute计算准确率:

>>> import numpy as np >>> def compute_metrics(eval_pred): ... predictions, labels = eval_pred ... predictions = np.argmax(predictions, axis=1) ... return accuracy.compute(predictions=predictions, references=labels)

该函数现在就绪,将在训练配置环节被Trainer调用。

五、训练模型

5.1 定义标签映射id2labellabel2id

训练前先建立「类别 id ↔ 标签名」的双向映射:

>>> id2label = {0: "NEGATIVE", 1: "POSITIVE"} >>> label2id = {"NEGATIVE": 0, "POSITIVE": 1}

为什么这两张映射很重要?从源码看,PreTrainedConfig在 src/transformers/configuration_utils.py 中把id2label/label2id作为标准字段保存进config.json;若不提供,配置会自动生成LABEL_0LABEL_1这样的占位名(见 configuration_utils.py 第 393-396 行)。显式传入id2label后,后续pipeline推理输出、model.config.id2label查询都会返回可读的"NEGATIVE"/"POSITIVE",而不是LABEL_0

5.2 加载分类模型

AutoModelForSequenceClassification加载 DistilBERT,并传入分类数与标签映射:

>>> from transformers import AutoModelForSequenceClassification, TrainingArguments, Trainer >>> model = AutoModelForSequenceClassification.from_pretrained( ... "distilbert/distilbert-base-uncased", num_labels=2, id2label=id2label, label2id=label2id ... )

注意加载的是...ForSequenceClassification变体:它在 DistilBERT 主干之上附加了一个分类头(classification_head),输出形状为[batch, num_labels]的 logits。DistilBERT 的完整实现位于 src/transformers/models/distilbert/modeling_distilbert.py。

5.3 配置TrainingArguments并启动训练

只剩三步:

  1. TrainingArguments中设置训练超参。唯一必填项是output_dir(模型保存位置);设置push_to_hub=True可把模型上传到 Hub(需已登录);Trainer会在每个 epoch 结束时评估精度并保存检查点。
  2. 把训练参数连同模型、数据集、分词器、数据收集器、compute_metrics一起传给Trainer
  3. 调用trainer.train()开始微调。
>>> training_args = TrainingArguments( ... output_dir="my_awesome_model", ... learning_rate=2e-5, ... per_device_train_batch_size=16, ... per_device_eval_batch_size=16, ... num_train_epochs=2, ... weight_decay=0.01, ... eval_strategy="epoch", ... save_strategy="epoch", ... load_best_model_at_end=True, ... push_to_hub=True, ... ) >>> trainer = Trainer( ... model=model, ... args=training_args, ... train_dataset=tokenized_imdb["train"], ... eval_dataset=tokenized_imdb["test"], ... processing_class=tokenizer, ... data_collator=data_collator, ... compute_metrics=compute_metrics, ... ) >>> trainer.train()

各关键参数说明:

参数取值作用
output_dir"my_awesome_model"检查点与最终模型的保存目录(必填)
learning_rate2e-5预训练模型微调的典型学习率量级
per_device_train_batch_size16单设备训练批大小
per_device_eval_batch_size16单设备评估批大小
num_train_epochs2训练轮数
weight_decay0.01权重衰减,缓解过拟合
eval_strategy/save_strategy"epoch"每个 epoch 结束时评估并保存检查点
load_best_model_at_endTrue训练结束后加载评估指标最优的检查点
push_to_hubTrue训练完成后把模型推送到 Hub

训练完成后,用trainer.push_to_hub()把模型分享给所有人:

>>> trainer.push_to_hub()

提示:Trainer的完整用法可参考仓库训练文档(docs/source/ar/training.md)。

5.4 进阶:用命令行脚本训练

如果你更习惯脚本化、参数化的训练流程(而非 notebook),仓库提供了完整的 PyTorch 分类训练脚本 examples/pytorch/text-classification/run_classification.py,配套说明见 examples/pytorch/text-classification/README.md。该脚本用HfArgumentParser把三个参数 dataclass(DataTrainingArgumentsModelArgumentsTrainingArguments)统一解析为命令行参数,其中与数据相关的常用项包括:

  • --dataset_name:通过 🤗 Datasets 加载的数据集名;
  • --text_column_names:输入数据集中的文本列名(多列时可用--text_column_delimiter拼接成一句);
  • --train_split_name/--validation_split_name/--test_split_name:自定义各阶段使用的 split 名;
  • --do_regression:执行回归而非分类(默认从数据集推断任务类型)。

此外,脚本还支持--max_length--pad_to_max_length等长度控制参数,与本文DataCollatorWithPadding的动态填充策略互为对照:批内填充(本文方案)通常更省时,而固定最大长度则便于跨数据集对齐序列长度。

六、推理(Inference)

微调完成后即可用于推理。

6.1 使用pipeline快速推理

最简方式是pipeline。创建一个情感分析 pipeline 并传入模型,再输入待分类文本:

>>> from transformers import pipeline >>> classifier = pipeline("sentiment-analysis", model="stevhliu/my_awesome_model") >>> classifier(text) [{'label': 'POSITIVE', 'score': 0.9994940757751465}]

其中text为:

>>> text = "This was a masterpiece. Not completely faithful to the books, but enthralling from beginning to end. Might be my favorite of the three."

源码级解析sentiment-analysis任务实际由 src/transformers/pipelines/text_classification.py 中的TextClassificationPipeline处理,其postprocess方法(第 178-219 行)决定了分数的计算方式:

  • num_labels > 1(本例num_labels=2)或problem_type == "single_label_classification":对 logits 做softmax
  • num_labels == 1problem_type == "multi_label_classification":做sigmoid
  • problem_type == "regression":不做任何变换(NONE);
  • 也可用function_to_apply参数显式指定"sigmoid"/"softmax"/"none"
  • top_k参数控制返回结果条数:top_k=1(默认)返回单个{"label", "score"}字典;top_k取更大值或None时返回按分数降序排列的多个标签字典——多分类任务下查看完整概率分布时有用;
  • 一个工程细节:_forward会检测模型forward签名中是否含use_cache参数并强制置为False(第 171-176 行),因为分类任务用不到 KV cache,强制关闭可避免无谓显存开销;
  • 文本对分类:传入{"text": ..., "text_pair": ...}字典即可,preprocess会将其转发给分词器的text/text_pair

6.2 手动推理:从 tokenize 到argmax

也可以不依赖 pipeline,手动复现整个推理链路。

第一步:分词并返回 PyTorch 张量:

>>> from transformers import AutoTokenizer >>> tokenizer = AutoTokenizer.from_pretrained("stevhliu/my_awesome_model") >>> inputs = tokenizer(text, return_tensors="pt")

第二步:把输入送入模型,取出logits

>>> from transformers import AutoModelForSequenceClassification >>> model = AutoModelForSequenceClassification.from_pretrained("stevhliu/my_awesome_model") >>> with torch.no_grad(): ... logits = model(**inputs).logits

第三步:取概率最高的类别 id,并用id2label映射回可读标签:

>>> predicted_class_id = logits.argmax().item() >>> model.config.id2label[predicted_class_id] 'POSITIVE'

可以看到,model.config.id2label正是训练时通过from_pretrained传入并随config.json持久化的那张映射表——这就是第五节强调显式传入id2label/label2id的原因。

七、小结与延伸

本指南完整覆盖了序列分类的标准工作流:

  1. 数据load_dataset加载 IMDb,text/label两字段;
  2. 预处理AutoTokenizer编码 +truncationDataset.map(batched=True)批量分词,DataCollatorWithPadding批内动态填充(自动把label重命名为labels);
  3. 评估evaluate.load("accuracy")+compute_metrics,每 epoch 评估并配合load_best_model_at_end保留最优检查点;
  4. 训练AutoModelForSequenceClassification加载分类头,TrainingArguments组织超参,Trainer.train()执行,push_to_hub()发布;
  5. 推理pipeline("sentiment-analysis")一行调用(softmax/sigmoid 自动选择),或手动tokenizer → model.forward → logits.argmax → config.id2label全链路复现。

想继续深入,可以阅读仓库中的序列分类任务文档原文 docs/source/ar/tasks/sequence_classification.md、分类训练脚本 examples/pytorch/text-classification/run_classification.py 及其 README,以及 DistilBERT 的 configuration_distilbert.py 与 modeling_distilbert.py 源码。

【免费下载链接】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),仅供参考

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

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

立即咨询