Pull requests / #3295

#3295 [Engine] serve: temperature 0 stays greedy - no model-card penalties on a greedy request (#2940)

open · @christopherrobertbrooks-tech · 0 Kommentare · Auf GitHub

BenchmarksSetup & installServer & APIAMD / HIPNVIDIA / CUDAModels & quantsDocumentationLinux

Beschreibung

## Problem and result

Since a8091f4d (#2685) the server merges the model card's sampling under every request. A request that asks for
`temperature: 0` keeps its temperature but still gets the card's `presence_penalty: 1.5` (Flash-Next when not
thinking; Qwen3.6 in both thinking states). The engine then samples from penalized logits: the answer is not the
greedy one, and on the Qwen3.6 engine the MTP drafts never run (`spec` needs `!smp.needs_logits()`), so every
temperature-0 request shows `drafts accepted 0 of 0`. Still the case on 0.2.0-beta.

With this change, when the request, the shared Chat settings or the config's `sampling` block (the first of them
that sets a temperature) asks for temperature 0, the card's penalties are left out. The rest of the card (top_p and
top_k, which greedy decoding ignores) and any penalty the request or the config sets itself still apply. `/props`
reports the same. Requests that do not ask for temperature 0 are unchanged.

## Related discussion

Replaces #3119 (closed in the 0.2.0 tracker reset; GitHub can't reopen it after the rebase). Resolves #2940: its first suggestion (temperature 0 skips the card's set). The second (a config `sampling` block
replacing the card instead of merging over it) is left alone.

## Approach

`model_card_sampling(arch, thinking, greedy=False)` drops `presence_penalty`, `frequency_penalty` and
`repetition_penalty` when `greedy` is set; `asks_greedy(*layers)` says whether the first layer that sets a
temperature sets 0. `_run` and `/props` pass it. One sentence in `docs/DETAILS.md` after "Greedy is only for who
asks for it". Rebased on main (e88ee39).

## Validation

Revision: this branch (main e88ee39 + one commit). GPU runs: the v0.2.0-beta tag (3d1fb48, engine 0.1.45.3) with
this commit applied to its `serve/server.py`, built for sm_70 with CUDA 12.9. Tesla V100-PCIe-32GB, i7-13700KF,
16 GB RAM, Linux. Qwen3.6-35B-A3B UD-Q4_K_XL (setup's pinned file),
`--native --max-context 131072 --prefill auto --mtp 2`, every routed expert in VRAM, `reasoning_effort: none`.

**Passed:**

- `python -m unittest serve.test_model_card_sampling`: 8 tests OK. The two new ones
  (`test_greedy_gets_no_card_penalty`, `test_asks_greedy`) fail on main (ImportError: `asks_greedy`).
- All 52 `serve/test_*.py` files on main and on this branch: the same result for every file (see Failed).
- The same prompt at `temperature: 0`, 0.2.0-beta vs this branch; "true greedy" = the same request with
  `presence_penalty: 0` added:

| request | server | text = true greedy | drafts accepted | decode |
| --- | --- | --- | ---: | ---: |
| prose | 0.2.0-beta | no | 0 of 0 | 114.3 tok/s |
| prose | this branch | **yes** | 115 of 166 | **166.4 tok/s** |
| code | 0.2.0-beta | no | 0 of 0 | 111.6 tok/s |
| code | this branch | **yes** | 260 of 280 | **193.5 tok/s** |

- `strata-bench-v100/benchmark.py` (temperature 0, fresh prompts filled to each size, 256-token answers, engine
  `/metrics`, 3 runs per size, medians), decode tok/s:

| prompt tokens | 256 | 1,000 | 4,096 | 16,384 | 32,768 | 65,536 | 114,688 |
| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
| 0.2.0-beta (no drafts) | 109.3 | 104.7 | 85.7 | 59.7 | 40.3 | 23.4 | 14.6 |
| this branch (3,103 of 4,540 drafts accepted) | **156.5** | **156.4** | **116.7** | 57.6 | 34.6 | 19.6 | 11.6 |
| 0.2.0-beta + config `"sampling": {"presence_penalty": 0}` | 156.9 | 157.2 | 117.0 | 57.7 | 34.6 | 19.6 | 11.6 |

  Prefill is the same in all three (1,168 / 1,733 / 1,793 / 1,606 / 1,360 / 984 / 602 tok/s).

**Failed:** `serve/test_responses.py` `NoLeakedSampler.test_server_close_ends_the_sampler` (a thread count:
`1 != 2`), on main and on this branch alike, and on and off on 0.1.45 too.

**Not run:** the Flash-Next engine live, AMD (HIP), Intel, Mac, and the batch path (`--batch N`). This changes the
Python server only, so there is no backend to build.

## Limits

From 16K up the drafts cost on this card with the default FP32 K/V cache (11.6 vs 14.6 tok/s at 114,688). That is
MTP's own trade-off, the same as before a8091f4d, not something this change adds; the long-context decode itself
is #2464.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Mehr auf der Site

Links zu Install, Modellen, Releases.