Skip to content

Fix registry argument validation for muon_hyperball - #312

Merged
skyw merged 2 commits into
NVIDIA-NeMo:mainfrom
v0ropaev:fix/registry-muon-hyperball-args
Oct 20, 2026
Merged

skyw merged 2 commits into
NVIDIA-NeMo:mainfrom
v0ropaev:fix/registry-muon-hyperball-args

Conversation

@v0ropaev

Copy link
Copy Markdown
Contributor

registry.get_configured_optimizer_cls("muon_hyperball", lr=0.01, hyperball_radius=1.0) raises TypeError: Optimizer 'MuonHyperball' does not accept arguments: {'lr'}. The same happens for momentum, nesterov and every other Muon argument. validate_optimizer_args only looks at signature(opt_cls), and MuonHyperball.__init__ is (*args, hyperball_radius, hyperball_eps=1e-15, **kwargs), so the only names it accepts are args, hyperball_radius, hyperball_eps and kwargs. The nanogpt example works around this by hand in build_optimizer by merging in Muon's signature when the name is muon_hyperball.

The validation now walks the class MRO and collects the named parameters of each __init__, moving on to the parent only while the current __init__ takes **kwargs. The *args and **kwargs entries are no longer counted as argument names. MuonHyperball is the only registered optimizer with **kwargs in its signature, so every other optimizer stops at its own __init__ and accepts the same names as before. For MuonHyperball the walk stops at Muon, so names that only exist further up, like scaled_orthogonalize_fn on OrthogonalizedOptimizer, are still rejected.

One side effect is that weight_update_hook now passes validation for muon_hyperball, since Muon's __init__ takes it. MuonHyperball still raises KeyError for it when the optimizer is constructed, so the error shows up there instead of at validation time. I didn't special case it in the registry. I also left the nanogpt workaround alone. That example looks up classes through the registry but does its own argument check and never calls validate_optimizer_args, so it can be simplified separately.

I added two tests to tests/test_registry.py. One builds muon_hyperball through get_configured_optimizer_cls with lr, momentum, nesterov and hyperball_radius and constructs it on a unit norm parameter. The other checks that nonexistent_arg, args, kwargs and scaled_orthogonalize_fn are rejected for MuonHyperball. On main the first test errors with TypeError and the args and kwargs cases fail, and with the change all of them pass. I ran python tests/test_registry.py --device=cpu --seed=42 (18 tests OK) and python tests/test_orthogonalized_optimizer.py (145 tests OK) on CPU with torch 2.14.1 and Python 3.12. I also looped over all 27 registered optimizers and compared the accepted names before and after. They are identical for all of them except muon_hyperball, which now accepts every Muon argument and no longer accepts args or kwargs. ruff 0.9.9 (check, isort and format) is clean on both changed files and mypy 1.19.1 is clean on registry.py.

validate_optimizer_args built the set of accepted names from
signature(opt_cls) alone. MuonHyperball.__init__ takes
(*args, hyperball_radius, hyperball_eps=1e-15, **kwargs) and hands
everything else to Muon, so the check only allowed the literal names
args, hyperball_radius, hyperball_eps and kwargs. Every real Muon
argument was rejected, e.g.
get_configured_optimizer_cls("muon_hyperball", lr=0.01, hyperball_radius=1.0)
raised TypeError for lr, while args=... and kwargs=... passed.

Walk the MRO instead and collect the named parameters of each __init__,
continuing to the parent only while the current __init__ takes
**kwargs. *args and **kwargs themselves are no longer treated as
argument names. Optimizers without **kwargs, which is every other
registered one, stop at their own __init__ and keep the same accepted
names as before.

Signed-off-by: Dmitry Voropaev <dy.voropaev@gmail.com>
@copy-pr-bot

copy-pr-bot Bot commented Oct 20, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@greptile-apps

greptile-apps Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no actionable issues were found.

Summary

The PR lets muon_hyperball accept arguments forwarded to its parent constructor.

  • Muon Hyperball accepts the options it forwards to Muon.

Reviews (2) · Last reviewed commit: "Use a plain loop to collect init params ..." · Reviewed by Greptile

@skyw skyw left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Largely LGTM. Couple of small comments, will approve after.

Thanks for the contribution. It has been on my list to redesign the registry, it is very limited and not definitely not bullet proof at the moment.

Comment thread emerging_optimizers/registry.py Outdated
"""Checks if kwargs are valid for the optimizer class signature."""
sig = signature(opt_cls)
supported_params = set[str]()
for klass in opt_cls.__mro__:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

class?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed it to cls, class itself is a keyword.

Comment thread emerging_optimizers/registry.py Outdated
continue
init_params = signature(vars(klass)["__init__"]).parameters.values()
supported_params.update(
p.name for p in init_params if p.kind not in (Parameter.VAR_POSITIONAL, Parameter.VAR_KEYWORD)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hard to read comprehension, favor plain for loop.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, it's a plain loop now.

Signed-off-by: Dmitry Voropaev <dy.voropaev@gmail.com>
@skyw

skyw commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

/ok to test 521873f

@skyw
skyw enabled auto-merge (squash) October 20, 2026 20:21
@skyw
skyw merged commit af5aa76 into NVIDIA-NeMo:main Oct 20, 2026
31 checks passed

This branch was successfully deployed

2 active deployments
public — 521873f4 Deployed Oct 20, 2026 by copy-pr-bot[bot] via release / finalize / notify #286
test — 521873f4 Deployed Oct 20, 2026 by copy-pr-bot[bot] via cicd-wait-in-queue #1097
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants