Skip to content

Commit 7b1c2a2

Browse files
committed
Further speed up torch sampling
1 parent 62d6d5d commit 7b1c2a2

2 files changed

Lines changed: 30 additions & 28 deletions

File tree

megatron/core/inference/inference_request.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
from megatron.core.inference.sampling_params import SamplingParams
1414
from megatron.core.tokenizers import MegatronTokenizer
15-
from megatron.core.utils import internal_api
15+
from megatron.core.utils import experimental_api
1616

1717

1818
def serialize_tensor(tensor: torch.Tensor) -> bytes:
@@ -229,7 +229,7 @@ def deserialize(cls, obj: dict) -> "DynamicInferenceEvent":
229229
return event
230230

231231

232-
@internal_api
232+
@experimental_api
233233
@dataclass(kw_only=True)
234234
class DynamicInferenceRequest(InferenceRequest):
235235
"""Class for one inference request

megatron/core/inference/text_generation_controllers/text_generation_controller.py

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,6 @@ def _init_dynamic_sampling_tensors(self):
8989
vocab_size = self.inference_wrapped_model.inference_wrapper_config.padded_vocab_size
9090

9191
self._sampling_backend = "torch"
92-
93-
# Initialize bookkeeping tensors.
94-
self._sampling_logits_cuda = torch.empty(
95-
max_requests, vocab_size, dtype=logits_dtype, device=device
96-
)
9792
self._sampled_tokens_cuda = torch.empty(max_requests, dtype=torch.int64, device=device)
9893

9994
# Keep track of request metadata.
@@ -116,6 +111,11 @@ def _init_dynamic_sampling_tensors(self):
116111
# Used for inefficient torch sampling.
117112
if self._sampling_backend == "torch":
118113
self._torch_sampling_buckets: Iterator[Tuple] = []
114+
elif self._sampling_backend == "flashinfer":
115+
self._sampling_logits_cuda = torch.empty(
116+
max_requests, vocab_size, dtype=logits_dtype, device=device
117+
)
118+
raise NotImplementedError
119119

120120
def tokenize_prompt(self, prompt: str, add_BOS: bool = False) -> List[int]:
121121
"""Utility to tokenize the input prompts.
@@ -593,23 +593,10 @@ def _dynamic_step_forward_logits(self, input_ids: Tensor, position_ids: Tensor)
593593
pp_group=self.pp_group,
594594
)
595595

596-
# Last token logits.
597-
if self._materialize_only_last:
598-
# When materialize_only_last_token_logits is true, last_token_logits is
599-
# already called in the forward pass of GPT.
600-
last_token_logits = logits.squeeze(0)
601-
else:
602-
last_token_logits = context.last_token_logits(logits)
603-
# Copy last_token_logits to contiguous buffer.
604-
self._sampling_logits_cuda[: self._active_request_count].copy_(
605-
last_token_logits, non_blocking=True
606-
)
607-
608596
return logits
609597

610598
def _dynamic_step_sample_bookkeeping(self):
611599
"""Perform bookkeeping necessary to sample logits for dynamic batching."""
612-
613600
if self._sampling_backend == "torch":
614601
# Bucketize the core sampling parameters.
615602
# Doing so via list comprehension is orders of magnitude faster than via torch.
@@ -633,27 +620,43 @@ def _dynamic_step_sample_bookkeeping(self):
633620
(indices, temp[rep], top_k[rep], top_p[rep]) for indices, rep in bucket_map.values()
634621
)
635622

636-
def _dynamic_step_sample_logits(self):
637-
"""Sample tokens from logits for dynamic batching."""
623+
def _dynamic_step_sample_logits(self, logits: Tensor):
624+
"""Sample tokens from logits for dynamic batching.
625+
626+
Args:
627+
logits (Tensor): The logits from the forward pass.
628+
"""
638629
# TODO(ksanthanam): Evaluate whether it makes more sense to sample on 1 rank
639630
# and then broadcast the sampled tokens rather than broadcasting the raw logits.
631+
# Last token logits.
632+
if self._materialize_only_last:
633+
# When materialize_only_last_token_logits is true, last_token_logits is
634+
# already called in the forward pass of GPT.
635+
last_token_logits = logits.squeeze(0)
636+
else:
637+
last_token_logits = context.last_token_logits(logits)
638+
640639
if self._sampling_backend == "torch":
641640
# Concatenate the outputs once to prevent repeated small writes.
642641
token_list = []
643642
indices_list = []
644643

645644
for indices, temp, top_k, top_p in self._torch_sampling_buckets:
646645
token_list.append(
647-
self._torch_sampling_func(
648-
self._sampling_logits_cuda[indices, :], temp, top_k, top_p
649-
)
646+
self._torch_sampling_func(last_token_logits[indices, :], temp, top_k, top_p)
650647
)
651648
indices_list.append(torch.tensor(indices))
652649

653650
# Single write to the output tensor.
654651
sampled_tokens = torch.cat(token_list, dim=0)
655652
sampled_indices = torch.cat(indices_list, dim=0)
656653
self._sampled_tokens_cuda[sampled_indices] = sampled_tokens
654+
elif self._sampling_backend == "flashinfer":
655+
# Copy last_token_logits to contiguous buffer.
656+
self._sampling_logits_cuda[: self._active_request_count].copy_(
657+
last_token_logits, non_blocking=True
658+
)
659+
raise NotImplementedError
657660

658661
def _dynamic_step_log_probs_bookkeeping(self) -> Tuple[bool, bool]:
659662
"""Perform bookkeeping necessary to compute log probs for dynamic batching.
@@ -850,10 +853,9 @@ async def async_generate_output_tokens_dynamic_batch(
850853
# NOTE [TDE]: This will be moved once CPU and GPU methods are separated.
851854
await asyncio.sleep(0)
852855

853-
self._dynamic_step_sample_bookkeeping()
854-
self._dynamic_step_sample_logits()
855-
856856
return_log_probs, return_top_n_logprobs = self._dynamic_step_log_probs_bookkeeping()
857+
self._dynamic_step_sample_bookkeeping()
858+
self._dynamic_step_sample_logits(logits)
857859

858860
log_probs = None
859861
top_n_logprobs = None

0 commit comments

Comments
 (0)