Skip to content

Return top-p/top-k sampling mask/nucleas - #27408

Merged
hnyls2002 merged 12 commits into
sgl-project:mainfrom
hari-harmonic:hari/keep-sampling-mask
Jul 13, 2026
Merged

hnyls2002 merged 12 commits into
sgl-project:mainfrom
hari-harmonic:hari/keep-sampling-mask

Conversation

@hari-harmonic

@hari-harmonic hari-harmonic commented Jun 6, 2026 •

Copy link
Copy Markdown
Contributor

Implement keep-sampling-mask / top-p & top-k replay runtime support through request parsing, sampling, scheduling, detokenization, disaggregation metadata, and the model gateway.

Motivation

Modifications

Accuracy Tests

test/registered/sampling/test_sampling_mask.py was added to check the following:

  • basic validations: each sampled token has an attached sampling mask, size of each sampling mask <= specified top-k, and the sampled token always exists in the sampling mask.
  • verifies under deterministic inference that sampled tokens when return_sampling_mask=True are identical to those returned when return_sampling_mask=False, the default path.
  • validates that the sampling mask and renormalized logprobs are mathematically correct. This is done by querying the server with return_logprob = True and top_logprobs_num = TOP_K with temperature 1, which returns the unnormalized logprobs of the TOP_K most probable tokens. From here, we can reconstruct the sampling mask (modulo some possible boundary off-by-ones) and compute the renormalized logprobs offline.

Speed Tests and Profiling

Checklist

Review and Merge Process

  1. Ping Merge Oncalls to start the process. See the PR Merge Process.
  2. Get approvals from CODEOWNERS and other reviewers.
  3. Trigger CI tests with comments or contact authorized users to do so.
    • Common commands include /tag-and-rerun-ci, /tag-run-ci-label, /rerun-failed-ci
  4. After green CI and required approvals, ask Merge Oncalls or people with Write permission to merge the PR.

CI States

Latest PR Test (Base): ⏳ Run #29291142253
Latest PR Test (Extra): ❌ Run #29291141839

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@ByronHsu ByronHsu left a comment

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.

Thanks for adding this. The Python/SRT side looks broadly safe to me, and the feature itself seems useful.

A few requests before this moves forward:

  1. Can we rename the PR/title to avoid making this sound DeepSeek V3.2-specific? From the implementation, return_sampling_mask is generic sampling metadata. It is not inherently tied to one model.

  2. Please add an end-to-end test in the usual server-launch + sample-request style. The smoke script is useful for manual validation, but I’d like a checked-in test that launches a small server/model, sends a /generate request with return_sampling_mask=true, and verifies.

  3. Please revert the sgl-model-gateway raw-JSON/extra-body plumbing in this PR. Switching /generate from Json<GenerateRequest> to Json<Value> and threading route_generate_with_extra through the router stack feels too hacky for a known first-class field.

    For Miles, let’s make this change directly in radixark/sgl-router-for-miles instead. That is the router we will use going forward, and it has the protocol structs plus router code in one repo, so we can add return_sampling_mask directly to GenerateRequest and keep the handler typed.

  4. Please clean up the new scripts/ additions.

  5. After this lands on main, please merge/cherry-pick it into sglang-miles.

@hari-harmonic

hari-harmonic commented Jun 12, 2026 •

Copy link
Copy Markdown
Contributor Author

Thanks for adding this. The Python/SRT side looks broadly safe to me, and the feature itself seems useful.

A few requests before this moves forward:

  1. Can we rename the PR/title to avoid making this sound DeepSeek V3.2-specific? From the implementation, return_sampling_mask is generic sampling metadata. It is not inherently tied to one model.
  2. Please add an end-to-end test in the usual server-launch + sample-request style. The smoke script is useful for manual validation, but I’d like a checked-in test that launches a small server/model, sends a /generate request with return_sampling_mask=true, and verifies.
  3. Please revert the sgl-model-gateway raw-JSON/extra-body plumbing in this PR. Switching /generate from Json<GenerateRequest> to Json<Value> and threading route_generate_with_extra through the router stack feels too hacky for a known first-class field.
    For Miles, let’s make this change directly in radixark/sgl-router-for-miles instead. That is the router we will use going forward, and it has the protocol structs plus router code in one repo, so we can add return_sampling_mask directly to GenerateRequest and keep the handler typed.
  4. Please clean up the new scripts/ additions.
  5. After this lands on main, please merge/cherry-pick it into sglang-miles.

Thank you for your review! Your suggestions make sense to me, this PR was more so intended to be a proof-of-concept prior to further cleanup. I will work on doing the suggestions over the coming days.

@hari-harmonic
hari-harmonic force-pushed the hari/keep-sampling-mask branch from 09b21c1 to 1102107 Compare June 17, 2026 00:06
@hari-harmonic hari-harmonic changed the title Add Deepseek V3.2's Keep Sampling mask response support Return top-p/top-k sampling nucleas Jun 17, 2026
@hari-harmonic hari-harmonic changed the title Return top-p/top-k sampling nucleas Return top-p/top-k sampling mask/nucleas Jun 17, 2026
@hari-harmonic

Copy link
Copy Markdown
Contributor Author

Hi @ByronHsu, I believe I have addressed the main points of your feedback and have opened a much cleaner routing PR here radixark/sgl-router-for-miles#7 to use serde. I added an e2e server test script as well in place of the old smoke test script. Please let me know if you have additional feedback that I can address -- thanks!

@ByronHsu

Copy link
Copy Markdown
Collaborator

lgtm. please turn the pr to "ready for review" and make the ci pass. current lint is failing too

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@hari-harmonic
hari-harmonic force-pushed the hari/keep-sampling-mask branch from 627102b to 34ff1b3 Compare June 23, 2026 17:12
@lawrence-harmonic

Copy link
Copy Markdown
Contributor

/tag-and-rerun-ci

@hari-harmonic
hari-harmonic force-pushed the hari/keep-sampling-mask branch from b4fc262 to e175d71 Compare July 10, 2026 03:29
@hari-harmonic
hari-harmonic force-pushed the hari/keep-sampling-mask branch from e175d71 to cf117ee Compare July 11, 2026 15:47
@hnyls2002

Copy link
Copy Markdown
Collaborator

CI States

Latest PR Test (Base): ✅ Run #29158553156
Latest PR Test (Extra): ❌ Run #29158552915

# Conflicts:
#	python/sglang/srt/disaggregation/prefill.py
@hnyls2002
hnyls2002 merged commit a909077 into sgl-project:main Jul 13, 2026
73 of 92 checks passed
kpham-sgl added a commit to zRzRzRzRzRzRzR/sglang that referenced this pull request Jul 14, 2026
Main's sgl-project#27408 added an unconditional req.return_sampling_mask read in
MetadataBuffers.set_buf; the SimpleNamespace req stub predates it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
raspberryice pushed a commit to raspberryice/sglang that referenced this pull request Jul 16, 2026
… sort

The top-p nucleus capture ran a full-vocab `probs.sort` (~150k) AND a per-row
`.item()` GPU->CPU sync on every decode step (both in `get_top_p_token_ids_from_probs`
and `renorm_logprob_over_top_p`, which the sampler calls per token). On the Qwen3.6
codeforces S2 top-p run this slowed decode enough to push trajectories into the 1800s
trajectory-timeout -> tokens_per_gpu_per_sec down, aborted-trajectory length shorter,
empty_trajectory_ratio ~15% (baseline ~0%). See
notes/training_logs/ioi/2026-07-16_qwen3_6_stage2_topp_mask_replay_observations.md.

Port the structure of upstream sglang PR sgl-project#27408 (Return top-p/top-k sampling
mask/nucleus) against our v0.5.10 tree:
- `_top_p_keep_mask_bounded`: gather only the top-K (`torch.topk`, MASK_TOPK_DEFAULT=128)
  instead of a full-vocab sort, since the kept nucleus is a tiny prefix (measured width
  p99 ~11 / max ~35). K is DECOUPLED from the sampling top_k on purpose: no recipe /
  `--rollout-top-k` change, no distribution change -- it only bounds capture width.
  Silent-truncation guard: any row whose nucleus reaches the K-th column is recomputed
  with the full sort and spliced in (warns), so correctness never depends on K.
- `get_top_p_token_ids_from_probs`: also drop the per-row `.item()` sync -- vectorized
  `nonzero` + a single batched `.cpu()`, split back into per-row lists on host.
- `renorm_logprob_over_top_p`: same sort removed (same per-decode-step hot path); build
  the vocab-order keep-mask by setting only kept positions (nonzero gather) since the
  bounded path pads unused columns with index 0.

No slime-side / launcher / wire-format change (still top_p_token_ids + offsets).
Tests: test/srt/test_top_p_replay_logprob.py +2 (topk-vs-full-sort equivalence,
wide-nucleus fallback); all 9 pass. New extractor verified byte-exact (order+values)
vs the old one across seeds. CPU-validated only; on-GPU perf recovery pending.
Chronostasys pushed a commit to MindLab-Research/sglang that referenced this pull request Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

model-gateway run-ci CI: run the baseline test suite on this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants