AI微调实战学习:用LoRA在消费级显卡上跑通一次完整微调
微调最容易被误解成“必须有一堆A100”。
其实用LoRA这类参数高效方法,单张8GB显存的消费级显卡就能跑通一次完整的微调流程。
下面按实际动手顺序走一遍:准备数据、装环境、改训练脚本、处理显存问题、验证效果。
先搞清楚这次微调要解决什么
微调不是让模型重新学说话,而是在已有能力上适配你的任务。
本文选一个最简单的场景:情感分类,把用户评论分成正面和负面。
选它是因为数据量小、训练快、效果容易验证,适合作为AI微调实战学习的第一个练手项目。
适用条件是:你有NVIDIA显卡(8GB显存起步)、能装Python 3.10、愿意按命令逐条执行。
如果连PyTorch都没装过,建议先跑通一个MNIST例子再回来。
数据准备:格式比数量重要
微调数据通常用JSONL,每行一个样本。
分类任务的格式如下:
{"text": "物流很快,包装完好", "label": 1}
{"text": "用了两天就坏了,客服也不回", "label": 0}
label用0和1表示负面和正面。每类至少准备100条,太少模型学不到规律。
数据来源可以自己标注,也可以用公开数据集筛选。
注意训练集和验证集要分开,验证集占总量的10%到20%。
环境安装与依赖版本
用conda建一个干净环境,避免和系统Python冲突:
conda create -n finetune python=3.10 -y
conda activate finetune
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
pip install transformers datasets peft accelerate
这里指定cu118版本的PyTorch,对应CUDA 11.8。
如果你的驱动只支持CUDA 12,把cu118换成cu121。
装完后用以下命令确认显卡能被识别:
python -c "import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))"
输出True和显卡型号才算正常。
如果输出False,先检查驱动版本,不要急着改代码。
用LoRA挂载到预训练模型
选一个小模型作为基座,比如distilbert-base-uncased,它只有约6600万参数,适合显存有限的机器。
LoRA的思路是冻结原模型权重,只训练少量低秩矩阵,显存占用和训练时间都会大幅下降。
核心配置片段如下:
from peft import LoraConfig, get_peft_model
from transformers import AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained(
"distilbert-base-uncased", num_labels=2
)
lora_config = LoraConfig(
r=8,
lora_alpha=16,
target_modules=["q_lin", "v_lin"],
lora_dropout=0.1,
bias="none",
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
target_modules要写模型里注意力层的实际名称。
DistilBERT用q_lin和v_lin,换成BERT则是query和value。
写错会直接报找不到模块,按报错信息里的层名改即可。
训练参数与显存不足的处理
训练用Hugging Face的Trainer,关键参数建议先这样设:
training_args = TrainingArguments(
output_dir="./lora-out",
per_device_train_batch_size=8,
gradient_accumulation_steps=2,
learning_rate=2e-4,
num_train_epochs=3,
logging_steps=20,
evaluation_strategy="epoch",
save_strategy="epoch",
fp16=True,
)
如果启动后报CUDA out of memory,按顺序尝试:把per_device_train_batch_size降到4或2;
把gradient_accumulation_steps相应调大保持等效批量;
确认fp16=True已开启。不要一上来就改模型结构,先降批量通常就能解决。
训练结束后,LoRA权重会保存在./lora-out目录下,文件很小,通常只有几MB。
效果验证与常见坑
验证分两步。
先看训练日志里的验证集准确率是否在上升,如果连续几个epoch不动,可能是学习率太低或数据标签有问题。
再用几段没参与训练的新文本手动测试:
from peft import PeftModel
base = AutoModelForSequenceClassification.from_pretrained("distilbert-base-uncased", num_labels=2)
model = PeftModel.from_pretrained(base, "./lora-out")
model.eval()
# 对tokenize后的输入做推理,看预测类别是否合理
几个容易踩的坑:
- 标签顺序搞反:训练时label 1代表正面,推理时却按相反顺序解读,结果全错。
- 验证集混入训练集:准确率虚高,上线就崩。切分数据时先打乱再切。
- 忘了切eval模式:推理前调用
model.eval(),否则dropout会影响结果稳定性。
跑通这一轮后,你可以把同样的流程套到自己的数据上,只改数据格式和num_labels。
微调的门槛不在算力,而在数据质量和参数调试的耐心。