NVIDIA Nemotron Reasoning Challenge · LoRA r≤32 · greedy eval

Learnability is necessary, not sufficient.

A technical retrospective on fine-tuning a rank-32 LoRA adapter for Nemotron-3-Nano. The project separates three bottlenecks that are easy to conflate: solver coverage, token-by-token trace learnability, and inference-runtime parity.

Read the method Confounds caught Code & repro 3D architecture explorer Canonical writeup ↗ Kaggle competition ↗
Local validation gain
+20.3pp
bit_manipulation 33.3% → 53.6% · teacher-forced probe → derivation-first trace fix
Best public LB
0.58
Adapter A · public leaderboard · final private standing in §06
Same weights, two runtimes
25.3pp
text_encryption swing across two local vLLM environments · byte-identical weights · attribution caveat in §04
01 / Premise

Correct traces are only the first ceiling.

Under greedy decoding, a correct solver trace still fails if the model cannot reproduce its consequential tokens in sequence. Solver coverage, trace learnability, and runtime parity must be measured separately.

The competition scored six reasoning categories under greedy decoding on a frozen backbone with a LoRA adapter capped at rank 32. In that setting, the training target must be both correct and locally predictable. Because all categories share one adapter, a trace redesign can improve one task while shifting behavior in another.

Constraint
r ≤ 32

Low-rank delta. Format regularity is what fits in the budget, not solver breadth.

Eval
greedy

Token-by-token reproducibility is the pass/fail line. No sampling to hide divergence.

Shared
1 adapter

Six categories, one LoRA. Divergent trace formats interfere through shared weights.

02 / Method

Teacher-forced logprob probing.

A single forward pass over the ground-truth trace, checking at every position whether the gold token is still the model's argmax. The first position where it drops to rank > 1 is where greedy decoding is guaranteed to diverge. It diagnoses format-level learnability, not answer correctness.

The diagnostic move is applying teacher-forcing not to measure loss, but to localize where a trace becomes un-reproducible (a cousin of Tong Hui Kang's min-logprob confidence signal — provenance in §08). Run one forward pass with the reference trace forced as input. At each position, compare the model's argmax against the forced token: the first position where the ground-truth token is no longer the argmax (rank > 1) is where greedy decoding will not reproduce the trace. At the divergence points we observed, the gold token's logprob sat between −0.7 and −2.3 — near-ties the model resolves in favor of a different token. Aggregating first-divergence points across a category tells you whether the failure is a solver problem or a format problem — and format problems are fixable within the rank budget.

This was a one-off post-hoc diagnostic, not a continuous pre-submission loop — an honest scoping note, since the difference matters for how much the method actually drove iteration.

Input

Ground-truth trace, teacher-forced. One forward pass, no generation.

Signal

Per-token rank of the forced token — divergence is where it stops being the argmax.

Output

First-divergence position — where greedy is guaranteed to break.

Verdict

Solver gap vs format gap. Only the latter is cheap to fix.

one forward pass divergence = rank > 1 first-divergence aggregation post-hoc, not a loop
03 / Local Validation

A format-only intervention recovered 20.3 points locally.

On bit_manipulation, the probe localized a recurring format divergence early in the trace: 44 of 47 failing traces first diverged at the rule-statement line. Rewriting the trace to derive that line — not touching the solver logic — moved local accuracy from 33.3% to 53.6% (+20.3pp). That's the proof the diagnostic points at real, addressable failures.

The failures clustered at the rule declaration, where the operator and operand indices appeared before the trace had derived them. Reordering the trace so those values were computed first improved the category without changing the solver. The result shows that trace structure itself can be the binding constraint.

Before · v9 traces
33.3%

28/84 on the frozen dev split. Greedy divergence at a fixed structural position (rule statement). Solver was fine; format wasn't reproducible.

After · v13, verified
53.6%

45/84 (+20.3pp). Derivation-first trace format, same solver, only the bit_manipulation traces changed — the diagnostic pointed true.

Scope of the gain. The 33.3% → 53.6% result is a canonical local measurement on dev_frozen with vLLM 0.20.1. The submitted adapter scored 0.56 public-LB versus the 0.58 baseline, so the local improvement did not transfer directly.

Shared-adapter tradeoff. The longer bit-manipulation traces also reduced text_encryption accuracy through cross-task interference. The net overall local gain was about 1 point. Full version-by-version evidence is in RESULTS.md and the canonical writeup.

04 / Runtime Parity

Runtime parity was a material hidden variable.

Byte-identical weights produced a 25.3-point text_encryption swing across two local inference environments. The result establishes that runtime differences were material, although the exact Spark 2 attribution and the runtime share of the Kaggle gap remain inferred.

text_encryption · byte-identical LoRA weights (cmp-verified)
Same adapter. Same prompts. Greedy. Truncation 0.0 on both local runs. The 43.4% artifact is attributed to Spark 2 by session evidence; its engine version was not recorded in the artifact.
KagglevLLM 0.17.1 (reported)
n/a
Spark 1vLLM 0.20.1
68.7%
Spark 2vLLM 0.22.1
43.4%

Kaggle's row is honest by omission: the leaderboard exposes only an overall score, never per-task accuracy — so text_encryption under vLLM 0.17.1 (a version user-reported from the competition, not locally verifiable) is unmeasurable. What is measurable: the fully-packaged adapter scores 0.58 on the Kaggle public LB against 0.694 locally, an ≈11pp residual attributed — inferred, not confirmed — to the same runtime-version divergence the two local bars demonstrate directly.

For scale: local greedy evaluation carries a measured ±0.5pp run-to-run noise floor, so a ~25pp swing is more than 50× ordinary non-determinism.

The practical conclusion reframes the scoreboard: a runtime gap this size swamps the adapter-quality signal you think you're measuring, so ordinary submission-level deltas cannot be read cleanly until the inference stack is pinned. Local gains should be treated as environment-specific until tested under deployment parity.

05 / Controlled Revisions

Three interpretations failed a cleaner ablation.

Each case below began with a plausible explanation for a score movement. A later single-variable comparison narrowed or overturned that explanation.

Corrected interpretation

The C2 converter fix regressed the score, so the bug was "load-bearing" — the scrambled weights were somehow helping.

The regression was a packaging confound, not evidence that scrambled weights were beneficial. The reshape fix is mathematically correct; its isolated Kaggle effect remains untested.

Corrected interpretation

"This was never a runtime divergence problem" — an earlier draft's framing.

The later same-weights comparison showed that runtime divergence was material. Its exact contribution to the Kaggle gap remains inferred.

C2 · converter bug

Transposed lora_B reshape — (out,r,E) where it should be (out,E,r) — scrambled 23 MoE layers × 128 experts. Fix is math-correct; clean Kaggle effect still confounded by C11.

C8 · packaging

v13's naive-packaged submission scored 0.55 (public LB) — a packaging confound, not trace quality; the A-packaged v13 resubmission scored 0.56. Score movement ≠ adapter movement.

Phantoms

text_encryption phantom signal and backbone-prefix rename noise — both ruled out as measurement artifacts, not real levers.

06 / What Held

What survived verification.

Parity claims require a verification table: confirmed, inferred, or assumed — never blurred. The durable Kaggle levers were mundane and real: packaging, not traces.

ClaimEvidence stateEffect
target_modules must be a list, not regex, on Kaggle vLLM 0.17.1 (C9/C10) — single-variable A/B on byte-identical weights, regex 0.55 → list 0.57confirmed+2pp public LB
Mixed-rank experts must be padded to r32 or declared via rank_pattern, or Kaggle's loader mis-applies themconfirmed0.56 → 0.57–0.58 public LB
Mechanism of the list lever — 0.17.1 silently under-applies a regex target_modulesinferrednot run on 0.17.1 locally
C2 lora_B reshape fix is mathematically correctconfirmedround-trip verified
C7 runtime divergence is a dominant contributor to the local↔Kaggle gap — not the sole causeinferred25.3pp local swing · ≈11pp Kaggle residual
Clean isolated Kaggle effect of the C2 fixassumeduntested — confounded by C11
Backbone-prefix rename is noise, not signalconfirmed≤1pp, sign-inconsistent across A/Bs

Sources: RESULTS.md packaging ladder (Kaggle public-LB submission matrix 2026-06-13: A backbone+list 0.58 · model.model+list 0.57 · model.model+regex 0.55, weights byte-identical) · BACKBONE_DIAGNOSTIC.md §2 (prefix-only A/B) · docs/SESSION_LOG.md C9/C10/C11 entries.

Final standing: public LB 0.58 · private LB 0.604 · rank 3488/4182. Public and private are different metrics over different held-out splits; every per-submission score on this page — the ladder above included — is a public-LB value, and a public-LB delta does not necessarily predict private standing. The private split held slightly above the public one.

07 / Takeaways

A reusable debugging loop emerged.

The transferable result is a workflow for locating format-level divergence, redesigning traces, and separating adapter changes from packaging and runtime effects.

Move the probe earlier

Huikang used min-logprob probing continuously as a pre-submission gate. This project used it post hoc on one failing category. The higher-leverage workflow is to run the probe after every training iteration, before spending a leaderboard submission.

Method

Teacher-forced logprob probing localizes format-level greedy divergence in one forward pass — a cheap, reusable diagnostic.

Hygiene

Single-variable ablations caught C7, C8, and C11. Explicit on-page reversals signal rigor, not weakness.

Hidden variable

Runtime version parity can dominate apparent adapter quality. Pin it before trusting any local→leaderboard extrapolation.

Framing

Trace learnability > solver coverage under greedy decoding at low rank. Format is the binding constraint.

08 / Repository & Provenance

Reproducibility.

Public repo, Apache-2.0, with a clean provenance trail for third-party contributions.

Code & docs: github.com/kpeterson1/nemotron-reasoning (Apache-2.0) · canonical writeup · RESULTS.md · OPEN_QUESTIONS.md (corrections C1–C11).

Attribution: the min-logprob (teacher-forced) diagnostic and the character-by-character cipher decode are tonghuikang's contributions — his public writeup and midpoint Open Prize–winning repository were the structural benchmark for this work. Our application of them — post-hoc format-learnability diagnosis, and naming our own confounds — is original. Provenance for the reference copies we worked from: references/README.md.

@misc{peterson2026nemotron,
  title = {Trace-Learnability Diagnostics for LoRA on Nemotron-3-Nano},
  author = {Peterson, Kelly},
  year = {2026},
  note = {NVIDIA Nemotron Reasoning Challenge retrospective}
}