Skip to content

Commit 0838ce8

Browse files
authored
[Misc][MRV2] Align V2 Model Runner with Upstream (vllm-project#12731)
### What this PR does / why we need it? This PR introduces several updates and alignments for the Ascend backend in vLLM: - **Top-K Top-P Sampler Patching**: Overrides `apply_top_k_top_p` to use the `ascendc` operator instead of Triton on NPU, bypassing the upstream Triton routing which is broken on Ascend for batch sizes >= 8. - **Model Runner Alignments**: - Uses `sort_batch_req_ids` from upstream. [https://github.com/vllm-project/vllm/pull/47381](url) - Cleans up unused attributes (`cudagraph_and_dp_padding`, `self.input_batch`). - Updates draft token and logit calculation to support speculative decoding with multiple new sampled tokens per step (`num_bonus_tokens`). ### Does this PR introduce _any_ user-facing change? No. ### How was this patch tested? CI/CD testing with existing tests. - vLLM version: v0.25.1 - vLLM main: vllm-project/vllm@fe784ff Signed-off-by: zouzy <zouzongyu@huawei.com>
1 parent d6a3401 commit 0838ce8

2 files changed

Lines changed: 41 additions & 34 deletions

File tree

vllm_ascend/worker/v2/model_runner.py

Lines changed: 40 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@
3636
)
3737
from vllm.v1.worker.gpu.model_runner import GPUModelRunner
3838

39+
from vllm_ascend.utils import vllm_version_is
40+
41+
if not vllm_version_is("0.25.1"):
42+
from vllm.v1.worker.gpu.model_runner import sort_batch_req_ids
43+
3944
from vllm_ascend.ascend_config import get_ascend_config
4045
from vllm_ascend.ascend_forward_context import (
4146
MoECommType,
@@ -118,22 +123,15 @@ def __init__(self, vllm_config: VllmConfig, device: torch.device):
118123
pin_memory=True,
119124
)
120125

126+
# NOTE: In GPUModelRunner, decode_query_len is initialized in execute_model(),
127+
# +1 is hardcoded here but not in vllm.
128+
self.decode_query_len = self.num_speculative_steps + 1
121129
# Set _mc2_tokens_capacity and _reserved_mc2_mask for MoE communication optimization.
122130
# TODO: remove set_cos_and_sin (together with update_cos_sin) when mla can properly handle cos/sin internally
123-
self.decode_query_len = self.num_speculative_steps + 1
124131
set_cos_and_sin(vllm_config, self.max_num_reqs, self.decode_query_len, self.dtype, self.device)
125132
set_mc2_tokens_capacity(vllm_config, self.max_num_reqs, self.decode_query_len)
126133
set_mc2_mask(vllm_config, self.device)
127134

128-
# we need to use return value of `get_cudagraph_and_dp_padding`
129-
# to set forward_context in `run_fullgraph`.
130-
# so we can inherit `execute_model` method.
131-
self.cudagraph_and_dp_padding: tuple[int, torch.Tensor | None, int] | None = None
132-
133-
# we need to use input_batch to set forward_context in run_fullgraph.
134-
# so we can inherit `execute_model` method.
135-
self.input_batch: AscendInputBatch | None = None
136-
137135
def initialize_kv_cache(self, kv_cache_config: KVCacheConfig) -> None:
138136
with graph_manager_wrapper(self):
139137
super().initialize_kv_cache(kv_cache_config)
@@ -171,9 +169,13 @@ def prepare_inputs(
171169
num_tokens_per_req = scheduler_output.num_scheduled_tokens
172170
num_reqs = len(num_tokens_per_req)
173171

174-
# Decode first, then prefill.
175172
# batch_idx -> req_id
176-
req_ids = sorted(num_tokens_per_req, key=num_tokens_per_req.get) # type: ignore
173+
if vllm_version_is("0.25.1"):
174+
# vllm 0.25.1 does not have sort_batch_req_ids;
175+
# TODO: remove this patch when main2main is applied.
176+
req_ids = sorted(num_tokens_per_req, key=num_tokens_per_req.get) # type: ignore
177+
else:
178+
req_ids = sort_batch_req_ids(num_tokens_per_req, self.decode_query_len)
177179

178180
self._update_seq_lens_cpu(scheduler_output, req_ids)
179181

@@ -202,7 +204,7 @@ def prepare_inputs(
202204

203205
# Get the number of draft tokens for each request.
204206
draft_tokens = scheduler_output.scheduled_spec_decode_tokens
205-
num_draft_tokens_per_req: np.ndarray | None = None
207+
num_draft_tokens_per_req = None
206208
if not draft_tokens:
207209
# No draft token scheduled (common case).
208210
total_num_draft_tokens = 0
@@ -212,21 +214,21 @@ def prepare_inputs(
212214
expanded_idx_mapping = idx_mapping
213215
expanded_local_pos = torch.zeros(num_reqs, dtype=torch.int32, device=self.device)
214216
else:
215-
num_draft_tokens_arr = np.array(
216-
[len(draft_tokens.get(req_id, ())) for req_id in req_ids],
217+
num_draft_tokens_per_req = np.fromiter(
218+
(len(draft_tokens.get(req_id, ())) for req_id in req_ids),
217219
dtype=np.int32,
220+
count=num_reqs,
218221
)
219-
num_draft_tokens_per_req = num_draft_tokens_arr
220-
total_num_draft_tokens = int(num_draft_tokens_arr.sum())
221-
total_num_logits = num_reqs + total_num_draft_tokens
222-
223-
num_logits = num_draft_tokens_arr + 1
222+
num_bonus_tokens = self.model_state.num_new_sampled_tokens_per_step
223+
total_num_draft_tokens = int(num_draft_tokens_per_req.sum())
224+
total_num_logits = num_reqs * num_bonus_tokens + total_num_draft_tokens
225+
num_logits = num_draft_tokens_per_req + num_bonus_tokens
224226
cu_num_logits_np = np.empty(num_reqs + 1, dtype=np.int32)
225227
cu_num_logits_np[0] = 0
226228
np.cumsum(num_logits, out=cu_num_logits_np[1:])
227229
cu_num_logits = async_copy_to_gpu(cu_num_logits_np, device=self.device)
228230

229-
max_expand_len = self.num_speculative_steps + 1
231+
max_expand_len = self.decode_query_len
230232
expanded_idx_mapping, expanded_local_pos = expand_idx_mapping(
231233
idx_mapping, total_num_logits, cu_num_logits, max_expand_len
232234
)
@@ -256,7 +258,7 @@ def prepare_inputs(
256258
async_copy_to_gpu(query_start_loc_np, out=self.input_buffers.query_start_loc)
257259

258260
query_start_loc_np = query_start_loc_np[: num_reqs_padded + 1]
259-
query_start_loc = self.input_buffers.query_start_loc[: num_reqs + 1]
261+
query_start_loc = self.input_buffers.query_start_loc[: num_reqs_padded + 1]
260262
prefill_len_np = self.req_states.prefill_len.np[idx_mapping_np]
261263
num_computed_prefill_tokens_np = self.req_states.num_computed_prefill_tokens[idx_mapping_np]
262264
is_prefilling_np = num_computed_prefill_tokens_np < prefill_len_np
@@ -281,7 +283,7 @@ def prepare_inputs(
281283
self.input_buffers.positions,
282284
self.input_buffers.seq_lens,
283285
)
284-
seq_lens = self.input_buffers.seq_lens[:num_reqs]
286+
seq_lens = self.input_buffers.seq_lens[:num_reqs_padded]
285287

286288
# Pad for full CUDA graph mode.
287289
self.input_buffers.seq_lens_np[num_reqs_padded:] = 0
@@ -298,11 +300,9 @@ def prepare_inputs(
298300
self.req_states.draft_tokens,
299301
cu_num_logits,
300302
total_num_logits,
303+
self.model_state.num_new_sampled_tokens_per_step,
301304
)
302305

303-
input_ids = self.input_buffers.input_ids[:num_tokens_after_padding]
304-
positions = self.input_buffers.positions[:num_tokens_after_padding]
305-
306306
# CPU upper bound on seq_lens (num_computed_tokens + num_scheduled_tokens).
307307
# Added by vLLM PR #40654 to avoid GPU->CPU sync for seq_lens.
308308
seq_lens_cpu_upper_bound_np = np.zeros(num_reqs_padded, dtype=np.int32)
@@ -313,12 +313,18 @@ def prepare_inputs(
313313
)
314314
seq_lens_cpu_upper_bound = torch.from_numpy(seq_lens_cpu_upper_bound_np)
315315
num_computed_tokens_np = self.req_states.num_computed_tokens_np[idx_mapping_np]
316+
316317
max_seq_len_np = None
317-
if getattr(self, "use_pp", False):
318-
# max_seq_len is only consumed by the PP `compute_need_sampled_mask`.
318+
if self.use_pp:
319+
# max_seq_len is only consumed by the PP `compute_need_sampled_mask`
319320
max_seq_len_np = self.req_states.max_seq_len[idx_mapping_np]
320321

321-
self.input_batch = AscendInputBatch(
322+
prompt_lens = None
323+
if self.model_config.rswa_window is not None:
324+
# prompt_lens is only used in R-SWA case.
325+
prompt_lens = self.req_states.prompt_len.gpu[idx_mapping]
326+
327+
input_batch = AscendInputBatch(
322328
req_ids=req_ids,
323329
num_reqs=num_reqs,
324330
num_reqs_after_padding=num_reqs_padded,
@@ -341,24 +347,24 @@ def prepare_inputs(
341347
prefill_len_np=prefill_len_np,
342348
num_computed_prefill_tokens_np=num_computed_prefill_tokens_np,
343349
max_seq_len_np=max_seq_len_np,
344-
input_ids=input_ids,
345-
positions=positions,
350+
input_ids=self.input_buffers.input_ids[:num_tokens_after_padding],
351+
positions=self.input_buffers.positions[:num_tokens_after_padding],
346352
is_padding=self.input_buffers.is_padding[:num_tokens_after_padding],
347353
logits_indices=logits_indices,
348354
cu_num_logits=cu_num_logits,
349355
cu_num_logits_np=cu_num_logits_np,
350356
has_structured_output_reqs=scheduler_output.has_structured_output_requests,
351357
# TODO: only populated for R-SWA (not supported yet).
352-
prompt_lens=None,
358+
prompt_lens=prompt_lens,
353359
# extra attributes for ascend npus.
354360
seq_lens_np=self.input_buffers.seq_lens_np,
355361
attn_state=attn_state,
356362
)
357363

358364
# For mla/sfa, update cos/sin. Here is for execute_model.
359-
update_cos_sin(self.input_batch.positions)
365+
update_cos_sin(input_batch.positions)
360366

361-
return self.input_batch
367+
return input_batch
362368

363369
def postprocess(
364370
self,

vllm_ascend/worker/worker.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,7 @@ def compile_or_warm_up_model(self) -> CompilationTimes:
761761
bind_cpus(self.local_rank)
762762
except Exception as e:
763763
logger.warning("Bind cpus failed in rank%s: %s Skip binding cpu.", self.local_rank, e)
764+
764765
# Reset the seed to ensure that the random state is not affected by
765766
# the model initialization and profiling.
766767
set_random_seed(self.model_config.seed)

0 commit comments

Comments
 (0)