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

微调后对话

复制代码
就写到这里,后续有什么新的内容再分享吧,微调学习才刚起步还需要多多实践,还有数据集制作等很多内容要学习
相关推荐
LinkTime_Cloud7 分钟前
OpenAI 陷“GPT门”风波,付费用户遭遇模型偷换与性能降级
人工智能·gpt
GoldenSpider.AI9 分钟前
从“氛围编程“到“氛围研究“:OpenAI的GPT-5与未来自动化研究之路
人工智能·gpt-5·vibe coding·氛围编程·mark chen·jakub pachocki
IT_陈寒23 分钟前
SpringBoot实战:这5个隐藏技巧让我开发效率提升200%,90%的人都不知道!
前端·人工智能·后端
x新观点23 分钟前
联想乐享重构智能搜索生态:ThinkPad T14p 2025升级信息首触“企业智能双胞胎”
人工智能
大有数据可视化26 分钟前
机器学习+数字孪生:从诊断到自主决策的跨越
人工智能·机器学习
西岭千秋雪_29 分钟前
Spring AI alibaba Prompt模板&Advisor自定义
java·人工智能·spring·prompt
CV实验室29 分钟前
NeurIPS 2025 | 北大等提出C²Prompt:解耦类内与类间知识,攻克FCL遗忘难题!
人工智能·计算机视觉·prompt·论文·cv
catchadmin37 分钟前
如何在 PHP 升级不踩坑?学会通过阅读 RFC 提前预知版本变化
开发语言·后端·php
风象南1 小时前
商业化必备:SpringBoot 实现许可证控制
后端
盟接之桥2 小时前
盟接之桥说制造:源头制胜,降本增效:从“盟接之桥”看供应链成本控制的底层逻辑
大数据·网络·人工智能·安全·制造