LLM 课程文档
LoRA (低秩自适应)
并获得增强的文档体验
开始使用
LoRA (低秩自适应)
微调大型语言模型是一个资源密集的过程。LoRA 是一种允许我们用少量参数微调大型语言模型的技术。它的工作原理是向注意力权重添加和优化较小的矩阵,通常将可训练参数减少约 90%。
理解 LoRA
LoRA(低秩自适应)是一种参数高效的微调技术,它冻结预训练模型权重,并将可训练的秩分解矩阵注入到模型的层中。LoRA 不是在微调期间训练所有模型参数,而是通过低秩分解将权重更新分解为较小的矩阵,从而在保持模型性能的同时,显著减少可训练参数的数量。例如,当应用于 GPT-3 175B 时,与完全微调相比,LoRA 将可训练参数减少了 10,000 倍,GPU 内存需求减少了 3 倍。您可以在 LoRA 论文中阅读更多关于 LoRA 的信息。
LoRA 通过向 Transformer 层添加成对的秩分解矩阵来工作,通常侧重于注意力权重。在推理期间,这些适配器权重可以与基础模型合并,从而不会产生额外的延迟开销。LoRA 特别适用于将大型语言模型适应于特定任务或领域,同时保持资源需求可管理。
LoRA 的主要优势
内存效率:
- 只有适配器参数存储在 GPU 内存中
- 基础模型权重保持冻结,并且可以以较低精度加载
- 使在消费级 GPU 上微调大型模型成为可能
训练特性:
- 原生 PEFT/LoRA 集成,设置最少
- 支持 QLoRA(量化 LoRA),以获得更好的内存效率
适配器管理:
- 检查点期间的适配器权重保存
- 将适配器合并回基础模型的功能
使用 PEFT 加载 LoRA 适配器
PEFT 是一个库,它为加载和管理 PEFT 方法(包括 LoRA)提供了统一的接口。它允许您轻松加载和切换不同的 PEFT 方法,从而更容易地实验不同的微调技术。
适配器可以使用 load_adapter()
加载到预训练模型上,这对于尝试权重未合并的不同适配器非常有用。使用 set_adapter()
函数设置活动适配器权重。要返回基础模型,您可以使用 unload() 来卸载所有 LoRA 模块。这使得在不同的特定于任务的权重之间切换变得容易。
from peft import PeftModel, PeftConfig
config = PeftConfig.from_pretrained("ybelkada/opt-350m-lora")
model = AutoModelForCausalLM.from_pretrained(config.base_model_name_or_path)
lora_model = PeftModel.from_pretrained(model, "ybelkada/opt-350m-lora")
使用 trl 和 SFTTrainer 以及 LoRA 微调 LLM
trl
中的 SFTTrainer 通过 PEFT 库提供与 LoRA 适配器的集成。这意味着我们可以像使用 SFT 一样微调模型,但使用 LoRA 来减少我们需要训练的参数数量。
我们将在示例中使用 PEFT 中的 LoRAConfig
类。设置只需要几个配置步骤
- 定义 LoRA 配置(秩、alpha、dropout)
- 使用 PEFT 配置创建 SFTTrainer
- 训练并保存适配器权重
LoRA 配置
让我们了解一下 LoRA 配置和关键参数。
参数 | 描述 |
---|---|
r (秩) | 用于权重更新的低秩矩阵的维度。通常在 4-32 之间。较低的值提供更高的压缩率,但表达能力可能较差。 |
lora_alpha | LoRA 层的缩放因子,通常设置为秩值的 2 倍。较高的值会导致更强的适应效果。 |
lora_dropout | LoRA 层的 Dropout 概率,通常为 0.05-0.1。较高的值有助于防止训练期间的过拟合。 |
bias | 控制偏置项的训练。选项为“none”、“all”或“lora_only”。“none”对于内存效率最常见。 |
target_modules | 指定将 LoRA 应用于哪些模型模块。可以是“all-linear”或特定模块,如“q_proj,v_proj”。更多模块可以实现更大的适应性,但会增加内存使用量。 |
将 TRL 与 PEFT 结合使用
PEFT 方法可以与 TRL 结合使用进行微调,以减少内存需求。我们可以在加载模型时将 LoraConfig
传递给模型。
from peft import LoraConfig
# TODO: Configure LoRA parameters
# r: rank dimension for LoRA update matrices (smaller = more compression)
rank_dimension = 6
# lora_alpha: scaling factor for LoRA layers (higher = stronger adaptation)
lora_alpha = 8
# lora_dropout: dropout probability for LoRA layers (helps prevent overfitting)
lora_dropout = 0.05
peft_config = LoraConfig(
r=rank_dimension, # Rank dimension - typically between 4-32
lora_alpha=lora_alpha, # LoRA scaling factor - typically 2x rank
lora_dropout=lora_dropout, # Dropout probability for LoRA layers
bias="none", # Bias type for LoRA. the corresponding biases will be updated during training.
target_modules="all-linear", # Which modules to apply LoRA to
task_type="CAUSAL_LM", # Task type for model architecture
)
上面,我们使用了 device_map="auto"
来自动将模型分配到正确的设备。您也可以使用 device_map={"": device_index}
将模型手动分配到特定设备。
我们还需要使用 LoRA 配置定义 SFTTrainer
。
# Create SFTTrainer with LoRA configuration
trainer = SFTTrainer(
model=model,
args=args,
train_dataset=dataset["train"],
peft_config=peft_config, # LoRA configuration
max_seq_length=max_seq_length, # Maximum sequence length
processing_class=tokenizer,
)
✏️ 试一试! 基于上一节中微调的模型进行构建,但使用 LoRA 对其进行微调。使用 HuggingFaceTB/smoltalk
数据集微调 deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B
模型,使用我们上面定义的 LoRA 配置。
合并 LoRA 适配器
在使用 LoRA 进行训练后,您可能希望将适配器权重合并回基础模型,以便更轻松地部署。这将创建一个包含组合权重的单个模型,从而无需在推理期间单独加载适配器。
合并过程需要注意内存管理和精度。由于您需要同时加载基础模型和适配器权重,请确保有足够的 GPU/CPU 内存可用。在 transformers
中使用 device_map="auto"
将根据您的硬件找到模型的正确设备。
在整个过程中保持一致的精度(例如,float16),使其与训练期间使用的精度相匹配,并以相同的格式保存合并后的模型以进行部署。
合并实现
在训练 LoRA 适配器后,您可以将适配器权重合并回基础模型。以下是操作方法
import torch
from transformers import AutoModelForCausalLM
from peft import PeftModel
# 1. Load the base model
base_model = AutoModelForCausalLM.from_pretrained(
"base_model_name", torch_dtype=torch.float16, device_map="auto"
)
# 2. Load the PEFT model with adapter
peft_model = PeftModel.from_pretrained(
base_model, "path/to/adapter", torch_dtype=torch.float16
)
# 3. Merge adapter weights with base model
merged_model = peft_model.merge_and_unload()
如果您在保存的模型中遇到大小差异,请确保您也保存了分词器
# Save both model and tokenizer
tokenizer = AutoTokenizer.from_pretrained("base_model_name")
merged_model.save_pretrained("path/to/save/merged_model")
tokenizer.save_pretrained("path/to/save/merged_model")
✏️ 试一试! 将适配器权重合并回基础模型。使用 HuggingFaceTB/smoltalk
数据集微调 deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B
模型,使用我们上面定义的 LoRA 配置。