返回教程列表
高级AI教程
2026/6/25

LoRA 与 QLoRA 微调大模型

LoRA 通过低秩矩阵适配实现参数高效微调,QLoRA 进一步引入 4-bit 量化。本文演示在单卡 24G 显存上微调 7B 模型的完整流程。

53

阅读

👍

0

点赞

💬

0

评论

# LoRA 与 QLoRA 微调大模型

简介

在大模型时代,微调(Fine-tuning)是让预训练模型适应特定任务的关键技术。然而,传统全参数微调需要消耗巨大的计算资源——一个 7B 参数的模型全量微调需要约 60GB 显存,这让大多数研究者和开发者望而却步。

**LoRA(Low-Rank Adaptation)** 和 **QLoRA(Quantized LoRA)** 的出现彻底改变了这一局面。通过低秩矩阵分解和量化技术的结合,我们可以在单张 24GB 显存的 GPU 上完成 7B 参数模型的微调,大幅降低了定制大模型的门槛。

LoRA 核心原理

什么是低秩适配?

LoRA 的核心思想源于一个关键假设:**大模型在微调过程中,权重矩阵的更新本质上处于一个低秩空间**。换句话说,我们不需要调整全部参数,只需要学习一小部分“增量信息”即可实现有效的任务适配。

LoRA 对预训练权重矩阵 $W_0 \in \mathbb{R}^{d \times k}$ 进行低秩分解:

$$W = W_0 + \Delta W = W_0 + BA$$

其中:

  • $B \in \mathbb{R}^{d \times r}$ 和 $A \in \mathbb{R}^{r \times k}$ 是可训练的低秩矩阵
  • $r \ll \min(d, k)$ 是秩(rank),通常取 4-64
  • 前向传播时:$h = W_0 x + BAx$
  • LoRA 的优势

  • **显存效率**:仅需训练约 0.1%-1% 的原始参数
  • **推理零延迟**:推理时可合并 $W_0 + BA$ 为新权重
  • **可插拔**:可针对不同任务保存多个 LoRA 权重,灵活切换
  • **收敛稳定**:实验表明 LoRA 收敛行为与全量微调相近
  • QLoRA 核心原理

    QLoRA 在 LoRA 基础上引入了**NF4(4-bit NormalFloat)量化**技术,进一步降低显存占用:

    | 优化技术 | 描述 | 显存节省 |

    |---------|------|---------|

    | 4-bit NF4 量化 | 将权重压缩到 4-bit | ~4x |

    | 双重量化 | 对量化常数再次量化 | ~2x |

    | 分页注意力 | 处理内存峰值 | 稳定性 |

    **关键洞察**:LoRA 参数仍使用 fp16/bf16 训练,但基座模型的 4-bit 量化大幅减少了 **模型权重** 的显存占用,使得 7B 模型从 ~14GB 降至 ~3.5GB。

    环境准备与依赖安装

    硬件要求

  • GPU:NVIDIA RTX 3090 / 4090 或 A100(24GB 显存)
  • 内存:建议 32GB+ 系统内存
  • 存储:至少 50GB 可用空间(模型 + 数据集)
  • 依赖安装

    # 创建虚拟环境

    conda create -n qlora python=3.10

    conda activate qlora

    # 安装核心依赖(以 PEFT 库为例)

    pip install transformers accelerate peft datasets bitsandbytes

    pip install flash-attn --no-build-isolation # 可选,加速注意力计算

    # 验证安装

    python -c "import peft, transformers, bitsandbytes; print('环境配置成功')"

    完整实操流程

    以下代码演示使用 QLoRA 在中文指令数据集上微调 ChatGLM3-6B:

    1. 数据准备

    from datasets import load_dataset

    # 加载alpaca格式的中文数据

    dataset = load_dataset("yahma/alpaca-chinese", split="train")

    dataset = dataset.shuffle(seed=42).select(range(1000)) # 演示用少量数据

    def format_instruction(sample):

    """构建指令微调格式"""

    return {

    "prompt": f"指令: {sample['instruction']}\n输入: {sample['input']}\n输出: ",

    "response": sample['output']

    }

    dataset = dataset.map(format_instruction, remove_columns=dataset.column_names)

    2. 模型加载(4-bit 量化)

    import torch

    from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig

    # QLoRA 量化配置

    quantization_config = BitsAndBytesConfig(

    load_in_4bit=True,

    bnb_4bit_compute_dtype=torch.bfloat16,

    bnb_4bit_use_double_quant=True,

    bnb_4bit_quant_type="nf4"

    )

    model_name = "THUDM/chatglm3-6b"

    tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)

    model = AutoModelForCausalLM.from_pretrained(

    model_name,

    quantization_config=quantization_config,

    device_map="auto",

    trust_remote_code=True

    )

    3. LoRA 配置与模型准备

    from peft import LoraConfig, get_peft_model, TaskType

    lora_config = LoraConfig(

    task_type=TaskType.CAUSAL_LM,

    r=8, # 秩,越大越强但更慢

    lora_alpha=16, # 缩放因子

    lora_dropout=0.05,

    target_modules=[ # 指定要添加 LoRA 的层

    "query_key_value",

    "dense",

    "dense_h_to_4h",

    "dense_4h_to_h"

    ],

    bias="none"

    )

    model = get_peft_model(model, lora_config)

    model.print_trainable_parameters()

    # 输出示例: trainable params: 4,194,304 || all params: 6,383,874,560 || trainable%: 0.0657

    4. 训练配置与启动

    from transformers import TrainingArguments

    training_args = TrainingArguments(

    output_dir="./chatglm3-lora",

    per_device_train_batch_size=4,

    gradient_accumulation_steps=4, # 等效 batch_size=16

    learning_rate=1e-4,

    num_train_epochs=3,

    fp16=True,

    logging_steps=10,

    save_strategy="epoch",

    optim="paged_adamw_8bit", # 节省优化器显存

    max_grad_norm=0.3,

    )

    trainer = Trainer(

    model=model,

    args=training_args,

    train_dataset=dataset,

    data_collator=data_collator,

    )

    trainer.train()

    5. 模型推理与权重合并

    # 加载 LoRA 权重进行推理

    from peft import PeftModel

    base_model = AutoModelForCausalLM.from_pretrained(

    model_name, quantization_config=quantization_config

    )

    model

    评论 (0)

    暂无评论,来说点什么吧