目錄
前言
一、什么是模型微調(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 應用的關鍵技能之一。如果說預訓練模型是“萬能工具箱”,那么微調就是“選對合適的工具并精修”。掌握這項技術,你就能迅速把通用模型打造成特定任務的專家。