隨著預訓練大模型(如BERT、GPT、ViT、LLaMA、CLIP等)的崛起,人工智能進入了一個新的范式:預訓練-微調(Pre-train, Fine-tune)。這些大模型在海量數據上學習到了通用的、強大的表示能力和世界知識。然而,要將這些通用模型應用于特定的下游任務或領域,通常還需要進行微調(Fine-tuning)。
微調的核心在于調整預訓練模型的參數,使其更好地適應目標任務的數據分布和特定需求。但大模型通常擁有數十億甚至數萬億的參數,直接進行全參數微調會帶來巨大的計算資源和存儲挑戰。本章將深入探討大模型微調的策略,以及如何采用高效訓練技術來應對這些挑戰。
4.1 大模型微調:從通用到專精
4.1.1 為什么需要微調?
盡管預訓練大模型具有強大的泛化能力,但它們在預訓練階段看到的數據通常是通用的、領域無關的。當我們需要它們完成特定領域的任務時,例如醫療文本分類、法律問答、特定風格的圖像生成等,通用知識可能不足以滿足需求。微調的目的是:
- 適應任務特異性: 調整模型,使其更好地理解和處理特定任務的輸入輸出格式及語義。
- 適應數據分布: 將模型知識遷移到目標任務的特定數據分布上,提高模型在目標數據上的性能。
- 提升性能: 通常,經過微調的模型在特定下游任務上的表現會顯著優于直接使用預訓練模型。
- 提高效率: 相較于從頭開始訓練一個新模型,微調一個預訓練大模型通常更快、更有效。
4.1.2 全參數微調 (Full Fine-tuning)
核心思想: 全參數微調是最直接的微調方法,它解凍(unfreeze)預訓練模型的所有參數,并使用目標任務的標注數據對其進行端到端(end-to-end)的訓練。
原理詳解: 在全參數微調中,我們加載一個預訓練模型的權重,然后像訓練一個普通神經網絡一樣,使用新的數據集和損失函數來訓練它。由于模型的所有層都參與梯度計算和參數更新,理論上模型可以最大程度地適應新任務。
優點:
- 性能潛力大: 如果資源允許且數據集足夠大,全參數微調通常能達到最佳性能。
- 概念簡單: 實現起來相對直接。
缺點:
- 計算資源需求巨大: 對于擁有數十億參數的大模型,全參數微調需要大量的GPU顯存和計算時間。
- 存儲成本高昂: 每個下游任務都需要存儲一套完整的模型參數,不便于多任務部署。
- 災難性遺忘(Catastrophic Forgetting): 在小規模數據集上進行微調時,模型可能會“遺忘”在預訓練階段學到的通用知識,導致在其他任務上的性能下降。
Python示例:簡單文本分類的全參數微調
我們將使用一個預訓練的BERT模型進行情感分類任務的全參數微調。
Python
import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments
from datasets import load_dataset, Dataset
import numpy as np
from sklearn.metrics import accuracy_score, precision_recall_fscore_support# 1. 加載預訓練模型和分詞器
model_name = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=2) # 2個類別:正面/負面情感# 2. 準備數據集 (使用Hugging Face datasets庫加載一個情感分析數據集)
# 這里使用 'imdb' 數據集作為示例
# 如果是第一次運行,會自動下載
print("Loading IMDb dataset...")
dataset = load_dataset("imdb")# 預處理數據
def preprocess_function(examples):return tokenizer(examples["text"], truncation=True, padding="max_length", max_length=128)tokenized_imdb = dataset.map(preprocess_function, batched=True)# 重命名標簽列為 'labels' 以符合Trainer的要求
tokenized_imdb = tokenized_imdb.rename_columns({"label": "labels"})
# 移除原始文本列
tokenized_imdb = tokenized_imdb.remove_columns(["text"])
# 設置格式為PyTorch tensors
tokenized_imdb.set_format("torch")# 劃分訓練集和測試集
small_train_dataset = tokenized_imdb["train"].shuffle(seed=42).select(range(2000)) # 使用小部分數據進行演示
small_eval_dataset = tokenized_imdb["test"].shuffle(seed=42).select(range(500))# 3. 定義評估指標
def compute_metrics(p):predictions, labels = ppredictions = np.argmax(predictions, axis=1)precision, recall, f1, _ = precision_recall_fscore_support(labels, predictions, average='binary')acc = accuracy_score(labels, predictions)return {'accuracy': acc,'f1': f1,'precision': precision,'recall': recall}# 4. 配置訓練參數
training_args = TrainingArguments(output_dir="./results_full_finetune",num_train_epochs=3, # 訓練輪次per_device_train_batch_size=16, # 訓練批次大小per_device_eval_batch_size=16, # 評估批次大小warmup_steps=500, # 學習率預熱步數weight_decay=0.01, # 權重衰減logging_dir='./logs_full_finetune', # 日志目錄logging_steps=100,evaluation_strategy="epoch", # 每個epoch結束后評估save_strategy="epoch", # 每個epoch結束后保存模型load_best_model_at_end=True, # 訓練結束后加載最佳模型metric_for_best_model="f1", # 衡量最佳模型的指標report_to="none" # 不上傳到任何在線平臺
)# 5. 初始化Trainer并開始訓練
trainer = Trainer(model=model,args=training_args,train_dataset=small_train_dataset,eval_dataset=small_eval_dataset,compute_metrics=compute_metrics,
)print("\n--- BERT 全參數微調示例 ---")
# 檢查是否有GPU可用
if torch.cuda.is_available():print(f"Using GPU: {torch.cuda.get_device_name(0)}")
else:print("No GPU available, training on CPU (will be slow).")trainer.train()print("\nFull fine-tuning completed. Evaluation results:")
eval_results = trainer.evaluate()
print(eval_results)
代碼說明:
- 我們使用了Hugging Face
transformers
庫的Trainer
API,它極大地簡化了訓練過程。 AutoTokenizer
和AutoModelForSequenceClassification
自動加載BERT模型和對應的分詞器。load_dataset("imdb")
用于獲取情感分類的示例數據。preprocess_function
將文本轉換為模型可以理解的token ID序列。TrainingArguments
用于配置各種訓練參數,如學習率、批次大小、保存策略等。compute_metrics
定義了用于評估模型性能的指標。trainer.train()
啟動訓練過程。
4.1.3 參數高效微調 (Parameter-Efficient Fine-tuning, PEFT)
核心思想: PEFT旨在解決全參數微調的缺點,它通過只微調預訓練模型中少量新增或現有參數,同時凍結大部分預訓練參數,從而大大降低計算和存儲成本,并有效避免災難性遺忘。
PEFT方法可以分為幾大類:
- 新增適配器模塊: 在預訓練模型的中間層或輸出層插入小型的可訓練模塊(Adapter)。
- 軟提示: 優化輸入中少量連續的、可學習的“軟提示”或“前綴”,而不是修改模型參數。
- 低秩適應: 通過低秩分解來近似全參數更新,減少可訓練參數。
我們將重點介紹其中最流行且高效的幾種方法。
4.1.3.1 LoRA (Low-Rank Adaptation)
- 顯著減少可訓練參數: 大幅降低顯存消耗和訓練時間。
- 避免災難性遺忘: 預訓練權重凍結,保護了通用知識。
- 部署高效: 可以在推理時合并權重,不增加額外延遲。
- 多任務部署: 針對不同任務,只需存儲和加載很小的 (BA) 矩陣。
Python示例:使用peft
庫進行LoRA微調
我們將使用Hugging Face的peft
庫對預訓練的GPT-2模型進行LoRA微調,用于文本生成任務。
首先,確保安裝peft
庫:
Bash
<