如何使用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分钟左右,最大的耗时还是模型下载

微调后对话

复制代码
就写到这里,后续有什么新的内容再分享吧,微调学习才刚起步还需要多多实践,还有数据集制作等很多内容要学习
相关推荐
小a彤3 分钟前
elec-ops-inspection:电力巡检缺陷检测,NPU推理速度提升3倍
人工智能·cann
鹿导的通天塔31 分钟前
99%的人都不知道Codex 的 goal 神技!完整设置及提示词模板教学
后端
ZhengEnCi35 分钟前
09aaa-LayerNorm是什么?
人工智能
这是谁的博客?38 分钟前
AI Agent 安全架构设计:漏洞分析与防护策略深度解析
人工智能·安全·网络安全·ai·agent·安全架构·架构设计
人月神话-Lee44 分钟前
【图像处理】Sobel 边缘检测——让机器“看见“轮廓
图像处理·人工智能·计算机视觉·ios·ai编程·swift
冬奇Lab1 小时前
Agent系列(四):工具调用深度解析——Agent 的手和眼
人工智能·llm
Black蜡笔小新1 小时前
自动化AI算法训练服务器DLTM助力医学影像分析进入AI智能分析新时代
人工智能·算法·自动化
冬奇Lab2 小时前
一天一个开源项目(第111篇):Understand Anything - 把代码库变成可探索知识图谱的 AI 引擎
人工智能·开源·llm
猿饵块2 小时前
git--github
人工智能
黎阳之光2 小时前
黎阳之光:以视频孪生重构智慧防火,打造“天空地人智”一体化森林防火新范式
大数据·运维·人工智能·物联网·安全