원클릭으로
add-optimizer
Add a new optimizer to KempnerForge. Covers implementation, registry hook, config fields, tests, and a preset TOML.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Add a new optimizer to KempnerForge. Covers implementation, registry hook, config fields, tests, and a preset TOML.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Run `uv sync` and the four CI gate checks (ruff check, ruff format, pyright, pytest unit). First command after cloning. Auto-handles non-CUDA hosts via `--no-sources`.
First-run setup. Detect SLURM account/partition/QoS from env and write configs/cluster/local.toml so every other skill can preflight.
Per-subsystem status report. What is implemented, what is tested, what is planned but unwired, and known limitations.
Walk through KempnerForge's subsystems in the order a forward pass encounters them. Starting point for anyone new to the codebase.
Submit a training job via sbatch. Wraps singlenode.sh for one node and multinode.sh for multiple. Injects account, partition, QoS, and time overrides from local.toml.
End-to-end one-GPU sanity check. Runs a short training loop to confirm torch, CUDA, NCCL, uv, and the dataloader all work before committing to longer runs.
| name | add-optimizer |
| description | Add a new optimizer to KempnerForge. Covers implementation, registry hook, config fields, tests, and a preset TOML. |
Run:
uv run python scripts/check_env.py
Baseline only: uv, repo layout. Optional follow-up for the GPU smoke step at the end: uv run python scripts/check_env.py --requires gpu.
Registered optimizers: adamw, lion, schedule_free_adamw, muon Registry: kempnerforge/config/registry.py (registry.register_optimizer("")) Optimizer builders live in: kempnerforge/training/optimizer.py Top-level builder: kempnerforge/training/optimizer.py::build_optimizer(model, config) — creates decay/no-decay param groups, looks up builder from registry, calls it Builder signature: fn(param_groups: list[dict], config: OptimizerConfig) -> torch.optim.Optimizer Config dataclass: kempnerforge/config/optimizer.py::OptimizerConfig Existing fields: name, lr, weight_decay, betas, eps, fused, muon_momentum, muon_ns_steps, muon_adam_lr, schedule_free_warmup_steps Existing tests: tests/unit/test_optimizer.py, tests/unit/test_additional_optimizers.py
Assume preflight has passed.
Implement the optimizer class in kempnerforge/training/optimizer.py. Follow the Lion example starting around line 47 for a full-from-scratch class. If you are wrapping an existing torch optimizer (like AdamW), the builder alone is enough — no class needed.
For a from-scratch optimizer:
class MyOpt(torch.optim.Optimizer):
def __init__(self, params, lr=1e-3, ...):
defaults = dict(lr=lr, ...)
super().__init__(params, defaults)
@torch.no_grad()
def step(self, closure=None):
loss = None
if closure is not None:
with torch.enable_grad():
loss = closure()
for group in self.param_groups:
for p in group["params"]:
if p.grad is None:
continue
# update p.data using p.grad and self.state[p]
return loss
Register the builder. Pattern from optimizer.py:
@registry.register_optimizer("my_opt")
def _build_my_opt(
param_groups: list[dict],
config: OptimizerConfig,
) -> torch.optim.Optimizer:
return MyOpt(
param_groups,
lr=config.lr,
...,
)
The builder MUST accept param_groups (a list of dicts built by build_optimizer) rather than a flat model.parameters(), because build_optimizer pre-splits decay and no-decay groups.
Add optimizer-specific fields to OptimizerConfig in kempnerforge/config/optimizer.py if needed. Validate them in __post_init__. Keep defaults backward-compatible so existing configs do not break.
Add unit tests. Put narrow unit tests under tests/unit/test_optimizer.py or tests/unit/test_additional_optimizers.py (either is fine; group with similar optimizers). Cover at minimum:
step() updates parameters.opt.state_dict() then opt.load_state_dict(...)) preserves behavior.weight_decay per group does not leak).Add a preset TOML under configs/train/ to demonstrate the optimizer end-to-end. Use configs/train/7b_16gpu_muon.toml as a template. The preset should override [optimizer].name and any new fields you added.
Optional: update docs/training/optimizers.md if it exists and covers registered optimizers (verify by ls docs/training/ and grep the doc).
uv run pytest tests/unit/test_optimizer.py tests/unit/test_additional_optimizers.py -v passes.uv run ruff check kempnerforge/ tests/ is clean.uv run ruff format --check kempnerforge/ tests/ passes (CI runs this too).uv run python scripts/train.py configs/train/debug.toml --data.dataset_path=<path> --optimizer.name=my_opt --train.max_steps=20. Loss must decrease.build_optimizer passes a param_groups list, not a parameter generator. The builder signature must be (param_groups, config).fused=True paths require CUDA tensors. Guard with config.fused and torch.cuda.is_available() when passing fused= to a torch optimizer.scheduler.name="none". Adding a scheduler on top of one that manages its own warmup inside step() will double-count.__init__.py re-exports. Discovery is via the registry only — re-exports create a second source of truth that drifts..to_local() vs DTensor ops.ValueError at import time — choose a unique name./kempnerforge:explain-architecture — see the "Optimizer and scheduler" section for where this fits in the training loop./kempnerforge:smoke-test — run after adding, to validate end to end on 1 GPU.