Chapter 04
MMEngine Runner 与 XTuner 边界
XTuner 跑在 MMEngine 上。MMEngine 是 OpenMMLab 生态的"PyTorch Lightning 版",提供 Runner / Hook / Registry 等抽象。本章把这些过一遍,让你看懂 XTuner config 在写什么。
4.1整体调用栈
flowchart TB
CLI[xtuner train cfg.py]
CLI --> Cfg["读 cfg.py → Config 对象"]
Cfg --> Runner["MMEngine Runner"]
Runner --> Train[Runner.train]
Train --> Loop[每 step:]
Loop --> Forward[model.forward → loss]
Loop --> Backward[loss.backward]
Loop --> Optim[optim.step]
Loop --> Hooks[Hooks: log / save / eval]
4.2Registry:用字符串注册类
MMEngine 的核心机制是 Registry——把类按名字注册到一个全局表,配置里用 dict 指定 type:
# 注册(XTuner 内部)
from mmengine.registry import MODELS
@MODELS.register_module()
class SupervisedFinetune(nn.Module):
def __init__(self, llm, lora=None, ...):
...
# 使用(config 里)
model = dict(
type=SupervisedFinetune, # 直接用类
# 或:type="SupervisedFinetune",字符串也行
llm=dict(type=AutoModelForCausalLM.from_pretrained, ...),
lora=dict(type=LoraConfig, r=64),
)
这种"dict 配置 + Registry 解析"是 OpenMMLab 全家桶共用的范式。
4.3Runner:训练循环包装
Runner 是 MMEngine 顶层:你给它 model / dataloader / optim / scheduler / hooks,它跑完整训练循环。
from mmengine.runner import Runner
runner = Runner(
model=model,
train_dataloader=train_dl,
optim_wrapper=optim_cfg,
param_scheduler=scheduler_cfg,
train_cfg=dict(by_epoch=True, max_epochs=3),
default_hooks=dict(
timer=dict(type=IterTimerHook),
logger=dict(type=LoggerHook, interval=10),
param_scheduler=dict(type=ParamSchedulerHook),
checkpoint=dict(type=CheckpointHook, interval=1),
),
custom_hooks=[
dict(type=EvaluateChatHook, ...), # XTuner 自家 Hook
],
)
runner.train()
所有这些 dict 都来自 XTuner config,由 Runner 解析成实际对象。
4.4Hook:定时插入逻辑
Hook = "训练某阶段执行的回调"。MMEngine 自带 7 个默认 hook:
| Hook | 触发 |
|---|---|
| IterTimerHook | 每 iter 起止 |
| LoggerHook | 每 N iter 打日志 |
| ParamSchedulerHook | 每 iter / epoch 更新 lr |
| CheckpointHook | 每 N epoch 保存 |
| DistSamplerSeedHook | 每 epoch 重置 sampler |
| RuntimeInfoHook | 注入 runtime 信息 |
| EMAHook | (可选) EMA 平滑权重 |
XTuner 自定义 hook:
EvaluateChatHook:训练中定期跑几个 prompt 看输出;VarlenAttnArgsToMessageHubHook:传递 packing 参数;DatasetInfoHook:打印数据集信息。
4.5XTuner 与 MMEngine 的边界
| 谁负责 | 什么 |
|---|---|
| MMEngine | Runner / Hook / Registry / Config 读取 / 分布式启动 |
| XTuner | SFT/DPO/VL model wrapper / 数据集 preprocessor / chat template / convert 工具 |
| transformers | base 模型加载 |
| peft | LoRA / DoRA |
| DeepSpeed | ZeRO 切分 |
4.6这种设计的优劣
| 优 | 劣 |
|---|---|
| 跟 OpenMMLab 全家桶一致 | 不熟 MMEngine 时学习曲线陡 |
| Hook 机制灵活 | dict 配置容易写错 |
| config 是 Python 可编程 | 不如 YAML / TOML 直观 |
| 跟 MMCV / MMDetection 等共享生态 | 跟 HF 风格(Trainer) 不一致 |
4.7这章你需要带走的
- XTuner 跑在 MMEngine 上,配置是 Python 文件 + Registry;
- 核心抽象:Runner(顶层)+ Hook(插件)+ Registry(注册表);
- 用 dict + type=Class 的方式写配置;
- XTuner 主要贡献:SFT/DPO/VL model wrapper + 数据 preprocessor + chat template。
4.8 CLI entry_point.py:13 个子命令
xtuner 命令的 dispatcher 在 xtuner/entry_point.py:12-253,cli() 函数(line 276-338)按 MODES 元组路由:
| 子命令 | 位置 | 用途 |
|---|---|---|
list-cfg | tools/list_cfg.py | 列出所有 594 个内置 config |
copy-cfg | tools/copy_cfg.py | 把 config 复制到自定义路径 |
log-dataset | tools/log_dataset.py | 预览数据集 token 化结果 |
check-custom-dataset | tools/check_custom_dataset.py | 校验自定义数据 config |
train | tools/train.py:162-309 | ★ 启动训练(NPROC_PER_NODE → torchrun) |
test | tools/test.py | batch 评测 |
chat | tools/chat.py | 交互聊天 |
convert {pth_to_hf,merge,split} | tools/model_converters/ | checkpoint 转换 |
preprocess {arxiv,refcoco} | tools/data_preprocess/ | 数据预处理 |
mmbench / eval_refcoco | tools/mmbench.py / tools/eval_refcoco.py | VLM 评测 |
cli() 多卡逻辑:检测 NNODES / NPROC_PER_NODE 环境变量,决定用 torchrun 还是直接 subprocess.run;端口未指定时随机 20000-29999。
4.9 model wrapper 源码定位
| 类 | 位置 | 负责 |
|---|---|---|
SupervisedFinetune | xtuner/model/sft.py:36-105 | SFT 主类(含 sequence parallel + DeepSpeed 集成) |
DPO | xtuner/model/dpo.py:44-60 | 持 reference model,beta-sigmoid loss |
ORPO | xtuner/model/orpo.py | 不要 reference model 的偏好优化 |
RewardModel | xtuner/model/reward.py:1-60 | RLHF 奖励模型 |
LLaVA | xtuner/model/llava.py | 图文 SFT wrapper |
InternVL | xtuner/model/internvl.py | InternVL VL 融合 |
| 工具 | xtuner/model/utils.py | LoadWoInit / find_all_linear_names / traverse_dict |