A high-throughput and memory-efficient inference and serving engine for LLMs
Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git
Synced Nov 15, 23:30 UTC
[V1] Get input tokens from scheduler (#13339)
Signed-off-by: Woosuk Kwon <woosuk.kwon@berkeley.edu>
Woosuk Kwon committed
Feb 17, 2025 at 11:01 UTC
4c21ce9ebabcdd0892b5b213f04541ad86507a66
4 files changed
+139
-139
tests/v1/worker/test_gpu_model_runner.py
+1
@@ -154,6 +154,7 @@ def test_update_states_request_resumed(model_runner):
154
cached_req_data = CachedRequestData(
155
req_id=req_id,
156
resumed_from_preemption=False,
157
+ new_token_ids=[],
158
new_block_ids=[],
159
num_computed_tokens=0,
160
)
vllm/v1/core/scheduler.py
+28
-15
@@ -121,6 +121,8 @@ class Scheduler:
121
encoder_budget = self.max_num_encoder_input_tokens
122
# Spec decode-related.
123
scheduled_spec_decode_tokens: Dict[str, List[int]] = {}
124
+
125
+ # For logging.
126
scheduled_timestamp = time.monotonic()
127
128
# First, schedule the RUNNING requests.
@@ -187,6 +189,15 @@ class Scheduler:
189
token_budget -= num_new_tokens
190
req_index += 1
191
192
+ # Speculative decode related.
193
+ if request.spec_token_ids:
194
+ num_scheduled_spec_tokens = (num_new_tokens +
195
+ request.num_computed_tokens -
196
+ request.num_tokens)
197
+ if num_scheduled_spec_tokens > 0:
198
+ scheduled_spec_decode_tokens[request.request_id] = (
199
+ request.spec_token_ids[:num_scheduled_spec_tokens])
200
+
201
# Encoder-related.
202
if encoder_inputs_to_schedule:
203
scheduled_encoder_inputs[request.request_id] = (
@@ -196,11 +207,6 @@ class Scheduler:
207
self.encoder_cache_manager.allocate(request, i)
208
encoder_budget = new_encoder_budget
209
199
- # Speculative decode related.
200
- if request.spec_token_ids:
201
- scheduled_spec_decode_tokens[
202
- request.request_id] = request.spec_token_ids
203
-
210
# Record the LoRAs in scheduled_running_reqs
211
requested_loras: Set[int] = set()
212
if self.lora_config:
@@ -324,23 +330,24 @@ class Scheduler:
330
# Construct the scheduler output.
331
new_reqs_data = [
332
NewRequestData.from_request(req,
327
- req_to_new_block_ids[req.request_id],
328
- req.num_computed_tokens)
333
+ req_to_new_block_ids[req.request_id])
334
for req in scheduled_new_reqs
335
]
336
resumed_reqs_data = [
337
self._make_cached_request_data(
338
req,
339
+ num_scheduled_tokens[req.request_id],
340
+ len(scheduled_spec_decode_tokens.get(req.request_id, ())),
341
req_to_new_block_ids[req.request_id],
335
- req.num_computed_tokens,
342
resumed_from_preemption=True,
343
) for req in scheduled_resumed_reqs
344
]
345
running_reqs_data = [
346
self._make_cached_request_data(
347
req,
348
+ num_scheduled_tokens[req.request_id],
349
+ len(scheduled_spec_decode_tokens.get(req.request_id, ())),
350
req_to_new_block_ids[req.request_id],
343
- req.num_computed_tokens,
351
resumed_from_preemption=False,
352
) for req in scheduled_running_reqs
353
]
@@ -349,8 +356,8 @@ class Scheduler:
356
scheduled_cached_reqs=resumed_reqs_data + running_reqs_data,
357
num_scheduled_tokens=num_scheduled_tokens,
358
total_num_scheduled_tokens=total_num_scheduled_tokens,
352
- scheduled_encoder_inputs=scheduled_encoder_inputs,
359
scheduled_spec_decode_tokens=scheduled_spec_decode_tokens,
360
+ scheduled_encoder_inputs=scheduled_encoder_inputs,
361
num_common_prefix_blocks=num_common_prefix_blocks,
362
# finished_req_ids is an existing state in the scheduler,
363
# instead of being newly scheduled in this step.
@@ -366,22 +373,28 @@ class Scheduler:
373
def _make_cached_request_data(
374
self,
375
request: Request,
376
+ num_scheduled_tokens: int,
377
+ num_scheduled_spec_tokens: int,
378
new_block_ids: List[int],
370
- num_computed_tokens: int,
379
resumed_from_preemption: bool,
380
) -> "CachedRequestData":
381
# OPTIMIZATION: Cache the CachedRequestData objects to avoid creating
382
# them at each scheduling step.
375
- if request.request_id in self._cached_reqs_data:
376
- req_data = self._cached_reqs_data[request.request_id]
383
+ num_computed_tokens = request.num_computed_tokens
384
+ num_regular_tokens = num_scheduled_tokens - num_scheduled_spec_tokens
385
+ new_token_ids = request.all_token_ids[
386
+ num_computed_tokens:num_computed_tokens + num_regular_tokens]
387
+ req_data = self._cached_reqs_data.get(request.request_id)
388
+ if req_data is not None:
389
req_data.resumed_from_preemption = resumed_from_preemption
390
+ req_data.new_token_ids = new_token_ids
391
req_data.new_block_ids = new_block_ids
392
req_data.num_computed_tokens = num_computed_tokens
393
else:
394
req_data = CachedRequestData.from_request(request,
395
resumed_from_preemption,
383
- new_block_ids,
384
- num_computed_tokens)
396
+ new_token_ids,
397
+ new_block_ids)
398
self._cached_reqs_data[request.request_id] = req_data
399
return req_data
400
vllm/v1/core/scheduler_output.py
+8
-7
@@ -30,7 +30,6 @@ class NewRequestData:
30
cls,
31
request: "Request",
32
block_ids: List[int],
33
- num_computed_tokens: int,
33
) -> "NewRequestData":
34
return cls(
35
req_id=request.request_id,
@@ -41,7 +40,7 @@ class NewRequestData:
40
mm_positions=request.mm_positions,
41
sampling_params=request.sampling_params,
42
block_ids=block_ids,
44
- num_computed_tokens=num_computed_tokens,
43
+ num_computed_tokens=request.num_computed_tokens,
44
lora_request=request.lora_request,
45
)
46
@@ -54,6 +53,7 @@ class CachedRequestData:
53
# the request's block IDs. If True, new_block_ids will be used as the
54
# request's block IDs instead of appending to the existing block IDs.
55
resumed_from_preemption: bool
56
+ new_token_ids: List[int]
57
new_block_ids: List[int]
58
num_computed_tokens: int
59
@@ -62,14 +62,15 @@ class CachedRequestData:
62
cls,
63
request: "Request",
64
resumed_from_preemption: bool,
65
+ new_token_ids: List[int],
66
new_block_ids: List[int],
66
- num_computed_tokens: int,
67
) -> "CachedRequestData":
68
return cls(
69
req_id=request.request_id,
70
resumed_from_preemption=resumed_from_preemption,
71
+ new_token_ids=new_token_ids,
72
new_block_ids=new_block_ids,
72
- num_computed_tokens=num_computed_tokens,
73
+ num_computed_tokens=request.num_computed_tokens,
74
)
75
76
@@ -91,9 +92,9 @@ class SchedulerOutput:
92
# Total number of tokens scheduled for all requests.
93
# Equal to sum(num_scheduled_tokens.values())
94
total_num_scheduled_tokens: int
94
- # req_id -> spec_decode_tokens
95
- # If a request does not have any spec decode tokens, it will
96
- # not be included in the dictionary.
95
+ # req_id -> spec_token_ids
96
+ # If a request does not have any spec decode tokens, it will not be
97
+ # included in the dictionary.
98
scheduled_spec_decode_tokens: Dict[str, List[int]]
99
# req_id -> encoder input indices that need processing.
100
# E.g., if a request has [0, 1], it could mean the vision encoder needs
vllm/v1/worker/gpu_model_runner.py
+102
-117
@@ -2,7 +2,7 @@
2
3
import gc
4
import time
5
-from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Union, cast
5
+from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Union
6
7
import numpy as np
8
import torch
@@ -184,7 +184,6 @@ class GPUModelRunner(LoRAModelRunnerMixin):
184
self.max_model_len,
185
self.max_num_tokens),
186
dtype=np.int32)
187
- self.arange_cpu = torch.from_numpy(self.arange_np)
187
# NOTE(woosuk): These tensors are "stateless", i.e., they are literally
188
# a faster version of creating a new tensor every time. Thus, we should
189
# not make any assumptions about the values in these tensors.
@@ -327,7 +326,17 @@ class GPUModelRunner(LoRAModelRunnerMixin):
326
req_state = self.requests[req_id]
327
328
# Update the cached states.
330
- req_state.num_computed_tokens = req_data.num_computed_tokens
329
+ num_computed_tokens = req_data.num_computed_tokens
330
+ req_state.num_computed_tokens = num_computed_tokens
331
+ # Add the sampled token(s) from the previous step (if any).
332
+ # This doesn't include "unverified" tokens like spec decode tokens.
333
+ num_new_tokens = (num_computed_tokens +
334
+ len(req_data.new_token_ids) -
335
+ req_state.num_tokens)
336
+ new_token_ids = (req_data.new_token_ids[-num_new_tokens:]
337
+ if num_new_tokens > 0 else [])
338
+ req_state.output_token_ids.extend(new_token_ids)
339
+ # Update the block IDs.
340
if not req_data.resumed_from_preemption:
341
# Append the new blocks to the existing block IDs.
342
req_state.block_ids.extend(req_data.new_block_ids)
@@ -346,12 +355,30 @@ class GPUModelRunner(LoRAModelRunnerMixin):
355
356
# Update the persistent batch.
357
self.input_batch.num_computed_tokens_cpu[req_index] = (
349
- req_data.num_computed_tokens)
350
- start_index = len(req_state.block_ids) - len(
351
- req_data.new_block_ids)
358
+ num_computed_tokens)
359
+ start_index = (len(req_state.block_ids) -
360
+ len(req_data.new_block_ids))
361
self.input_batch.block_table.append_row(req_index, start_index,
362
req_data.new_block_ids)
363
+ # Add new_token_ids to token_ids_cpu.
364
+ start_token_index = num_computed_tokens
365
+ end_token_index = num_computed_tokens + len(req_data.new_token_ids)
366
+ self.input_batch.token_ids_cpu[
367
+ req_index,
368
+ start_token_index:end_token_index] = req_data.new_token_ids
369
+ # Add spec_token_ids to token_ids_cpu.
370
+ spec_token_ids = scheduler_output.scheduled_spec_decode_tokens.get(
371
+ req_id, [])
372
+ if spec_token_ids:
373
+ start_index = end_token_index
374
+ end_token_index += len(spec_token_ids)
375
+ self.input_batch.token_ids_cpu[
376
+ req_index, start_index:end_token_index] = spec_token_ids
377
+ # NOTE(woosuk): `num_tokens` here may include spec decode tokens.
378
+ self.input_batch.num_tokens[req_index] = end_token_index
379
380
+ # Check if the batch has changed. If not, we can skip copying the
381
+ # sampling metadata from CPU to GPU.
382
batch_changed = len(removed_req_indices) > 0 or len(req_ids_to_add) > 0
383
384
# Add the new or resumed requests to the persistent batch.
@@ -374,7 +401,8 @@ class GPUModelRunner(LoRAModelRunnerMixin):
401
return batch_changed
402
403
def _prepare_inputs(
377
- self, scheduler_output: "SchedulerOutput"
404
+ self,
405
+ scheduler_output: "SchedulerOutput",
406
) -> Tuple[FlashAttentionMetadata, torch.Tensor]:
407
total_num_scheduled_tokens = scheduler_output.total_num_scheduled_tokens
408
assert total_num_scheduled_tokens > 0
@@ -387,24 +415,14 @@ class GPUModelRunner(LoRAModelRunnerMixin):
415
416
# Get the number of scheduled tokens for each request.
417
# TODO: The Python loop can be slow. Optimize.
390
- num_scheduled_tokens_list: List[int] = []
418
+ num_scheduled_tokens = np.empty(num_reqs, dtype=np.int32)
419
max_num_scheduled_tokens = 0
392
- all_spec_token_ids: List[int] = []
393
- num_spec_tokens_list: List[int] = []
420
for i, req_id in zip(range(num_reqs), self.input_batch.req_ids):
421
assert req_id is not None
422
num_tokens = scheduler_output.num_scheduled_tokens[req_id]
397
- num_scheduled_tokens_list.append(num_tokens)
423
+ num_scheduled_tokens[i] = num_tokens
424
max_num_scheduled_tokens = max(max_num_scheduled_tokens,
425
num_tokens)
400
- spec_token_ids = scheduler_output.scheduled_spec_decode_tokens.get(
401
- req_id, [])
402
- all_spec_token_ids.extend(spec_token_ids)
403
- num_spec_tokens_list.append(len(spec_token_ids))
404
-
405
- num_scheduled_tokens: np.ndarray = np.array(num_scheduled_tokens_list,
406
- dtype=np.int32)
407
- assert max_num_scheduled_tokens > 0
426
427
# Get request indices.
428
# E.g., [2, 5, 3] -> [0, 0, 1, 1, 1, 1, 1, 2, 2, 2]
@@ -441,78 +459,6 @@ class GPUModelRunner(LoRAModelRunnerMixin):
459
token_indices = (positions_np +
460
req_indices * self.input_batch.token_ids_cpu.shape[1])
461
444
- use_spec_decode = len(all_spec_token_ids) > 0
445
- if use_spec_decode:
446
-
447
- # 1. Write spec_token_ids to input batch.
448
- # Step 1. Get req indices that perform spec decode and repeat
449
- # the req indices by the number of spec tokens. Note
450
- # for requests that don't perform spec decode, the
451
- # number of spec tokens is 0 and the req index is
452
- # repeated 0 times.
453
- # E.g., num_spec_tokens_list: [3, 0, 2, 0, 1]
454
- # spec_req_indices: [0, 0, 0, 2, 2, 4]
455
- spec_req_indices = np.repeat(self.arange_np[:num_reqs],
456
- num_spec_tokens_list)
457
- # spec_offsets: offsets within each spec token list.
458
- # E.g., [1, 2, 3, 1, 2, 1], TODO: avoid the for loop here
459
- spec_offsets = np.concatenate(
460
- [self.arange_np[1:val + 1] for val in num_spec_tokens_list])
461
- # spec_seq_offsets: offsets within each sequence.
462
- # E.g., num_computed_tokens_cpu: [1, 4, 3, 6, 2]
463
- # after repeating: [1, 1, 1, 3, 3, 2]
464
- # spec_seq_offsets: [1, 1, 1, 3, 3, 2] + [1, 2, 3, 1, 2, 1]
465
- # = [2, 3, 4, 4, 5, 3]
466
- spec_seq_offsets = np.repeat(
467
- self.input_batch.num_computed_tokens_cpu[:num_reqs],
468
- num_spec_tokens_list) + spec_offsets
469
- # cumsums_spec_offsets: [0, 0, 0, 2M, 2M, 4M] + [2, 3, 4, 4, 5, 3]
470
- cumsums_spec_offsets = (
471
- spec_seq_offsets +
472
- spec_req_indices * self.input_batch.token_ids_cpu.shape[1])
473
- cumsums_spec_offsets = torch.from_numpy(cumsums_spec_offsets).to(
474
- torch.int64)
475
- all_spec_token_ids = torch.tensor(all_spec_token_ids,
476
- device="cpu",
477
- dtype=self.input_ids_cpu.dtype)
478
-
479
- # Step 2. Write spec token ids to input_ids_cpu.
480
- self.input_batch.token_ids_cpu_tensor.flatten().scatter_(
481
- 0, cumsums_spec_offsets, all_spec_token_ids)
482
-
483
- # 2. Get spec decode logits indices.
484
- # E.g., num_scheduled_tokens: [4, 100, 3, 100, 2]
485
- # cu_num_tokens: [4, 104, 107, 207, 209]
486
- # num_spec_tokens_list: [3, 0, 2, 0, 1]
487
- # num_sampled_tokens: [4, 1, 3, 1, 2]
488
- # spec_decode_logits_indices:
489
- # [0, 1, 2, 3, 103, 104, 105, 106, 206, 207, 208]
490
- num_spec_tokens_np = np.array(num_spec_tokens_list, dtype=np.int32)
491
- num_sampled_tokens = num_spec_tokens_np + 1
492
- # logits_start_loc: [0, 103, 104, 206, 207]
493
- logits_start_loc = cu_num_tokens - num_sampled_tokens
494
- # [0, 103, 104, 206, 207] ->
495
- # [0, 0, 0, 0, 103, 104, 104, 104, 206, 207, 207]
496
- logits_start_loc = np.repeat(logits_start_loc, num_sampled_tokens)
497
- # The following three lines:
498
- # [4, 1, 3, 1, 2] -> [0, 1, 2, 3, 0, 0, 1, 2, 0, 0, 1]
499
- # Step 1. [4, 1, 3, 1, 2] -> [4, 5, 8, 9, 11]
500
- cu_num_sampled_tokens = np.cumsum(num_sampled_tokens)
501
- # Step 2. [4, 5, 8, 9, 11] -> [0, 4, 5, 8, 9]
502
- # -> [0, 0, 0, 0, 4, 5, 5, 5, 8, 9, 9]
503
- cumsums_sampled_offsets = np.repeat(
504
- cu_num_sampled_tokens - num_sampled_tokens, num_sampled_tokens)
505
- # Step 3. [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
506
- # - [0, 0, 0, 0, 4, 5, 5, 5, 8, 9, 9]
507
- # -> [0, 1, 2, 3, 0, 0, 1, 2, 0, 0, 1]
508
- total_num_sampled_tokens = num_sampled_tokens.sum()
509
- sampled_arange = (self.arange_np[:total_num_sampled_tokens] -
510
- cumsums_sampled_offsets)
511
-
512
- # [0, 0, 0, 0, 103, 104, 104, 104, 206, 207, 207] ->
513
- # [0, 1, 2, 3, 103, 104, 105, 106, 206, 207, 208]
514
- spec_decode_logits_indices = logits_start_loc + sampled_arange
515
-
462
# NOTE(woosuk): We use torch.index_select instead of np.take here
463
# because torch.index_select is much faster than np.take for large
464
# tensors.
@@ -606,9 +552,11 @@ class GPUModelRunner(LoRAModelRunnerMixin):
552
suffix_kv_lens=suffix_kv_lens,
553
)
554
555
+ use_spec_decode = len(
556
+ scheduler_output.scheduled_spec_decode_tokens) > 0
557
if use_spec_decode:
610
- logits_indices = torch.from_numpy(spec_decode_logits_indices).to(
611
- self.device, non_blocking=True)
558
+ logits_indices = self._calc_spec_decode_metadata(
559
+ scheduler_output, cu_num_tokens)
560
else:
561
# NOTE(woosuk): Due to chunked prefills, the batch may contain
562
# partial requests. While we should not sample any token
@@ -762,6 +710,53 @@ class GPUModelRunner(LoRAModelRunnerMixin):
710
711
mrope_pos_ptr += completion_part_len
712
713
+ def _calc_spec_decode_metadata(
714
+ self,
715
+ scheduler_output: "SchedulerOutput",
716
+ cu_num_tokens: np.ndarray,
717
+ ) -> Tuple[torch.Tensor, torch.Tensor]:
718
+ # Get the number of spec decode tokens for each request.
719
+ num_reqs = self.input_batch.num_reqs
720
+ num_spec_decode_tokens = np.empty(num_reqs, dtype=np.int32)
721
+ for i, req_id in zip(range(num_reqs), self.input_batch.req_ids):
722
+ assert req_id is not None
723
+ num_spec_decode_tokens[i] = len(
724
+ scheduler_output.scheduled_spec_decode_tokens.get(req_id, ()))
725
+
726
+ # Get spec decode logits indices.
727
+ # E.g., num_scheduled_tokens: [4, 100, 3, 100, 2]
728
+ # cu_num_tokens: [4, 104, 107, 207, 209]
729
+ # num_spec_tokens_list: [3, 0, 2, 0, 1]
730
+ # num_sampled_tokens: [4, 1, 3, 1, 2]
731
+ # spec_decode_logits_indices:
732
+ # [0, 1, 2, 3, 103, 104, 105, 106, 206, 207, 208]
733
+ num_sampled_tokens = num_spec_decode_tokens + 1
734
+ # logits_start_loc: [0, 103, 104, 206, 207]
735
+ logits_start_loc = cu_num_tokens - num_sampled_tokens
736
+ # [0, 103, 104, 206, 207] ->
737
+ # [0, 0, 0, 0, 103, 104, 104, 104, 206, 207, 207]
738
+ logits_start_loc = np.repeat(logits_start_loc, num_sampled_tokens)
739
+ # The following three lines:
740
+ # [4, 1, 3, 1, 2] -> [0, 1, 2, 3, 0, 0, 1, 2, 0, 0, 1]
741
+ # Step 1. [4, 1, 3, 1, 2] -> [4, 5, 8, 9, 11]
742
+ cu_num_sampled_tokens = np.cumsum(num_sampled_tokens)
743
+ # Step 2. [4, 5, 8, 9, 11] -> [0, 4, 5, 8, 9]
744
+ # -> [0, 0, 0, 0, 4, 5, 5, 5, 8, 9, 9]
745
+ cumsums_sampled_offsets = np.repeat(
746
+ cu_num_sampled_tokens - num_sampled_tokens, num_sampled_tokens)
747
+ # Step 3. [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
748
+ # - [0, 0, 0, 0, 4, 5, 5, 5, 8, 9, 9]
749
+ # -> [0, 1, 2, 3, 0, 0, 1, 2, 0, 0, 1]
750
+ total_num_sampled_tokens = num_sampled_tokens.sum()
751
+ sampled_arange = (self.arange_np[:total_num_sampled_tokens] -
752
+ cumsums_sampled_offsets)
753
+
754
+ # [0, 0, 0, 0, 103, 104, 104, 104, 206, 207, 207] ->
755
+ # [0, 1, 2, 3, 103, 104, 105, 106, 206, 207, 208]
756
+ spec_decode_logits_indices = logits_start_loc + sampled_arange
757
+ return torch.from_numpy(spec_decode_logits_indices).to(
758
+ self.device, non_blocking=True)
759
+
760
def _prepare_sampling(
761
self,
762
batch_changed: bool,
@@ -773,7 +768,9 @@ class GPUModelRunner(LoRAModelRunnerMixin):
768
for req_id, req in self.requests.items()}
769
770
sampling_metadata = self.input_batch.make_sampling_metadata(
776
- req_id_output_token_ids, req_to_spec_token_ids, not batch_changed)
771
+ req_id_output_token_ids,
772
+ req_to_spec_token_ids,
773
+ skip_copy=not batch_changed)
774
return sampling_metadata
775
776
def _execute_encoder(self, scheduler_output: "SchedulerOutput"):
@@ -960,28 +957,24 @@ class GPUModelRunner(LoRAModelRunnerMixin):
957
# TODO(woosuk): The following loop can be slow since it iterates over
958
# the requests one by one. Optimize.
959
num_reqs = self.input_batch.num_reqs
963
- request_seq_lens: List[Tuple[int, CachedRequestState, int]] = []
960
+ req_ids: List[str] = []
961
+ # Because `input_batch.req_ids` is a list of length `max_num_reqs`,
962
+ # we need to stop at `num_reqs`.
963
+ # FIXME(woosuk): This is hacky. Refactor.
964
for i, req_id in zip(range(num_reqs), self.input_batch.req_ids):
965
assert req_id is not None
966
+ req_ids.append(req_id)
967
req_state = self.requests[req_id]
968
seq_len = (req_state.num_computed_tokens +
969
scheduler_output.num_scheduled_tokens[req_id])
969
- if seq_len >= req_state.num_tokens:
970
- request_seq_lens.append((i, req_state, seq_len))
971
- else:
972
- # Ignore the sampled token from the partial request.
970
+ if seq_len < req_state.num_tokens:
971
+ # Ignore the sampled token.
972
# Rewind the generator state as if the token was not sampled.
973
generator = self.input_batch.generators.get(i)
974
if generator is not None:
975
# This relies on cuda-specific torch-internal impl details
976
generator.set_offset(generator.get_offset() - 4)
977
979
- # num_reqs entries should be non-None
980
- assert all(
981
- req_id is not None for req_id in
982
- self.input_batch.req_ids[:num_reqs]), "req_ids contains None"
983
- req_ids = cast(List[str], self.input_batch.req_ids[:num_reqs])
984
-
978
# NOTE: GPU -> CPU Sync happens here.
979
# Move as many CPU operations as possible before this sync point.
980
logprobs_tensors = sampler_output.logprobs_tensors
@@ -994,29 +987,21 @@ class GPUModelRunner(LoRAModelRunnerMixin):
987
scheduler_output,
988
)
989
997
- # Update batch with the valid generated tokens.
990
+ # Get the valid generated tokens.
991
sampled_token_ids = sampler_output.sampled_token_ids
992
max_gen_len = sampled_token_ids.shape[-1]
993
if max_gen_len == 1:
994
+ # No spec decode tokens.
995
valid_sampled_token_ids = sampled_token_ids.tolist()
1002
- for i, req_state, seq_len in request_seq_lens:
1003
- token_id = valid_sampled_token_ids[i][0]
1004
- self.input_batch.token_ids_cpu[i, seq_len] = token_id
1005
- req_state.output_token_ids.append(token_id)
1006
- self.input_batch.num_tokens[i] += 1
996
else:
997
+ # Includes spec decode tokens.
998
valid_mask = sampled_token_ids != INVALID_TOKEN_ID
999
gen_lens = valid_mask.sum(dim=1).tolist()
1000
+ # TODO(woosuk): Optimize this.
1001
valid_sampled_token_ids = [
1002
seq.tolist()
1003
for seq in sampled_token_ids[valid_mask].split(gen_lens)
1004
]
1014
- self.input_batch.num_tokens[:num_reqs] += gen_lens
1015
- for i, req_state, seq_len in request_seq_lens:
1016
- target_slice = slice(seq_len - gen_lens[i] + 1, seq_len + 1)
1017
- self.input_batch.token_ids_cpu[
1018
- i, target_slice] = valid_sampled_token_ids[i]
1019
- req_state.output_token_ids.extend(valid_sampled_token_ids[i])
1005
1006
model_runner_output = ModelRunnerOutput(
1007
req_ids=req_ids,