Skip to content

Commit ac4d54b

Browse files
authored
[Refactor][BugFix] P-eagle and lmhead bugfix and Reduce sample reactor (vllm-project#10781)
### What this PR does / why we need it? When both the P-eagle and lmhead features are enabled, dummyrun is used for accompaniment, which causes token_indices_to_sample to be too long and exceed the value of max_num_reqs_across_dp. As a result, in lmhead, no padding is performed. Therefore, when P-eagle is enabled, an error is reported at position 1 exit. The solution is to pad the corresponding length to the initial length and restore the length when num_indices is too long. ### Does this PR introduce _any_ user-facing change? no ### How was this patch tested? UT and Tests - vLLM version: v0.23.0 - vLLM main: vllm-project/vllm@967c5c3 --------- Signed-off-by: lilinsiman <lilinsiman@gmail.com>
1 parent 55c27ec commit ac4d54b

1 file changed

Lines changed: 119 additions & 58 deletions

File tree

vllm_ascend/spec_decode/llm_base_proposer.py

Lines changed: 119 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -980,15 +980,19 @@ def _propose(
980980
return draft_token_ids
981981

982982
def compute_draft_token_ids(self, hidden_states: torch.Tensor):
983-
logits = self.model.logits_processor(self.model.lm_head, hidden_states)
984-
if not hasattr(self.model, "draft_id_to_target_id") or self.model.draft_id_to_target_id is None:
983+
if self.method in ("eagle3", "dflash"):
984+
logits = self.model.logits_processor(self.model.lm_head, hidden_states)
985+
if not hasattr(self.model, "draft_id_to_target_id") or self.model.draft_id_to_target_id is None:
986+
return greedy_sample(logits)
987+
logits = logits.contiguous()
988+
next_token = greedy_sample(logits)
989+
bias = torch.index_select(self.model.draft_id_to_target_id, dim=0, index=next_token.view(-1)).view(
990+
next_token.shape
991+
)
992+
return next_token + bias
993+
else:
994+
logits = self.model.compute_logits(hidden_states)
985995
return greedy_sample(logits)
986-
logits = logits.contiguous()
987-
next_token = greedy_sample(logits)
988-
bias = torch.index_select(self.model.draft_id_to_target_id, dim=0, index=next_token.view(-1)).view(
989-
next_token.shape
990-
)
991-
return next_token + bias
992996

993997
def _run_merged_draft(
994998
self,
@@ -1036,6 +1040,17 @@ def _run_merged_draft(
10361040
)
10371041

10381042
num_indices = token_indices_to_sample.shape[0]
1043+
if lmhead_tp_enable():
1044+
max_num_reqs_across_dp = (
1045+
self.vllm_config.scheduler_config.max_num_seqs * self.runner.uniform_decode_query_len
1046+
)
1047+
# It is necessary to evaluate the case where num_indices becomes large
1048+
# in the context of the dummy‑run accompaniment of p‑eagle.
1049+
if num_indices > max_num_reqs_across_dp:
1050+
ori_token_indices_to_sample = token_indices_to_sample
1051+
else:
1052+
ori_token_indices_to_sample = None
1053+
10391054
if self.pcp_size > 1:
10401055
# remove graph padding before all_gather
10411056
hidden_states = hidden_states[:num_input_tokens]
@@ -1058,43 +1073,49 @@ def _run_merged_draft(
10581073
)
10591074

10601075
if lmhead_tp_enable():
1061-
max_num_reqs_across_dp = (
1062-
self.vllm_config.scheduler_config.max_num_seqs * self.runner.uniform_decode_query_len
1063-
)
10641076
token_indices_to_sample = nn.functional.pad(
10651077
token_indices_to_sample, (0, max_num_reqs_across_dp - num_indices)
10661078
)
10671079

10681080
sample_hidden_states = last_hidden_states[token_indices_to_sample]
10691081

1070-
if get_ascend_config().enable_reduce_sample and self.method in ("eagle3", "dflash"):
1071-
draft_token_ids = self.compute_draft_token_ids(sample_hidden_states)
1072-
if lmhead_tp_enable() and num_indices < draft_token_ids.shape[0]:
1073-
draft_token_ids = draft_token_ids[:num_indices]
1074-
token_indices_to_sample = token_indices_to_sample[:num_indices]
1075-
else:
1076-
if get_ascend_config().enable_reduce_sample and self.method in ("mtp"):
1077-
if not hasattr(self.model.model, "compute_logits"):
1078-
draft_token_ids = self.compute_draft_token_ids(sample_hidden_states)
1079-
if lmhead_tp_enable() and num_indices < draft_token_ids.shape[0]:
1080-
draft_token_ids = draft_token_ids[:num_indices]
1081-
token_indices_to_sample = token_indices_to_sample[:num_indices]
1082-
else:
1083-
logits = self.model.compute_logits(sample_hidden_states)
1084-
if lmhead_tp_enable():
1085-
logits = get_lmhead_tp_group().all_to_all(logits)
1086-
else:
1087-
logits = self.model.model.logits_processor._gather_logits(logits)
1088-
if lmhead_tp_enable() and num_indices < logits.shape[0]:
1089-
logits = logits[:num_indices]
1090-
token_indices_to_sample = token_indices_to_sample[:num_indices]
1091-
draft_token_ids = logits.argmax(dim=-1)
1082+
if get_ascend_config().enable_reduce_sample:
1083+
if self.method in ("eagle3", "dflash", "mtp"):
1084+
draft_token_ids = self.compute_draft_token_ids(sample_hidden_states)
1085+
if lmhead_tp_enable():
1086+
draft_token_ids, token_indices_to_sample = self._align_tensor_and_indices(
1087+
draft_token_ids,
1088+
num_indices,
1089+
token_indices_to_sample,
1090+
ori_token_indices_to_sample,
1091+
is_logits=False,
1092+
)
10921093
else:
10931094
logits = self.model.compute_logits(sample_hidden_states)
1094-
if lmhead_tp_enable() and num_indices < logits.shape[0]:
1095-
logits = logits[:num_indices]
1096-
token_indices_to_sample = token_indices_to_sample[:num_indices]
1095+
if lmhead_tp_enable():
1096+
logits = get_lmhead_tp_group().all_to_all(logits)
1097+
else:
1098+
logits = self.model.model.logits_processor._gather_logits(logits)
1099+
if lmhead_tp_enable():
1100+
logits, token_indices_to_sample = self._align_tensor_and_indices(
1101+
logits,
1102+
num_indices,
1103+
token_indices_to_sample,
1104+
ori_token_indices_to_sample,
1105+
is_logits=True,
1106+
)
10971107
draft_token_ids = logits.argmax(dim=-1)
1108+
else:
1109+
logits = self.model.compute_logits(sample_hidden_states)
1110+
if lmhead_tp_enable():
1111+
logits, token_indices_to_sample = self._align_tensor_and_indices(
1112+
logits,
1113+
num_indices,
1114+
token_indices_to_sample,
1115+
ori_token_indices_to_sample,
1116+
is_logits=True,
1117+
)
1118+
draft_token_ids = logits.argmax(dim=-1)
10981119

10991120
# Early exit if there is only one draft token to be generated.
11001121
if self.num_speculative_tokens == 1 or self.parallel_drafting:
@@ -1220,34 +1241,28 @@ def _run_merged_draft(
12201241
)
12211242

12221243
sample_hidden_states = last_hidden_states[token_indices_to_sample]
1223-
if get_ascend_config().enable_reduce_sample and self.method in ("eagle3", "dflash"):
1224-
draft_token_ids = self.compute_draft_token_ids(sample_hidden_states)
1225-
if lmhead_tp_enable() and num_indices < draft_token_ids.shape[0]:
1226-
draft_token_ids = draft_token_ids[:num_indices]
1227-
token_indices_to_sample = token_indices_to_sample[:num_indices]
1228-
else:
1229-
if get_ascend_config().enable_reduce_sample and self.method in ("mtp"):
1230-
if not hasattr(self.model.model, "compute_logits"):
1231-
draft_token_ids = self.compute_draft_token_ids(sample_hidden_states)
1232-
if lmhead_tp_enable() and num_indices < draft_token_ids.shape[0]:
1233-
draft_token_ids = draft_token_ids[:num_indices]
1234-
token_indices_to_sample = token_indices_to_sample[:num_indices]
1235-
else:
1236-
logits = self.model.compute_logits(sample_hidden_states)
1237-
if lmhead_tp_enable():
1238-
logits = get_lmhead_tp_group().all_to_all(logits)
1239-
else:
1240-
logits = self.model.model.logits_processor._gather_logits(logits)
1241-
if lmhead_tp_enable() and num_indices < logits.shape[0]:
1242-
logits = logits[:num_indices]
1243-
token_indices_to_sample = token_indices_to_sample[:num_indices]
1244-
draft_token_ids = logits.argmax(dim=-1)
1244+
if get_ascend_config().enable_reduce_sample:
1245+
if self.method in ("eagle3", "dflash", "mtp"):
1246+
draft_token_ids = self.compute_draft_token_ids(sample_hidden_states)
1247+
if lmhead_tp_enable() and num_indices < draft_token_ids.shape[0]:
1248+
draft_token_ids = draft_token_ids[:num_indices]
1249+
token_indices_to_sample = token_indices_to_sample[:num_indices]
12451250
else:
12461251
logits = self.model.compute_logits(sample_hidden_states)
1252+
if lmhead_tp_enable():
1253+
logits = get_lmhead_tp_group().all_to_all(logits)
1254+
else:
1255+
logits = self.model.model.logits_processor._gather_logits(logits)
12471256
if lmhead_tp_enable() and num_indices < logits.shape[0]:
12481257
logits = logits[:num_indices]
12491258
token_indices_to_sample = token_indices_to_sample[:num_indices]
12501259
draft_token_ids = logits.argmax(dim=-1)
1260+
else:
1261+
logits = self.model.compute_logits(sample_hidden_states)
1262+
if lmhead_tp_enable() and num_indices < logits.shape[0]:
1263+
logits = logits[:num_indices]
1264+
token_indices_to_sample = token_indices_to_sample[:num_indices]
1265+
draft_token_ids = logits.argmax(dim=-1)
12511266

12521267
# TODO(wenlong): get more than one token for tree attention
12531268
hidden_states = hidden_states[:batch_size]
@@ -2110,3 +2125,49 @@ def maybe_all_gather_and_unpad(
21102125
if hidden_states is not None:
21112126
hidden_states = torch.ops.vllm.maybe_all_gather_and_maybe_unpad(hidden_states.contiguous(), True)
21122127
return last_hidden_states, positions, hidden_states
2128+
2129+
# In the context of the dummy‑run accompaniment of p‑eagle, when num_indices becomes large,
2130+
# enabling the LM head feature causes token_indices_to_sample to switch from padding to trimming.
2131+
# The trimmed length may not be an integer multiple of the speculative length,
2132+
# in which case padding is required to restore it to the original length.
2133+
def _align_tensor_and_indices(
2134+
self,
2135+
tensor,
2136+
num_indices,
2137+
token_indices_to_sample,
2138+
ori_token_indices_to_sample,
2139+
is_logits=False,
2140+
):
2141+
"""
2142+
Align the tensor (either draft_token_ids or logits) and token_indices_to_sample
2143+
to the length specified by num_indices.
2144+
2145+
Args:
2146+
tensor: The tensor to be aligned (draft_token_ids or logits)
2147+
num_indices: The target length
2148+
token_indices_to_sample: The current index tensor
2149+
ori_token_indices_to_sample: The original index tensor (used for restoration)
2150+
is_logits: Whether the tensor is logits (affects the padding dimension and padding value)
2151+
2152+
Returns:
2153+
The adjusted tensor and token_indices_to_sample
2154+
"""
2155+
if tensor.shape[0] == num_indices:
2156+
return tensor, token_indices_to_sample
2157+
2158+
if tensor.shape[0] > num_indices:
2159+
# Trim to the target length.
2160+
tensor = tensor[:num_indices]
2161+
token_indices_to_sample = token_indices_to_sample[:num_indices]
2162+
else:
2163+
# Padding to the target length.
2164+
pad_size = num_indices - tensor.shape[0]
2165+
if is_logits:
2166+
# logits: shape [seq_len, vocab_size], Padding at the end of the seq dimension.
2167+
tensor = nn.functional.pad(tensor, (0, 0, 0, pad_size), value=-1e9)
2168+
else:
2169+
# draft_token_ids: shape [seq_len], Padding at the end
2170+
tensor = nn.functional.pad(tensor, (0, pad_size))
2171+
token_indices_to_sample = ori_token_indices_to_sample
2172+
2173+
return tensor, token_indices_to_sample

0 commit comments

Comments
 (0)