trainer-dev
hyper_models/trainer/**
examples/training_demo/**
dp_shard_size=8
train
HyperParallel 已经具备 DeviceMesh、DTensor、声明式分片、FSDP/HSDP 以及多种组合并行能力,但完整训练 还需要解决另一组编排问题:
当前分支已经形成以 TrainerConfig + Target + BaseTrainer + TextTrainer + Callback 为核心的实现,并新增 examples/training_demo 作为 Qwen3-30B-A3B/WikiText/FSDP 示例。需要通过 RFC 固化当前职责边界,明确 已实现能力与占位接口,避免把配置面的可表达性误认为运行时支持。
TrainerConfig + Target + BaseTrainer + TextTrainer + Callback
examples/training_demo
本 RFC 固化以下能力:
parse_training_args()
--section.field=value
Target
TextTrainer
BaseTrainer
DistributedSetup/MeshContext
HyperAutoModelForCausalLM.from_pretrained()
list[dict[str, Any]]
以下能力不属于本期验收范围:
hyper_models/trainer/ ├── config.py │ ├── TrainerConfig 及各配置 dataclass │ ├── Target:延迟构建协议 │ └── save_configs:当前为空实现 ├── base.py │ ├── BackgroundPrefetcher / HyperIter │ └── BaseTrainer:组件构建、训练步、训练循环、资源销毁 ├── text_trainer.py │ └── TextTrainer:文本训练规范入口,以 composition 方式复用 BaseTrainer └── callbacks/ ├── base.py:TrainerState 与 Callback 生命周期 ├── environ_meter_callback.py:指标生产与跨 rank 归约 ├── logging_callback.py:rank 0 结构化日志 ├── tqdm_callback.py:rank 0 进度条 ├── evaluate_callback.py:评估触发占位 ├── garbage_collection_callback.py:GC 与 device cache 清理 └── temp_log_callback.py:TqdmCallback 的兼容别名
Trainer 目录只负责训练编排。具体能力的唯一所有者如下:
hyper_models/config/
TrainerConfig
components/distributed/infrastructure.py
_transformers/
components/distributed/
config.model.build(distributed_setup=...)
components/data/
components/loss/
components/optim/
hyper_models/trainer/
_target_
--field=value
training.init_device
list[dict]
ModelOutput.loss
torch.nn.Module
mean_global_loss()
loss_aggregation
gc_steps
empty_cache_steps
save_configs()
WandbConfig
plan_overhead
nullcontext()
当前规范入口为:
from hyper_models.config.manager import parse_training_args from hyper_models.trainer.text_trainer import TextTrainer config = parse_training_args() trainer = TextTrainer(config) trainer.train()
BaseTrainer 是实现载体,不作为当前示例的直接用户入口。TextTrainer 通过 composition 持有 BaseTrainer,并显式选择文本训练需要的构建阶段与生命周期。
python -m examples.training_demo.train_text \ examples/training_demo/train.yaml \ --training.max_steps=10 \ --optimizer.lr=0.0002
CLI override 规则:
YAML 中包含 _target_ 的节点会被解析为:
Target( resolved_callable, target_path="package.module.callable", **configured_kwargs, )
运行时调用:
component = target.build(**runtime_kwargs)
最终参数为:
configured kwargs + applicable runtime kwargs
同名运行时参数覆盖配置参数。若 target 不接受 **kwargs,Target.build() 会过滤 target 签名中不存在的 运行时参数,使不同组件可以共享统一的依赖注入调用方式。
**kwargs
Target.build()
model
tokenizer
training
accelerator
fsdp_config
mixed_precision
gradient_checkpointing
loss_fn
data_transform
dataset
collate_fn
dataloader
optimizer
lr_scheduler
packed_sequence/magi/peft
checkpoint/debug/wandb
train.yaml + CLI overrides | v parse_training_args() YAML -> typed dataclasses + Target tree | v TextTrainer(config) | +--> BaseTrainer._setup() | process group + device + seed + DistributedSetup/MeshContext | +--> config.model.build(distributed_setup=...) | HyperAutoModel -> sharding plan -> FSDP -> materialize | +--> loss / tokenizer / transform / dataset / collator / dataloader | +--> train_steps -> optimizer -> scheduler -> contexts -> callbacks | v TextTrainer.train() epoch -> optimizer step -> micro batches -> forward/backward -> HSDP sync -> grad clip -> optimizer/scheduler -> callbacks | v synchronize -> destroy_process_group
配置解析只验证结构、类型和 callable 签名,不创建占用设备内存或依赖分布式状态的对象。所有需要 model、 mesh、tokenizer、dataset 或 optimizer 的组件通过 Target.build() 延迟到 Trainer 构建阶段。
BaseTrainer._setup() 创建唯一的 DistributedSetup。AutoModel、loss 归约、dataloader 分片和 callback 指标 归约都读取同一 MeshContext,禁止各组件自行构造第二套 DeviceMesh。
BaseTrainer._setup()
DistributedSetup
MeshContext
_build_model() 调用 model target 后,模型必须已经完成本次路径需要的构造、分片、FSDP 包裹和物化。 Trainer 只在此之后构建 optimizer,避免 parameter identity、tied weights 或 sharding 改变后 optimizer 持有 过期参数引用。
_build_model()
DataLoader 的 local batch size 为:
local_step_batch_size = global_batch_size / dp_size
每个 DP rank 的 micro-batch 数为:
num_micro_batches = global_batch_size / (micro_batch_size * dp_size)
MakeMicroBatchCollator 将 local optimizer batch 切为固定的 list[dict]。因此训练循环不需要再次猜测 梯度累积边界。
MakeMicroBatchCollator
forward、backward、FSDP sync、grad clip 和 optimizer step 保持在 train_step() 中;指标、展示、评估触发 和内存清理通过 callback 生命周期接入。Callback 不修改 optimizer step 的控制流。
train_step()
EnvironMeterCallback 是 step_train_metrics 和 step_env_metrics 的唯一生产者。Logging 与 Tqdm callback 只消费这两个字典,不重复做 collective 或重新计算 loss、tokens/s 和 memory 指标。
EnvironMeterCallback
step_train_metrics
step_env_metrics
TextTrainer.__init__() 当前按下列顺序构建:
TextTrainer.__init__()
1. _setup 2. _build_model 3. _build_loss 4. _build_model_assets 5. _build_data_transform 6. _build_dataset 7. _build_collate_fn 8. _build_dataloader 9. _compute_train_steps 10. _build_optimizer 11. _build_lr_scheduler 12. _build_training_context 13. _init_callbacks
_setup() 执行:
_setup()
torch.distributed
当前主 mesh 轴顺序为:
dp_replicate? -> dp_shard? -> cp? -> tp?
demo 使用:
world_size=8 dp_shard_size=8 dp_replicate_size=1 tp=cp=ep=pp=1 mesh=(dp_shard=8)
模型 target 接收 distributed_setup 和 peft_config。当前 demo 的 AutoModel 路径依次执行:
distributed_setup
peft_config
读取 HF config -> meta/no-init 构造 Qwen3-MoE -> 可选 ShardingPlanner -> per-layer + root FSDP wrapping -> to_empty 到当前 NPU -> 参数/缓冲区初始化 -> model.train()
Loss 默认使用 ModelOutputLoss 读取 model_output.loss。若配置 loss_fn,其 target 必须构建为 torch.nn.Module,并接受 Trainer 传入的 model_output 与 labels。
ModelOutputLoss
model_output.loss
model_output
labels
当前构建依赖为:
tokenizer + model_config -> data_transform -> dataset -> collate_fn(num_micro_batch) -> dataloader(dataset, collate_fn, DP topology)
demo 数据链路为:
Salesforce/wikitext / wikitext-2-raw-v1 / train -> PlainTextDataTransform -> tokenizer.encode(add_special_tokens=False) -> 每篇追加 EOS -> 串联并裁成固定 1024-token 样本 -> input_ids + attention_mask + labels -> DistributedSampler -> MakeMicroBatchCollator -> list[dict]
global_batch_size 必须能被 micro_batch_size * dp_size 整除;每个 local optimizer batch 也必须能被 num_micro_batches 整除。不满足时在构建阶段报错。
global_batch_size
micro_batch_size * dp_size
num_micro_batches
每个 optimizer step 执行:
next(data_iterator) -> micro_batches -> global_step += 1 -> on_step_begin -> device synchronize -> 统计整个 local step 的 loss tokens -> for each micro batch: 调整 reshard_after_backward 仅最终 micro batch 开启 FSDP gradient sync/all-reduce 统计当前 micro batch tokens non_blocking 搬运到 device model(..., use_cache=False) loss_fn(model_output, labels) DP+CP token-weighted loss normalization backward -> hsdp_sync_stream -> clip_grad_norm_ -> optimizer.step under SkipDTensorDispatch -> optimizer.zero_grad -> scheduler.step -> on_step_end
在读取 HSDP 异步梯度结果和执行梯度裁剪前必须完成 hsdp_sync_stream()。Optimizer 更新放在 SkipDTensorDispatch 内,避免 optimizer 对本地参数执行原始 tensor 操作时进入 DTensor dispatch。
hsdp_sync_stream()
SkipDTensorDispatch
当前路径使用 token-weighted loss:
local micro loss * current micro valid tokens / DP+CP global valid tokens for the whole optimizer step * dp_size
乘以 dp_size 用于抵消 FSDP 对 shard group 梯度的平均。若开启 sequence parallel,还会在 TP group 汇总 token 数并除以 sequence-parallel size。token 总数为 0 但 loss 非 0 时必须报错。
dp_size
Callback 顺序固定为:
EnvironMeterCallback -> LoggingCallback -> TqdmCallback -> EvaluateCallback -> GarbageCollectionCallback
logging_steps
EnvironMeter 必须先于展示 callback 执行,以保证同一步的指标已经完成 collective 并写入共享字典。
训练达到 max_steps、epoch 结束或 dataloader 耗尽后:
max_steps
on_train_end()
BackgroundPrefetcher 的停止操作必须设置 stop event、清空 queue,并以有限 timeout join worker,避免退出时 无限等待后台线程。
training.max_steps
num_train_epochs
world_size
tp_size * cp_size
dp_shard_size
dp_shard
pp_size
ep_size
IGNORE_INDEX
.loss
下列情况必须明确失败,而不是静默宣称 Trainer 已支持:
转测qwen-moe网络,30B规格 支持tp/cp/ep/fsdp并行能力(当前迭代不支持pp),支持重计算、swap、支持梯度累加(gbs/dp/mbs > 1开启) 支持validate/production双模式,双模式精度要一致 支持断点续训,集群故障导致训练中断,拉起后可恢复至断点状态继续训练。 支持在线加载HF数据集;离线转换hf数据集为megatron格式数据集,然后加载megatron格式数据集 转测需要验收: 1、精度的自洽,保证输入、权重一致的情况下,变换并行策略、重计算策略、梯度累加长度等保持loss曲线在500step下符合验收标准(0轴波动,误差范围在xxx以内)
转测qwen-moe网络,30B规格 支持tp/cp/ep/fsdp并行能力(当前迭代不支持pp),支持重计算、swap、支持梯度累加(gbs/dp/mbs > 1开启) 支持validate/production双模式,双模式精度要一致 支持断点续训,集群故障导致训练中断,拉起后可恢复至断点状态继续训练。 支持在线加载HF数据集;离线转换hf数据集为megatron格式数据集,然后加载megatron格式数据集
转测需要验收: 1、精度的自洽,保证输入、权重一致的情况下,变换并行策略、重计算策略、梯度累加长度等保持loss曲线在500step下符合验收标准(0轴波动,误差范围在xxx以内)
本 RFC 只定义这一条验证用例,不增加单元测试、组合并行矩阵、数值对拍或性能测试。
环境要求:
Qwen/Qwen3-30B-A3B
Salesforce/wikitext
执行命令:
bash examples/training_demo/run.sh
该脚本串行执行:
python -m examples.training_demo.prepare_model examples/training_demo/train.yaml -> torchrun --nproc_per_node=8 --module examples.training_demo.train_text \ examples/training_demo/train.yaml
默认配置:
(dp_shard=8)
【RFC】HyperModels Trainer 统一编排与端到端训练闭环
0. 基本信息
trainer-devhyper_models/trainer/**examples/training_demo/**dp_shard_size=8trainsplit,固定长度 1024 tokens1. 背景
HyperParallel 已经具备 DeviceMesh、DTensor、声明式分片、FSDP/HSDP 以及多种组合并行能力,但完整训练
还需要解决另一组编排问题:
当前分支已经形成以
TrainerConfig + Target + BaseTrainer + TextTrainer + Callback为核心的实现,并新增examples/training_demo作为 Qwen3-30B-A3B/WikiText/FSDP 示例。需要通过 RFC 固化当前职责边界,明确已实现能力与占位接口,避免把配置面的可表达性误认为运行时支持。
2. 目标与非目标
2.1 目标
本 RFC 固化以下能力:
scheduler、并行拓扑和 callback cadence。
parse_training_args()解析配置,并支持--section.field=value形式的强类型 CLI 覆盖。Target延迟构建需要运行时依赖的组件,配置解析阶段不提前创建 model、dataset 或 optimizer。TextTrainer作为当前文本训练规范入口,按显式依赖顺序组装BaseTrainer的各阶段。DistributedSetup/MeshContext只创建一次,并注入 AutoModel 构建路径。HyperAutoModelForCausalLM.from_pretrained()原子完成构造、分片、FSDP 包裹和物化;Trainer不再执行第二次并行化。
list[dict[str, Any]],该列表表示一个 optimizer step 内的全部 micro batches。step 和指标发布。
examples/training_demo端到端用例验收 Trainer 完整链路。2.2 非目标
以下能力不属于本期验收范围:
examples/training_demo之外的验证用例。3. 当前代码结构与职责
Trainer 目录只负责训练编排。具体能力的唯一所有者如下:
hyper_models/config/TrainerConfigcomponents/distributed/infrastructure.py_transformers/、components/distributed/config.model.build(distributed_setup=...)components/data/或用户 targetcomponents/loss/components/optim/或用户 targethyper_models/trainer/4. 当前支持矩阵
_target_延迟构建--field=value,不支持通过 override 更换_target_training.init_devicedp_shard_size=8list[dict]ModelOutput.losstorch.nn.Modulemean_global_loss()loss_aggregation可配置,但当前训练步未分派到该语义gc_steps、empty_cache_steps独立控制save_configs()为空,Trainer 未注册 checkpointer callbackWandbConfig存在,但 callback 未接入plan_overheadtarget 当前未被 Trainer 或 AutoModel 消费nullcontext(),NaN/Inf 检查未接入5. 对外接口
5.1 Python 入口
当前规范入口为:
from hyper_models.config.manager import parse_training_args from hyper_models.trainer.text_trainer import TextTrainer config = parse_training_args() trainer = TextTrainer(config) trainer.train()BaseTrainer是实现载体,不作为当前示例的直接用户入口。TextTrainer通过 composition 持有BaseTrainer,并显式选择文本训练需要的构建阶段与生命周期。5.2 CLI 入口
CLI override 规则:
--field=value;Target参数的 dotted path;_target_。5.3
Target构建协议YAML 中包含
_target_的节点会被解析为:Target( resolved_callable, target_path="package.module.callable", **configured_kwargs, )运行时调用:
最终参数为:
同名运行时参数覆盖配置参数。若 target 不接受
**kwargs,Target.build()会过滤 target 签名中不存在的运行时参数,使不同组件可以共享统一的依赖注入调用方式。
5.4 YAML 配置分组
modeltokenizertrainingacceleratorfsdp_configplan_overheadmixed_precisiongradient_checkpointingloss_fndata_transformdatasetcollate_fndataloaderoptimizerlr_schedulerpacked_sequence/magi/peftcheckpoint/debug/wandb6. 总体设计
6.1 目标架构
6.2 核心设计决策
D1:配置解析与对象构建分离
配置解析只验证结构、类型和 callable 签名,不创建占用设备内存或依赖分布式状态的对象。所有需要 model、
mesh、tokenizer、dataset 或 optimizer 的组件通过
Target.build()延迟到 Trainer 构建阶段。D2:分布式拓扑单一所有权
BaseTrainer._setup()创建唯一的DistributedSetup。AutoModel、loss 归约、dataloader 分片和 callback 指标归约都读取同一
MeshContext,禁止各组件自行构造第二套 DeviceMesh。D3:模型构建是原子阶段
_build_model()调用 model target 后,模型必须已经完成本次路径需要的构造、分片、FSDP 包裹和物化。Trainer 只在此之后构建 optimizer,避免 parameter identity、tied weights 或 sharding 改变后 optimizer 持有
过期参数引用。
D4:一个 dataloader item 对应一个 optimizer step
DataLoader 的 local batch size 为:
每个 DP rank 的 micro-batch 数为:
MakeMicroBatchCollator将 local optimizer batch 切为固定的list[dict]。因此训练循环不需要再次猜测梯度累积边界。
D5:训练核心显式,外围能力使用 callback
forward、backward、FSDP sync、grad clip 和 optimizer step 保持在
train_step()中;指标、展示、评估触发和内存清理通过 callback 生命周期接入。Callback 不修改 optimizer step 的控制流。
D6:指标只计算一次
EnvironMeterCallback是step_train_metrics和step_env_metrics的唯一生产者。Logging 与 Tqdm callback只消费这两个字典,不重复做 collective 或重新计算 loss、tokens/s 和 memory 指标。
7. 构建流程
TextTrainer.__init__()当前按下列顺序构建:7.1 分布式初始化
_setup()执行:torch.distributed;accelerator与fsdp_config推导DistributedSetup/MeshContext;save_configs()。当前主 mesh 轴顺序为:
demo 使用:
7.2 模型与 loss
模型 target 接收
distributed_setup和peft_config。当前 demo 的 AutoModel 路径依次执行:Loss 默认使用
ModelOutputLoss读取model_output.loss。若配置loss_fn,其 target 必须构建为torch.nn.Module,并接受 Trainer 传入的model_output与labels。7.3 数据链路
当前构建依赖为:
demo 数据链路为:
global_batch_size必须能被micro_batch_size * dp_size整除;每个 local optimizer batch 也必须能被num_micro_batches整除。不满足时在构建阶段报错。7.4 训练步
每个 optimizer step 执行:
在读取 HSDP 异步梯度结果和执行梯度裁剪前必须完成
hsdp_sync_stream()。Optimizer 更新放在SkipDTensorDispatch内,避免 optimizer 对本地参数执行原始 tensor 操作时进入 DTensor dispatch。7.5 Loss 归一化
当前路径使用 token-weighted loss:
乘以
dp_size用于抵消 FSDP 对 shard group 梯度的平均。若开启 sequence parallel,还会在 TP group汇总 token 数并除以 sequence-parallel size。token 总数为 0 但 loss 非 0 时必须报错。
7.6 Callback 生命周期
Callback 顺序固定为:
logging_steps在 global rank 0 输出稳定排序的完整指标行EnvironMeter 必须先于展示 callback 执行,以保证同一步的指标已经完成 collective 并写入共享字典。
7.7 训练结束与资源清理
训练达到
max_steps、epoch 结束或 dataloader 耗尽后:on_train_end();BackgroundPrefetcher 的停止操作必须设置 stop event、清空 queue,并以有限 timeout join worker,避免退出时
无限等待后台线程。
8. 约束与失败语义
8.1 配置约束
model与optimizertarget 必填;training.max_steps若设置,必须为正整数;max_steps时,dataloader 必须具有正的有限长度;num_train_epochs必须为正整数;torch.nn.Module。8.2 拓扑约束
world_size必须能被tp_size * cp_size整除;dp_size必须能被dp_shard_size整除;dp_shard的 mesh 维;pp_size和ep_size尚未进入 Trainer demo 的 world-size 闭环,不得仅通过修改 YAML 视为已支持。8.3 Batch 与 loss 约束
list[dict];labels;labels中的IGNORE_INDEX不计入有效 token;global_batch_size必须整除micro_batch_size * dp_size;.loss,或由自定义 loss 明确处理;8.4 Fail-closed 原则
下列情况必须明确失败,而不是静默宣称 Trainer 已支持:
dp_shard;9. 唯一验证用例
9.1
examples/training_demo端到端 Trainer 跑通本 RFC 只定义这一条验证用例,不增加单元测试、组合并行矩阵、数值对拍或性能测试。
环境要求:
Qwen/Qwen3-30B-A3Bconfig/tokenizer;Salesforce/wikitext;执行命令:
该脚本串行执行:
默认配置:
10. 验收标准
(dp_shard=8)DeviceMesh 和 Qwen3-MoE per-layer/root FSDP wrapping;