main
py 132 lines 4.96 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 import numpy as np
4 import torch
5
6 from vllm.sampling_params import SamplingParams
7 from vllm.v1.sample.ops.topk_topp_sampler import apply_top_k_top_p
8 from vllm.v1.worker.gpu.buffer_utils import UvaBackedTensor
9 from vllm.v1.worker.gpu.sample.gumbel import apply_temperature
10 from vllm.v1.worker.gpu.sample.min_p import apply_min_p
11
12 NO_LOGPROBS = -1
13 _NP_INT64_MIN = np.iinfo(np.int64).min
14 _NP_INT64_MAX = np.iinfo(np.int64).max
15
16
17 class SamplingStates:
18 def __init__(self, max_num_reqs: int, vocab_size: int):
19 self.max_num_reqs = max_num_reqs
20 self.vocab_size = vocab_size
21
22 self.temperature = UvaBackedTensor(max_num_reqs, dtype=torch.float32)
23 self.top_k = UvaBackedTensor(max_num_reqs, dtype=torch.int32)
24 self.top_p = UvaBackedTensor(max_num_reqs, dtype=torch.float32)
25 self.min_p = UvaBackedTensor(max_num_reqs, dtype=torch.float32)
26 self.seeds = UvaBackedTensor(max_num_reqs, dtype=torch.int64)
27 # Tracks whether `seed` was set explicitly by the user, so callers
28 # can fall back from RNG paths that don't honor per-request seeds.
29 self.seeds_set = np.zeros(max_num_reqs, dtype=bool)
30
31 # Initialize top_k and top_p manually because 0 is an invalid value for them.
32 self.top_k.np.fill(self.vocab_size)
33 self.top_k.copy_to_uva()
34 self.top_p.np.fill(1.0)
35 self.top_p.copy_to_uva()
36
37 self.num_logprobs = np.empty(self.max_num_reqs, dtype=np.int32)
38 # -1 means no logprobs are requested.
39 self.num_logprobs.fill(NO_LOGPROBS)
40
41 def add_request(self, req_idx: int, sampling_params: SamplingParams) -> bool:
42 temperature = sampling_params.temperature
43 top_k = sampling_params.top_k
44 top_p = sampling_params.top_p
45 min_p = sampling_params.min_p
46
47 self.temperature.np[req_idx] = temperature
48 self.top_p.np[req_idx] = top_p
49 if top_k <= 0 or top_k > self.vocab_size:
50 top_k = self.vocab_size
51 self.top_k.np[req_idx] = top_k
52 self.min_p.np[req_idx] = min_p
53
54 seed = sampling_params.seed
55 self.seeds_set[req_idx] = seed is not None
56 if seed is None:
57 seed = np.random.randint(_NP_INT64_MIN, _NP_INT64_MAX)
58 self.seeds.np[req_idx] = seed
59
60 num_logprobs = sampling_params.logprobs
61 if num_logprobs is None:
62 num_logprobs = NO_LOGPROBS
63 elif num_logprobs == -1:
64 num_logprobs = self.vocab_size
65 self.num_logprobs[req_idx] = num_logprobs
66
67 return temperature != 0.0 and (
68 temperature != 1.0
69 or min_p != 0.0
70 or top_k != self.vocab_size
71 or top_p != 1.0
72 )
73
74 def apply_staged_writes(self) -> None:
75 self.temperature.copy_to_uva()
76 self.top_p.copy_to_uva()
77 self.top_k.copy_to_uva()
78 self.min_p.copy_to_uva()
79 self.seeds.copy_to_uva()
80
81 def apply_temperature(
82 self,
83 logits: torch.Tensor,
84 expanded_idx_mapping: torch.Tensor,
85 idx_mapping_np: np.ndarray,
86 ) -> None:
87 temp_np = self.temperature.np[idx_mapping_np]
88 if np.all((temp_np == 0.0) | (temp_np == 1.0)):
89 # No request requires temperature. Skip the kernel launch.
90 return
91
92 apply_temperature(logits, expanded_idx_mapping, self.temperature.gpu)
93
94 def apply_min_p(
95 self,
96 logits: torch.Tensor,
97 expanded_idx_mapping: torch.Tensor,
98 idx_mapping_np: np.ndarray,
99 ) -> None:
100 if np.all(self.min_p.np[idx_mapping_np] == 0.0):
101 # No request uses min_p. Skip the kernel launch.
102 return
103 apply_min_p(logits, expanded_idx_mapping, self.min_p.gpu)
104
105 def get_top_k_top_p(
106 self, expanded_idx_mapping: torch.Tensor, idx_mapping_np: np.ndarray
107 ) -> tuple[torch.Tensor | None, torch.Tensor | None]:
108 do_top_k = np.any(self.top_k.np[idx_mapping_np] != self.vocab_size)
109 do_top_p = np.any(self.top_p.np[idx_mapping_np] != 1.0)
110 top_k = self.top_k.gpu[expanded_idx_mapping] if do_top_k else None
111 top_p = self.top_p.gpu[expanded_idx_mapping] if do_top_p else None
112 return top_k, top_p
113
114 def apply_top_k_top_p(
115 self,
116 logits: torch.Tensor,
117 expanded_idx_mapping: torch.Tensor,
118 idx_mapping_np: np.ndarray,
119 ) -> torch.Tensor:
120 top_k, top_p = self.get_top_k_top_p(expanded_idx_mapping, idx_mapping_np)
121 if top_k is None and top_p is None:
122 return logits
123 return apply_top_k_top_p(logits, top_k, top_p)
124
125 def any_greedy(self, idx_mapping_np: np.ndarray) -> bool:
126 return bool(np.any(self.temperature.np[idx_mapping_np] == 0.0))
127
128 def any_explicit_seed(self, idx_mapping_np: np.ndarray) -> bool:
129 return bool(np.any(self.seeds_set[idx_mapping_np]))
130
131 def max_num_logprobs(self, idx_mapping_np: np.ndarray) -> int:
132 return int(np.max(self.num_logprobs[idx_mapping_np]))