基于 LoRA(Low-Rank Adaptation)的千问小模型微调代码

import torch
from datasets import load_dataset
from transformers import (
    AutoModelForCausalLM,
    AutoTokenizer,
    TrainingArguments,
    BitsAndBytesConfig,
    DataCollatorForLanguageModeling
)
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
from trl import SFTTrainer

# 1. 配置参数
MODEL_NAME = "Qwen/Qwen-7B-Chat"  # 千问7B模型
DATASET_NAME = "timdettmers/openassistant-guanaco"  # 示例数据集
OUTPUT_DIR = "./qianwen-finetuned"
LORA_R = 8
LORA_ALPHA = 32
LORA_DROPOUT = 0.05
TRAIN_BATCH_SIZE = 2
GRADIENT_ACCUMULATION_STEPS = 4
LEARNING_RATE = 2e-4
NUM_EPOCHS = 3
FP16 = True  # 如果GPU支持FP16混合精度训练

# 2. 加载数据集并预处理
def format_prompt(sample):
    """格式化对话数据为千问模型所需格式"""
    prompt = f"### 问题: {sample['question']}\n### 回答: {sample['response']}"
    return {"text": prompt}

dataset = load_dataset(DATASET_NAME)['train']
dataset = dataset.map(format_prompt)

# 3. 加载分词器
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
tokenizer.pad_token = tokenizer.eos_token  # 设置填充token

# 4. 配置量化参数(4-bit量化以节省显存)
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_use_double_quant=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.float16
)

# 5. 加载模型
model = AutoModelForCausalLM.from_pretrained(
    MODEL_NAME,
    quantization_config=bnb_config,
    device_map="auto",
    trust_remote_code=True
)
model = prepare_model_for_kbit_training(model)

# 6. 配置LoRA
lora_config = LoraConfig(
    r=LORA_R,
    lora_alpha=LORA_ALPHA,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
    lora_dropout=LORA_DROPOUT,
    bias="none",
    task_type="CAUSAL_LM"
)

# 应用LoRA适配器
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()  # 打印可训练参数比例

# 7. 配置训练参数
training_args = TrainingArguments(
    output_dir=OUTPUT_DIR,
    per_device_train_batch_size=TRAIN_BATCH_SIZE,
    gradient_accumulation_steps=GRADIENT_ACCUMULATION_STEPS,
    learning_rate=LEARNING_RATE,
    num_train_epochs=NUM_EPOCHS,
    fp16=FP16,
    logging_dir=f"{OUTPUT_DIR}/logs",
    logging_steps=10,
    save_strategy="epoch",
    report_to="none",
    optim="paged_adamw_8bit"  # 使用8bit优化器
)

# 8. 初始化训练器
trainer = SFTTrainer(
    model=model,
    train_dataset=dataset,
    peft_config=lora_config,
    dataset_text_field="text",
    max_seq_length=512,
    tokenizer=tokenizer,
    args=training_args,
    data_collator=DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)
)

# 9. 开始训练
trainer.train()

# 10. 保存模型
model.save_pretrained(f"{OUTPUT_DIR}/lora_model")
tokenizer.save_pretrained(f"{OUTPUT_DIR}/tokenizer")

# 11. 推理示例
def generate_response(prompt, max_length=200):
    inputs = tokenizer(prompt, return_tensors="pt").to("cuda")
    outputs = model.generate(
        **inputs,
        max_length=max_length,
        temperature=0.7,
        do_sample=True
    )
    return tokenizer.decode(outputs[0], skip_special_tokens=True)

# 测试微调后的模型
test_prompt = "### 问题: 什么是人工智能?\n### 回答:"
print(generate_response(test_prompt))

<think>我们正在讨论LoRA技术,用户要求了解其概念和使用方法。根据提供的引用,我们需要整理LoRA的核心原理、实现方法以及应用场景。引用内容总结:[^1]:LoRA是一种微调技术,通过引入低秩矩阵调整预训练大模型(如BERT、GPT)的权重,以减少计算和存储开销。[^2]:LoRA利用矩阵分解和低秩近似减少微调参数,降低训练成本,同时保持性能。[^3]:LoRA的灵感来自矩阵低秩近似,因为大型模型的权重矩阵通常具有冗余性,可以通过低秩分解减少参数量。[^4]:介绍了LoRA的变种与改进,如QLoRA(量化)、AdaLoRA(动态分配秩)、DoRA(分解权重)、LoRA-GA(优化初始化)和MoRA(高秩适应)。[^5]:LoRA通常只加在SelfAttention层的Q,K,V,O矩阵上,并提到与Adapter的区别(这里用户题未要求,但可简要提及)。根据用户题"我想了解低秩适应微调LoRA)的概念和使用方法",我们将回答分为两部分:1.概念(核心原理)2.使用方法(实现方式、典型应用场景、变种等)结构安排:一、LoRA的基本概念1.1题背景(为什么需要LoRA?)1.2核心思想1.3数学原理二、LoRA的实现方法2.1微调过程2.2参数添加位置2.3具体实现步骤(伪代码代码示例)三、LoRA的变体与应用场景3.1主要变种(参考引用[4])3.2典型应用场景四、与其它微调方法的对比(简要)五、总结注意事项:使用数学表达式时,按照系统指令,行内公式用$...$,独立公式用$$...$$。由于引用中提供了多个公式,我们结合引用[3]的数学原理来写。开始组织回答:</think> ### Low-Rank Adaptation (LoRA) 微调技术详解 #### 一、核心概念 **LoRA**是一种针对预训练大模型(如BERT、GPT等)的参数高效微调技术,其核心是通过**低秩分解**引入额外的轻量级适配矩阵$A$和$B$,使模型在适应新任务时仅需微调少量参数[^1][^3]。 **与传统微调的对比**: | 特征 | 传统微调 | LoRA微调 | |--------------|--------------------------|--------------------------| | 参数更新范围 | 全量权重更新 | 仅低秩矩阵$A$/$B$更新 | | 显存占用 | 高(需存储梯度/优化状态)| 极低(只新增0.1%-1%参数)| | 计算开销 | 高(反向传播全模型) | 低(仅计算适配层梯度) | | 任务切换效率 | 需重新训练整个模型 | 快速切换(保留原权重) | #### 二、数学原理 1. **低秩近似基础**: 给定预训练权重矩阵$W_0 \in \mathbb{R}^{d \times k}$,LoRA将其增量更新分解为两个低秩矩阵的乘积: $$ \Delta W = BA \quad \text{其中} \quad B \in \mathbb{R}^{d \times r}, \ A \in \mathbb{R}^{r \times k}, \ r \ll \min(d,k) $$ 微调后的权重变为:$W = W_0 + BA$[^3]。 2. **前向传播流程**: 对输入$h$,输出为: $$ h' = W_0 h + B(Ah) $$ 新增计算量仅来自$Ah$和$B(Ah)$的乘法操作,复杂度为$O(d \cdot r + r \cdot k)$,远低于全参更新$O(d \cdot k)$[^2]。 #### 三、实现方法 ```python import torch.nn as nn class LoRALayer(nn.Module): def __init__(self, base_layer, rank=8): super().__init__() self.base_layer = base_layer # 冻结的预训练层 d, k = base_layer.weight.shape self.A = nn.Parameter(torch.randn(d, rank)) # 低秩矩阵A self.B = nn.Parameter(torch.zeros(rank, k)) # 低秩矩阵B def forward(self, x): base_output = self.base_layer(x) # 原始输出 lora_output = x @ (self.A @ self.B).T # 低秩适配输出 return base_output + lora_output ``` **关键实现步骤**: 1. **选择适配层**:通常添加在Transformer的$Q, K, V, O$矩阵(自注意力层)[^5],其他层如MLP保持冻结。 2. **秩$r$设置**:经验取值$r=8$或$r=16$(任务复杂度越高,$r$需增大)。 3. **初始化策略**: - $A$用高斯分布初始化,$B$初始化为零矩阵 - 使用LoRA-GA优化技术可加速收敛[^4] #### 四、应用场景与变体 | 场景类型 | 推荐变体 | 核心优势 | |------------------|-------------|------------------------------| | 显存受限(单卡) | QLoRA[^4] | 量化权重(4/8-bit)省显存 | | 多任务迁移 | AdaLoRA[^4] | 动态调整不同模块的秩$r$ | | 高精度任务 | DoRA[^4] | 分解权重为幅度向量+方向矩阵 | | 复杂推理任务 | MoRA[^4] | 高秩适应(需更高算力) | **典型应用**: - **领域自适应**:金融/医疗文本微调时节省90%训练资源[^2] - **多语言扩展**:冻结原模型,用LoRA添加新语言适配器 - **轻量化部署**:将$BA$合并到$W_0$中,推理无额外开销[^1] #### 五、性能对比 1. **参数效率**: LoRA微调0.5%-2%参数量(如175B GPT-3仅需14M可训参数),比全量微调参数减少$100-1000$倍[^2]。 2. **收敛速度**: 在GLUE基准测试中,LoRA达到与传统微调相同性能,训练时间缩短$40\%$-60%[^3][^4]。 3. **任务兼容性**: 在文本分类、机器翻译、指令微调等任务中均验证有效[^5]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

甜辣uu

谢谢关注再接再厉

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值