Skip to content

feat(config): add v6.1 ruleset and pin RNG seeds from submission ruleset#389

Open
arekay-nv wants to merge 6 commits into
mainfrom
feat/random-seeds
Open

feat(config): add v6.1 ruleset and pin RNG seeds from submission ruleset#389
arekay-nv wants to merge 6 commits into
mainfrom
feat/random-seeds

Conversation

@arekay-nv

Copy link
Copy Markdown
Collaborator

Adds the MLPerf Inference v6.1 RoundRuleset (schedule/sample_index seeds from loadgen/mlperf.conf; per-model latency targets unchanged from v5.1) and makes it CURRENT. The registry now registers every known round by version, so both v5.1 and v6.1 are resolvable.

When a config carries submission_ref, _resolve_and_validate now pins the runtime RNG seeds from the selected ruleset during construction — before the config is dumped to the report dir, so the persisted config.yaml, RuntimeSettings, and report all reflect the seeds that actually ran. The ruleset value wins over any user-supplied seed (mirrors LoadGen locking core seeds from user.conf). Lenient by design: an unregistered ruleset leaves the config unchanged, so placeholder/non-submission configs are unaffected.

Duration/latency overrides and the runtime-path integration (surfacing ruleset latency targets in the report) are deferred to a follow-up.

What does this PR do?

Type of change

  • Bug fix
  • New feature
  • Documentation update
  • Refactor/cleanup

Related issues

Testing

  • Tests added/updated
  • All tests pass locally
  • Manual testing completed

Checklist

  • Code follows project style
  • Pre-commit hooks pass
  • Documentation updated (if needed)

Adds the MLPerf Inference v6.1 RoundRuleset (schedule/sample_index seeds from
loadgen/mlperf.conf; per-model latency targets unchanged from v5.1) and makes
it CURRENT. The registry now registers every known round by version, so both
v5.1 and v6.1 are resolvable.

When a config carries submission_ref, _resolve_and_validate now pins the
runtime RNG seeds from the selected ruleset during construction — before the
config is dumped to the report dir, so the persisted config.yaml,
RuntimeSettings, and report all reflect the seeds that actually ran. The
ruleset value wins over any user-supplied seed (mirrors LoadGen locking core
seeds from user.conf). Lenient by design: an unregistered ruleset leaves the
config unchanged, so placeholder/non-submission configs are unaffected.

Duration/latency overrides and the runtime-path integration (surfacing ruleset
latency targets in the report) are deferred to a follow-up.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@arekay-nv arekay-nv requested a review from a team July 2, 2026 19:59
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

MLCommons CLA bot All contributors have signed the MLCommons CLA ✍️ ✅

@github-actions github-actions Bot requested a review from nvzhihanj July 2, 2026 19:59

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request introduces the MLPerf Inference v6.1 ruleset, including its official RNG seeds, and updates the default submission template to reference v6.1. It also implements a mechanism in BenchmarkConfig to automatically override and pin runtime RNG seeds based on the selected submission ruleset, ensuring compliance. Feedback is provided regarding the definition of _v6_1, where copying the mutable benchmark_rulesets dictionary instead of sharing its reference with _v5_1 is recommended to prevent potential side effects.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/inference_endpoint/config/rulesets/mlcommons/rules.py Outdated

@arekay-nv arekay-nv left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Review Council — Multi-AI Code Review

Reviewed by: Codex + Claude | Depth: thorough

Codex: no actionable correctness issues. Claude: 5 posted (1 shared-dict finding on rules.py:282 was dropped as a duplicate of the existing gemini-code-assist comment). See the summary comment below for the tiered breakdown.

return

updates: dict[str, int] = {}
if ruleset.scheduler_rng_seed is not None:

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

[Claude] medium (testing): The two is not None seed branches and the if not updates: return early-exit are never exercised — both registered MLCommons rulesets set both seeds. ruleset_base.py documents None as a valid "unseeded randomization" value, so a partial ruleset (one seed None) or a no-op ruleset (both None) is a supported, reachable state. Add a test that registers a throwaway RoundRuleset(scheduler_rng_seed=None, sample_index_rng_seed=<int>) (and one with both None) and asserts only the set seed is pinned / the config is left unchanged.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

There is a semantic issue beyond the branch coverage discussed above: None currently means two different things. BenchmarkSuiteRuleset documents it as unseeded randomization, and RoundRuleset.apply_user_config passes it through to random.Random(None); this config path instead skips the override and retains the default/user seed, usually 42. The same ruleset therefore behaves differently depending on its construction path.

Suggested fix: preserve the existing contract by making the runtime/report seed fields nullable and always applying both ruleset values, including None:

updates = {
    "scheduler_random_seed": ruleset.scheduler_rng_seed,
    "dataloader_random_seed": ruleset.sample_index_rng_seed,
}

If nullable seeds are not intended, the alternative is to remove None from the ruleset contract and reject such rulesets explicitly. Either way, the two runtime-construction paths should agree.

"""Only the round seeds rotate; per-model targets are identical."""
v5_1 = get_ruleset("mlperf-inference-v5.1")
v6_1 = get_ruleset("mlperf-inference-v6.1")
assert v6_1.benchmark_rulesets == v5_1.benchmark_rulesets

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

[Claude] low (testing): v6_1.benchmark_rulesets == v5_1.benchmark_rulesets is identity-trivially true — _v6_1 is built with benchmark_rulesets=_v5_1.benchmark_rulesets (the same dict object), so this passes without actually verifying the per-model targets. (If the shared reference is replaced by a copy — see the existing suggestion on rules.py:282 — this becomes a real structural check.) Consider asserting a concrete expected value, e.g. a specific model's max_tpot_latency_ms, instead.

Comment thread src/inference_endpoint/config/ruleset_registry.py Outdated
Comment thread src/inference_endpoint/config/rulesets/mlcommons/rules.py Outdated
Comment thread src/inference_endpoint/config/schema.py Outdated
@arekay-nv

Copy link
Copy Markdown
Collaborator Author

Review Council — Multi-AI Code Review

Reviewed by: Codex (gpt-5.5, xhigh) + Claude | Depth: thorough

Codex: "changes consistently register the new MLCommons round and apply the selected ruleset seeds into runtime configuration without introducing an evident functional regression. No actionable correctness issues."

Claude: 6 findings; 1 dropped as a duplicate of the existing gemini-code-assist comment on rules.py:282 (shared mutable-dict reference). 5 posted inline.

No critical/high issues. The core logic (frozen-model mutation via model_copy + object.__setattr__, lenient resolution, ruleset-wins seed lock, before-dump ordering) reviewed clean under both reviewers.

🟡 Should Fix (medium)

# File Line Category Reviewer Summary
1 config/schema.py 1055 testing Claude is not None seed branches + if not updates early-exit are untested — a None-seed ruleset is a documented, supported state

🔵 Consider (low)

# File Line Category Reviewer Summary
2 .../mlcommons/test_rules.py 147 testing Claude benchmark_rulesets == assertion is identity-trivially true (same dict object) — verifies nothing
3 config/ruleset_registry.py 85 design Claude No duplicate-version guard — a future round sharing a version string would be silently overwritten
4 .../mlcommons/rules.py 280 docs/verify Claude Compliance-locked seeds match docs/RANDOM_SEEDS.md (@ v6.0.0pre) but should be confirmed against the tagged v6.1 mlperf.conf
5 config/schema.py 1068 error-handling Claude logger.info("Pinned RNG seeds …") fires multiple times per run (with_updates re-validates) — consider debug

Related: the existing gemini-code-assist comment on rules.py:282 (copy the shared benchmark_rulesets dict) would also resolve finding #2 if applied.

Commit hygiene: 1 commit, 0 fixups — clean.

Signed-off-by: Rashid Kaleem <230885705+arekay-nv@users.noreply.github.com>

@arekay-nv arekay-nv left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Review Council — Multi-AI Code Review (re-review of 346bd6b)

Reviewed by: Codex (gpt-5.5, xhigh) + Claude | Depth: thorough

Codex: no introduced correctness issues. Claude: 7 findings — 6 posted inline below, 1 summary-only (outside diff). The prior run's 6 findings are all resolved by 346bd6b. See the summary comment for the tiered breakdown.

Comment thread src/inference_endpoint/config/rulesets/mlcommons/rules.py Outdated
Comment thread src/inference_endpoint/config/schema.py Outdated
Comment thread src/inference_endpoint/config/rulesets/mlcommons/rules.py Outdated
ValueError: If a ruleset is already registered under ``name`` (guards
against two rounds silently sharing a version string).
"""
if name in _RULESET_REGISTRY:

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

[Claude] low (api-contract): This guard makes the module non-idempotent — _auto_register_mlcommons() runs at import time, so a second call or an importlib.reload of this module (previously a silent overwrite) now raises ValueError mid-import. No current caller reloads, so nothing breaks today, but reload-safety is gone. If that matters, use dict.setdefault/an in-check for the auto-register path while keeping the raise for external callers.

if not updates:
return

new_runtime = self.settings.runtime.model_copy(update=updates)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

[Claude] low (error-handling): self.settings.runtime.model_copy(update=updates) — pydantic v2 model_copy(update=...) bypasses validation and does not verify that update keys are real fields (it writes straight into __dict__, even with extra="forbid"). The keys "scheduler_random_seed"/"dataloader_random_seed" are hardcoded strings decoupled from the RuntimeConfig field definitions; if either field is renamed, this silently attaches a junk attribute and leaves the real seed at its default with no error. Consider deriving the names from the model (or a shared constant) so a rename fails loudly.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Follow-up after the field-name guard: model_copy(update=...) still bypasses value validation. I registered a ruleset with scheduler_rng_seed="oops" and obtained a successfully validated BenchmarkConfig whose runtime seed was a str.

Suggested fix: rebuild through Pydantic validation instead of an unvalidated copy:

new_runtime = type(self.settings.runtime).model_validate(
    {**self.settings.runtime.model_dump(), **updates}
)

With extra="forbid", this also catches unknown fields, making the manual key guard redundant while validating seed values. Please add an invalid-seed regression test.

ruleset_registry._RULESET_REGISTRY.pop(name, None)

@pytest.mark.unit
def test_partial_none_seed_pins_only_set_seed(self, register_temp_ruleset):

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

[Claude] low (testing): Nice coverage of the scheduler-None (test_partial_none_seed_pins_only_set_seed) and both-None (test_all_none_seed_leaves_config_unchanged) cases. The mirror partial — scheduler_rng_seed set, sample_index_rng_seed=None — is never exercised, so the sample_index_rng_seed is not None False branch is only hit when updates is already empty. Consider adding that combination for symmetry.

@arekay-nv

Copy link
Copy Markdown
Collaborator Author

Review Council — Multi-AI Code Review (re-review of 346bd6b)

Reviewed by: Codex (gpt-5.5, xhigh) + Claude | Depth: thorough

Codex: "I did not find any introduced correctness issues in the diff. The new ruleset registration and seed pinning logic appears consistent with the updated tests and existing config/runtime flow."

Claude: 7 findings — 6 posted inline, 1 summary-only (outside the diff). No critical/high. The core logic (frozen-model mutation via model_copy + object.__setattr__, ruleset-wins seed lock, before-dump ordering) reviewed clean under both reviewers.

Prior round resolved: all 6 findings from the first Review Council run are addressed by 346bd6b — shared-dict → copied, duplicate-version guard added, logger.infologger.debug, and the None-seed + concrete-target tests added.

🟡 Should Fix (medium)

# File Line Category Summary
1 config/rulesets/mlcommons/rules.py 276 documentation Comment references docs/RANDOM_SEEDS.md, which is not tracked in the repo — a dangling ref that already misled a reviewer (violates AGENTS.md). Commit the doc or inline the rationale.
2 config/schema.py 1046 data-integrity A type=SUBMISSION config with an unregistered submission_ref.ruleset silently falls back to default seeds (42/42) → non-compliant submission that looks valid. Make it a hard error for SUBMISSION.

🔵 Consider (low)

# File Line Category Summary
3 config/rulesets/mlcommons/rules.py 283 design rules.copy() is a 2-level copy, not the "Deep copy" the commit claims — leaf rulesets (with a mutable reported_metrics list) are still shared with v5.1. Latent; deepcopy or a shared-immutable note.
4 config/ruleset_registry.py 52 api-contract New duplicate guard makes the module non-idempotent — a re-import / importlib.reload now raises mid-import instead of silently overwriting.
5 config/schema.py 1062 error-handling model_copy(update=...) bypasses validation and field-name checks; the hardcoded "..._random_seed" keys are decoupled from RuntimeConfig — a future field rename fails silently.
6 tests/unit/config/test_schema.py 827 testing The mirror partial-None case (scheduler set, sample_index_rng_seed=None) is untested; that is not None False branch is only hit with an already-empty updates.
7 tests/unit/config/test_schema.py 167 documentation Pre-existing test pins ruleset="mlperf-inference-v6.0", which is not registered (only v5.1/v6.1). Outside the diff, so not posted inline — with the new override it now logs a "not registered" warning every run. Bump to v6.1.

Commit hygiene: 2 commits, 0 fixups — clean.

Signed-off-by: Rashid Kaleem <230885705+arekay-nv@users.noreply.github.com>
@arekay-nv arekay-nv requested a review from viraatc July 7, 2026 01:18
@arekay-nv

Copy link
Copy Markdown
Collaborator Author

with the following section in the client config file (for deepseek for instance):

submission_ref:
  model: deepseek-r1 
  ruleset: mlperf-inference-v6.1

results_summary.json should contain the following lines:

"seeds": {
    "scheduler_random_seed": 16159082839903944936,
    "dataloader_random_seed": 2747215439041700203,
    "warmup_random_seed": 42
  }

@arekay-nv arekay-nv left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Review Council — Multi-AI Code Review (independent)

Reviewed by Codex + Claude | depth: thorough | posted inline: 4

Codex reported no correctness issues. Claude's findings below (none critical/high — the PR is fundamentally sound).

try:
ruleset = self.submission_ref.get_ruleset_instance()
except KeyError as e:
if self.type == TestType.SUBMISSION:

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

[Claude] medium / api-contract: Breaking change for existing v6.0 submission configs. This branch raises ValidationError at config-load when a type=submission config names an unregistered ruleset. The prior submission_template.yaml on main shipped ruleset: "mlperf-inference-v6.0", which is not registered (only v5.1 / v6.1 / mlcommons-current are). Any user config copied from the old template now hard-fails to load instead of running. The behavior is correct in principle (a submission must pin official seeds), but it warrants a changelog / migration note for in-flight v6.0 configs.

"""
# Register every known round under its version-specific name
for ruleset in mlcommons_rounds:
_RULESET_REGISTRY.setdefault(f"mlperf-inference-{ruleset.version}", ruleset)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

[Claude] medium / design: setdefault bypasses the duplicate guard added to register_ruleset in this same PR. If two entries in ALL_ROUNDS ever share a .version, the second is silently dropped (first-wins) with no error — the ValueError guard at line 53 is unreachable from this primary registration path. Production correctness then rests solely on the test_round_versions_are_unique unit test being run. Consider registering rounds through register_ruleset (so duplicates fail loudly at import) and handling re-import idempotency with a sentinel, rather than trading a runtime invariant for a test-only one.

datasets=[{"path": "test.jsonl"}],
submission_ref=SubmissionReference(model="test", ruleset="does-not-exist"),
)
assert cfg.settings.runtime.scheduler_random_seed == 42

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

[Claude] low / testing: Untested new branches. (1) The unknown-runtime-fields raise (schema.py:1075) has no test — nothing injects a bogus key (and it's currently unreachable anyway). (2) _auto_register_mlcommons's claimed idempotency is asserted only in a docstring; no test calls it twice to prove setdefault avoids the duplicate error. (3) The SUBMISSION unregistered-ruleset raise is exercised only via direct BenchmarkConfig(...) construction, not via the from-config YAML path (the real user entry point). Add tests for (2) and (3).

benchmark_rulesets={
# Keep the model-singleton keys; deep-copy only the per-model rules so
# v6.1's mutable leaves (e.g. reported_metrics) can't leak into v5.1.
model: copy.deepcopy(rules)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

[Claude] low / design: Deep-copy correctness rides on enum-deepcopy identity. copy.deepcopy(rules) recurses into the inner dict's keys; lookups like benchmark_rulesets[model][opt_prio] keep working only because OptimizationPriority is an Enum and copy.deepcopy(member) is member. If it ever became a plain class without __deepcopy__, every apply_user_config lookup with the module-level singleton would KeyError. Prefer {k: copy.deepcopy(v) for k, v in rules.items()} to preserve keys explicitly. (The deep copy is also purely defensive — nothing currently mutates reported_metrics — so a key-preserving shallow copy would be equally safe and clearer about intent.)

@arekay-nv

Copy link
Copy Markdown
Collaborator Author

Review Council — Multi-AI Code Review (independent)

Reviewed by Codex + Claude | depth: thorough

These reviews were run independently of any prior context — Codex in an isolated worktree, Claude fresh — assessing the diff on its own merits (no assumed verification).

Codex: no correctness issues found (reviewed against merge-base(main)).
Claude: 7 findings — none critical/high; the PR is fundamentally sound. 4 posted inline, 2 already covered by existing comments, 1 off-hunk (below).

🟡 Should Fix (medium)

# File Line Category Status Summary
1 config/schema.py 1048 api-contract ✅ inline Old type=submission configs with ruleset: mlperf-inference-v6.0 (the value the previous template shipped) now hard-fail to load — worth a migration/changelog note.
2 config/templates/submission_template.yaml 51 documentation ⚠️ off-hunk The scheduler_random_seed: 42 / dataloader_random_seed: 42 comments are misleading: this template is type: submission + v6.1, so the seeds are pinned from the ruleset and 42 is never used. Drop or annotate the fields.
3 config/schema.py 1063 error-handling 🔁 already-commented User seeds are silently overridden and logged only at debug; the override fires for any config with a submission_ref (only the error path is gated to SUBMISSION), so offline/online configs referencing a ruleset also get seeds rewritten.
4 config/ruleset_registry.py 96 design ✅ inline setdefault bypasses the new duplicate guard — a duplicate .version in ALL_ROUNDS is silently dropped; correctness depends on test_round_versions_are_unique running.

🔵 Consider (low)

# File Line Category Status Summary
5 config/schema.py 1075 design 🔁 already-commented The unknown-runtime-fields raise is unreachable (updates only ever holds two valid hard-coded keys) and wouldn't catch the rename it claims to guard.
6 tests/unit/config/test_schema.py 803 testing ✅ inline Untested new branches: registry idempotency (double-call), and the SUBMISSION unregistered-ruleset raise via the from-config YAML path.
7 config/rulesets/mlcommons/rules.py 287 design ✅ inline deepcopy of benchmark_rulesets keeps working only because OptimizationPriority is an enum (deepcopy(member) is member); prefer a key-preserving copy.

Commit hygiene: 3 commits, clean — no squash needed.

arekay-nv added 3 commits July 7, 2026 11:05
Signed-off-by: arekay-nv <230885705+arekay-nv@users.noreply.github.com>
Signed-off-by: arekay-nv <230885705+arekay-nv@users.noreply.github.com>
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.

3 participants