main
py 122 lines 4.76 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 import torch
5 import torch.nn as nn
6 from typing_extensions import override
7
8 from vllm.config import VllmConfig
9 from vllm.config.utils import replace
10 from vllm.logger import init_logger
11 from vllm.model_executor.model_loader import get_model
12 from vllm.tokenizers.registry import get_tokenizer
13 from vllm.v1.spec_decode.llm_base_proposer import SpecDecodeBaseProposer
14 from vllm.v1.spec_decode.vocab_mapping import VocabMapping
15
16 logger = init_logger(__name__)
17
18
19 class DraftModelProposer(SpecDecodeBaseProposer):
20 def __init__(
21 self,
22 vllm_config: VllmConfig,
23 device: torch.device,
24 runner=None,
25 ):
26 super().__init__(
27 vllm_config=vllm_config,
28 device=device,
29 pass_hidden_states_to_model=False,
30 runner=runner,
31 )
32 self._raise_if_draft_tp_mismatch()
33
34 self.use_heterogeneous_vocab = self.speculative_config.use_heterogeneous_vocab
35
36 spec = self.speculative_config
37 if self.use_heterogeneous_vocab:
38 # Heterogeneous vocabularies: build a VocabMapping to translate
39 # token IDs between the two tokenizers and constrain draft logits
40 # to the intersection so rejection sampling stays lossless.
41 target_tokenizer = get_tokenizer(
42 spec.target_model_config.tokenizer,
43 trust_remote_code=spec.target_model_config.trust_remote_code,
44 )
45 draft_tokenizer = get_tokenizer(
46 spec.draft_model_config.model,
47 trust_remote_code=spec.draft_model_config.trust_remote_code,
48 )
49 self.vocab_mapping: VocabMapping | None = VocabMapping(
50 target_tokenizer=target_tokenizer,
51 draft_tokenizer=draft_tokenizer,
52 target_vocab_size=spec.target_model_config.get_vocab_size(),
53 draft_vocab_size=spec.draft_model_config.get_vocab_size(),
54 device=device,
55 )
56 else:
57 self._raise_if_vocab_size_mismatch()
58 self.vocab_mapping = None
59
60 def _raise_if_vocab_size_mismatch(self):
61 self.speculative_config.verify_equal_vocab_size_if_draft_model()
62
63 def _raise_if_draft_tp_mismatch(self):
64 # Note(Tomas Ruiz) If we run the target model with TP > 1 and
65 # the draft model with TP = 1, then the different TP ranks collide.
66 # Specifically when all ranks compile the draft model on rank 0
67 # (because TP=1), then the torch compile cache is overwritten and corrupted.
68 # We need a mechanism like this: https://github.com/vllm-project/vllm/pull/5414
69 # To prevent this error, we assert that both TP sizes must be the same.
70 spec_cfg = self.speculative_config
71 tgt_tp = spec_cfg.target_parallel_config.tensor_parallel_size
72 draft_tp = spec_cfg.draft_parallel_config.tensor_parallel_size
73 if draft_tp != tgt_tp:
74 raise ValueError(
75 f"Currently, 'draft_tensor_parallel_size' and 'tensor_parallel_size' "
76 f"must be the same. Got {draft_tp} and {tgt_tp}. "
77 "Please pass 'draft_tensor_parallel_size' in the speculative_config."
78 )
79
80 @override
81 def _create_draft_vllm_config(self) -> VllmConfig:
82 base = super()._create_draft_vllm_config()
83 spec = self.speculative_config
84 target_parallel = base.parallel_config
85
86 return replace(
87 base,
88 quant_config=None,
89 parallel_config=replace(
90 spec.draft_parallel_config,
91 rank=target_parallel.rank,
92 decode_context_parallel_size=(
93 target_parallel.decode_context_parallel_size
94 ),
95 cp_kv_cache_interleave_size=target_parallel.cp_kv_cache_interleave_size,
96 dcp_comm_backend=target_parallel.dcp_comm_backend,
97 dcp_q_replicate=target_parallel.dcp_q_replicate,
98 ),
99 model_config=spec.draft_model_config,
100 )
101
102 @override
103 def _get_model(self) -> nn.Module:
104 from vllm.compilation.backends import set_model_tag
105
106 draft_vllm_config = self._create_draft_vllm_config()
107 with set_model_tag("draft_model"):
108 model = get_model(
109 vllm_config=draft_vllm_config,
110 prefix="draft_model",
111 )
112 return model
113
114 @override
115 def _maybe_share_embeddings(self, target_language_model: nn.Module) -> None:
116 # Draft models don't share embeddings with the target model
117 pass
118
119 @override
120 def _maybe_share_lm_head(self, target_language_model: nn.Module) -> None:
121 # Draft models don't share lm_head with the target model
122 pass