跳到主要内容大语言模型微调指南:LoRA 原理与实践代码 | 极客日志PythonAI算法
大语言模型微调指南:LoRA 原理与实践代码
综述由AI生成大语言模型微调概念,对比 SFT 与 RLHF,深入解析 LoRA 低秩适配原理及数学基础。通过 Hugging Face Transformers 库实战演示电影评论分类任务,涵盖数据准备、模型加载、PEFT 配置及训练评估全流程。文章补充了模型合并与量化部署方案,并提供最佳实践建议,帮助开发者低成本实现模型定制化。
月亮邮递员28 浏览 导读
本文介绍微调(Fine-tuning)的基本概念,以及如何对语言模型进行微调。从 GPT-3 到 ChatGPT、从 GPT-4 到 GitHub Copilot 的过程中,微调扮演了重要角色。什么是微调?微调能解决什么问题?什么是 LoRA?如何进行微调?本文将解答以上问题,并通过代码实例展示如何使用 LoRA 进行微调。
微调是利用已经训练好的模型(通常是大型的预训练模型)作为起点,在新的数据集进一步训练模型,从而使其更适合特定的应用场景。即使非专业算法同学,只要硬件成本可控,也可动手尝试微调自己的模型。
1. 什么是 Fine-tuning
GPT-3 使用大量互联网上的语料训练完成后,并不完全适合对话场景。例如输入'中国的首都是哪里?',基于训练后的模型参数推理,结果可能不准确。这是因为训练数据中相关句子的概率分布与特定对话需求存在差异。需要多阶段的优化过程使模型更擅长处理对话,并更好地理解和回应用户需求。
GPT-3 模型的微调过程包括几个关键步骤:
- 大规模文本数据集预训练:形成基础的语言能力。
- 监督微调(SFT):让模型适应对话任务,生成更符合人类习惯的文本。
- 基于人类反馈的强化学习(RLHF):使用用户反馈数据(如赞踩、评分),进一步优化输出质量,确保多轮对话连贯有效。
- 持续微调与更新:适应新需求并确保输出的安全性和伦理性。
1.1 为什么要 Fine-tuning
1.1.1 强化特定任务能力
- 特定领域增强:将通用任务能力在特定领域加强。例如情感分类,预训练模型虽有此能力,但微调可显著增强。
- 注入新知识:通过微调让模型学习新信息,例如自我认知类问题:'你是谁?''谁创造了你?',微调后可获得预期内回答。
1.1.2 提高模型性能
- 减少幻觉:降低或消除模型生成虚假或不相关信息的情况。
- 提高一致性:虽每次生成内容不同,但质量维持在较高水平,避免一次很好一次很差。
- 避免不必要输出:例如让模型委婉拒绝评价宗教等敏感话题,适用于安全测试和监管审查。
- 降低延迟:通过优化和微调,使用较小参数量的模型达到预期效果,减少响应时间。
1.1.3 避免数据泄漏
- 本地部署:选择本地服务器或虚拟私有云运行模型,自主控制性强。
- 防止泄漏:核心竞争优势是长年积累的领域数据,本地微调可防止数据外泄。
- 安全风险可控:机密数据可自定义高级别的安全微调环境,而非委托给第三方推理服务。
1.1.4 降低成本
- 避免从零训练:从头训练大模型成本极高(如 Llama 3.1 405B 需数千张 H100)。在开源模型上微调,结合量化技术,门槛大幅降低。
- 降低请求成本:相同性能下,微调模型参数量更少,推理成本更低。
- 资源控制权:自主平衡模型性能、耗时、吞吐量,为成本优化提供空间。
1.2 相关概念区分
1.2.1 RLHF 与 SFT
目前 OpenAI 公开信息显示,ChatGPT 的主要改进是通过微调和 RLHF 实现。流程大致为:预训练 → 微调(SFT) → 强化学习(RLHF) → 模型修剪与优化。
- RLHF(基于人类反馈的强化学习):一种强化学习具体方式。模型通过与环境交互学习决策策略,最大化长期累积奖励。在 NLP 中用于优化输出以符合期望目标。
- SFT(监督微调):在有明确标签的情况下对预训练模型进行微调。还有无监督微调(Unsupervised FT)和自监督微调(Self-Supervised FT)。
在生产实践中,虽然 RLHF 可提升表现,但对特定任务采用 SFT 往往效果更好。RLHF 成本高,依赖大量人工标注数据,相对 SFT 使用较少。
1.2.2 继续预训练与微调
- 继续预训练:在已预训练模型基础上,进一步在特定领域未标注的大规模数据上训练,提高对该领域的理解。适用于行业大模型构建。
- 微调:目的是优化模型在特定任务上的表现,通常在小规模任务数据集上进行。
两者可结合:通用预训练 → 继续预训练(行业/部门) → 微调(具体业务小组)。
2. 如何 Fine-tuning
2.1 微调基本原理
微调是基于已训练好的神经网络模型,通过对其参数进行细微调整,使其更好适应特定任务。根据微调范围分为全模型微调和部分微调。
- 全模型微调:更新所有参数,适用于目标任务差异较大场景,但资源消耗大,易过拟合。
- 部分微调:仅更新部分参数,冻结其他参数,减少计算存储成本,降低过拟合风险。
生产中常用参数高效微调(PEFT),通过引入低秩矩阵(如 LoRA)或适配层,减少资源需求。
2.2 什么是 LoRA
2.2.1 基本概念
LoRA(Low-Rank Adaptation)通过引入低秩矩阵来减少微调过程中需要更新的参数数量,显著降低计算资源需求。
可重用性:LoRA 不改变原模型参数,不同任务的低秩矩阵可分别存储加载,灵活应用于不同任务。例如在手机终端跑大模型,针对不同任务动态加载 LoRA 参数,相比一个任务一个模型,大幅节省空间。
2.2.2 原理分析
研究表明,模型适应特定任务时并不需要用到所有复杂能力。原始矩阵维度较高,假设为 $d_k$ 维矩阵 $W_0$,调整方式为矩阵加法增加 $ riangle W$。若 $ riangle W$ 仍为 $d \times k$ 维,参数量多。LoRA 将其表示为低秩分解:
$$ h = W_0 + \triangle W = W_0 + BA $$
其中 $B \in \mathbb{R}^{d \times r}, A \in \mathbb{R}^{r \times k}$,且秩 $r \ll \min(d, k)$。
举例计算:$d=1000, k=1000$,全量调整需 100w 参数。若 $r=4$,仅需 $1000 \times 4 + 4 \times 1000 = 8000$ 个参数。
论文实验表明,在调整 Transformer 权重矩阵时,$r=1$ 时对特定任务就有非常好效果。通常 $r$ 设置为 1~8,经验值常为 4。
2.3 微调过程
- 准备数据:收集标注数据,分训练集/验证集,进行 Tokenization。
- 配置参数:设置 LoRA 参数、学习率,确保收敛。
- 训练模型:在训练集上训练,调整超参数防过拟合。
- 评估模型:在验证集上评估性能。
- 高质量:Garbage in garbage out,数据质量至关重要。
- 多样性:覆盖更多场景,类似测试用例。
- 人工生成:避免语言模型生成的隐含模式。
- 数量适中:LoRA 论文显示 100 条有明显改善,1000 条左右效果不错。OpenAI 建议至少 10 条,通常 50-100 条可见明显提升。
2.4 使用 LoRA 微调代码分析
本节使用 LoRA 微调 distilbert/distilbert-base-uncased 模型,实现对电影评论的情感分类(正面/负面)。数据集为 stanfordnlp/imdb。使用 Colab 免费 T4 GPU,1000 条数据,10 个 Epoch,约 6 分钟完成。微调前准确率 50%,微调后达 87%。
2.4.1 库安装与包引入
!pip install datasets
!pip install transformers
!pip install evaluate
!pip install torch
!pip install peft
from datasets import load_dataset, DatasetDict, Dataset
from transformers import (
AutoTokenizer,
AutoConfig,
AutoModelForSequenceClassification,
DataCollatorWithPadding,
TrainingArguments,
Trainer)
from peft import PeftModel, PeftConfig, get_peft_model, LoraConfig
import evaluate
import torch
import numpy as np
2.4.2 微调数据构造
imdb_dataset = load_dataset("stanfordnlp/imdb")
N = 1000
rand_idx = np.random.randint(24999, size=N)
x_train = imdb_dataset['train'][rand_idx]['text']
y_train = imdb_dataset['train'][rand_idx]['label']
x_test = imdb_dataset['test'][rand_idx]['text']
y_test = imdb_dataset['test'][rand_idx]['label']
dataset = DatasetDict({
'train': Dataset.from_dict({'label': y_train, 'text': x_train}),
'validation': Dataset.from_dict({'label': y_test, 'text': x_test})
})
print(np.array(dataset['train']['label']).sum() / len(dataset['train']['label']))
{
"label": 0,
"text": "Not a fan, don't recommend."
}
2.4.3 加载初始模型
from transformers import AutoModelForSequenceClassification
model_checkpoint = 'distilbert-base-uncased'
id2label = {0: "Negative", 1: "Positive"}
label2id = {"Negative": 0, "Positive": 1}
model = AutoModelForSequenceClassification.from_pretrained(
model_checkpoint, num_labels=2, id2label=id2label, label2id=label2id)
模型架构为 6 层 Transformer,LoRA 影响 q_lin 层的权重(768*768 矩阵)。
2.4.4 Tokenize 与 Pad 预处理
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint, add_prefix_space=True)
if tokenizer.pad_token is None:
tokenizer.add_special_tokens({'pad_token': '[PAD]'})
model.resize_token_embeddings(len(tokenizer))
def tokenize_function(examples):
text = examples["text"]
tokenizer.truncation_side = "left"
tokenized_inputs = tokenizer(
text,
return_tensors="np",
truncation=True,
max_length=512,
padding='max_length'
)
return tokenized_inputs
tokenized_dataset = dataset.map(tokenize_function, batched=True)
from transformers import DataCollatorWithPadding
data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
- 数字化对齐:Tokenize 将文本转化为整数序列,对应词汇表中的单词或子词。
- 减少词汇量:切分为最小单位,降低复杂性,处理罕见词。
- 并行计算:统一固定长度,便于并行计算,长文本截断,短文本填充。
2.4.5 微调配置与训练
import torch
from peft import LoraConfig, get_peft_model
import evaluate
accuracy = evaluate.load("accuracy")
def compute_metrics(p):
predictions, labels = p
predictions = np.argmax(predictions, axis=1)
return {"accuracy": accuracy.compute(predictions=predictions, references=labels)}
peft_config = LoraConfig(
task_type="SEQ_CLS",
r=1,
lora_alpha=32,
lora_dropout=0.01,
target_modules=['q_lin']
)
model = get_peft_model(model, peft_config)
model.print_trainable_parameters()
输出显示可训练参数占比不到 1%,参数量越大,比例越小。
lr = 1e-3
batch_size = 4
num_epochs = 10
from transformers import TrainingArguments
training_args = TrainingArguments(
output_dir=model_checkpoint + "-lora-text-classification",
learning_rate=lr,
per_device_train_batch_size=batch_size,
per_device_eval_batch_size=batch_size,
num_train_epochs=num_epochs,
weight_decay=0.01,
evaluation_strategy="epoch",
save_strategy="epoch",
load_best_model_at_end=True,
)
from transformers import Trainer
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_dataset["train"],
eval_dataset=tokenized_dataset["validation"],
tokenizer=tokenizer,
data_collator=data_collator,
compute_metrics=compute_metrics,
)
trainer.train()
2.5 部署与推理优化
微调完成后,LoRA 权重可以合并到基座模型中,也可以单独加载。合并模型可减少推理时的内存占用,因为不再需要实时计算低秩矩阵加法。
from peft import PeftModel
merged_model = model.merge_and_unload()
merged_model.save_pretrained("./merged_model")
量化加速:
对于生产环境,建议结合量化技术(如 INT8 或 FP4)进一步降低显存需求。可使用 bitsandbytes 库加载量化模型。
2.6 最佳实践总结
- 数据清洗:确保训练数据无噪声,格式统一。
- 参数调优:
r 值通常从 4 开始尝试,alpha 设为 r 的 2 倍左右。
- 早停机制:监控验证集 Loss,防止过拟合。
- 混合精度训练:开启
fp16 或 bf16 加速训练并节省显存。
3. 结语
本文介绍了微调的基本概念,以及如何对语言模型进行微调。微调虽成本低于大模型的预训练,但对于大量参数的模型微调成本仍非常之高。好在随着算力增长,微调的成本门槛会越来越低,应用场景也会越来越多。
高质量的输入非常重要,类似于人去学习技能。阅读经典,反复阅读,才能掌握精髓。希望本文能帮助开发者快速上手大模型微调技术。
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- RSA密钥对生成器
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
- Mermaid 预览与可视化编辑
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
- 随机西班牙地址生成器
随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online
- Gemini 图片去水印
基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
- curl 转代码
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online