Skip to content

Commit 28be4ae

Browse files
authored
[https://nvbugs/6460072][fix] Split the caller — for use_lm_head_tp_in_adp and is_all_greedy_sample, keep… (NVIDIA#16440)
Signed-off-by: ZhaoyangWang <zhaoyangw@nvidia.com>
1 parent fd74257 commit 28be4ae

2 files changed

Lines changed: 48 additions & 20 deletions

File tree

tensorrt_llm/_torch/speculative/eagle3.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -894,18 +894,17 @@ def _forward_linear_draft_loop(self, inputs, attn_metadata, spec_metadata,
894894
self._d2t,
895895
draft_step=i)
896896

897-
# When ADP+LM-head-TP pads logits to max_num_requests, the
898-
# padded rows are zero-filled placeholders only required so
899-
# every TP rank produces logits of identical shape for the
900-
# LM-head-TP all-gather. Drop them *before* sampling: the
901-
# per-request sampling params (temperatures/top_k/top_p) are
902-
# sized to token_count (== batch_size), so the padded logits
903-
# would otherwise fail to broadcast in apply_temperature. This
904-
# also keeps next_draft_tokens and the draft_probs buffer
905-
# token_count-sized without a post-hoc trim.
897+
# ADP+LM-head-TP logits are the LM-head-TP group's row-stacked
898+
# batch (each rank's rows padded to max_num_requests, then
899+
# all-gathered along dim 0) with the vocab sharded across the
900+
# group. Rows [:token_count] would be group rank 0's requests,
901+
# not this rank's, and a per-rank argmax would return a
902+
# shard-local index -- so keep the full stacked logits and let
903+
# greedy_sample_draft_with_tp_gather combine the group's vocab
904+
# shards and slice this rank's own row segment; only then trim
905+
# the max_num_requests padding down to token_count.
906906
mapping_lm_head_tp = None
907907
if use_lm_head_tp_in_adp:
908-
logits = logits[:token_count]
909908
# The MTP head built this per-forward mapping when producing
910909
# the vocab-sharded logits; the sampler needs it to gather.
911910
mapping_lm_head_tp = getattr(
@@ -917,6 +916,8 @@ def _forward_linear_draft_loop(self, inputs, attn_metadata, spec_metadata,
917916
batch_size,
918917
draft_step=i,
919918
mapping_lm_head_tp=mapping_lm_head_tp)
919+
if use_lm_head_tp_in_adp:
920+
new_draft_token = new_draft_token[:token_count]
920921
next_draft_tokens.append(new_draft_token)
921922

922923
# Update hidden states for the next iteration.

tensorrt_llm/_torch/speculative/interface.py

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,12 +1378,15 @@ def maybe_gather_sharded_draft_logits(self,
13781378
(see ``_draft_logits_are_sharded``); replicated full-vocab logits are
13791379
returned unchanged.
13801380
1381-
Plain TP gathers vocab shards over ``self.mapping``. Under ADP + LM-head
1382-
TP the worker has already trimmed the LM-head-TP padding rows so each rank
1383-
holds ``[token_count, vocab_shard]`` for its own tokens; a vocab-dim
1384-
all-gather over ``mapping_lm_head_tp`` restores full vocab (no token
1385-
re-slice is needed after the trim).
1386-
"""
1381+
Plain TP gathers vocab shards over ``self.mapping``. ADP + LM-head TP
1382+
never reaches this path: rejection sampling (the only consumer of
1383+
advanced draft sampling) is config-gated off under attention DP, and
1384+
the group-stacked sharded logits it produces are handled by the greedy
1385+
path in ``greedy_sample_draft_with_tp_gather``.
1386+
"""
1387+
assert mapping_lm_head_tp is None, (
1388+
"Advanced draft sampling is not supported under ADP + LM-head TP "
1389+
"(rejection sampling is config-gated off with attention DP)")
13871390
if (spec_metadata is None or spec_metadata.is_all_greedy_sample
13881391
or not self._draft_logits_are_sharded(logits, spec_metadata)):
13891392
return logits
@@ -1750,7 +1753,26 @@ def greedy_sample_draft_with_tp_gather(self,
17501753
vocab-sharded (see ``_draft_logits_are_sharded``) -- e.g. a borrowed or
17511754
gathered full-vocab draft head. Returns tokens in draft-vocab space (the
17521755
caller applies d2t). Expects 2D ``[num_tokens, vocab_shard]`` logits.
1756+
1757+
Under ADP + LM-head TP (``mapping_lm_head_tp`` given) the logits are the
1758+
LM-head-TP group's row-stacked batch (``tp_size`` segments of
1759+
``max_num_requests`` padded rows, all-gathered along dim 0 by the MTP
1760+
shared head) with the vocab sharded across the group. The global argmax
1761+
must combine the group's vocab shards, and each rank must read its own
1762+
row segment at offset ``tp_rank * max_num_requests`` -- NOT rows
1763+
``[:batch]``, which belong to group rank 0.
17531764
"""
1765+
if (mapping_lm_head_tp is not None
1766+
and getattr(mapping_lm_head_tp, "tp_size", 1) > 1):
1767+
from ..distributed.ops import allgather
1768+
combined = self._get_local_max_and_combined(logits,
1769+
mapping_lm_head_tp)
1770+
gathered = allgather(combined, mapping_lm_head_tp, dim=-1)
1771+
group_size = mapping_lm_head_tp.tp_size
1772+
local_rows = logits.shape[0] // group_size
1773+
own_segment = gathered.view(group_size, local_rows,
1774+
-1)[mapping_lm_head_tp.tp_rank]
1775+
return self._get_draft_tokens_from_gathered(own_segment)
17541776
mapping = self.mapping
17551777
sharded = self._draft_logits_are_sharded(logits, spec_metadata)
17561778
if (sharded and mapping is not None
@@ -1760,9 +1782,9 @@ def greedy_sample_draft_with_tp_gather(self,
17601782
combined = self._get_local_max_and_combined(logits)
17611783
gathered = allgather(combined, mapping, dim=-1)
17621784
return self._get_draft_tokens_from_gathered(gathered)
1763-
# No TP gather for attention-DP (incl. ADP + LM-head TP): each rank owns
1764-
# its own requests, so a per-rank argmax is the correct proposal and a
1765-
# cross-rank gather here would desync the ranks (see
1785+
# No cross-rank gather for plain attention-DP: each rank owns its own
1786+
# requests with replicated full-vocab logits, so a per-rank argmax is
1787+
# the correct proposal and a gather would desync the ranks (see
17661788
# _draft_logits_are_sharded). Plain argmax; caller applies d2t.
17671789
return torch.argmax(logits, dim=-1).type(torch.int32)
17681790

@@ -1908,7 +1930,12 @@ def sample_draft_tokens(self,
19081930
tokens = self.greedy_sample_draft_with_tp_gather(
19091931
logits.reshape(-1, logits.shape[-1]), spec_metadata,
19101932
mapping_lm_head_tp)
1911-
tokens = tokens.reshape(batch_shape)
1933+
if mapping_lm_head_tp is None:
1934+
tokens = tokens.reshape(batch_shape)
1935+
# else: ADP+LM-head-TP (2D step form only) -- the sampler returned
1936+
# this rank's own row segment, 1/tp_size of the stacked input rows,
1937+
# so the input batch shape no longer applies. Keep as-is; the
1938+
# caller trims the max_num_requests padding to token_count.
19121939
else:
19131940
# Advanced sampling gathers the vocab-sharded draft logits to full
19141941
# vocab, then samples (scattering this step's proposal distribution

0 commit comments

Comments
 (0)