Source code for kempnerforge.config.optimizer

"""Optimizer configuration."""

from __future__ import annotations

import math
from dataclasses import dataclass, field

WEIGHT_DECAY_SCOPES = ("exclude_norms_and_biases", "all")
MUON_ADJUST_LR_MODES = ("original", "match_rms_adamw", "spectral_unclamped")
MUON_ORTHOGONALIZE_MODES = ("local", "exact")


[docs] def checked_lr_multipliers(multipliers: object) -> dict[str, float]: """Return ``multipliers`` as a ``{module: multiplier}`` dict of floats. Raises: ValueError: ``multipliers`` is not a dict, a key is not a non-empty string, or a value is not a positive finite number. """ if not isinstance(multipliers, dict): raise ValueError(f"lr_multipliers must map module names to numbers, got {multipliers!r}") checked: dict[str, float] = {} for module, multiplier in multipliers.items(): if not isinstance(module, str) or not module: raise ValueError(f"lr_multipliers keys must be module names, got {module!r}") if ( isinstance(multiplier, bool) or not isinstance(multiplier, int | float) or not 0 < multiplier < math.inf ): raise ValueError( f"lr_multipliers[{module!r}] must be a positive finite number, got {multiplier!r}" ) checked[module] = float(multiplier) return checked
[docs] @dataclass class OptimizerConfig: """Optimizer settings.""" name: str = "adamw" lr: float = 3e-4 weight_decay: float = 0.1 betas: tuple[float, float] = (0.9, 0.95) eps: float = 1e-8 fused: bool = True muon_momentum: float = 0.95 muon_ns_steps: int = 5 muon_adam_lr: float | None = None muon_nesterov: bool = False muon_adjust_lr: str = "original" muon_orthogonalize: str = "local" muon_router: bool = False schedule_free_warmup_steps: int = 0 weight_decay_scope: str = "exclude_norms_and_biases" lr_multipliers: dict[str, float] = field(default_factory=dict) def __post_init__(self) -> None: if self.lr <= 0: raise ValueError("lr must be positive") if self.weight_decay < 0: raise ValueError("weight_decay must be non-negative") if self.weight_decay_scope not in WEIGHT_DECAY_SCOPES: raise ValueError( f"weight_decay_scope must be one of {WEIGHT_DECAY_SCOPES}, " f"got {self.weight_decay_scope!r}" ) if not (0 <= self.betas[0] < 1 and 0 <= self.betas[1] < 1): raise ValueError("betas must be in [0, 1)") if not (0 < self.muon_momentum < 1): raise ValueError("muon_momentum must be in (0, 1)") if self.muon_ns_steps <= 0: raise ValueError("muon_ns_steps must be positive") if self.muon_adjust_lr not in MUON_ADJUST_LR_MODES: raise ValueError( f"muon_adjust_lr must be one of {MUON_ADJUST_LR_MODES}, got {self.muon_adjust_lr!r}" ) if self.muon_orthogonalize not in MUON_ORTHOGONALIZE_MODES: raise ValueError( f"muon_orthogonalize must be one of {MUON_ORTHOGONALIZE_MODES}, " f"got {self.muon_orthogonalize!r}" ) if self.schedule_free_warmup_steps < 0: raise ValueError("schedule_free_warmup_steps must be non-negative") self.lr_multipliers = checked_lr_multipliers(self.lr_multipliers) nested = sorted(module for module in self.lr_multipliers if "/" in module) if nested: raise ValueError( f"lr_multipliers names modules {nested} with '/', which would log one module's " "lr/<module> under another's; name the modules of vlm.module_patterns without it" )