博客文章

用 Unsloth 微调 Qwen 3.5:手把手教程

Unsloth 微调 Qwen 3.5 的完整指南,涵盖安装、LoRA 和 QLoRA 配置、训练参数设置,以及导出微调后的模型。

用 Unsloth 微调 Qwen 3.5:手把手教程

用 Unsloth 微调 Qwen 3.5:手把手教程

微调是让通用模型在你的特定任务上表现更好的最快方式。如果你一直在搜索 unsloth qwen3.5unsloth qwen 3.5,方向是对的。Unsloth 是目前最高效的开源模型微调工具之一,和 Qwen 3.5 配合得很好。

这篇指南会走完整个流程:Unsloth 是什么、为什么适合用来微调 Qwen 3.5,以及从安装到导出模型的完整步骤。如果你想在投入微调时间之前先测试 Qwen 3.5 的能力,可以先免费试用 Qwen 3.5

Unsloth 是什么

Unsloth 是一个开源库,能让大语言模型的微调速度显著提升、内存使用大幅降低。它通过自定义 CUDA 内核和关键训练操作的优化实现来达到这个效果。

实际好处很直接:

  • 训练速度提升 2 倍,相比标准 Hugging Face 训练循环
  • 内存使用最多减少 60%,意味着你可以在同一块 GPU 上微调更大的模型
  • 优化不会损失精度
  • 与 Hugging Face 生态无缝集成,包括 Transformers、TRL 和 PEFT

对于 Qwen 3.5,Unsloth 直接支持其模型架构,不需要自定义补丁或变通方案。

为什么用 Unsloth 微调 Qwen 3.5

核心原因是效率。Qwen 3.5 模型从 1.5B 到更大的尺寸都有,即使是较小的变体也能从减少内存使用和更快的迭代中受益。

如果你用的是单张消费级 GPU(比如 RTX 3090 或 4090),Unsloth 可能决定你能不能微调 7B 级别的模型。没有它,你可能需要租用云 GPU 或者退而求其次选择更小的模型。

Unsloth 还简化了 LoRA 和 QLoRA 的工作流程,这是微调 Qwen 3.5 最常用的方法,不需要重新训练所有模型权重。

前置条件

开始之前,你需要:

  • 一台配备 NVIDIA GPU 的机器(7B 级别模型建议 16GB+ 显存)
  • Python 3.10 或更高版本
  • CUDA 11.8 或更高版本
  • 基本的 Python 和命令行经验

对于较小的 Qwen 3.5 变体(1.5B、4B),使用 QLoRA 时最低只需 8GB 显存。

第 1 步:安装 Unsloth

最干净的安装方式是用 pip。先创建一个新的虚拟环境:

python -m venv unsloth-env
source unsloth-env/bin/activate
pip install unsloth

Unsloth 会拉取它的依赖项,包括正确版本的 Transformers、PEFT 和 TRL。如果遇到 CUDA 版本问题,查看 Unsloth GitHub 仓库获取特定版本的安装说明。

第 2 步:加载 Qwen 3.5 模型

Unsloth 提供了 FastLanguageModel 类,自动应用优化来加载模型:

from unsloth import FastLanguageModel

model, tokenizer = FastLanguageModel.from_pretrained(
    model_name="Qwen/Qwen3.5-7B",
    max_seq_length=4096,
    load_in_4bit=True,  # 使用 QLoRA 节省显存
)

设置 load_in_4bit=True 启用 QLoRA,将基础模型量化为 4 位精度,同时保持可训练的 LoRA 权重在更高精度。这能大幅减少显存使用,对质量的影响很小。

模型名称使用对应的 Hugging Face 标识符。常见选项包括:

  • Qwen/Qwen3.5-1.5B 最小变体
  • Qwen/Qwen3.5-7B 能力和效率的良好平衡
  • Qwen/Qwen3.5-14B 如果你有更多 GPU 显存

第 3 步:配置 LoRA

接下来给模型添加 LoRA 适配器。这些是在基础模型权重冻结的情况下进行微调的小型可训练层:

model = FastLanguageModel.get_peft_model(
    model,
    r=16,              # LoRA 秩
    lora_alpha=16,     # LoRA 缩放因子
    lora_dropout=0,    # Dropout(Unsloth 推荐设为 0)
    target_modules=[
        "q_proj", "k_proj", "v_proj", "o_proj",
        "gate_proj", "up_proj", "down_proj",
    ],
    bias="none",
    use_gradient_checkpointing="unsloth",  # 内存高效的检查点
)

关键参数说明:

  • r(秩):控制 LoRA 适配器的大小。值越高捕获的复杂度越多,但使用更多显存。16 是一个好的起点。
  • target_modules:对哪些层应用 LoRA。上面的列表覆盖了主要的注意力层和前馈层。
  • use_gradient_checkpointing:设为 "unsloth" 使用优化版本,比标准梯度检查点使用更少内存。

第 4 步:准备训练数据

训练数据需要格式化为对话或指令-响应对。以下是使用 Alpaca 格式的简单示例:

from datasets import load_dataset

dataset = load_dataset("your-dataset-name", split="train")

# 格式化为聊天模板
def format_prompt(example):
    return {
        "text": tokenizer.apply_chat_template(
            [
                {"role": "user", "content": example["instruction"]},
                {"role": "assistant", "content": example["output"]},
            ],
            tokenize=False,
        )
    }

dataset = dataset.map(format_prompt)

关键是使用 tokenizer 的 apply_chat_template 方法,确保训练数据格式与模型推理时期望的格式一致。

第 5 步:开始训练

使用 TRL 的 SFTTrainer 设置训练器:

from trl import SFTTrainer
from transformers import TrainingArguments

trainer = SFTTrainer(
    model=model,
    tokenizer=tokenizer,
    train_dataset=dataset,
    dataset_text_field="text",
    max_seq_length=4096,
    args=TrainingArguments(
        per_device_train_batch_size=2,
        gradient_accumulation_steps=4,
        warmup_steps=10,
        num_train_epochs=1,
        learning_rate=2e-4,
        fp16=True,
        logging_steps=10,
        output_dir="outputs",
        seed=42,
    ),
)

trainer.train()

根据可用显存调整 per_device_train_batch_sizegradient_accumulation_steps。如果显存不够,先减小 batch size。

第 6 步:导出模型

训练完成后,有几种导出方式:

只保存 LoRA 适配器

model.save_pretrained("qwen35-lora")
tokenizer.save_pretrained("qwen35-lora")

只保存小型 LoRA 适配器权重。后续使用时加载基础模型并应用适配器。

合并并保存完整模型

model.save_pretrained_merged("qwen35-merged", tokenizer)

将 LoRA 权重合并到基础模型中并保存完整结果。文件更大但部署更简单。

导出为 GGUF 格式供 Ollama 使用

model.save_pretrained_gguf("qwen35-gguf", tokenizer, quantization_method="q4_k_m")

直接导出为 GGUF 格式,可以加载到 Ollama 或 llama.cpp 进行本地推理。q4_k_m 量化在文件大小和质量之间提供了良好的平衡。

常见问题和技巧

  • 显存不足:减小 batch size,使用 QLoRA(load_in_4bit=True),或切换到更小的 Qwen 3.5 变体。
  • 训练缓慢:确保 Unsloth 的优化已激活。模型加载时应该能看到确认信息。
  • 效果不好:先检查数据质量。微调会放大数据中的模式,好的和坏的都会。
  • 聊天格式问题:始终使用 apply_chat_template 格式化训练数据。格式不匹配是微调效果差的最常见原因之一。

微调什么内容

最成功的微调项目从清晰、狭窄的任务开始。广泛的改进很难实现,特定的改进则容易得多。好的候选项包括:

  • 为你的应用定制一致的输出格式
  • 领域特定的知识或术语
  • 特定的写作风格或语气
  • 任务特定的行为(分类、提取、摘要)

微调之前,确认基础模型是否已经能做到你需要的。先用仔细的提示词免费试用 Qwen 3.5。有时候提示工程就够了,而且比微调便宜得多。

常见问题

应该微调哪个大小的 Qwen 3.5?

从能合理处理你任务的最小模型开始。微调 7B 模型比微调 14B 模型快得多也便宜得多,对于很多任务,微调后的小模型就够用了。

需要多少训练数据?

对于 LoRA 微调,100-500 条高质量样本就能看到有意义的效果。更多数据有帮助,但质量比数量更重要。

能在 Mac 上微调吗?

Unsloth 目前需要 NVIDIA GPU。Mac 上的微调可以考虑基于 MLX 的替代方案,但它们总体上还不太成熟。

训练需要多长时间?

在单张 RTX 4090 上使用 Unsloth,微调 7B 模型的 1000 条样本通常需要 15-30 分钟完成一个 epoch。更大的模型和数据集按比例增长。

Q-Chat Team

Q-Chat Team

用 Unsloth 微调 Qwen 3.5:手把手教程 | Qwen 博客