Chapter 04

MMEngine Runner 与 XTuner 边界

📌 commit 964f70e读懂 OpenMMLab 风格的训练抽象

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:

4.5XTuner 与 MMEngine 的边界

谁负责什么
MMEngineRunner / Hook / Registry / Config 读取 / 分布式启动
XTunerSFT/DPO/VL model wrapper / 数据集 preprocessor / chat template / convert 工具
transformersbase 模型加载
peftLoRA / DoRA
DeepSpeedZeRO 切分

4.6这种设计的优劣

跟 OpenMMLab 全家桶一致不熟 MMEngine 时学习曲线陡
Hook 机制灵活dict 配置容易写错
config 是 Python 可编程不如 YAML / TOML 直观
跟 MMCV / MMDetection 等共享生态跟 HF 风格(Trainer) 不一致

4.7这章你需要带走的

4.8 CLI entry_point.py:13 个子命令

xtuner 命令的 dispatcher 在 xtuner/entry_point.py:12-253cli() 函数(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_refcocotools/mmbench.py / tools/eval_refcoco.pyVLM 评测

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