已开启
【RFC】hyper-parallel 支持torchtitan 风格 Module/Config —— Part 3 训练组件Configurable化 #141
changzherui创建于 5月15日
5月15日 修改标题为 “hyper-parallel 支持torchtitan 风格 Module/Config —— M3 训练组件”,原标题为“hyper-parallel 支持torchtitan 风格 Module/Config —— M3”
5月15日 修改标题为 “hyper-parallel 支持torchtitan 风格 Module/Config —— M3 训练组件”,原标题为“hyper-parallel 支持torchtitan 风格 Module/Config —— M3”
5月15日 修改标题为 “hyper-parallel 支持torchtitan 风格 Module/Config —— M3 训练组件Configurable化”,原标题为“hyper-parallel 支持torchtitan 风格 Module/Config —— M3 训练组件”
5月15日 修改标题为 “hyper-parallel 支持torchtitan 风格 Module/Config —— M3 训练组件Configurable化”,原标题为“hyper-parallel 支持torchtitan 风格 Module/Config —— M3 训练组件”
5月15日 修改标题为 “【RFC】hyper-parallel 支持torchtitan 风格 Module/Config —— M3 训练组件Configurable化”,原标题为“hyper-parallel 支持torchtitan 风格 Module/Config —— M3 训练组件Configurable化”
5月15日 修改标题为 “【RFC】hyper-parallel 支持torchtitan 风格 Module/Config —— M3 训练组件Configurable化”,原标题为“hyper-parallel 支持torchtitan 风格 Module/Config —— M3 训练组件Configurable化”
5月25日 修改标题为 “【RFC】hyper-parallel 支持torchtitan 风格 Module/Config —— Part 3 训练组件Configurable化”,原标题为“【RFC】hyper-parallel 支持torchtitan 风格 Module/Config —— M3 训练组件Configurable化”
5月25日 修改标题为 “【RFC】hyper-parallel 支持torchtitan 风格 Module/Config —— Part 3 训练组件Configurable化”,原标题为“【RFC】hyper-parallel 支持torchtitan 风格 Module/Config —— M3 训练组件Configurable化”
5月25日 修改了issue 的描述
Part 3 —
hyper_parallel/components/训练组件 Configurable 化1. 目标
让 optimizer / lr_scheduler / loss / tokenizer / dataloader / checkpoint / profiler / metrics 都变成
Configurable组件,每个__init__(self, config)接受自己的Config,config.build(...)即构造。2. 任务边界(新增文件)
新增包目录
hyper_parallel/components/:optimizer.pybase.py:555-604 _build_optimizerOptimizersContainer(Configurable)+OptimizersInBackwardContainer(Configurable);Config(lr, betas, eps, weight_decay, foreach, fused, decay_keywords, loss_aggregation);__init__(self, cfg, model_parts: list[Module])内部跑 decay / no_decay 分组逻辑torchtitan/components/optimizer.pylr_scheduler.pybase.py:606-637 _build_lr_schedulerLRSchedulersContainer(Configurable):cosine + warmup,复制_lr_lambda逻辑;Config(warmup_steps, decay_style, lr_min, lr_max);__init__(self, cfg, optimizers, training_steps)torchtitan/components/lr_scheduler.pyloss.pymodels/qwen3_5/model.py:361-373的F.cross_entropyBaseLoss(Configurable)+CrossEntropyLoss(Configurable);可选ChunkedCELoss;模型 forward 重构为返回 logits,loss 由loss.build()(logits, labels)计算torchtitan/components/loss.pytokenizer.pyllm_trainer.py:72-104 _build_model_assetsBaseTokenizer(Configurable)+HuggingFaceTokenizer(Configurable);Config(path, trust_remote_code, pad_token)torchtitan/components/tokenizer.pydataloader.pybase.py:248-405 _build_dataset / collate / dataloader+llm_trainer.py:202-381BaseDataLoader(Configurable)+HuggingFaceTextDataLoader / DummyDataLoader / PresetPtDataLoader;build(dp_world_size, dp_rank, tokenizer, seq_len)返回StatefulDataLoadertorchtitan/components/dataloader.pycheckpoint.pybase.py:1273-1417 _load_weights / _load_hf_safetensors / _load_hyper_dcp+ 现CheckpointCallbackCheckpointManager(Configurable):封装core/distributed_checkpoint.load+state_dict_adapter;Config(output_dir, save_steps, save_async, save_hf_weights, load_path)torchtitan/components/checkpoint.pyprofiler.pyProfilerCallbackProfiler(Configurable):torch.profiler / mindspore profiler 跨后端封装;Config(enabled, output_dir, wait_steps, warmup_steps, active_steps)torchtitan/components/profiler.pymetrics.pyLoggingCallback / TensorBoardCallback / WandbCallbackMetricsProcessor(Configurable):tb / wandb / throughput;Config(report_to, log_steps, tensorboard, wandb)torchtitan/components/metrics.py3. 核心设计点
3.1 组件
Config字段名 = 旧 yaml 字段名例如
OptimizersContainer.Config的字段必须包含lr / weight_decay / eps / betas / foreach,与trainer/config.py:195 OptimizerConfig字段一致 —— 这样 M2 的_legacy_to_trainer_config能一对一映射。3.2 新旧路径共享同一份"算法实现"
M3 的实现就是把
_build_*函数体搬到组件__init__;M5 中旧BaseTrainer._build_optimizer改为:def _build_optimizer(self): if isinstance(self.args, HyperTrainer.Config): # 新路径 self.optimizer = self.args.optimizer.build(model_parts=[self.model]) else: # 旧路径 # base.py:555-604 原逻辑保持不变 ...3.3 示例:
OptimizersContainerclass OptimizersContainer(Configurable): @dataclass(kw_only=True, slots=True) class Config(Configurable.Config): lr: float = 1e-4 betas: tuple[float, float] = (0.9, 0.999) eps: float = 1e-8 weight_decay: float = 0.01 foreach: bool | None = None fused: bool | None = None decay_keywords: tuple[str, ...] = ("bias", "layernorm", "norm", "rmsnorm") loss_aggregation: str = "token_weighted" def __init__(self, cfg: "OptimizersContainer.Config", *, model_parts: list): # 直接搬 base.py:566-600 的逻辑: decay_params, no_decay_params = [], [] seen = set() for m in model_parts: for n, p in m.named_parameters(): if not p.requires_grad or id(p) in seen: continue seen.add(id(p)) lname = n.lower() bucket = no_decay_params if any(k in lname for k in cfg.decay_keywords) else decay_params bucket.append(p) param_groups = [ {"params": decay_params, "weight_decay": cfg.weight_decay}, {"params": no_decay_params, "weight_decay": 0.0}, ] self._optimizer = torch.optim.AdamW( param_groups, lr=cfg.lr, betas=cfg.betas, eps=cfg.eps, foreach=cfg.foreach, ) def step(self): self._optimizer.step() def zero_grad(self): self._optimizer.zero_grad() # ... 实现 .state_dict / .load_state_dict 等接口4. 与 torchtitan 接口差异说明
CheckpointManager封装 hyper 的 DCP(core/distributed_checkpoint/load),不是 torchDistributedCheckpointingMetricsProcessor整合多个 callback —— 现状 hyper 有 13 个 callback(base.py:680)散落MetricsProcessor作为"组件式入口",内部丢给 BaseTrainer 走老接口;M8 统一tokenizer / dataloader字段保留 hyper 现用名(text_key / streaming / num_workers / pin_memory)Literal[str]而非torch.dtypeDummyDataLoader / PresetPtDataLoader是 hyper 独有的两个特殊路径llm_trainer.py:202-341已有逻辑,要保留5. 开发步骤(每个组件 0.5 d)
按依赖顺序:
optimizer → lr_scheduler → loss → tokenizer → dataloader → checkpoint → profiler → metrics。每个组件统一流程:
_build_<x>函数体逐行复制到<X>Container.__init__。self.args.train.<x>的访问改为self.config.<field>。Config()、build(...)后与旧_build_<x>同种子 + 同输入下产物 bit-exact。6. 验证标准
新建
tests/torch/ut/components/,每个组件 1 个对照测试:test_optimizer.pymodel_parts喂给旧_build_optimizer和OptimizersContainer.Config(...).build(model_parts=[m]),参数分组、lr / wd / betas / foreach完全相同test_lr_scheduler.pytest_loss.pyCrossEntropyLoss.Config().build()(logits, labels)与F.cross_entropy(...)数值一致test_tokenizer.pytest_dataloader.pyDummyDataLoader / HuggingFaceTextDataLoader / PresetPtDataLoader产 1 步样本与旧路径完全一致test_checkpoint.pytest_profiler.pytest_metrics.py通过门槛:
BaseTrainer._build_*(base.py:555-700)0 修改。7. 工期 & 依赖
Configurable)