Transformers 微调预训练模型:原理到实践(Ubuntu22.04 + Conda)

作者:吴业亮
博客:wuyeliang.blog.csdn.net

一、Transformers微调核心原理

1.1 预训练+微调的核心范式

Transformers模型的优势在于"通用预训练+任务特定微调":

  • 预训练:模型在海量无标注通用文本(如维基百科、书籍)上学习语言的通用表示(语法、语义、上下文关联),参数具备泛化能力;
  • 微调:在少量标注的特定任务数据(如情感分析、文本生成)上,调整预训练参数(或仅调整部分参数),让模型适配目标任务。

这种范式的核心是迁移学习------复用预训练学到的通用知识,避免从零训练(耗时、耗资源、数据需求大)。

1.2 微调的核心策略

根据显存/算力资源,常见微调策略分为3类:

策略 特点 适用场景
全微调(Full Fine-tuning) 所有参数更新,效果最好,但显存/算力消耗最大 大显存(≥16G)、小模型
冻结+微调(Freeze-then-Fine-tune) 冻结底层特征提取层(预训练核心层),仅微调顶层任务头/最后1-2层 小显存(8G)、大模型
低秩适配(LoRA/QLoRA) 冻结主模型参数,仅训练低秩矩阵(适配层),训练后合并到主模型 极小显存(4G)、超大模型(如LLaMA、GPT-2)

1.3 关键技术组件

  • Tokenizer(分词器):与预训练模型配套,将文本转为模型可识别的token id/注意力掩码/位置编码;
  • Dataset(数据集):标准化数据格式(如Hugging Face Datasets),支持批量加载/预处理;
  • TrainingArguments(训练参数):配置学习率、批次大小、训练轮数、保存路径、显存优化(如FP16)等;
  • Trainer/Accelerate:Hugging Face封装的训练框架,简化分布式训练、显存优化、日志记录等;
  • 任务头(Task Head):预训练模型顶层新增的适配层(如分类任务的全连接层、生成任务的线性层)。

二、环境搭建(Ubuntu22.04 + Conda)

2.1 安装Conda(若未安装)

Ubuntu22.04下安装Miniconda(轻量版):

bash 复制代码
# 下载Miniconda安装包(适配x86_64)
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh

# 执行安装(一路回车,最后输入yes同意conda init)
bash Miniconda3-latest-Linux-x86_64.sh

# 重启终端,验证conda
conda --version  # 输出conda版本即成功

2.2 创建并激活Conda环境

创建Python3.10环境(适配Transformers最新版):

bash 复制代码
# 创建环境(命名为transformers-finetune,Python3.10)
conda create -n transformers-finetune python=3.10 -y

# 激活环境
conda activate transformers-finetune

2.3 安装核心依赖

(1)基础依赖
bash 复制代码
# 安装PyTorch(适配CUDA 11.8,若显卡支持更高版本可调整)
# 先查看显卡CUDA版本:nvidia-smi(输出中"CUDA Version")
conda install pytorch torchvision torchaudio pytorch-cuda=11.8 -c pytorch -c nvidia -y

# 安装Hugging Face核心库
pip install transformers datasets accelerate evaluate scikit-learn

# 可选:安装LoRA依赖(进阶用)
pip install peft bitsandbytes
(2)系统依赖(Ubuntu22.04补全)

避免后续数据加载/可视化报错:

bash 复制代码
sudo apt update && sudo apt install -y libgl1-mesa-glx libglib2.0-0

2.4 验证环境

bash 复制代码
# 验证PyTorch+CUDA
python -c "import torch; print(torch.cuda.is_available())"  # 输出True即CUDA可用

# 验证Transformers
python -c "from transformers import pipeline; print(pipeline('sentiment-analysis')('I love you'))"  # 输出情感分析结果即成功

三、实战:文本分类任务微调BERT

IMDB情感分析任务 (二分类:正面/负面评价)为例,使用bert-base-uncased预训练模型做全微调。

3.1 任务与数据集说明

  • 数据集:IMDB(5万条电影评论,训练集2.5万,测试集2.5万);
  • 模型:bert-base-uncased(12层BERT,小写处理,约110M参数);
  • 目标:微调后实现评论情感的精准分类。

3.2 完整微调代码

创建finetune_bert_imdb.py,代码注释全覆盖关键步骤:

python 复制代码
import torch
from datasets import load_dataset
from transformers import (
    AutoTokenizer, AutoModelForSequenceClassification,
    TrainingArguments, Trainer, DataCollatorWithPadding
)
import evaluate
import numpy as np

# ====================== 1. 配置基础参数 ======================
MODEL_NAME = "bert-base-uncased"  # 预训练模型名称
MAX_LENGTH = 128  # 文本最大长度(超出截断,不足补齐)
BATCH_SIZE = 16   # 批次大小(根据显存调整,8G显存建议设8)
EPOCHS = 3        # 训练轮数
LEARNING_RATE = 2e-5  # BERT微调常用学习率(1e-5~5e-5)
OUTPUT_DIR = "./bert-imdb-finetune"  # 模型保存路径
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"

# ====================== 2. 加载数据集 ======================
# 加载IMDB数据集(自动下载,首次需等待)
dataset = load_dataset("imdb")
# 拆分训练集/验证集(训练集取10%做验证,加快测试)
dataset = dataset["train"].train_test_split(test_size=0.1)
train_dataset = dataset["train"]
val_dataset = dataset["test"]
test_dataset = load_dataset("imdb")["test"]

# ====================== 3. 加载Tokenizer并预处理数据 ======================
# 加载与模型配套的分词器
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)

# 定义预处理函数:文本→token id/注意力掩码
def preprocess_function(examples):
    return tokenizer(
        examples["text"],
        truncation=True,  # 截断过长文本
        max_length=MAX_LENGTH,
        padding=False,    # 批量padding交给DataCollator
    )

# 批量预处理数据集(加速)
tokenized_train = train_dataset.map(preprocess_function, batched=True)
tokenized_val = val_dataset.map(preprocess_function, batched=True)
tokenized_test = test_dataset.map(preprocess_function, batched=True)

# 格式化数据集(匹配模型输入:labels为整数)
tokenized_train = tokenized_train.rename_column("label", "labels")
tokenized_val = tokenized_val.rename_column("label", "labels")
tokenized_test = tokenized_test.rename_column("label", "labels")
# 只保留模型需要的列(input_ids, attention_mask, labels)
tokenized_train.set_format("torch", columns=["input_ids", "attention_mask", "labels"])
tokenized_val.set_format("torch", columns=["input_ids", "attention_mask", "labels"])
tokenized_test.set_format("torch", columns=["input_ids", "attention_mask", "labels"])

# 数据collator:动态padding(同批次文本长度一致)
data_collator = DataCollatorWithPadding(tokenizer=tokenizer)

# ====================== 4. 加载预训练模型(带分类头) ======================
# AutoModelForSequenceClassification:自动添加分类头(num_labels=2表示二分类)
model = AutoModelForSequenceClassification.from_pretrained(
    MODEL_NAME,
    num_labels=2,  # 情感分析:0=负面,1=正面
    device_map=DEVICE  # 自动加载到GPU/CPU
)

# ====================== 5. 配置训练参数 ======================
training_args = TrainingArguments(
    output_dir=OUTPUT_DIR,          # 模型保存路径
    learning_rate=LEARNING_RATE,    # 学习率
    per_device_train_batch_size=BATCH_SIZE,  # 单卡批次大小
    per_device_eval_batch_size=BATCH_SIZE,   # 评估批次大小
    num_train_epochs=EPOCHS,        # 训练轮数
    weight_decay=0.01,              # 权重衰减(防止过拟合)
    logging_dir=f"{OUTPUT_DIR}/logs",  # 日志路径
    logging_steps=10,               # 每10步打印一次日志
    evaluation_strategy="epoch",    # 每轮结束评估一次
    save_strategy="epoch",          # 每轮结束保存一次模型
    load_best_model_at_end=True,    # 训练结束加载最优模型
    fp16=torch.cuda.is_available(), # 开启FP16(显存优化,GPU可用时)
)

# ====================== 6. 定义评估指标(准确率) ======================
accuracy = evaluate.load("accuracy")

def compute_metrics(eval_pred):
    """计算评估指标:输入为(预测logits,真实标签)"""
    logits, labels = eval_pred
    predictions = np.argmax(logits, axis=-1)  # logits转预测标签
    return accuracy.compute(predictions=predictions, references=labels)

# ====================== 7. 初始化Trainer并训练 ======================
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=tokenized_train,
    eval_dataset=tokenized_val,
    tokenizer=tokenizer,
    data_collator=data_collator,
    compute_metrics=compute_metrics,
)

# 开始训练
trainer.train()

# ====================== 8. 测试集评估 ======================
test_results = trainer.evaluate(tokenized_test)
print("测试集评估结果:", test_results)

# ====================== 9. 推理示例 ======================
def predict_sentiment(text):
    """推理函数:输入文本,输出情感标签和置信度"""
    inputs = tokenizer(
        text,
        return_tensors="pt",
        truncation=True,
        max_length=MAX_LENGTH,
        padding=True
    ).to(DEVICE)
    with torch.no_grad():
        outputs = model(**inputs)
    logits = outputs.logits
    probabilities = torch.softmax(logits, dim=-1)
    sentiment = "正面" if torch.argmax(probabilities) == 1 else "负面"
    confidence = probabilities[0][torch.argmax(probabilities)].item()
    return {"情感": sentiment, "置信度": round(confidence, 4)}

# 测试推理
test_texts = [
    "This movie is amazing! The acting is top-notch.",
    "Worst movie ever, I wasted 2 hours of my life."
]
for text in test_texts:
    result = predict_sentiment(text)
    print(f"文本:{text}\n结果:{result}\n")

# 保存最终模型
trainer.save_model(f"{OUTPUT_DIR}/final")

3.3 运行微调代码

bash 复制代码
# 确保conda环境激活
conda activate transformers-finetune

# 运行代码(若显存不足,可将BATCH_SIZE改为8/4)
python finetune_bert_imdb.py

3.4 关键输出说明

  • 训练过程:终端会打印每轮的训练损失、验证准确率;
  • 模型保存:./bert-imdb-finetune下会生成checkpoint-xxx(每轮检查点)和final(最终模型);
  • 推理结果:测试文本会输出"正面/负面"+置信度(通常准确率≥90%)。

四、进阶:LoRA低秩适配微调(显存优化)

若你的显卡显存≤8G,或想微调大模型(如bert-large-uncased、LLaMA),推荐使用LoRA策略(仅训练低秩矩阵,显存消耗减少80%+)。

4.1 LoRA核心原理

LoRA通过在Transformer的Attention层(Query/Value矩阵)插入低秩矩阵(A: d×r,B: r×k,r<<d,k),冻结主模型参数,仅训练A和B。训练完成后,将LoRA矩阵合并到主模型,不影响推理效率。

4.2 LoRA微调代码(修改自基础版)

仅需修改模型加载和训练部分,其余代码复用:

python 复制代码
# 新增导入LoRA相关库
from peft import LoraConfig, get_peft_model, PeftModel

# ====================== 4. 配置LoRA并加载模型 ======================
# LoRA配置
lora_config = LoraConfig(
    r=16,  # 低秩矩阵的秩(越小显存消耗越少,推荐8/16)
    lora_alpha=32,  # 缩放因子
    target_modules=["query", "value"],  # 目标层(BERT的Attention层)
    lora_dropout=0.05,
    bias="none",
    task_type="SEQ_CLS",  # 任务类型:序列分类
)

# 加载基础模型(冻结参数)
model = AutoModelForSequenceClassification.from_pretrained(
    MODEL_NAME,
    num_labels=2,
    device_map=DEVICE
)
# 应用LoRA适配
model = get_peft_model(model, lora_config)
# 打印可训练参数(仅LoRA层)
model.print_trainable_parameters()  # 输出:trainable params: ~0.1% of total params

# ====================== 训练/评估/推理 同基础版 ======================
# 训练完成后,合并LoRA权重到主模型(可选,便于推理)
base_model = AutoModelForSequenceClassification.from_pretrained(
    MODEL_NAME, num_labels=2, device_map=DEVICE
)
peft_model = PeftModel.from_pretrained(base_model, f"{OUTPUT_DIR}/final")
merged_model = peft_model.merge_and_unload()
# 保存合并后的模型
merged_model.save_pretrained(f"{OUTPUT_DIR}/merged")
tokenizer.save_pretrained(f"{OUTPUT_DIR}/merged")

五、常见问题与解决方案

5.1 显存不足(CUDA out of memory)

  • 降低批次大小(BATCH_SIZE改为4/2);
  • 开启FP16(代码中已配置fp16=True);
  • 使用LoRA/QLoRA策略;
  • 缩短文本最大长度(MAX_LENGTH改为64);
  • 冻结部分层(如model.bert.encoder.layer[:10].requires_grad = False)。

5.2 CUDA版本不匹配

5.3 数据预处理错误

  • 确保Tokenizer与模型配套(如bert-base-uncased必须用对应分词器);
  • 检查数据集列名(如IMDB的标签列是label,需重命名为labels匹配模型输入);
  • 批量预处理时设置batched=True,避免单条处理耗时。

5.4 训练过拟合

  • 增加权重衰减(weight_decay改为0.05);
  • 减少训练轮数(EPOCHS改为2);
  • 使用早停(TrainingArguments中添加early_stopping_patience=1);
  • 增加数据增强(如文本随机截断、同义词替换)。

六、总结

本文从原理到实践,覆盖了Transformers微调的核心逻辑、Ubuntu22.04+Conda环境搭建、基础全微调、进阶LoRA微调,以及常见问题解决方案。核心要点:

  1. 微调的本质是迁移学习,根据显存选择全微调/冻结微调/LoRA;
  2. Hugging Face生态(Transformers/Datasets/Trainer)大幅简化微调流程;
  3. 关键参数(学习率、批次大小、文本长度)需根据模型/显存调整。

后续可扩展方向:

  • 微调生成类模型(如GPT-2、LLaMA)完成文本生成;
  • 使用QLoRA(量化+LoRA)微调超大模型(如LLaMA-7B);
  • 分布式训练(多卡)加速微调(修改TrainingArgumentsnum_train_epochs+accelerate配置)。
相关推荐
Sol-itude9 小时前
Qwen3-8B大模型微调实战
大模型
AI大模型学徒12 小时前
大模型应用开发(九)_LangChain提示词模板
chatgpt·langchain·大模型·deepseek·提示词模板
袋鼠云数栈12 小时前
官宣!ChunJun 1.16 Release 版本发布!
大数据·经验分享·大模型
Yeliang Wu15 小时前
LLaMA-Factory 训练方法原理及实践(Ubuntu 22.04)
微调·分布式训练·量化·llamafactory
Yeliang Wu16 小时前
LLaMA-Factory 分布式训练实践
大模型·微调·分布式训练·llamafactory·调优算法
我很哇塞耶17 小时前
告别VAE压缩损耗,南京大学用DiP让扩散模型回归像素空间,实现10倍加速与SOTA级画质
人工智能·ai·大模型·图像生成
Yeliang Wu18 小时前
从原理到部署:LLaMA Factory 量化实战(Ubuntu 22.04)——PTQ/GPTQ/AWQ 等 9 种方法
大模型·微调·分布式训练·llamafactory·调优算法
Yeliang Wu18 小时前
LLaMA-Factory 加速技术全解析:FlashAttention/Unsloth/Liger Kernel 原理与 Ubuntu22.04 实践指南
微调·分布式训练·llamafactory·调优算法
七夜zippoe18 小时前
基于MLC-LLM的轻量级大模型手机端部署实战
android·智能手机·架构·大模型·mlc-llm