@@ -80,21 +80,29 @@ def __init__(
8080 def _init_dynamic_sampling_tensors (self ):
8181 """Initialize tensors needed for dynamic sampling."""
8282 context = self .inference_wrapped_model .inference_context
83+ self ._materialize_only_last = context .materialize_only_last_token_logits
8384 max_requests = context .max_total_requests
8485
8586 device = torch .cuda .current_device ()
8687 logits_dtype = self .inference_wrapped_model .inference_wrapper_config .params_dtype
8788 # Use padded vocab size because tokenizer vocab size might pad to nearest power of 2.
8889 vocab_size = self .inference_wrapped_model .inference_wrapper_config .padded_vocab_size
8990
91+ self ._sampling_backend = "torch"
92+
93+ # Keep track of request metadata.
94+ self ._active_request_count = None
95+ self ._request_metadata : Dict [str , Tensor ] = {}
96+
9097 # Initialize bookkeeping tensors.
91- self .sampling_logits_cuda = torch .empty (
98+ self ._sampling_logits_cuda = torch .empty (
9299 max_requests , vocab_size , dtype = logits_dtype , device = device
93100 )
94- self .sampled_tokens_cuda = torch .empty (max_requests , dtype = torch .int64 , device = device )
101+ self ._sampled_tokens_cuda = torch .empty (max_requests , dtype = torch .int64 , device = device )
95102
96103 # Used for inefficient torch sampling.
97- self .torch_sampling_buckets : List [Tuple ] = []
104+ if self ._sampling_backend == "torch" :
105+ self ._torch_sampling_buckets : List [Tuple ] = []
98106
99107 def tokenize_prompt (self , prompt : str , add_BOS : bool = False ) -> List [int ]:
100108 """Utility to tokenize the input prompts.
@@ -511,6 +519,13 @@ def _dynamic_step_context_init(
511519 # Turn off symmetric all reduces for prefill
512520 unwrapped_model .set_symmetric_ar (None )
513521
522+ # Get request metadata for this step.
523+ self ._active_request_count = context .total_request_count - context .paused_request_count
524+ self ._request_metadata = {
525+ label : tensor [context .paused_request_count : context .total_request_count ]
526+ for label , tensor in context .request_metadata .items ()
527+ }
528+
514529 # Get flat tokens, position ids.
515530 if construct_graph_dimensions is not None :
516531 return context .current_input_and_position_ids (
@@ -531,9 +546,6 @@ def _dynamic_step_forward_logits(self, input_ids: Tensor, position_ids: Tensor)
531546 inference_wrapper_config = self .inference_wrapped_model .inference_wrapper_config
532547
533548 context = self .inference_wrapped_model .inference_context
534- materialize_only_last_token_logits = context .materialize_only_last_token_logits
535-
536- active_request_count = context .total_request_count - context .paused_request_count
537549
538550 with torch .inference_mode ():
539551 logits = self .inference_wrapped_model .run_one_forward_step (
@@ -542,7 +554,7 @@ def _dynamic_step_forward_logits(self, input_ids: Tensor, position_ids: Tensor)
542554
543555 if self .model_is_pipeline_parallel :
544556 logits_seq_len = (
545- active_request_count if materialize_only_last_token_logits else input_ids .shape [1 ]
557+ self . _active_request_count if self . _materialize_only_last else input_ids .shape [1 ]
546558 )
547559 vocab_size = inference_wrapper_config .padded_vocab_size
548560 logits_shape = [1 , logits_seq_len , vocab_size ]
@@ -556,31 +568,22 @@ def _dynamic_step_forward_logits(self, input_ids: Tensor, position_ids: Tensor)
556568 tensor = logits ,
557569 pp_group = self .pp_group ,
558570 )
559- return logits
560-
561- def _dynamic_step_sample_bookkeeping (
562- self , * , backend : str = "torch" , request_metadata : Optional [Dict [str , Tensor ]] = None
563- ):
564- """Perform bookkeeping necessary to sample logits for dynamic batching.
565571
566- The ability to override the context's data is solely intended for
567- standalone use or testing, and should never be used in a running system.
572+ # Last token logits.
573+ if self ._materialize_only_last :
574+ # When materialize_only_last_token_logits is true, last_token_logits is
575+ # already called in the forward pass of GPT.
576+ last_token_logits = logits .squeeze (0 )
577+ else :
578+ last_token_logits = context .last_token_logits (logits )
579+ # Copy last_token_logits to contiguous buffer.
580+ self ._sampling_logits_cuda [:self ._active_request_count ].copy_ (last_token_logits , non_blocking = True )
568581
569- Args:
570- backend (str): The sampling backend to use.
571- request_metadata (Optional[Dict[str, Tensor]]): An override for the tensors
572- that manage request metadata, such as sampling parameters. By default, this
573- metadata is retrieved from the context.
574- """
575- assert backend in ["torch" ]
576- context = self .inference_wrapped_model .inference_context
577- if request_metadata is None :
578- request_metadata = {
579- label : tensor [context .paused_request_count : context .total_request_count ]
580- for label , tensor in context .request_metadata .items ()
581- }
582+ return logits
582583
583- if backend == "torch" :
584+ def _dynamic_step_sample_bookkeeping (self ):
585+ """Perform bookkeeping necessary to sample logits for dynamic batching."""
586+ if self ._sampling_backend == "torch" :
584587 # Bucketize the core sampling parameters.
585588 # Doing so via list comprehension is orders of magnitude faster than via torch.
586589 temp_hash = {}
@@ -600,144 +603,65 @@ def _dynamic_step_sample_bookkeeping(
600603 del temp_hash , bucket_cnt
601604
602605 # Get representatives for each equivalence class.
603- temp_reps = request_metadata ["temperature" ][bucket_reps ]
604- top_k_reps = request_metadata ["top_k" ][bucket_reps ]
605- top_p_reps = request_metadata ["top_p" ][bucket_reps ]
606+ temp_reps = self . _request_metadata ["temperature" ][bucket_reps ]
607+ top_k_reps = self . _request_metadata ["top_k" ][bucket_reps ]
608+ top_p_reps = self . _request_metadata ["top_p" ][bucket_reps ]
606609
607610 # Store the buckets and their equivalence class representatives.
608- self .torch_sampling_buckets = (
611+ self ._torch_sampling_buckets = (
609612 (sampling_buckets [idx ], temp_reps [idx ], top_k_reps [idx ], top_p_reps [idx ])
610613 for idx in range (len (sampling_buckets ))
611614 )
612615
613- return request_metadata
614-
615- def _dynamic_step_sample_logits (self , logits : Tensor , backend : str = "torch" ) -> Tensor :
616- """Sample tokens from logits for dynamic batching.
617-
618- Args:
619- logits (Tensor): The logits to sample from.
620- backend (str): The sampling backend to use.
621-
622- Returns:
623- new_sample (Tensor): The sampled tokens.
624- """
616+ def _dynamic_step_sample_logits (self ):
617+ """Sample tokens from logits for dynamic batching."""
625618 # TODO(ksanthanam): Evaluate whether it makes more sense to sample on 1 rank
626619 # and then broadcast the sampled tokens rather than broadcasting the raw logits.
627- assert backend in ["torch" ]
628-
629- context = self .inference_wrapped_model .inference_context
630- materialize_only_last_token_logits = context .materialize_only_last_token_logits
631-
632- # Last token logits.
633- if materialize_only_last_token_logits :
634- # When materialize_only_last_token_logits is true, last_token_logits is
635- # already called in the forward pass of GPT.
636- last_token_logits = logits .squeeze (0 )
637- else :
638- last_token_logits = context .last_token_logits (logits )
639- active_request_count = last_token_logits .size (0 )
640- # Copy last_token_logits to contiguous buffer.
641- self .sampling_logits_cuda [:active_request_count ].copy_ (last_token_logits , non_blocking = True )
642-
643- if backend == "torch" :
620+ if self ._sampling_backend == "torch" :
644621 # Concatenate the outputs once to prevent repeated small writes.
645622 token_list = []
646623 indices_list = []
647624
648- for indices , temp , top_k , top_p in self .torch_sampling_buckets :
625+ for indices , temp , top_k , top_p in self ._torch_sampling_buckets :
649626 sampled_tokens = self ._torch_sampling_func (
650- self .sampling_logits_cuda [indices , :], temp .item (), top_k .item (), top_p .item ()
627+ self ._sampling_logits_cuda [indices , :], temp .item (), top_k .item (), top_p .item ()
651628 )
652629 token_list .append (sampled_tokens )
653630 indices_list .append (indices )
654631
655632 # Single write to the output tensor.
656633 sampled_tokens = torch .cat (token_list , dim = 0 )
657634 sampled_indices = torch .cat (indices_list , dim = 0 )
658- self .sampled_tokens_cuda .index_copy_ (0 , sampled_indices , sampled_tokens )
659- return self .sampled_tokens_cuda [:active_request_count ].clone ()
635+ self ._sampled_tokens_cuda .index_copy_ (0 , sampled_indices , sampled_tokens )
660636
661- def _dynamic_step_log_probs_bookkeeping (
662- self , * , request_metadata : Optional [Dict [str , Tensor ]] = None
663- ) -> bool :
637+ def _dynamic_step_log_probs_bookkeeping (self ) -> Tuple [bool , bool ]:
664638 """Perform bookkeeping necessary to compute log probs for dynamic batching.
665639
666- Args:
667- request_metadata (Optional[Dict[str, Tensor]]): An override for the tensors
668- that manage request metadata, such as sampling parameters. By default, this
669- metadata is passed in from `_dynamic_step_sample_bookkeeping`.
670-
671640 Returns:
672641 return_log_probs (bool): Whether to return the sampled log_probs.
673642 """
674- context = self .inference_wrapped_model .inference_context
675- if request_metadata is None :
676- request_metadata = {
677- label : tensor [context .paused_request_count : context .total_request_count ]
678- for label , tensor in context .request_metadata .items ()
679- }
680- materialize_only_last_token_logits = context .materialize_only_last_token_logits
681-
682- return_log_probs = request_metadata ["return_log_probs" ]
683- skip_prompt_log_probs = request_metadata ["skip_prompt_log_probs" ]
684- top_n_log_probs = request_metadata ["top_n_logprobs" ] > 0
685-
686- to_check_prompt = return_log_probs & ~ skip_prompt_log_probs
687-
688- assert not (to_check_prompt .any () and materialize_only_last_token_logits ), (
689- "Prompt log probs cannot be calculated if only last token logits are materialized. "
690- "Set materialize_only_last_token_logits to False in DynamicInferenceContext "
691- "or skip_prompt_log_probs to True in SamplingParams."
692- )
693-
694- return return_log_probs .any ()
695-
696- def _dynamic_step_top_n_logprobs_bookkeeping (
697- self , * , request_metadata : Optional [Dict [str , Tensor ]] = None
698- ) -> bool :
699- """Perform bookkeeping necessary to compute top-n log probs for dynamic batching.
700-
701- Args:
702- request_metadata (Optional[Dict[str, Tensor]]): An override for the tensors
703- that manage request metadata, such as sampling parameters. By default, this
704- metadata is passed in from `_dynamic_step_sample_bookkeeping`.
705-
706- Returns:
707- return_top_n_logprobs (bool): Whether to return the sampled top-n log_probs.
708- """
709- context = self .inference_wrapped_model .inference_context
710- if request_metadata is None :
711- request_metadata = {
712- label : tensor [context .paused_request_count : context .total_request_count ]
713- for label , tensor in context .request_metadata .items ()
714- }
643+ return_log_probs = self ._request_metadata ["return_log_probs" ]
644+ skip_prompt_log_probs = self ._request_metadata ["skip_prompt_log_probs" ]
645+ top_n_log_probs = self ._request_metadata ["top_n_logprobs" ] > 0
715646
716- return_log_probs = request_metadata ["return_log_probs" ]
717- skip_prompt_log_probs = request_metadata ["skip_prompt_log_probs" ]
718- top_n_log_probs = request_metadata ["top_n_logprobs" ] > 0
647+ to_check_prompt = (return_log_probs | top_n_log_probs ) & ~ skip_prompt_log_probs
719648
720- to_check_prompt = top_n_log_probs & ~ skip_prompt_log_probs
721-
722- assert not (to_check_prompt .any () and materialize_only_last_token_logits ), (
649+ assert not (to_check_prompt .any () and self ._materialize_only_last ), (
723650 "Prompt log probs cannot be calculated if only last token logits are materialized. "
724651 "Set materialize_only_last_token_logits to False in DynamicInferenceContext "
725652 "or skip_prompt_log_probs to True in SamplingParams."
726653 )
727654
728- return top_n_log_probs .any ()
655+ return return_log_probs . any (), top_n_log_probs .any ()
729656
730657 def _dynamic_step_calculate_log_probs (self , logits : Tensor ) -> Optional [Tensor ]:
731658 """Calculate log probs from logits."""
732659 context = self .inference_wrapped_model .inference_context
733- materialize_only_last_token_logits = context .materialize_only_last_token_logits
734-
735- active_request_count = context .total_request_count - context .paused_request_count
736660
737661 return context .calculate_log_probs (
738662 logits ,
739- self .sampled_tokens_cuda [: active_request_count ],
740- only_last_token_logits = materialize_only_last_token_logits ,
663+ self ._sampled_tokens_cuda [: self . _active_request_count ],
664+ only_last_token_logits = self . _materialize_only_last ,
741665 )
742666
743667 def _dynamic_step_calculate_top_n_logprobs (
@@ -761,18 +685,15 @@ def _dynamic_step_calculate_top_n_logprobs(
761685 )
762686
763687 context = self .inference_wrapped_model .inference_context
764- materialize_only_last_token_logits = context .materialize_only_last_token_logits
765-
766- active_request_count = context .total_request_count - context .paused_request_count
767688
768689 # Handle decode-only mode (only last token)
769- if materialize_only_last_token_logits or context .is_decode_only ():
690+ if self . _materialize_only_last or context .is_decode_only ():
770691 # In decode mode or when only last token logits are materialized,
771692 # logits already represent only the last tokens
772- log_probs = log_probs_tensor [:active_request_count ]
693+ log_probs = log_probs_tensor [:self . _active_request_count ]
773694
774695 top_n_results = {}
775- for req_idx in range (active_request_count ):
696+ for req_idx in range (self . _active_request_count ):
776697 top_n = int (self .top_n_logprobs_cuda [req_idx ].item ())
777698 if top_n > 0 :
778699 # Get top-n logprobs and indices for this request (single token)
@@ -796,7 +717,7 @@ def _dynamic_step_calculate_top_n_logprobs(
796717 log_probs_per_request = log_probs .split (active_query_lengths .tolist (), dim = 0 )
797718
798719 top_n_results = {}
799- for req_idx in range (active_request_count ):
720+ for req_idx in range (self . _active_request_count ):
800721 top_n = int (self .top_n_logprobs_cuda [req_idx ].item ())
801722 if top_n > 0 :
802723 request_log_probs = log_probs_per_request [
@@ -823,31 +744,15 @@ def _dynamic_step_calculate_top_n_logprobs(
823744
824745 return top_n_results if top_n_results else None
825746
826- def _dynamic_step_context_bookkeeping (
827- self , new_sample : Tensor , request_metadata : Optional [Dict [str , Tensor ]] = None
828- ) -> Dict [str , Tensor ]:
747+ def _dynamic_step_context_bookkeeping (self ) -> Dict [str , Tensor ]:
829748 """Update the dynamic inference context after sampling.
830749
831- Args:
832- new_sample (Tensor): The newly sampled tokens.
833- request_metadata (Optional[Dict[str, Tensor]]): An override for the tensors
834- that manage request metadata, such as sampling parameters. By default, this
835- metadata is retrieved from the context.
836-
837750 Return:
838751 Dict [str, Tensor]: A dictionary containing:
839752 active_request_ids (Tensor): Current active request IDs.
840753 newly_paused_request_ids (Tensor): Newly paused request IDs.
841754 finished_request_ids (Tensor): Finished request IDs.
842755 """
843- context = self .inference_wrapped_model .inference_context
844- active_request_count = context .total_request_count - context .paused_request_count
845- if request_metadata is None :
846- request_metadata = {
847- label : tensor [context .paused_request_count : context .total_request_count ]
848- for label , tensor in context .request_metadata .items ()
849- }
850-
851756 # Active sequence lengths.
852757 active_request_ids = context .request_ids [
853758 context .paused_request_count : context .total_request_count
@@ -859,15 +764,15 @@ def _dynamic_step_context_bookkeeping(
859764 # Request finished if termination_id or length >= max_sequence_length.
860765 # Note: termination_id tensor has per-request termination IDs from mixed sampling
861766 active_request_mask = (
862- self .sampled_tokens_cuda [: active_request_count ] != request_metadata ["termination_id" ]
767+ self ._sampled_tokens_cuda [: self . _active_request_count ] != self . _request_metadata ["termination_id" ]
863768 ).byte () & torch .less (active_sequence_lengths , max_sequence_lengths ).byte ()
864769 finished_idxs = (
865770 torch .nonzero (active_request_mask == 0 , as_tuple = True )[0 ] + context .paused_request_count
866771 )
867772 finished_request_ids = context .request_ids [finished_idxs ]
868773
869774 # New sample gets updated in update_requests, so we pass in a clone
870- new_sample_copy = new_sample .clone ()
775+ new_sample_copy = self . _sampled_tokens_cuda [: self . _active_request_count ] .clone ()
871776
872777 # Update requests.
873778 newly_paused_request_ids = context .update_requests (active_request_mask , new_sample_copy )
@@ -919,11 +824,10 @@ async def async_generate_output_tokens_dynamic_batch(
919824 # NOTE [TDE]: This will be moved once CPU and GPU methods are separated.
920825 await asyncio .sleep (0 )
921826
922- request_metadata = self ._dynamic_step_sample_bookkeeping ()
923- new_sample = self ._dynamic_step_sample_logits (logits )
827+ self ._dynamic_step_sample_bookkeeping ()
828+ self ._dynamic_step_sample_logits ()
924829
925- return_log_probs = self ._dynamic_step_log_probs_bookkeeping (request_metadata )
926- return_top_n_logprobs = self ._dynamic_step_top_n_logprobs_bookkeeping (request_metadata )
830+ return_log_probs , return_top_n_log_probs = self ._dynamic_step_log_probs_bookkeeping ()
927831
928832 log_probs = None
929833 top_n_logprobs = None
@@ -937,10 +841,10 @@ async def async_generate_output_tokens_dynamic_batch(
937841 if skip_bookkeeping :
938842 request_bookkeeping = {}
939843 else :
940- request_bookkeeping = self ._dynamic_step_context_bookkeeping (new_sample )
844+ request_bookkeeping = self ._dynamic_step_context_bookkeeping ()
941845
942846 ret = {
943- "sample" : new_sample ,
847+ "sample" : self . _sampled_tokens_cuda [: self . _active_request_count ]
944848 "log_probs" : log_probs ,
945849 "top_n_logprobs" : top_n_logprobs ,
946850 "cuda_graph_request_count" : cuda_graph_request_count ,
0 commit comments