[#17022][fix] trtllm-eval: make --max_output_length reachable on aime25/aime26 - #17037
Draft
thorjohnsen wants to merge 1 commit into
Draft
[#17022][fix] trtllm-eval: make --max_output_length reachable on aime25/aime26#17037thorjohnsen wants to merge 1 commit into
thorjohnsen wants to merge 1 commit into
Conversation
…n aime25/aime26 `--max_output_length` is advertised as "Maximum generation length" on every `trtllm-eval` subcommand, but `_get_sampling_params` unconditionally overwrites `SamplingParams.max_tokens` with the task yaml's `max_gen_toks`. Passing a larger value does nothing, silently. The guard that exists for exactly this, `preserve_caller_max_tokens`, was unreachable from any text task because of two independent gates: `evaluate()` only forwarded it to the wrapper when `MULTIMODAL`, and the CLI flag was declared on `mmmu` alone. The guard logic itself was already correct. Three changes: - Forward `preserve_caller_max_tokens` to both wrappers. `LmEvalWrapper` already accepts the argument; only the forwarding was conditional. - Expose `--preserve_caller_max_tokens` on `aime25` and `aime26`, whose yaml pins `max_gen_toks: 32768`. - Warn once per run when a caller-supplied `max_tokens` is discarded in favor of the yaml value. The clamp is usually the right default, so it stays on; the hazard is that it was invisible. Default behavior is unchanged: without the flag the yaml still wins. Note this deliberately does *not* touch `longbench_v1`, which the issue also listed. That subcommand exposes neither `--max_output_length` nor `--max_input_length` and passes `sampling_params=None`, so there is no caller value to preserve and the flag would be inert there. Raising its per-subtask caps would need a separate change. Verified with DeepSeek-V4-Flash on AIME 2025 (4xGB300, TP4/EP4, greedy): at the 32768 cap, 3 of 30 problems ran past it mid-chain-of-thought and scored 0. The equivalent of this patch, applied as an in-process monkeypatch, resolved `max_tokens=131072` as intended and 2 of those 3 then terminated cleanly and scored correct (86.67 -> 93.33 exact_match, single greedy run each). Fixes NVIDIA#17022 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
--max_output_lengthis advertised as "Maximum generation length" on everytrtllm-evalsubcommand. It is placed intoSamplingParams.max_tokens(lm_eval.py:715,:1196), and then_get_sampling_paramsunconditionally overwrites it with the task yaml'smax_gen_toks. Passing a larger value does nothing, silently, and there is no workaround on text tasks.The guard that exists for exactly this case,
preserve_caller_max_tokens, was unreachable from any text task because of two independent gates:evaluate()passed it to the wrapper only for multimodal (lm_eval.py:623-627), so the textLmEvalWrapperkept its defaultFalse(lm_eval.py:65).--preserve_caller_max_tokenswas declared on exactly one subcommand,mmmu(lm_eval.py:1269).The guard logic itself was already correct — just unreachable.
Note the asymmetry that makes this surprising:
--max_input_lengthmaps totruncate_prompt_tokens, which is not inparams_mapping, so it works as documented.--temperature/--top_phave a dedicated escape hatch (sampling_override). Only the output budget is clobbered with no way out.Which tasks are affected depends on whether the yaml sets
max_gen_toks:aime25/aime26pin 32768;gsm8kandgpqa_diamondleave it unset, so the CLI value already survives there.The change
preserve_caller_max_tokensto both wrappers.LmEvalWrapperalready accepts the argument; only the forwarding was conditional.--preserve_caller_max_tokensonaime25andaime26.max_tokensis discarded in favor of the yaml value. The clamp is usually the right default — matching the reference harness recipe — so it stays on. The hazard was that it was invisible.Default behavior is unchanged: without the flag, the yaml still wins.
This deliberately does not touch
longbench_v1, which #17022 also listed. On closer reading that subcommand exposes neither--max_output_lengthnor--max_input_lengthand passessampling_params=None, so there is no caller value to preserve and the flag would be inert. Raising its per-subtask caps (32–512, appropriate for short extractive answers but too small for a thinking model) would be a separate change.Reported as #17022.
Test Coverage
No unit test is added —
_get_sampling_paramsneeds anLLMinstance to construct a wrapper through the normal path, and the existingtests/unittest/llmapi/suite has no lm-eval wrapper harness to extend. Suggestions on where this would best live are welcome.Verified directly instead, on DeepSeek-V4-Flash (4xGB300, TP4/EP4, greedy):
The defect. On
aime25at the 32768 cap, 3 of 30 problems (docs 13, 19, 23) ran past it mid-chain-of-thought, produced 91k–102k characters, never emitted</think>, and scored 0.--max_output_length 131072had no effect — the yaml's 32768 was reapplied per request.The fix. The equivalent of this patch, applied as an in-process monkeypatch forcing
preserve_caller_max_tokens=Trueon the text wrapper, with_get_sampling_paramsinstrumented to prove it took:2 of those 3 problems then terminated cleanly and scored correct (86.67 → 93.33 exact_match; single greedy run each, so per-run variance applies — see the discussion on #17022).
Behavioral checks against this branch, exercising
_get_sampling_paramsdirectly:max_tokensmax_gen_toksAlso confirmed the warning fires exactly once across repeated requests, and that
--preserve_caller_max_tokensis now registered onaime25/aime26/mmmuand absent fromgsm8k/longbench_v1.PR Checklist