@@ -90,24 +90,28 @@ def _init_dynamic_sampling_tensors(self):
9090
9191 self ._sampling_backend = "torch"
9292
93- # Keep track of request metadata.
94- self ._active_request_count : int = None
95- self ._active_request_slice : slice = None
96- self ._request_metadata : Tensor = None
97-
9893 # Initialize bookkeeping tensors.
9994 self ._sampling_logits_cuda = torch .empty (
10095 max_requests , vocab_size , dtype = logits_dtype , device = device
10196 )
10297 self ._sampled_tokens_cuda = torch .empty (max_requests , dtype = torch .int64 , device = device )
10398
104- self .temperature_cuda = torch .empty_like (self ._sampled_tokens_cuda , dtype = torch .float )
105- self .top_k_cuda = torch .empty_like (self ._sampled_tokens_cuda , dtype = torch .int32 )
106- self .top_p_cuda = torch .empty_like (self ._sampled_tokens_cuda , dtype = torch .float )
107- self .termination_id_cuda = torch .empty (max_requests , dtype = torch .int64 , device = device )
108- self .return_log_probs_cuda = torch .empty (max_requests , dtype = torch .bool , device = device )
109- self .skip_prompt_log_probs_cuda = torch .empty (max_requests , dtype = torch .bool , device = device )
110- self .top_n_logprobs_cuda = torch .empty (max_requests , dtype = torch .int32 , device = device )
99+ # Keep track of request metadata.
100+ self ._request_metadata_raw = {}
101+ for label , dtype , on_gpu in context .request_metadata_types :
102+ tensor = context .request_metadata [label ]
103+ if on_gpu :
104+ # This is just the same Tensor object as in the context.
105+ self ._request_metadata_raw [label ] = tensor
106+ else :
107+ # Create pinned tensors for request metadata that lives on CPU.
108+ # This is metadata which requires D2H copies, such as top_k for torch sampling.
109+ cpu_tensor = torch .empty_like (tensor , device = "cpu" , pin_memory = True )
110+ self ._request_metadata_raw [label ] = cpu_tensor
111+ # These are useful shorthands that are filled in during `_dynamic_step_context_init`.
112+ self ._active_request_count : int = None
113+ self ._active_request_slice : slice = None
114+ self ._request_metadata : Dict [str , Tensor ] = {}
111115
112116 # Used for inefficient torch sampling.
113117 if self ._sampling_backend == "torch" :
@@ -533,10 +537,21 @@ def _dynamic_step_context_init(
533537 self ._active_request_slice = slice (
534538 context .paused_request_count , context .total_request_count
535539 )
536- self ._request_metadata = {
537- label : tensor [self ._active_request_slice ]
538- for label , tensor in context .request_metadata .items ()
539- }
540+ for label , dtype , on_gpu in context .request_metadata_types :
541+ self ._request_metadata [label ] = self ._request_metadata_raw [label ][
542+ self ._active_request_slice
543+ ]
544+ if on_gpu :
545+ # _request_metadata_raw is just a pointer to the Tensor objects in the context.
546+ pass
547+ if not on_gpu :
548+ # We need a D2H copy from the context to the pinned memory buffer.
549+ self ._request_metadata [label ].copy_ (
550+ context .request_metadata [label ][
551+ self ._active_request_slice
552+ ],
553+ non_blocking = True ,
554+ )
540555
541556 # Get flat tokens, position ids.
542557 if construct_graph_dimensions is not None :
@@ -596,27 +611,6 @@ def _dynamic_step_forward_logits(self, input_ids: Tensor, position_ids: Tensor)
596611 def _dynamic_step_sample_bookkeeping (self ):
597612 """Perform bookkeeping necessary to sample logits for dynamic batching."""
598613
599- # Copy data into relevant tensors.
600- self .temperature_cuda [:self ._active_request_count ].copy_ (
601- self ._request_metadata ["temperature" ], non_blocking = True
602- )
603- self .top_k_cuda [:self ._active_request_count ] = self ._request_metadata ["top_k" ].to (
604- dtype = torch .int32 , copy = True , non_blocking = True
605- )
606- self .top_p_cuda [:self ._active_request_count ].copy_ (self ._request_metadata ["top_p" ], non_blocking = True )
607- self .termination_id_cuda [:self ._active_request_count ] = self ._request_metadata ["termination_id" ].to (
608- dtype = torch .int64 , copy = True , non_blocking = True
609- )
610- self .return_log_probs_cuda [:self ._active_request_count ] = self ._request_metadata ["return_log_probs" ].to (
611- dtype = torch .bool , copy = True , non_blocking = True
612- )
613- self .skip_prompt_log_probs_cuda [:self ._active_request_count ] = self ._request_metadata [
614- "skip_prompt_log_probs"
615- ].to (dtype = torch .bool , copy = True , non_blocking = True )
616- self .top_n_logprobs_cuda [:self ._active_request_count ] = self ._request_metadata [
617- "top_n_logprobs"
618- ].to (dtype = torch .int32 , copy = True , non_blocking = True )
619-
620614 if self ._sampling_backend == "torch" :
621615 # Bucketize the core sampling parameters.
622616 core_params = torch .stack (
@@ -632,12 +626,10 @@ def _dynamic_step_sample_bookkeeping(self):
632626 )
633627 order = torch .argsort (inv_indices , stable = True )
634628 sampling_buckets = torch .split (order , cnts .tolist ())
635- # Perform the D2H sync needed by `_torch_sampling_func` here.
636629 group_reps = torch .stack ([indices [0 ] for indices in sampling_buckets ], dim = 0 )
637- core_params_reps = core_params [group_reps ].detach ().cpu ()
638- temp_reps = core_params_reps [:, 0 ].tolist ()
639- top_k_reps = core_params_reps [:, 1 ].to (torch .int32 ).tolist ()
640- top_p_reps = core_params_reps [:, 2 ].tolist ()
630+ temp_reps = self ._request_metadata ["temperature" ][group_reps ].tolist ()
631+ top_k_reps = self ._request_metadata ["top_k" ][group_reps ].tolist ()
632+ top_p_reps = self ._request_metadata ["top_p" ][group_reps ].tolist ()
641633
642634 # Store the buckets and their equivalence class representatives.
643635 self ._torch_sampling_buckets = (
@@ -665,17 +657,17 @@ def _dynamic_step_sample_logits(self):
665657 # Single write to the output tensor.
666658 sampled_tokens = torch .cat (token_list , dim = 0 )
667659 sampled_indices = torch .cat (indices_list , dim = 0 )
668- self ._sampled_tokens_cuda . index_copy_ ( 0 , sampled_indices , sampled_tokens )
660+ self ._sampled_tokens_cuda [ sampled_indices ] = sampled_tokens
669661
670662 def _dynamic_step_log_probs_bookkeeping (self ) -> Tuple [bool , bool ]:
671663 """Perform bookkeeping necessary to compute log probs for dynamic batching.
672664
673665 Returns:
674666 return_log_probs (bool): Whether to return the sampled log_probs.
675667 """
676- return_log_probs = self .return_log_probs_cuda [: self . _active_request_count ]
677- skip_prompt_log_probs = self .skip_prompt_log_probs_cuda [: self . _active_request_count ]
678- top_n_log_probs = self .top_n_logprobs_cuda [: self . _active_request_count ] > 0
668+ return_log_probs = self ._request_metadata [ "return_log_probs" ]
669+ skip_prompt_log_probs = self ._request_metadata [ "skip_prompt_log_probs" ]
670+ top_n_log_probs = self ._request_metadata [ "top_n_logprobs" ] > 0
679671
680672 to_check_prompt = (return_log_probs | top_n_log_probs ) & ~ skip_prompt_log_probs
681673
@@ -727,7 +719,7 @@ def _dynamic_step_calculate_top_n_logprobs(
727719
728720 top_n_results = {}
729721 for req_idx in range (self ._active_request_count ):
730- top_n = int (self .top_n_logprobs_cuda [req_idx ].item ())
722+ top_n = int (self ._request_metadata [ "top_n_logprobs" ] [req_idx ].item ())
731723 if top_n > 0 :
732724 # Get top-n logprobs and indices for this request (single token)
733725 top_n_logits = torch .topk (log_probs [req_idx ], k = top_n )
@@ -751,12 +743,12 @@ def _dynamic_step_calculate_top_n_logprobs(
751743
752744 top_n_results = {}
753745 for req_idx in range (self ._active_request_count ):
754- top_n = int (self .top_n_logprobs_cuda [req_idx ].item ())
746+ top_n = int (self ._request_metadata [ "top_n_logprobs" ] [req_idx ].item ())
755747 if top_n > 0 :
756748 request_log_probs = log_probs_per_request [
757749 req_idx
758750 ] # [num_tokens_for_request, vocab_size]
759- skip_prompt = bool (self .skip_prompt_log_probs_cuda [req_idx ].item ())
751+ skip_prompt = bool (self ._request_metadata [ "skip_prompt_log_probs" ] [req_idx ].item ())
760752
761753 # If skip_prompt_log_probs is True, only compute for last token
762754 if skip_prompt and request_log_probs .size (0 ) > 1 :
@@ -780,6 +772,12 @@ def _dynamic_step_calculate_top_n_logprobs(
780772 def _dynamic_step_context_bookkeeping (self ) -> Dict [str , Tensor ]:
781773 """Update the dynamic inference context after sampling.
782774
775+ Args:
776+ new_sample (Tensor): The newly sampled tokens.
777+ request_metadata (Optional[Dict[str, Tensor]]): An override for the tensors
778+ that manage request metadata, such as sampling parameters. By default, this
779+ metadata is retrieved from the context.
780+
783781 Return:
784782 Dict [str, Tensor]: A dictionary containing:
785783 active_request_ids (Tensor): Current active request IDs.
@@ -799,8 +797,7 @@ def _dynamic_step_context_bookkeeping(self) -> Dict[str, Tensor]:
799797 # Request finished if termination_id or length >= max_sequence_length.
800798 # Note: termination_id tensor has per-request termination IDs from mixed sampling
801799 active_request_mask = (
802- self ._sampled_tokens_cuda [:self ._active_request_count ]
803- != self .termination_id_cuda [:self ._active_request_count ]
800+ self ._sampled_tokens_cuda [:self ._active_request_count ] != self ._request_metadata ["termination_id" ]
804801 ).byte () & torch .less (active_sequence_lengths , max_sequence_lengths ).byte ()
805802 finished_idxs = (
806803 torch .nonzero (active_request_mask == 0 , as_tuple = True )[0 ] + context .paused_request_count
0 commit comments