main
py 156 lines 5.52 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 from typing import Any
4
5 import torch
6 import torch.nn as nn
7
8 from vllm.compilation.backends import set_model_tag
9 from vllm.config import VllmConfig
10 from vllm.config.compilation import CUDAGraphMode
11 from vllm.forward_context import set_forward_context
12 from vllm.model_executor.model_loader import get_model
13 from vllm.v1.worker.gpu.dp_utils import DPSyncState
14 from vllm.v1.worker.gpu.input_batch import InputBatch
15 from vllm.v1.worker.gpu.spec_decode.speculator import DraftModelSpeculator
16
17
18 class ExtractHiddenStatesSpeculator(DraftModelSpeculator):
19 """Cache target hidden states while returning always-accepted draft tokens."""
20
21 def __init__(self, vllm_config: VllmConfig, device: torch.device):
22 assert vllm_config.speculative_config is not None
23 if vllm_config.speculative_config.draft_sample_method != "greedy":
24 raise ValueError(
25 "extract_hidden_states only supports draft_sample_method='greedy'"
26 )
27 super().__init__(vllm_config, device)
28
29 if self.num_speculative_steps != 1:
30 raise ValueError(
31 "extract_hidden_states requires num_speculative_tokens to be 1"
32 )
33 if self.speculative_config.disable_padded_drafter_batch:
34 raise ValueError(
35 "disable_padded_drafter_batch is not supported with "
36 "extract_hidden_states method"
37 )
38
39 self.supports_mm_inputs = False
40 layer_ids = getattr(
41 self.draft_model_config.hf_config,
42 "eagle_aux_hidden_state_layer_ids",
43 None,
44 )
45 if not layer_ids:
46 raise ValueError(
47 "eagle_aux_hidden_state_layer_ids must be set in the draft "
48 "model config for extract_hidden_states method"
49 )
50
51 self.num_hidden_states = len(layer_ids)
52 assert isinstance(self.dtype, torch.dtype)
53 self.hidden_states = torch.zeros(
54 self.max_num_tokens,
55 self.num_hidden_states,
56 self.vllm_config.model_config.get_hidden_size(),
57 dtype=self.dtype,
58 device=device,
59 )
60
61 def load_draft_model(
62 self,
63 target_model: nn.Module,
64 target_attn_layer_names: set[str],
65 ) -> nn.Module:
66 del target_model, target_attn_layer_names
67 with set_model_tag("extract_hidden_states"):
68 return get_model(
69 vllm_config=self.vllm_config,
70 model_config=self.draft_model_config,
71 )
72
73 def load_model(self, target_model: nn.Module) -> None:
74 super().load_model(target_model)
75 if len(self.draft_attn_layer_names) != 1:
76 raise ValueError(
77 "ExtractHiddenStatesModel should have exactly one attention "
78 f"layer, found {len(self.draft_attn_layer_names)}"
79 )
80
81 def init_cudagraph_manager(self, cudagraph_mode: CUDAGraphMode) -> None:
82 del cudagraph_mode
83
84 def capture(self) -> None:
85 return None
86
87 @torch.inference_mode()
88 def propose(
89 self,
90 input_batch: InputBatch,
91 attn_metadata: dict[str, Any],
92 slot_mappings: dict[str, torch.Tensor],
93 last_hidden_states: torch.Tensor,
94 aux_hidden_states: list[torch.Tensor] | None,
95 num_sampled: torch.Tensor,
96 num_rejected: torch.Tensor,
97 last_sampled: torch.Tensor,
98 next_prefill_tokens: torch.Tensor,
99 temperature: torch.Tensor,
100 seeds: torch.Tensor,
101 dp_sync: DPSyncState | None = None,
102 dummy_run: bool = False,
103 skip_attn_for_dummy_run: bool = False,
104 mm_inputs: tuple[list[torch.Tensor], torch.Tensor] | None = None,
105 is_profile: bool = False,
106 ) -> torch.Tensor:
107 del (
108 last_hidden_states,
109 num_sampled,
110 num_rejected,
111 next_prefill_tokens,
112 temperature,
113 seeds,
114 dummy_run,
115 mm_inputs,
116 is_profile,
117 )
118
119 draft_tokens = last_sampled[input_batch.idx_mapping, :1]
120 if skip_attn_for_dummy_run:
121 return draft_tokens
122 if aux_hidden_states is None:
123 raise ValueError(
124 "aux_hidden_states are required when using extract_hidden_states"
125 )
126 if len(aux_hidden_states) != self.num_hidden_states:
127 raise ValueError(
128 f"Expected {self.num_hidden_states} auxiliary hidden states, "
129 f"got {len(aux_hidden_states)}"
130 )
131
132 stacked_hidden_states = torch.stack(aux_hidden_states, dim=1)
133 num_tokens = stacked_hidden_states.shape[0]
134 self.hidden_states[:num_tokens].copy_(stacked_hidden_states)
135
136 draft_attn_metadata = {
137 name: attn_metadata[name] for name in self.draft_attn_layer_names
138 }
139 draft_slot_mappings = {
140 name: slot_mappings[name][:num_tokens]
141 for name in self.draft_attn_layer_names
142 }
143 with set_forward_context(
144 draft_attn_metadata,
145 self.vllm_config,
146 num_tokens=num_tokens,
147 num_tokens_across_dp=(
148 dp_sync.num_tokens_across_dp if dp_sync is not None else None
149 ),
150 cudagraph_runtime_mode=CUDAGraphMode.NONE,
151 slot_mapping=draft_slot_mappings,
152 is_padding=input_batch.is_padding[:num_tokens],
153 ):
154 self.model(hidden_states=self.hidden_states[:num_tokens])
155
156 return draft_tokens