如何使用LoRA通过微调增强大模型

一直以来更加把精力放在AI的应用上,但是随着时间的推移发现模型微调也是AI应用一个无法迈过的坎,学习的路还很长,写文章也是督促自己继续下去的动力

环境安装

首先我们要做的就是微调模型的环境安装,这里我列出一下我使用的版本

CUDA版本

pytorch版本

依赖包

ini 复制代码
pip install modelscope==1.16.1
pip install transformers==4.43.1
pip install accelerate==0.32.1
pip install peft==0.11.1
pip install datasets==2.20.0

如果发现下载缓慢可以更换pip的仓库源

arduino 复制代码
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

数据准备

这里我们可以从魔塔中寻找自己感兴趣的训数据集

李火旺的数据集一下就进入我是视野,这里有意思的数据集好像也不多

寻找数据集时需要注意找我们的训练方式可以直接使用的数据集,我这边使用的训练方式是SFT,火子哥这个数据集是DPO方式训练的,我不能直接使用,但是找到了另一个甄嬛的数据集,也是挺有意思的

数据集的数据结构

这里只介绍两种数据集的结构,下面这种我们决定使用的数据集就是甄嬛传的数据集

SFT(监督式微调,Supervised Fine-Tuning)

  1. instruction 提示语/用户输入/上下文
  2. input 可选补充信息,如果为空表示没有附加输入
  3. output 模型应该生成的答案(监督信号)

DPO 训练是一种"偏好对比学习"

  1. prompt 用户输入,给模型看的提示语
  2. chosen 一个好的(偏好更高的)模型回答
  3. rejected 一个差的、被拒绝的回答

这是chatgpt给出的区别解释

项目 SFT(有监督微调) DPO(直接偏好优化)
🔧 训练目标 学会输出"标准答案" 学会偏好"更好"的回答
📊 数据需求 单条 input + output 多条 input + (chosen, rejected) 对比数据
📦 数据难度 易收集(只需一个好答案) 难收集(要构造两个回答并打分优劣)
🧠 模型训练方式 监督学习 近似偏好学习(强化学习的简化版)
💬 学到的能力 更加规范、模板化 更符合人类偏好,更自然、人性化
🚧 训练稳定性 高,收敛快 依赖对比样本质量,调参更敏感
⚠️ 错误传播风险 输出错误直接作为学习目标,会放大数据缺陷 错误样本影响小,因训练的是倾向
✅ 模型偏好优化 强,适用于对齐阶段(如RLHF)
🤖 生成多样性 低,偏模板化 高,鼓励多样表达

训练代码

引入必要依赖

javascript 复制代码
from datasets import Dataset
import pandas as pd
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM, DataCollatorForSeq2Seq, TrainingArguments, Trainer, GenerationConfig
from peft import LoraConfig, TaskType, get_peft_model
  1. datasets.Dataset 用于构造训练数据集
  2. pandas 用于读取和处理 json 数据
  3. transformers 加载预训练模型、分词器、训练参数等
  4. peft 进行 LoRA 低秩适配训练

数据处理函数

ini 复制代码
def process_func(example):
    MAX_LENGTH = 384    # Llama分词器会将一个中文字切分为多个token,因此需要放开一些最大长度,保证数据的完整性
    input_ids, attention_mask, labels = [], [], []
    instruction = tokenizer(f"<|begin_of_text|><|start_header_id|>system<|end_header_id|>\n\nCutting Knowledge Date: December 2023\nToday Date: 26 Jul 2024\n\n现在你要扮演皇帝身边的女人--甄嬛<|eot_id|><|start_header_id|>user<|end_header_id|>\n\n{example['instruction'] + example['input']}<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n", add_special_tokens=False)  # add_special_tokens 不在开头加 special_tokens
    response = tokenizer(f"{example['output']}<|eot_id|>", add_special_tokens=False)
    input_ids = instruction["input_ids"] + response["input_ids"] + [tokenizer.pad_token_id]
    attention_mask = instruction["attention_mask"] + response["attention_mask"] + [1]  # 因为eos token咱们也是要关注的所以 补充为1
    labels = [-100] * len(instruction["input_ids"]) + response["input_ids"] + [tokenizer.pad_token_id]
    if len(input_ids) > MAX_LENGTH:  # 做一个截断
        input_ids = input_ids[:MAX_LENGTH]
        attention_mask = attention_mask[:MAX_LENGTH]
        labels = labels[:MAX_LENGTH]
    return {
        "input_ids": input_ids,
        "attention_mask": attention_mask,
        "labels": labels
    }

训练代码

ini 复制代码
if __name__ == "__main__":
    model = AutoModelForCausalLM.from_pretrained('./LLM-Research/Meta-Llama-3___1-8B-Instruct', device_map="auto",torch_dtype=torch.bfloat16)
    model.enable_input_require_grads() # 开启梯度检查点时,要执行该方法
    tokenizer = AutoTokenizer.from_pretrained('./LLM-Research/Meta-Llama-3___1-8B-Instruct', use_fast=False, trust_remote_code=True)
    tokenizer.pad_token = tokenizer.eos_token

    # 将JSON文件转换为CSV文件
    df = pd.read_json('huanhuan.json')
    ds = Dataset.from_pandas(df)
    tokenized_id = ds.map(process_func, remove_columns=ds.column_names)

    config = LoraConfig(
        task_type=TaskType.CAUSAL_LM,
        target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
        inference_mode=False, # 训练模式
        r=8, # Lora 秩
        lora_alpha=32, # Lora alaph,具体作用参见 Lora 原理
        lora_dropout=0.1# Dropout 比例
    )
    model = get_peft_model(model, config)
    model.print_trainable_parameters() # 打印总训练参数

    args = TrainingArguments(
        output_dir="./output/llama3_1_instruct_lora",
        per_device_train_batch_size=4,
        gradient_accumulation_steps=4,
        logging_steps=10,
        num_train_epochs=3,
        save_steps=100,
        learning_rate=1e-4,
        save_on_each_node=True,
        gradient_checkpointing=True
    )
    trainer = Trainer(
        model=model,
        args=args,
        train_dataset=tokenized_id,
        data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True),
    )
    trainer.train() # 开始训练
训练代码的补充解释
加载模型和分词器
ini 复制代码
model = AutoModelForCausalLM.from_pretrained(...)
tokenizer = AutoTokenizer.from_pretrained(...)
读取数据集并转换格式
ini 复制代码
df = pd.read_json('huanhuan.json')
ds = Dataset.from_pandas(df)
tokenized_id = ds.map(process_func, remove_columns=ds.column_names)
LORA配置并应用到模型
ini 复制代码
config = LoraConfig(...)
model = get_peft_model(model, config)
训练参数配置
ini 复制代码
args = TrainingArguments(...)
创建 Trainer 并开始训练
scss 复制代码
trainer = Trainer(...)
trainer.train()

模型选择

模型我们选择一个8B的小模型,也是在modelscope下载就可以

复制代码
Meta-Llama-3-8B-Instruct

可以使用下面的代码下载

java 复制代码
import torch
from modelscope import snapshot_download, AutoModel, AutoTokenizer
import os

model_dir = snapshot_download('LLM-Research/Meta-Llama-3-8B-Instruct', cache_dir='/root/autodl-tmp', revision='master')

下载时间有点长,可能要耐心等待一下

耗时2个小时左右,漫长的等待,都是钱啊

开始训练

我设置了进行3轮训练

整个流程耗时20分钟左右,最大的耗时还是模型下载

微调后对话

复制代码
就写到这里,后续有什么新的内容再分享吧,微调学习才刚起步还需要多多实践,还有数据集制作等很多内容要学习
相关推荐
ApeAssistant4 分钟前
Log4j2.xml配置总结,就这个标题就挺好
后端·apache log4j
WanderInk14 分钟前
揭秘Java协变返回类型:让你的API少一点强转,多一点优雅
java·后端
机器之心17 分钟前
「世界模型」也被泼冷水了?邢波等人揭开五大「硬伤」,提出新范式
人工智能
心在飞扬20 分钟前
AI开发应用 01-nodejs快速入门
后端·aigc·dnodejs
甲丁23 分钟前
国内 Claude Code 接入指南(免费获得国内代理$100额度)
人工智能
Ray6624 分钟前
「阅读笔记」elasticSearch 是什么?工作原理是怎么样的?
后端
机器之心25 分钟前
刚刚,为对抗哥大退学生开发的AI作弊器,哥大学生造了个AI照妖镜
人工智能
paopaokaka_luck25 分钟前
基于SpringBoot+Vue的非遗文化传承管理系统(websocket即时通讯、协同过滤算法、支付宝沙盒支付、可分享链接、功能量非常大)
java·数据库·vue.js·spring boot·后端·spring·小程序
Binary_ey31 分钟前
AR/VR 显示画质失真?OAS百叶窗波导案例破难题
人工智能·ar·vr·软件需求·光学软件
运营黑客34 分钟前
Grok 4,来了。
人工智能·学习·ai·aigc