Chapter 03

加载模型与分词器

用 FastLanguageModel 一步加载 4bit 模型与分词器,理解 max_seq_length、RoPE scaling,并注入 LoRA。

3.1 FastLanguageModel.from_pretrained

Unsloth 的入口是 FastLanguageModel,它包装了 HuggingFace 的模型与分词器,并接管了显存优化。一行调用同时拿到 modeltokenizer

from unsloth import FastLanguageModel
import torch

max_seq_length = 2048

model, tokenizer = FastLanguageModel.from_pretrained(
    model_name = "unsloth/Qwen2.5-7B-Instruct",
    max_seq_length = max_seq_length,
    dtype = None,          # None 自动检测(bf16/fp16)
    load_in_4bit = True,   # QLoRA 路径,省显存
    # token = "hf_...",  # 访问受限模型时填 HF token
)

3.2 参数逐个讲

model_name
模型标识。可用 Unsloth 预量化镜像(unsloth/xxx,下载更小)或 HF 原始名(Qwen/xxx)。
max_seq_length
训练/推理时的最大序列长度(token 数)。越大越占显存。要覆盖你数据里最长的样本,常用 1024/2048/4096。
dtype
计算精度。设 None 让 Unsloth 自动选:新卡(Ampere+)用 bf16,老卡用 fp16。
load_in_4bit
是否 4bit 量化加载。True = QLoRA(省显存);False = 16bit LoRA(更吃显存但精度略高)。
token
HuggingFace 访问令牌,下载 Llama 等需授权的模型时必填。
tokenizer(分词器)
把文本切成 token id 的组件,与模型配套。它还携带 chat template,第 4 章会用到。
RoPE scaling
旋转位置编码的缩放技术,用于把模型的上下文窗口扩展到超过预训练长度。Unsloth 内部自动处理。
特殊 token
bos/eos/pad,标记序列开始/结束/填充。缺 pad 时通常用 eos 代替,训练前要确认。

3.3 max_seq_length 与 RoPE scaling

max_seq_length 决定模型一次能看多长的文本。很多基础模型预训练窗口只有 2K/4K,但 Unsloth 通过内核级的 RoPE scaling 支持把窗口拉长(如 4K→8K),且自动完成——你只需把 max_seq_length 设成想要的长度即可,无需手动配置缩放因子。

选长度的经验

先统计数据集里样本的 token 长度分布,取 95 分位向上取整到 2 的幂。设太长白白浪费显存,设太短会截断样本、丢失信息。

3.4 注入 LoRA:get_peft_model

加载完基础模型后,用 get_peft_model 把可训练的 LoRA adapter 挂上去(超参含义见第 2 章):

model = FastLanguageModel.get_peft_model(
    model,
    r = 16,
    target_modules = ["q_proj", "k_proj", "v_proj", "o_proj",
                      "gate_proj", "up_proj", "down_proj"],
    lora_alpha = 16,
    lora_dropout = 0,
    bias = "none",
    use_gradient_checkpointing = "unsloth",
    random_state = 3407,
)

# 打印可训练参数占比,确认 LoRA 已生效
model.print_trainable_parameters()
# trainable params: 39,976,960 || all params: 7,655,..  || trainable%: 0.52

3.5 检查显存与设备

import torch
gpu = torch.cuda.get_device_properties(0)
used = round(torch.cuda.max_memory_reserved() / 1024**3, 2)
total = round(gpu.total_memory / 1024**3, 2)
print(f"GPU: {gpu.name} | 已用 {used}GB / 共 {total}GB")
加载即 OOM?

若加载模型这一步就爆显存:① 换更小的模型(如 3B);② 确认 load_in_4bit=True;③ 调小 max_seq_length;④ 关掉其他占用 GPU 的进程。

3.6 分词器初探

分词器把文本转成模型能读的 token id。训练前先感受一下:

ids = tokenizer("你好,Unsloth 微调很快").input_ids
print(ids)                          # [151644, 108386, ...]
print(tokenizer.decode(ids))          # 还原回文本
print("eos:", tokenizer.eos_token, "pad:", tokenizer.pad_token)

3.7 小结与下一步