Skip to content

Take argmax only over the last position - #248

Merged
JakeStevens merged 1 commit into
huggingface:mainfrom
JakeStevens:fix/prefill-argmax-full-logits
Aug 11, 2026
Merged

Take argmax only over the last position#248
JakeStevens merged 1 commit into
huggingface:mainfrom
JakeStevens:fix/prefill-argmax-full-logits

Conversation

@JakeStevens

Copy link
Copy Markdown
Collaborator

Parallel prefill returns logits for the whole prompt, and the sampling step argmaxed that entire tensor before indexing the last row:

next_token = torch.argmax(logits, dim=-1)[0, -1].item()

This means there is a bunch of unnecessary results.

Instead, slice first then argmax on that.

Only the parallel prefill path is affected. The sequential prefill fallback and the decode loop call argmax on single position logits, where the two forms are equivalent, and the other call sites in this file already slice.

Parallel prefill returns logits for the whole prompt, and the sampling step
argmaxed that entire tensor before indexing the last row:

    next_token = torch.argmax(logits, dim=-1)[0, -1].item()

For Llama 3.2 1B at a 1984-token prompt that scans [1, 1984, 128256] to
obtain a single token -- seq_len times the necessary work. Slice first
instead. Same result, and the cost stops scaling with prompt length.

Measured on an AMD EPYC Genoa devserver, 16 cores, MKL/OMP=1:

  prompt   dtype       before      after
   1984    float32   267.89 ms    0.14 ms
   1984    bfloat16 1150.24 ms    0.59 ms
   8128    float32  1094.65 ms    0.15 ms
   8128    bfloat16 4718.06 ms    0.59 ms

It lands hardest on reduced precision: torch's CPU argmax is roughly 4x
slower on bfloat16 than float32, so a bf16 model paid ~1.15 s of the 1.42 s
it took to pick one token at a 1984-token prompt.

This also distorts reported prefill throughput, because on_prompt_eval_end()
is recorded after the sampling step. Splitting forward() from the argmax on
Llama 3.2 1B showed the ExecuTorch forward gap between bf16 and fp32 was
-19 ms (bf16 faster) at a 1984-token prompt while the argmax gap was +886 ms;
at 8128 tokens, forward +856 ms against argmax +3651 ms. Nearly all of an
apparent bf16 regression was this line.

Only the parallel-prefill path is affected. The sequential-prefill fallback
and the decode loop call argmax on single-position logits, where the two
forms are equivalent, and the other call sites in this file already slice.
@HuggingFaceDocBuilderDev

Copy link
Copy Markdown

The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update.

@JakeStevens
JakeStevens merged commit eb1c302 into huggingface:main Aug 11, 2026
86 checks passed
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