自然语言处理【NLP】系列之文本分类——为情绪识别微调BERT(小白级入门教程)
本篇博文主要用来学习如何为一个文本分类任务微调BERT模型,本次具体要做的任务是情绪识别,属于入门级教程哦!
本篇博文继续参考:愤怒的可乐:【实战篇】是时候彻底弄懂BERT模型了(收藏,已修复)
https://helloai.blog.csdn.net/article/details/120232707
目录
首先用pandas读取csv,'D:\\nlp_prj\\IMDB.csv'是我csv数据集的存储路径。
把 Pandas DataFrame 转换成 HuggingFace Dataset
下载并加载用于预训练bert-base-uncased模型的分词器
从 Hugging Face 的 Dataset 对象中 删除不需要的列(字段)
本篇博文主要用来学习如何为一个文本分类任务微调BERT模型,本次具体要做的任务是情绪识别。在情绪识别任务领域,核心目标是精准地判断一个句子究竟蕴含正向情感还是负向情感。假设有一个句子:
I like reading.
重复上一节所讲过的步骤,大家可以和我一起过一遍:
首先对句子进行分词处理,并在分词结果的前后分别添加用于标识开始的 [CLS] 标记和用于分隔句子或表示结束的 [SEP] 标记。
接着,将这些标记输入到 BERT 模型中,经过模型内部的多层结构计算,得到每个标记对应的嵌入表示向量。
由于 [CLS] 标记的独特作用,它所对应的嵌入表示向量 R [CLS] 被认为是融合了整个句子语义信息的聚合表示。因此,我们仅选取这个 R [CLS] 嵌入向量,将其作为后续分类任务的输入特征,喂给一个带有 softmax 激活函数的前馈神经网络分类器,通过训练该分类器,使其能够基于这个句子级的嵌入表示来精准地完成情绪识别任务。
在从预训练的BERT中抽取嵌入表示的文章中,我们知道在提取句子的嵌入后,我们将R [CLS]
提供给分类器并训练分类器执行分类。类似地,在微调期间,我们也将R [CLS] 喂给一个分类并训练分类器执行分类。那么这个过程【微调预训练的BERT模型】与使用预训练的BERT模型作为特征提取器有何不同?
不同点在于:
- 在微调预训练的 BERT 模型时,我们不仅会更新分类器的参数,同时也会对 BERT 模型本身的参数进行更新,使其能够更好地适应特定的任务。
- 然而,当我们把预训练的 BERT 模型作为特征提取器时,我们仅更新分类器的参数,而保持预训练 BERT 模型的参数不变。在这种情况下,BERT 模型只是作为一个固定特征提取器,为分类器提供输入特征。
在对预训练的 BERT 模型进行微调时,我们有两种不同的策略来调整模型的参数:
第一种方式是将预训练的 BERT 模型与分类器视为一个整体,让它们的参数同时得到更新。这意味着在反向传播过程中,不仅分类器的参数会根据损失函数进行调整,BERT 模型内部的参数也会相应地进行更新,以适应当前的具体任务,这种方式可以使整个模型更好地协同工作,提升在特定任务上的表现。
第二种方式则只更新分类器的参数,而保持预训练 BERT 模型的参数不变。这种情况下,预训练的 BERT 模型就相当于一个固定不变的特征提取器,它提取出的特征向量被输入到分类器中,只有分类器的参数会根据任务进行优化调整。
了解完原理后,让我们正式开始探索如何使用 IMDB 数据集为情感分析任务微调预训练的 BERT 模型吧!!!
准备数据集
IMBD数据集下载链接在此:IMDB Dataset of 50K Movie Reviews,进入kaggle页面后下载数据集(需要先登录)。下载完成后是一个zip文件,需要先解压得到一个csv文件。该数据集包含 50,000 条电影评论,这些评论来自 IMDB 网站,每条评论都有一个表示情感倾向的标签,即正面或负面。数据内容如图所示,review是电影评论,sentiment是标签。

导入依赖
from transformers import BertForSequenceClassification, BertTokenizerFast, Trainer, TrainingArguments
from nlp import load_dataset
import torch
import numpy as np
import pandas as pd
from datasets import Dataset
from sklearn.preprocessing import LabelEncoder
首先用pandas读取csv,'D:\\nlp_prj\\IMDB.csv'是我csv数据集的存储路径。
df = pd.read_csv('D:\\nlp_prj\\IMDB.csv')
将文本标签转换为数字
le = LabelEncoder() #创建了一个 LabelEncoder 对象
df['labels'] = le.fit_transform(df['sentiment'])#fit_transform将值替换成对应的数字,存入新列labels
原始数据中的情感标签是字符串,例如:"positive", "negative", "positive", ...模型无法直接理解这些字符串,所以需要把它们转换成数字。
把 Pandas DataFrame 转换成 HuggingFace Dataset
dataset = Dataset.from_pandas(df)
把 Pandas DataFrame 转换成 HuggingFace Dataset,是为了让数据更高效、更规范地参与模型训练,特别是配合 Trainer 使用时必不可少的一步。Hugging Face 的 Trainer 类要求输入的数据是一个 Dataset 对象,而不是普通的 Pandas DataFrame 或 NumPy 数组。
打印第一条数据,验证是否成功
print(dataset[0])
将数据集拆分为训练和测试集
dataset = dataset.train_test_split(test_size=0.3)
输出数据集
print(dataset)
#输出为
DatasetDict({
train: Dataset({
features: ['review', 'sentiment', 'labels'],
num_rows: 35000
})
test: Dataset({
features: ['review', 'sentiment', 'labels'],
num_rows: 15000
})
})
创建训练集和测试集
train_set = dataset['train']
test_set = dataset['test']
下载并加载预训练的BERT模型
使用预训练的bert-base-uncased模型进行微调,因为我们做的是序列分类任务,所以可以使用BertForSequenceClassification类:
model = BertForSequenceClassification.from_pretrained('./uncased_L-12_H-768_A-12',num_labels=2)
google/bert_uncased_L-12_H-128_A-2 at main,进入该网址下载所有文件,下载后全部放入文件夹,取名为uncased_L-12_H-768_A-12,将该文件夹放入同py文件的同一个文件夹下。

下载并加载用于预训练bert-base-uncased模型的分词器
使用BertTokenizerFast类创建分词器而不是BertTokenizer。因为BertTokenizerFast相比BertTokenizer具有很多优势。
tokenizer = BertTokenizerFast.from_pretrained('./uncased_L-12_H-768_A-12')
定义process函数预处理数据集
将输入数据中的 'review' 文本字段用 BERT 分词器进行编码,并统一长度为 128,以便输入模型训练。这里,padding='max_length':把所有句子填充到指定的最大长度(这里是 128)。
truncation=True:如果句子超过最大长度,就截断。
def preprocess(data):
return tokenizer(data['review'], padding='max_length', truncation=True, max_length=128)
那么这个函数的返回值是什么呢?
假设有如下评论数据:
data = {
'review': [
"I love this movie!",
"This is the worst film ever.",
"It was an amazing experience."
]
}
经过函数的返回值是:
{
'input_ids': tensor([
[ 101, 1045, 2345, 2019, 2828, 102, 0, 0, 0, 0],
[ 101, 2019, 2073, 2046, 2213, 2026, 1012, 102, 0, 0],
[ 101, 2070, 3043, 2014, 16132, 102, 0, 0, 0, 0]
]),
'attention_mask': tensor([
[1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
[1, 1, 1, 1, 1, 1, 0, 0, 0, 0]
])
}
input_ids是每个词被分词后对应的 ID。比如 "I" → 1045,"love" → 2345 等;attention_mask 表示哪些位置是真实内容(1),哪些是填充的(0)。
使用preprocess函数预处理训练和测试数据集
使用 Hugging Face 的 datasets.Dataset.map() 方法对训练集和测试集进行预处理,对每一条评论文本调用 preprocess 函数(也就是 tokenizer),把原始文本转换为模型能接受的输入格式(如 input_ids, attention_mask 等)。
train_set = train_set.map(preprocess, batched=True, batch_size=16)
test_set = test_set.map(preprocess, batched=True, batch_size=16)
batched,类型是布尔值,默认值为False,作用是是否按批次处理(推荐设为 True)
batch_size,类型是整数,默认值是1000,作用是每个批次包含多少条数据,这里设置为16。
从 Hugging Face 的 Dataset 对象中 删除不需要的列(字段)
在 NLP 模型训练过程中,原始文本数据(如 'review')和原始标签(如 'sentiment',值为 "positive" 或 "negative")已经通过预处理函数(如 preprocess)被转换成了模型可以理解的数字格式(如 input_ids, attention_mask, labels 等)。因此,原始的文本字段(如 'review')不再需要。原始字符串形式的标签(如 'sentiment')也已经被编码成数字(如 0 和 1),所以也可以删除。
train_set = train_set.remove_columns(['review', 'sentiment'])
test_set = test_set.remove_columns(['review', 'sentiment'])
训练模型
设置超参数
# 设置超参数
batch_size = 8 # 每个设备上的 batch size(用于训练和评估)
epochs = 2 # 总共训练的轮数(epoch 数量)
warmup_steps = 500 # 学习率预热步数(前几步学习率逐渐增加)
weight_decay = 0.01 # 权重衰减系数(L2 正则化强度)
创建 TrainingArguments 对象,配置训练过程的各种参数
training_args = TrainingArguments(
output_dir='./results', # 输出目录,保存模型检查点等文件
num_train_epochs=epochs, # 总共训练多少轮
per_device_train_batch_size=batch_size, # 每个设备上用于训练的 batch size
per_device_eval_batch_size=batch_size, # 每个设备上用于评估的 batch size
warmup_steps=warmup_steps, # 学习率预热步数
weight_decay=weight_decay, # 权重衰减系数,防止过拟合
logging_dir='./logs', # 日志输出目录(例如 TensorBoard 使用)
optim="adamw_torch", # 使用 PyTorch 实现的 AdamW 优化器(修复警告)
)
创建 Trainer 对象,负责整个训练流程
trainer = Trainer(
model=model, # 要训练的模型(通常是 BertForSequenceClassification)
args=training_args, # 训练参数配置
train_dataset=train_set, # 训练数据集(HuggingFace Dataset 格式)
eval_dataset=test_set # 验证/测试数据集
)
开始训练
trainer.train()
在验证集上评估性能
trainer.evaluate()
查看评估结果
那么训练完毕后,如果想再次查看模型的评估结果,怎么实现呢?
1. 使用 Trainer.evaluate()
如果在训练结束后没有关闭Python 环境,并且 trainer 对象仍然存在,可以直接调用 evaluate() 方法来获取最新的评估结果。
results = trainer.evaluate()
print(results)
这将输出类似以下的结果(具体的指标取决于在 compute_metrics 函数中定义的内容):
{'eval_loss': 0.34, 'eval_accuracy': 0.89, 'eval_f1': 0.88}
2. 查看日志文件或 TensorBoard
如果在训练时配置了日志记录,比如设置了 logging_dir='./logs',那么可以使用 TensorBoard 来可视化训练和评估过程中的各种指标。
首先,确保已经安装了 TensorBoard:
pip install tensorboard
然后,在终端运行以下命令启动 TensorBoard:
tensorboard --logdir=./logs
打开浏览器并访问 http://localhost:6006,就可以看到训练和评估过程中的损失值、准确率等指标的变化趋势。
3. 保存和加载评估结果
如果希望保存评估结果以便日后查看,可以在评估之后将结果保存到文件中:
import json
results = trainer.evaluate()
# 将结果保存到 JSON 文件
with open('evaluation_results.json', 'w') as f:
json.dump(results, f)
# 以后可以从文件中读取结果
with open('evaluation_results.json', 'r') as f:
loaded_results = json.load(f)
print(loaded_results)
总结
通过这一章我们实现了一个完整的 BERT 文本分类模型训练流程,包括数据加载、预处理、模型训练和评估,适用于二分类情感分析任务。这也属于典型的 迁移学习中的“微调”(fine-tuning) 方法,即:使用 Hugging Face 提供的预训练 BERT 模型,在具体任务(如情感分析)数据上继续训练,从而让模型适应目标任务。
整体流程如下:
阶段 功能
数据准备 使用 Pandas 加载 CSV 数据并转换为 HuggingFace Dataset
标签编码 将文本标签(如 "positive"、"negative")转换为数字(0/1)
数据集划分 划分为训练集和测试集
分词器加载 加载 BERT 分词器(如 bert-base-uncased)
数据预处理 对文本字段进行分词、填充、截断等操作
删除原始列 删除不需要的原始文本和标签列
模型构建 加载预训练的 BERT 分类模型
训练配置 设置超参数和训练选项(batch size、epochs、优化器等)
模型训练 使用 Trainer API 进行训练
模型评估 在测试集上评估模型性能
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐

所有评论(0)