LoRA 和 QLoRA 都是针对  大语言模型(LLM)高效微调  的技术,核心目标是在降低计算资源消耗的同时,保持甚至提升模型微调效果。


一、LoRA

权重的更新矩阵(ΔW)具有“内在的低秩特性”,因此 ΔW 实际上可以用两个更小的矩阵(A 和 B)的乘积来近似表示。

  • 原始权重矩阵W(尺寸d * k)
  • 低秩矩阵A(d * r)
  • 低秩矩阵B(r * k)

(其中 r≪min(d,k),称为 “秩”),将参数更新表示为 ΔW=BA。

(一)工作原理

  1. 冻结预训练权重:保持原始模型的所有参数 W 不变,避免了在微调过程中损坏模型已有的知识。
  2. 注入旁路矩阵:在模型的某些层(通常是Transformer的Attention层的Q, K, V, O投影矩阵)旁,插入一对可训练的、低秩的矩阵 A和B。(矩阵A通常用随机高斯分布初始化。矩阵B通常初始化为零,这样一开始旁路为零,不影响原始模型输出。)
  3. 仅训练新增参数:在微调过程中,只训练优化这些新增的低秩矩阵 A和B 的参数。原始模型参数保持不变。
  4. 推理合并:训练完成后,可以将低秩矩阵和原始权重矩阵合并:W_new =  W + BA 。这样在推理时不会引入任何额外的延迟或计算开销,因为合并后的模型和原始模型结构完全一样。

(二)局限

仍需加载完整的预训练模型权重(通常为 FP16 精度),内存占用较高(例如,1750 亿参数模型需约 35GB 内存)。

(三)优势

参数量仅为全量微调的千分之一到万分之一;只需存储和优化极少的参数;大大降低了GPU显存需求。更快的训练速度和更低的计算成本。可以为一个基础模型训练多个不同的LoRA适配器(用于不同任务),加载不同的LoRA权重,可以快速在不同任务模型间切换。


二、QLoRA

在 LoRA 基础上引入模型量化,进一步降低内存需求,使大模型微调可在消费级 GPU 上实现。

(一)工作原理:

  1. 将预训练模型以4位精度(NF4) 量化加载并冻结,
  2. 再在量化后的权重上应用 LoRA
  3. 通过反向传播与梯度计算的方式保留其性能,在反向传播过程中,权重始终是以将4位权重反量化回BF16/FP16的高精度形式参与计算的,只是存储时是4位。这确保了训练过程的数值稳定性,使得用4位权重训练的模型最终性能几乎与全精度微调相当。

(二)关键技术

  • 4位 NormalFloat (NF4) 量化:一种针对神经网络权重分布最优化的4位数据类型。它比标准的INT4量化更能保持模型的性能。
  • 双量化:对第一次量化产生的量化常数(constants)进行第二次量化,进一步节省内存。这相当于对量化参数的“元量化”。
  • 分页优化器:利用NVIDIA统一内存特性,在GPU显存不足时自动将优化器状态转移到CPU RAM,防止内存溢出(OOM)错误。类似于电脑内存和虚拟内存的切换。

(三)局限

量化过程需额外计算,初始化时间略长。

(四)优势

内存需求比 LoRA 降低 4-5 倍;几乎不损失模型性能(与 LoRA 效果相当,尽管使用了量化,但通过NF4和反量化技巧,其微调效果被证明可以接近全精度微调)。保留 LoRA 的所有优点(低参数量、快速切换任务等)


三、实践

(一)代码实现步骤

  1. 平台:本地机器 或者租用GPU的云服务平台(AutoDL);
  2. 安装核心库;
  3. 数据处理:加载数据集、格式化数据、分词(Tokenization,将文本转换为 token);
  4. 加载量化模型:使用bitsandbytes加载 4 位量化的预训练模型;
  5. 配置 LoRA 适配器:通过peft设置 LoRA 参数;
  6. 设置训练参数;
  7. 启动训练;
  8. 监控显存和损失函数;
  9. 模型评估与测试:使用验证集评估困惑度(Perplexity)或任务指标(如准确率);
  10. 加载训练后的模型进行推理,测试生成效果;
  11. 合并模型:将 LoRA 适配器与基础模型合并,生成完整模型。

常用依赖库:

PyTorch 和 CUDA

PyTorch:深度学习框架
transformers:Hugging Face的模型库,加载预训练模型和tokenizer分词器
PEFT:核心库,提供LoRA、QLoRA等高效微调方法,管理 LoRA 适配器,仅训练少量低秩矩阵参数。
bitsandbytes:核心库,实现模型 4 位量化,将预训练模型权重压缩至低精度,降低显存占用。
datasets:方便地加载和处理数据集(如分词、格式转换)
accelerate:训练加速与分布式支持,自动处理 GPU/CPU 资源分配,支持单卡 / 多卡训练。
trl:简化RLHF过程,其中的SFTTrainer对QLoRA很好用
wandb (可选):训练可视化与监控,查看损失曲线
evaluate:评估工具

pip install peft transformers==4.35.2 datasets bitsandbytes tiktoken transformers_stream_generator accelerate trl evaluate

基座模型:从魔搭社区 或者 Hugging Face下载。

注意:确保下载的是原始预训练权重,而不是已经微调过的版本。

数据集(Dataset):

  • 魔搭社区找

  • 使用开源指令数据集,如Alpaca等。

  • 使用LLM生成。

格式:

[
  {
    "instruction": "将下面的英文翻译成中文。",
    "input": "Hello, world!",
    "output": "你好,世界!"
  }
]

(二)Llama-Factory开源工具微调

操作步骤:

  1. GPU云平台租机器(AutoDL)
  2. 本机通过SSH连接远程租用的服务器,进入/root/autodl-tmp目录
  3. git克隆Llama-Factory仓库、安装python3.10版本环境
  4. 进入Llama-Factory目录,安装相关依赖
  5. 下载基座模型
  6. 准备训练数据集文件,放到LlaMA-Factory/data目录下,并在dataset_info.json文件里配置训练数据集文件名
  7. 启动Llama-Factory,在可视化界面微调

(三)核心参数

1、秩(r)

控制 LoRA 新增的 “低秩矩阵” 维度,决定模型的拟合能力上限参数数量

r 越小:新增参数越少(更轻量),模型能学习的 “细节”更少;

r 越大:新增参数越多(略重),但能捕捉数据中更复杂的规律。

  • 过小:拟合不足,学不会核心规律,微调无效。
  • 过大:过拟合,换新数据(测试集)表现差;参数冗余,训练速度变慢、占用显存增加。

2、学习率(lr)

学习的速度,控制每次参数更新的 幅度,即模型根据训练误差调整参数的幅度。

  • 过小:训练太慢,需要极多轮次才能收敛,耗时耗资源;只学会了训练数据的表面规律,没理解深层逻辑。
  • 过大:损失值(loss)来回震荡,无法稳定下降。也可能loss 越来越大,模型输出完全混乱。

3、缩放因子(alpha)

微调力度的放大器,调整对原模型的 影响幅度,通常建议 alpha = r,此时更新幅度适中,既能保留原模型能力,又能融入新数据特征。

  • 过小:微调 “没劲儿”,训练后模型几乎没变化。
  • 过大:原模型的通用能力被 破坏;损失值(loss)剧烈波动。

4、训练轮次(epochs)

控制模型在 训练数据集上学习的次数

  • 过小:欠拟合,模型没学够,连训练数据里的基本规律都没掌握。
  • 过大:过拟合,模型把训练数据的 “噪音”(比如数据里的错别字、特殊表述)都当成规律记住,测试新数据时错误率飙升。

5、批大小(batch size)

模型更新时每次同时处理的 “样本数量”

  • 过小:单次样本太少,误差波动大,loss 忽高忽低 跳变;需要更多次更新才能跑完所有样本,导致训练变慢。
  • 过大:显卡装不下,显存溢出;泛化差,样本太集中,模型容易 “偏科”。

6、目标模块

指定模型微调哪些模块,即选择插入 LoRA 低秩矩阵的模块,主流是 Transformer 注意力层的 Q/K/V 投影层(如q_proj、k_proj)。

  • 选少 / 选错:只调 v_proj 忽略 q_proj,模型无法学习新领域的 “语义匹配规则”,效果差;
  • 选多:连 embedding 层(词嵌入)都调,参数冗余、破坏原模型基础语义(如 “医生” 词向量偏离通用含义)。

7、权重衰减

给 LoRA 参数加 “惩罚项”(让参数值尽量小),避免过度依赖某类特征。

  • 过小:惩罚不足,参数膨胀,过拟合。
  • 过多:惩罚过强,参数接近 0,等效 “没微调”。

8、序列长度(max_seq_length)

限制单次处理的文本长度(单位:token),超长截断、不足填充。

  • 过小问题:长文本关键信息被截断(如法律合同核心条款丢失)
  • 过大问题:显存暴增(OOM)、训练变慢(长文本计算量大)

9、梯度累积步数(gradient_accumulation_steps)

显存不足时,用 “多次 小batch size 累积梯度后 更新参数”,模拟大批量 效果(如 批次batch = 8 batch size + 累积 4 步 =  32)。

  • 过小:无法利用显存,仍等效小 batch,训练不稳定。
  • 过大:训练速度变慢(需 累积多步 才更新),异常时浪费更多计算。

(四)训练的监控与评估

1、微调效果监控
  • 离线工具:TensorBoard —— loss损失函数、梯度、学习率等变化情况。
  • Weights & Biases(W&B,又称 “权重与偏差”):一站式实验管理,自动记录超参数(如 r、alpha、学习率)、指标、代码版本,支持多实验对比(快速找到最优 LoRA 配置);可视化 损失曲线、学习率曲线、显存占用。适合需要对比不同 LoRA 参数组合的场景。

  • 显存占用:用 nvidia-smi(Linux)实时查看,若接近 24GB,需降低 batch size。

2、微调结果评估
  • evaluate:Hugging Face 生态的官方评估库,集成了 100 + 常用评估指标常用评估指标(如准确率、BLEU、ROUGE、F1 等),支持文本分类、生成、翻译、问答等几乎所有 NLP 任务。开箱即用,直接调用预定义指标(如evaluate.load("bleu")计算 BLEU 分数)。
  • evalscope:字节跳动推出的,高效的 “一站式评估解决方案”,提供全链路、多维度、可扩展的评估能力,支持 NLP 主流任务评估,支持批量输入测试集,自动调用模型推理、计算指标、生成可视化报告(无需手动拼接多个工具结果);支持分布式评估,可高效处理十万级甚至百万级测试样本;可自定义指标;支持本地部署。

EM:衡量生成答案与标准答案是否完全一致;

F1:衡量词级重叠度。

(五)常见问题与调试

1、显存不足(CUDA Out of Memory)

  • 降低 batch size。
  • 降低 max_seq_length。
  • 降低 LoRA 的 r 值。
  • 增加 梯度累积步数 来补偿变小的batch size。

2、训练损失不下降

  • 检查数据格式是否正确。
  • 尝试提高学习率 (如 2e-4 -> 5e-4)。
  • 确保你的数据集和任务相关且质量高。

损失函数波动大:

  • 可降低 学习率
  • 减小 batch size
  • 或增大 gradient_accumulation_steps

生成的结果毫无意义

  • 可能是训练步数不够,增加 num_train_epochs
  • 检查提示词模板是否和训练时一致。

防止过拟合:补正则化(增大权重衰减、增大丢弃)

(六)显存占用核心组成

  • 量化后的模型权重(4-bit NormalFloat 格式):例如,70 亿参数模型约占用 3.5GB 显存(每个参数 0.5 字节)。
  • LoRA 适配器参数:假设秩(Rank)设为 16,LoRA 参数约为原模型的 0.1%(700 万参数),存储 + 优化器状态约需 1.5GB。
  • 激活值与临时缓存:与批量大小(Batch Size)和序列长度直接相关。例如,Batch Size=8、序列长度 = 2048 时,需约 6-8GB。
  • 系统与框架开销:约 5GB(包括 PyTorch、CUDA 等运行时环境)。

总显存占用估算公式:总显存 ≈ 量化模型+LoRA参数+激活值+系统开销

实践中,通常关注

  • 激活值内存:序列长度和 Batch Size 的乘积,是显存消耗的 “杀手”。
  • LoRA 超参数:增大秩(Rank)或训练更多层会增加显存。例如,秩从 16 增至 32 时,LoRA 参数和优化器状态可能翻倍。

实战技巧:

  • 批量大小:从最小可行值(如 Batch Size=2)逐步增加,直至触发显存溢出,再回退一档。
  • 适配器:优先在注意力层的 Query/Value 矩阵插入适配器,而非全连接层。
  • 秩:根据任务复杂度选择秩(Rank):简单任务(如风格微调)用 8-16,复杂任务(如多轮对话)用 32-64。
  • 使用梯度检查点:通过torch.utils.checkpoint减少激活值存储,但会增加训练时间(约 10-20%)。


(七)在 RTX 3090/4090(24GB 显存)上,通过QLoRA 技术可训练的模型大小

基于使用bitsandbytes 库进行NF4量化分析,并采用AdamW优化器。

1. 7B 模型 (例如 LLaMA-2-7b, Mistral-7b)

体验非常轻松。这是24GB显卡的“甜点”尺寸。

典型配置

  • Batch Size:可以设置相对较大的批处理大小(如 16, 32 甚至更高)。

  • 序列长度:可以轻松支持 2048 或 4096 的上下文长度。

  • LoRA Rank (r):可以设置较高的秩(如 256, 512)以获得更好的性能,而不会爆显存。

  • 梯度累积:不需要或只需很少的步数。

显存占用:训练时显存占用通常在 12GB ~ 18GB 之间,留有充足余量。
 

2. 13B 模型 (例如 LLaMA-2-13b)

体验依然流畅。这是24GB显卡非常舒适和实用的选择。

典型配置

  • Batch Size:需要适当降低批处理大小(如 4, 8, 16)。

  • 序列长度:2048 很轻松,4096 需要小心调整。

  • LoRA Rank (r):常用的秩(64, 128)完全没问题。

  • 梯度累积:可能需要使用较小的梯度累积步数来等效增大batch size。

显存占用:训练时显存占用通常在 18GB ~ 22GB 之间,需要关注显存使用情况。

3. 33B/34B 模型 (例如 LLaMA-2-34b)

体验可行,但有挑战性。需要“精打细算”地配置参数,已经触及24GB显存的极限。

典型配置

  • Batch Size:必须设置得很小(通常为 1 或 2)。这是最大的限制。

  • 序列长度:可能需要降低到 1024 或 2048。尝试使用 4096 会非常困难,极易OOM(Out Of Memory)。

  • LoRA Rank (r):需要使用较低的秩(如 32, 64)。

  • 梯度累积:必须使用较高的梯度累积步数(如 8, 16)来补偿极小的batch size,以确保训练稳定性。

  • 启用CPU分页优化器:必须开启,以防止在偶尔的显存峰值下出现OOM。

显存占用:训练时显存占用会非常接近 24GB,任何额外的开销(如更长的序列、更大的秩)都会导致OOM。

建议:

使用监控工具:在训练时,使用 nvidia-smi或 nvitop等工具实时监控显存使用情况。

利用现有代码库:使用像 AxolotlPEFT (Parameter-Efficient Fine-Tuning) 库,它们已经内置了良好的QLoRA默认配置,并支持梯度检查点、分页优化器等特性,能帮你自动处理很多显存优化问题。

四、Adam 和 AdamW 优化器

1、Adam

结合动量(Momentum)自适应学习率(RMSProp)。维护一阶矩(均值,对应动量)和二阶矩(方差),更新时修正偏差,

2、AdamW

在 Adam 基础上增加了权重衰减,更适合抑制过拟合,将 权重衰减 与 梯度更新 解耦(更新时单独施加权重衰减),解决 Adam 权重衰减的偏差问题,更利于泛化。

五、样本

Zero-shot(零样本)One-shot(单样本)、Few-shot(少样本)

核心差异 在于 “用于学习新任务的标注样本数量”。

Zero-shot 模型无任何标注样本,仅靠任务描述完成新任务 0 个 让模型识别从未见过的 “长尾类别”(如 “区分不同品种的蝴蝶”,未给样本)
One-shot 模型仅用 1 个标注样本学习新任务 1 个 给模型 1 张 “梵高风格画作” 样本,让它生成新的梵高风格画
Few-shot 模型用少量(通常 2~100 个)标注样本学习新任务 2~100 个 给模型 5 个 “故障设备日志 + 故障类型” 的样本,让它分类新的设备日志

Logo

更多推荐