Lora微调模型

内容纲要

一、配置信息

ubuntu 22.04

二、安装GPU驱动、cuDNN 英伟达CUDA深度学习网络加速引擎、pytorch框架

1、教程链接

安装GPU驱动

验证是否安装成功

安装完成后,用这条命令一次性验证所有环境

python3 -c "
import torch
print('====================')
print('PyTorch 版本:', torch.__version__)
print('GPU 可用:', torch.cuda.is_available())
print('GPU 型号:', torch.cuda.get_device_name(0) if torch.cuda.is_available() else '无')
print('cuDNN 版本:', torch.backends.cudnn.version())
print('====================')
"

正确输出格式模版:

PyTorch 版本: 2.5.1+cu121
GPU 可用: True
GPU 型号: Tesla T4
cuDNN 版本: 90100

出现上述返回信息,就说明你的 PyTorch + GPU 环境已经完全就绪了。

三、开始微调

3.1、安装微调所学的核心且常用的工具

pip install transformers datasets peft accelerate bitsandbytes trl sentencepiece modelscope huggingface
  1. PEFT (Parameter-Efficient Fine-Tuning):参数高效微调库
    PEFT 的核心目标是“省钱省力”。在大模型时代,全量微调(Fine-Tuning)所有参数需要巨大的显存和算力。PEFT 提供了一系列技术(如最知名的 LoRA),允许你冻结模型绝大部分参数,只微调极少量的新增参数(通常仅占原模型参数的 0.1%-5%)。

  2. Accelerate:硬件适配与分布式训练库
    Accelerate 的核心目标是“一套代码,到处运行”。它是由 Hugging Face 推出的轻量级库,用于抽象底层硬件的差异。
    有什么用:无论你是在单张 CPU、单张 GPU、多张 GPU(单机多卡/多机多卡)还是 TPU 上运行模型,使用 Accelerate 后,你几乎不需要修改原本的 PyTorch 训练代码。它自动化了混合精度训练(FP16/BF16)、分布式环境初始化等繁琐配置,极大降低了多卡训练和显存优化的门槛。

  3. bitsandbytes:模型量化与显存压缩库
    bitsandbytes 的核心目标是“把模型变小”。它专注于提供高效的低精度(8-bit、4-bit)CUDA 算子,主要用于模型量化(Quantization)。这能让模型的显存占用降低。著名的 QLoRA 微调技术,就是结合了 bitsandbytes 的 4位量化和 PEFT 的 LoRA 技术,实现了在极低显存下的高效微调。

  4. TRL (Transformer Reinforcement Learning):大模型强化学习与对齐库
    TRL 的核心目标是“让模型更听话(对齐人类偏好)”。它是 Hugging Face 推出的专门用于大语言模型对齐和微调的框架。
    有什么用:它封装了复杂的强化学习流程,支持 SFT(监督微调)、PPO(近端策略优化) 和 DPO(直接偏好优化) 等主流算法。当你想让大模型不仅会说话,还能按照人类的价值观、安全规范或特定偏好来回答问题时(即 RLHF 过程),TRL 是最主流的工具。它与 Transformers 和 PEFT 完美兼容。

  5. SentencePiece:无监督文本分词工具
    SentencePiece 的核心目标是“把文字切成模型能懂的碎片”。它是一个由 Google 推出的、语言无关的文本分词(Tokenizer)和去分词(Detokenizer)框架。
    有什么用:它不依赖特定语言的预处理(比如中文不需要提前用 Jieba 分词),而是直接在原始文本(包括空格)上进行无监督学习,将句子切分成子词(Subword)单元(常用算法如 BPE 或 Unigram)。目前绝大多数主流大模型(如 LLaMA、T5、ChatGLM 等)的底层分词器都是基于 SentencePiece 构建的。

总结它们在实际工作流中的关系:
如果你要微调一个大模型,通常的流程是:用 SentencePiece 处理文本数据,用 bitsandbytes 把模型量化以节省显存,用 PEFT (LoRA) 进行参数高效微调,用 Accelerate 来加速训练并适配你的多卡环境,最后如果你想让模型更符合人类偏好,还可以用 TRL 进行进一步的强化学习对齐。

3.2、再次安装torch包的命令(可跳过)

如果上述的包,强制把torch包升级了,导致cuda版本不适配,需要重新执行一遍安装torch包的命令

pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu117

3.3. 数据集下载

ModelScope:https://modelscope.cn/datasets →搜 alpaca_zh->下载数据集
数据集准备(放在 /opt/lora/data.json)

3.2、nano train.py

# 环境变量禁用flops
import os
os.environ["TRANSFORMERS_NO_FLOPS"] = "1"

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

# 配置
MODEL_PATH = "Qwen/Qwen1.5-0.5B-Chat"
DATA_PATH = "./data-1000.json"
OUTPUT_DIR = "./lora_output"

# 4bit量化
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_use_double_quant=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.float16
)

# LoRA
lora_config = LoraConfig(
    r=8,
    lora_alpha=16,
    target_modules=["q_proj", "v_proj"],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
)

# 分词器
tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"

# 模型
model = AutoModelForCausalLM.from_pretrained(
    MODEL_PATH,
    quantization_config=bnb_config,
    device_map="auto",
    trust_remote_code=True,
    use_cache=False
)
model = prepare_model_for_kbit_training(model)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()

# 数据集
raw_ds = load_dataset("json", data_files=DATA_PATH, split="train")
def build_text(sample):
    prompt = f"<|im_start|>user\n{sample['instruction']}<|im_end|>\n<|im_start|>assistant\n{sample['output']}<|im_end|>"
    return {"text": prompt}
ds = raw_ds.map(build_text)

def tokenize_fn(examples):
    return tokenizer(examples["text"], truncation=True, max_length=512)
token_ds = ds.map(tokenize_fn, batched=True, remove_columns=["instruction","input","output","text"])

data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)

# 训练参数,添加disable_flops计算
training_args = TrainingArguments(
    output_dir=OUTPUT_DIR,
    per_device_train_batch_size=1,
    gradient_accumulation_steps=4,
    learning_rate=2e-4,
    num_train_epochs=3,
    logging_steps=10,
    save_strategy="epoch",
    fp16=True,
    optim="paged_adamw_8bit",
    gradient_checkpointing=True,
    report_to="none",
    overwrite_output_dir=True
)

# 重写model.floating_point_ops,直接返回0,彻底绕过报错
def empty_flops(*args,**kwargs):
    return 0.0
model.floating_point_ops = empty_flops

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=token_ds,
    data_collator=data_collator
)

if __name__ == "__main__":
    trainer.train()
    trainer.save_model(OUTPUT_DIR)
    tokenizer.save_pretrained(OUTPUT_DIR)

3.3. 开始微调训练

python3 train.py

3.4. 编辑测试文件:

nano test-inference.py
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel

base_name = "Qwen/Qwen1.5-0.5B-Chat"
lora_path = "./lora_output/checkpoint-150"

tokenizer = AutoTokenizer.from_pretrained(base_name, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(base_name, load_in_4bit=True, device_map="auto", trust_remote_code=True)
model = PeftModel.from_pretrained(model, lora_path)

prompt = "<|im_start|>user\n列出 5 种不同类型的水果。<|im_end|>\n<|im_start|>assistant\n"
inp = tokenizer(prompt, return_tensors="pt").to("cuda")
out = model.generate(**inp, max_new_tokens=128)
print(tokenizer.decode(out[0]))

3.5. 执行测试推理的文件

python3 test-inference.py

4. 调整训练参数

4.1. LoRA 结构(最关键,大概率 r 太小 / 只训少量层)

from peft import LoraConfig
lora_config = LoraConfig(
    r=16,               # 原来如果是4/8 → 改成16(容量不足loss下不去)
    lora_alpha=32,      # alpha=2×r固定
    target_modules=[
        "q_proj","k_proj","v_proj","o_proj",
        "gate_proj","up_proj","down_proj"
    ], # 全层,不要只q/v,小模型必须全开
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
)

r 过小 = 适配器容量不够,模型存不下指令,loss 卡死高位。

4.2. 学习率(头号元凶,loss 停滞首选改 lr),training_args
原 lr<8e-5 → 改成 1.5e-4 ~ 2e-4(1.5e-4 稳妥)
必须加预热:warmup_ratio=0.05(总步数 5% 预热)+ lr_scheduler_type="cosine"余弦衰减
lr 太低参数更新微弱,loss 长期横盘 2.2~2.4;太高 loss 震荡不收敛。

4.3. 有效批次(梯度不稳导致收敛差)

per_device_train_batch_size=1

有效batch=8,显存不够就accum=4

gradient_accumulation_steps=8

4.4. 训练轮次
num_train_epochs=3,别超过 4,小样本极易过拟合。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部