【机器学习深度学习】模型微调的基本概念与流程
目录
前言
一、什么是模型微调(Fine-tuning)?
二、预训练 vs 微调:什么关系?
三、微调的基本流程(以BERT为例)
1️⃣ 准备数据
2️⃣ 加载预训练模型和分词器
3️⃣ 数据编码与加载
4️⃣ 定义优化器
5️⃣ 开始训练
6️⃣ 评估与保存模型
四、是否要冻结 BERT 层?
五、完整训练示例代码
5.1 环境依赖
5.2 执行代码
总结:微调的优势
前言
在自然语言处理(NLP)快速发展的今天,预训练模型如 BERT 成为了众多任务的基础。但光有预训练模型并不能解决所有问题,模型微调 的技术应运而生。它让通用模型具备了“专才”的能力,使其能更好地服务于特定任务,如情感分析、问答系统、命名实体识别等。
本文将带你快速理解——什么是模型微调,它的基本流程又是怎样的?
一、什么是模型微调(Fine-tuning)?
✅ 概念通俗解释:
微调,就是在别人学得很好的“通用知识”上,加入你自己的“专业训练”。
具体来说,像 BERT 这样的预训练语言模型已经通过大规模语料学习了大量语言规律,比如语法结构、词语搭配等。我们不需要从头训练它,而是在此基础上继续用小规模、特定领域的数据进行训练,让模型更好地完成某个具体任务。
二、预训练 vs 微调:什么关系?
阶段 | 目标 | 数据类型 | 举例 |
---|---|---|---|
预训练(Pre-training) | 学习通用语言知识 | 大规模通用语料 | 维基百科、图书馆语料 |
微调(Fine-tuning) | 适应特定任务 | 少量任务特定数据 | 产品评论、医疗文本、法律文书 |
一句话总结:
🔁 预训练是“打基础”,微调是“练专业”。
三、微调的基本流程(以BERT为例)
让我们以“使用 BERT 进行情感分析”为例,梳理整个微调流程:
1️⃣ 准备数据
我们需要将文本和标签准备好,通常是一个 CSV 文件,比如:
评论内容 | 情感标签 |
---|---|
这部电影太好看了! | 正面 |
烂片,浪费时间。 | 负面 |
我们会将“正面”转换为 1
,负面为 0
,方便模型学习。
2️⃣ 加载预训练模型和分词器
from transformers import BertTokenizer, BertForSequenceClassificationtokenizer = BertTokenizer.from_pretrained('bert-base-chinese')
model = BertForSequenceClassification.from_pretrained('bert-base-chinese', num_labels=2)
此时模型的主体结构已经包含了 BERT 和一个分类头(Classification Head)。
3️⃣ 数据编码与加载
使用分词器将文本转为模型输入格式:
tokens = tokenizer("这部电影太好看了!", padding='max_length', truncation=True, return_tensors="pt")
你还需要构建自定义数据集类(Dataset),并使用 DataLoader 加载:
from torch.utils.data import DataLoadertrain_loader = DataLoader(my_dataset, batch_size=16, shuffle=True)
4️⃣ 定义优化器
from transformers import AdamWoptimizer = AdamW(model.parameters(), lr=5e-5)
▲优化器的作用是:根据损失函数的值,自动调整模型的参数,使模型表现越来越好。
▲通俗理解
优化器就像你走路的“策略”:
它告诉你“往哪边走,走多快,怎么避开障碍”,最终尽可能走到山底。
▲优化器做了什么?
神经网络训练时,每一轮都会:
计算当前模型的预测误差(损失函数 loss)
反向传播得到每个参数的梯度(方向)
👉 优化器根据梯度,更新参数的值
就像你爬山时,不断踩点 → 看地形 → 决定下一个落脚点。
组件 | 类比 | 作用 |
---|---|---|
损失函数 | 地图高度 | 告诉你你离目标有多远 |
梯度 | 当前坡度 | 告诉你往哪里走 |
优化器 | 走路策略 | 告诉你怎么调整步伐走得更快更稳 |
5️⃣ 开始训练
model.train()
for batch in train_loader:outputs = model(**batch)loss = outputs.lossloss.backward()optimizer.step()optimizer.zero_grad()
通常我们会训练几个 epoch,让模型逐渐学会如何从文本中识别情感。
6️⃣ 评估与保存模型
训练完成后,我们可以在验证集上评估准确率,并保存模型:
torch.save(model.state_dict(), "bert_sentiment.pth")
四、是否要冻结 BERT 层?
微调过程中,有两种策略:
-
全模型微调(默认): 所有 BERT 层和分类头都参与训练。效果通常更好,但对显存要求高。
-
冻结 BERT,仅训练分类头: 保持 BERT 权重不变,只训练新加的分类层。适合数据量小或设备受限的场景。
冻结代码示例:
for param in model.bert.parameters():param.requires_grad = False
【两种微调策略对比】
策略 是否冻结BERT层? 训练内容 优点 缺点 ✅ 全部微调 ❌ 不冻结 BERT + 分类层一起训练 效果最好,能深入适配任务 训练慢,显存占用大 🚫 只微调分类层 ✅ 冻结 BERT 只训练分类层 快速,适合小数据、低配置 表现可能略逊一筹
【举个通俗类比】
想象你雇了一个精通语文的老师(BERT),但你只想让他教学生写作文(分类任务):
全模型微调:老师重新备课、重新学习学生情况,全面参与教学(耗时但有效)。
只调分类层:老师照搬旧知识,只教作文技巧,不深入了解学生(快速但效果一般)。
【什么时候选择“冻结 BERT 层”?】
数据量很小(如只有几百个样本)
硬件资源有限(显存小、设备性能弱)
快速原型验证,先试试看效果
【小结一句话】
冻结 BERT 层就是让预训练好的 BERT 不再学习,只训练新增的部分;
不冻结则是让整个 BERT 跟着任务数据一起再“进修”一轮,效果更强,但代价更高。你也可以先冻结一部分,再逐步解冻,称为 层级微调(layer-wise unfreezing),也是一个进阶策略。
五、完整训练示例代码
5.1 环境依赖
1、安装Pytorch
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126
注意:
▲安装pytorch前先确定自己电脑是否有GPU,没有请安装cpu版本的;
pip3 install torch torchvision torchaudio
▲确保CUDA 12.6版本可以兼容
确定是否兼容可参考该文章对应内容:【CUDA&cuDNN安装】深度学习基础环境搭建_cudnn安装教程-CSDN博客
2、安装transformers
pip install transformers
3、安装scikit-learn
pip install scikit-learn
scikit-learn 是一个专注于传统机器学习的工具箱,涵盖从模型训练、评估到数据处理的一整套流程。
5.2 执行代码
import torch
from transformers import BertTokenizer, BertForSequenceClassification, AdamW
from torch.utils.data import Dataset, DataLoader
from sklearn.metrics import accuracy_score
import pandas as pd# 1. 自定义数据集类
class SentimentDataset(Dataset):def __init__(self, texts, labels, tokenizer, max_len=128):self.texts = textsself.labels = labelsself.tokenizer = tokenizerself.max_len = max_lendef __len__(self):return len(self.texts)def __getitem__(self, idx):inputs = self.tokenizer(self.texts[idx],truncation=True,padding='max_length',max_length=self.max_len,return_tensors='pt')return {'input_ids': inputs['input_ids'].squeeze(0),'attention_mask': inputs['attention_mask'].squeeze(0),'labels': torch.tensor(self.labels[idx], dtype=torch.long)}# 2. 加载数据
df = pd.read_csv("data.csv") # 假设 CSV 有 'text' 和 'label' 列
train_texts, train_labels = df['text'].tolist(), df['label'].tolist()# 3. 初始化 tokenizer 和 model
tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')
model = BertForSequenceClassification.from_pretrained('bert-base-chinese', num_labels=2)# 4. 构建 DataLoader
train_dataset = SentimentDataset(train_texts, train_labels, tokenizer)
train_loader = DataLoader(train_dataset, batch_size=16, shuffle=True)# 5. 设置优化器
optimizer = AdamW(model.parameters(), lr=5e-5)# 6. 训练过程
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)
model.train()for epoch in range(3): # 可改为你想要的轮数total_loss = 0preds, targets = [], []for batch in train_loader:input_ids = batch['input_ids'].to(device)attention_mask = batch['attention_mask'].to(device)labels = batch['labels'].to(device)outputs = model(input_ids=input_ids, attention_mask=attention_mask, labels=labels)loss = outputs.losslogits = outputs.logitsoptimizer.zero_grad()loss.backward()optimizer.step()total_loss += loss.item()preds += torch.argmax(logits, dim=1).tolist()targets += labels.tolist()acc = accuracy_score(targets, preds)print(f"Epoch {epoch+1} | Loss: {total_loss:.4f} | Accuracy: {acc:.4f}")# 7. 保存模型
torch.save(model.state_dict(), "bert_finetuned.pth")
总结:微调的优势
✅ 少量数据就能训练出效果不错的模型
✅ 迁移学习加速开发,节省计算资源
✅ 灵活应对不同领域任务,如医学、法律、金融等
模型微调是现代 AI 应用的关键技能之一。如果说预训练模型是“万能工具箱”,那么微调就是“选对合适的工具并精修”。掌握这项技术,你就能迅速把通用模型打造成特定任务的专家。