Repository navigation
Conversation
|
No actionable comments were generated in the recent review. Walkthrough
ChangesSpeculative sampler request updates
Estimated code review effort: 3 (Moderate) | ~20 minutes Change: Refactor Possibly related PRs
Suggested reviewers: Merge Risk:
|
JunyiXu-nv
left a comment
There was a problem hiding this comment.
Runtime part LGTM. The compact rows match the per-slot reads (new_tokens[step][slot][beam], new_tokens_lens and next_draft_tokens by slot) on random shapes and slot subsets, add_token did only the read plus add_new_token, and _request_common_handling has no other caller. The new cpu_only test runs via l0_cpu.yml's speculative/hw_agnostic entry.
|
Could you please rebase this branch onto the latest upstream |
…date_requests Index the host copies of the one-model speculative sampler store with the slots of the batch's unfinished requests before converting them to Python lists. The store holds one row per preallocated sequence slot, so converting all of it made the per-step cost grow with max_num_sequences instead of the batch. AI assistance (Cursor) was used for this change. Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: YangHaoooooo <233765393+Hang-get@users.noreply.github.com>
afb753f to
da82467
Compare
|
Rebased onto current main ( |
Dev Engineer Review
SpecSampler.update_requestsnow filters completed requests before conversion. It converts only the host-tensor rows for active requests' sequence slots (new_tokens,new_tokens_lens,next_draft_tokens). The loop reads those rows by compact batch position (row).token_windows[request_index]anddraft_lens[req_idx]still use request-position indexing. This matches the diff.Review points:
add_tokenis removed from the import and the loop. Each token now comes fromnew_tokens_rows[row][i]andreq.add_new_token(new_token, beam_idx). The diff does not show the old helper's body. Confirm thatadd_tokenonly appended the token, so that behavior matches._request_common_handlingnow takes one request's draft-token list instead of the batch-shaped list. It no longer indexes bypy_seq_slot. Any other caller of this method must pass a per-request list. The diff shows only this call site.num_new_tokens <= max_accepted_path_lenassertion still runs before token reads. Its behavior is unchanged.pyexecutor.samplerimport.QA Engineer Review
Test files changed:
tests/unittest/_torch/speculative/hw_agnostic/test_spec_sampler_update_requests.py, with one parameterized test,test_update_requests_reads_each_request_slot_row. It is markedpytest.mark.cpu_only.verify_lensisNoneor[3, 2, 1, 2].The test covers:
py_num_accepted_draft_tokens,py_num_draft_tokens_verified,py_rewind_len,py_draft_tokens, andpy_decoding_iter.Test-list membership: a
git grepoftests/integration/test_lists/at HEAD for the test filename returned no matches. The test does not appear intest-db/CI lists orqa/manual-QA lists. This is a unit test, so these lists do not apply.Coverage verdict: sufficient for row selection and request updates. It does not cover GPU execution, end-to-end serving, or the stop-criteria paths, because
handle_stop_criteriais stubbed to returnFalse.Current-head CI and test results are not available.
Per-File QA Perspective
tensorrt_llm/_torch/speculative/spec_sampler_base.py: Verify updates for active requests whose sequence slots are scattered, including batches that contain completed requests. Verify that verification-window checks, accepted-token bounds, and stop handling still behave correctly.tests/unittest/_torch/speculative/hw_agnostic/test_spec_sampler_update_requests.py: Adds a CPU-only unit test for row selection and request updates, covering both verification-length paths. It is not in the integration CI or manual-QA lists.Description
SpecSampler.update_requestsruns once per step for every one-model speculative decoding mode. Aftersampler_event.synchronize()it converted the host copies of the whole sampler store to nested Python lists:new_tokens([max_draft_len + 1, max_num_sequences, 1]),new_tokens_lensandnext_draft_tokens. The store has one row per preallocated sequence slot, but the loop only reads the rows of the batch's requests, so the conversion cost depended onmax_num_sequencesrather than on the batch.This change indexes the three host tensors with the slots of the batch's unfinished requests, converts only those rows, and reads them by row position in the validation and update loops.
token_windowsanddraft_lensare still indexed by request position._request_common_handlingnow receives the request's own draft row. Device work, the D2H copies and the request updates are unchanged.Closes #22016.
Benchmark
CPU only, main
37e6e677against this change (spec_sampler_base.pyis identical on the current base70fe2b2a6). Both versions ofupdate_requestsran on identical host tensors, with request stubs implementingadd_new_token,get_num_tokens,get_tokensandfinish_by, and the realhandle_stop_criteria; native bindings were stubbed for the import. Intel Xeon Platinum 8352Y, CPython 3.12.3, PyTorch 2.15.0+cpu, one pinned core; 20 warmups, then nine rounds of 15-50 timed calls, median of the round medians.2048 is the default
max_batch_size; most DeepSeek-R1-0528 MTP configs underexamples/configs/databaseuse 512, including all concurrency-1 configs. A full store is not slower, because each request's tokens become one flat list instead of one single-element list per token.Test Coverage
tests/unittest/_torch/speculative/hw_agnostic/test_spec_sampler_update_requests.py(cpu_only): requests on scattered slots of a 16-slot store, with a finished request between them so that row positions differ from request positions, for uniform and ragged verification windows. It checks the appended tokens, the accepted/verified/rewind counts and the next draft tokens against each request's slot row. 2 passed, on this branch and on main.tests/unittest/_torch/speculative/hw_agnostic/test_ragged_spec_sampler.py, which drivesupdate_requeststhroughsample_async(verify windows, pending steps, slot reuse): 85 passed.runtime_draft_lenabove and below the store width, end-id, length and stop-word finishes, invalid windows) gave identical request updates and identical exceptions.pre-commit run --fileson both files: all hooks passed, including Ruff, ruff-format, codespell, the test-list AST check and Pyrefly (no diagnostics).Local test runs used
--noconftestwith an in-process stub for the native bindings; this machine has no usable GPU or TensorRT-LLM build. Thel0_cpulist already includesunittest/_torch/speculative/hw_agnostic. Not run: GPU tests and end-to-end serving benchmarks.PR Checklist
AI assistance (Cursor) was used for this change.