大模型 LoRA 微调:高效训练的秘密武器

目录

[1. 引言](#1. 引言)

[2. 环境准备](#2. 环境准备)

[3. 加载模型和分词器](#3. 加载模型和分词器)

[4. LoRA 算法简介](#4. LoRA 算法简介)

[5. 配置 LoRA 参数](#5. 配置 LoRA 参数)

参数解释

[6. 数据加载与预处理](#6. 数据加载与预处理)

[7. 训练超参数配置](#7. 训练超参数配置)

参数解释

[8. 训练模型](#8. 训练模型)

[9. 结论](#9. 结论)

github代码仓库https://github.com/huangxiaoye6/LLM-tuning

在自然语言处理(NLP)领域,大模型的微调一直是一个热门话题。传统的全量微调需要大量的计算资源和时间,而低秩自适应(LoRA)微调则提供了一种更加高效的解决方案。本文将详细介绍如何使用 LoRA 对 Qwen3-0.6B 模型进行微调,并深入探讨其中涉及的算法和参数。

1. 引言

大语言模型在各种 NLP 任务中表现出色,但由于其庞大的参数数量,全量微调往往变得非常昂贵。LoRA 通过在模型的某些层引入可训练的低秩矩阵,减少了需要训练的参数数量,从而显著降低了计算成本和内存需求。

2. 环境准备

首先,我们需要导入必要的库,并设置一些环境变量以避免警告信息。

python 复制代码
from peft import prepare_model_for_kbit_training,LoraConfig,get_peft_model
from transformers import AutoModelForCausalLM,AutoTokenizer,TrainingArguments,Trainer,default_data_collator
from datasets import load_dataset
import evaluate
import os
import warnings
warnings.filterwarnings('ignore')
os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "expandable_segments:True"

3. 加载模型和分词器

我们选择 Qwen3-0.6B 作为基础模型,并使用AutoModelForCausalLMAutoTokenizer来加载模型和分词器。

python 复制代码
model_name="Qwen/Qwen3-0.6B"
model=AutoModelForCausalLM.from_pretrained(model_name,device_map='auto',torch_dtype="auto")
tokenizer=AutoTokenizer.from_pretrained(model_name)

4. LoRA 算法简介

LoRA 的核心思想是通过在预训练模型的权重矩阵上添加低秩分解矩阵来实现微调。具体来说,对于一个权重矩阵 W,LoRA 将其更新为 \(W + \Delta W\),其中 \(\Delta W = BA\),B 和 A 是低秩矩阵。这样,我们只需要训练 B 和 A,而不需要更新整个 W。

5. 配置 LoRA 参数

在使用 LoRA 进行微调之前,我们需要配置一些参数。

python 复制代码
model = prepare_model_for_kbit_training(model)

lora_config = LoraConfig(
    r=16,  # LoRA矩阵的秩
    lora_alpha=32,  # LoRA alpha参数
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],  # 要应用LoRA的模块
    lora_dropout=0.05,  # Dropout概率
    bias="none",  # 是否训练偏置
    task_type="CAUSAL_LM",  # 任务类型
)

model = get_peft_model(model, lora_config)
model.print_trainable_parameters()  # 打印可训练参数

参数解释

  • r :LoRA 矩阵的秩,决定了低秩矩阵的维度。较小的r值可以减少训练参数的数量,但可能会影响模型的表达能力。
  • lora_alpha:缩放因子,用于调整低秩矩阵的影响程度。
  • target_modules :指定要应用 LoRA 的模块。在这个例子中,我们选择了注意力机制中的q_proj, k_proj, v_proj, 和 o_proj 模块。
  • lora_dropout:Dropout 概率,用于防止过拟合。
  • bias:是否训练偏置项。
  • task_type:任务类型,这里是因果语言模型(CAUSAL_LM)。

6. 数据加载与预处理

我们使用load_dataset函数从 JSON 文件中加载训练集和验证集。

复制代码
dataset = load_dataset('json', data_files={
    'train': '../数据集/data/train.json',
    'validation': '../数据集/data/eval.json'
})

然后,我们定义了两个函数来处理数据和进行分词。

复制代码
def process_fun(example):
    question=[]
    answer=[]
    for i in example['conversations']:
        for j in i:
            if j['from']=='human':
                question.append(j['value'])
            elif j['from']=='gpt':
                answer.append(j['value'])
    return {'question':question,'answer':answer}

process_data=dataset.map(process_fun,batched=True,remove_columns=dataset['train'].column_names)

def tokenizer_fun(examples):
    # 构建完整的指令格式(问:{问题}\n答:{答案})
    instructions = []
    for q, a in zip(examples['question'], examples['answer']):
        instruction = f"问:{q}\n答:{a}"
        instructions.append(instruction)
    
    encoded = tokenizer(
        instructions,
        max_length=512,
        truncation=True,
        padding="max_length",
        return_tensors="pt"
    )
    
    labels = encoded["input_ids"].clone()
    
    # 定位"答:"的位置,标记需要预测的部分
    answer_start_token = tokenizer.encode("答:", add_special_tokens=False)[0]
    
    # 遍历批次中的每个样本
    for i in range(len(labels)):
        # 找到每个样本中"答:"的第一个token位置
        answer_positions = (labels[i] == answer_start_token).nonzero(as_tuple=True)[0]
        if len(answer_positions) > 0:
            # 只取第一个"答:"的位置
            first_answer_pos = answer_positions[0]
            # 将"答:"之前的token标记为-100(忽略计算损失)
            labels[i, :first_answer_pos] = -100
    
    return {
        "input_ids": encoded["input_ids"],
        "attention_mask": encoded["attention_mask"],
        "labels": labels
    }

tokenized_dataset = process_data.map(
    tokenizer_fun,
    batched=True,
    remove_columns=process_data['train'].column_names
)

7. 训练超参数配置

我们使用TrainingArguments来配置训练参数。

复制代码
training_args = TrainingArguments(
    output_dir="./lora_train_qwen_0.6B_model",
    logging_steps=100,
    logging_dir='./runs',
    eval_strategy='epoch',
    num_train_epochs=3,
    per_device_train_batch_size=4,
    per_device_eval_batch_size=4,
    learning_rate=2e-5,
    weight_decay=0.01,
    save_strategy='epoch',
    load_best_model_at_end=True,
    metric_for_best_model='eval_loss',
    gradient_accumulation_steps=4,  # 如果GPU内存有限
)

参数解释

  • output_dir:训练结果的保存目录。
  • logging_steps:每多少步记录一次日志。
  • eval_strategy:评估策略,这里选择按 epoch 评估。
  • num_train_epochs:训练的轮数。
  • per_device_train_batch_size:每个设备的训练批次大小。
  • learning_rate:学习率,控制参数更新的步长。
  • weight_decay:权重衰减,用于防止过拟合。
  • save_strategy:保存策略,这里选择按 epoch 保存。
  • load_best_model_at_end:训练结束后是否加载最优模型。
  • metric_for_best_model:用于选择最优模型的指标,这里是验证集损失。
  • gradient_accumulation_steps:梯度累积步数,用于处理 GPU 内存有限的情况。

8. 训练模型

最后,我们使用Trainer类来训练模型。

复制代码
trainer=Trainer(
    model=model,
    args=training_args,
    eval_dataset=tokenized_dataset["validation"],
    train_dataset=tokenized_dataset["train"],
    data_collator=default_data_collator,
)

trainer.train()
trainer.save_model('./lora_train_qwen')

9. 结论

通过使用 LoRA 微调,我们可以在不牺牲太多模型性能的情况下,显著减少训练所需的计算资源和时间。本文详细介绍了如何使用 LoRA 对 Qwen3-0.6B 模型进行微调,并深入探讨了其中涉及的算法和参数。希望这篇文章能帮助你更好地理解和应用 LoRA 微调技术。

相关推荐
vlln12 小时前
【论文解读】rStar:用互洽方法增强 SLM(小型语言模型) 推理能力
人工智能·深度学习·语言模型·自然语言处理·transformer
勤奋的知更鸟18 小时前
深度学习神经网络架构Transformer深刻理解
深度学习·神经网络·transformer
Crabfishhhhh2 天前
神经网络学习-神经网络简介【Transformer、pytorch、Attention介绍与区别】
pytorch·python·神经网络·学习·transformer
追风哥哥2 天前
Transformer、RNN (循环神经网络) 和 CNN (卷积神经网络)的区别
rnn·深度学习·cnn·卷积神经网络·transformer
机器学习之心2 天前
Transformer-GRU、Transformer、CNN-GRU、GRU、CNN五模型时序预测对比
cnn·gru·transformer·cnn-gru·transformer-gru·五模型时序预测对比
Ai尚研修-贾莲2 天前
最新Transformer模型及深度学习前沿技术应用
人工智能·深度学习·transformer·生成式模型·图神经网络·注意力机制·目标检测算法
从零开始学习人工智能3 天前
LHM深度技术解析:基于多模态Transformer的单图秒级可动画3D人体重建模型
深度学习·3d·transformer
小扳3 天前
Web 毕设篇-适合小白、初级入门练手的 Spring Boot Web 毕业设计项目:智驿AI系统(前后端源码 + 数据库 sql 脚本)
java·数据库·人工智能·spring boot·transformer·课程设计
1296004524 天前
机器学习的可解释性
人工智能·深度学习·自然语言处理·transformer