Text Generation
Transformers
Safetensors
qwen3
custom_generate
conversational
text-generation-inference
Instructions to use transformers-community/group-beam-search with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use transformers-community/group-beam-search with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="transformers-community/group-beam-search", device_map="auto") messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# Load model directly from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("transformers-community/group-beam-search") model = AutoModelForCausalLM.from_pretrained("transformers-community/group-beam-search", device_map="auto") messages = [ {"role": "user", "content": "Who are you?"}, ] inputs = tokenizer.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=40) print(tokenizer.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Inference
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use transformers-community/group-beam-search with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "transformers-community/group-beam-search" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "transformers-community/group-beam-search", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/transformers-community/group-beam-search
- SGLang
How to use transformers-community/group-beam-search with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "transformers-community/group-beam-search" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "transformers-community/group-beam-search", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "transformers-community/group-beam-search" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "transformers-community/group-beam-search", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use transformers-community/group-beam-search with Docker Model Runner:
docker model run hf.co/transformers-community/group-beam-search
Optimize group beam search by sharing the initial prefill across beams
#6
by lavrenko - opened
- custom_generate/generate.py +75 -7
custom_generate/generate.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
| 1 |
import torch
|
| 2 |
from transformers import LogitsProcessor, LogitsProcessorList, StoppingCriteriaList, GenerationConfig
|
|
|
|
| 3 |
from transformers.generation.utils import (
|
| 4 |
GenerationMixin,
|
| 5 |
GenerateBeamDecoderOnlyOutput,
|
|
@@ -241,6 +242,34 @@ def _group_beam_search(
|
|
| 241 |
device = input_ids.device
|
| 242 |
|
| 243 |
batch_beam_size, cur_len = input_ids.shape
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 244 |
# Does not exist anymore in recent versions!
|
| 245 |
if hasattr(model, "_get_initial_cache_position"):
|
| 246 |
model_kwargs = model._get_initial_cache_position(cur_len, input_ids.device, model_kwargs)
|
|
@@ -313,12 +342,37 @@ def _group_beam_search(
|
|
| 313 |
else 1
|
| 314 |
)
|
| 315 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 316 |
# do one decoder step on all beams of all sentences in batch
|
| 317 |
model_inputs = model.prepare_inputs_for_generation(
|
| 318 |
-
|
| 319 |
next_sequence_length=next_sequence_length,
|
| 320 |
is_first_iteration=is_first_iteration,
|
| 321 |
-
**
|
| 322 |
)
|
| 323 |
|
| 324 |
# prepare variable output controls (note: some models won't accept all output controls)
|
|
@@ -344,7 +398,10 @@ def _group_beam_search(
|
|
| 344 |
continue
|
| 345 |
|
| 346 |
if output_scores:
|
| 347 |
-
|
|
|
|
|
|
|
|
|
|
| 348 |
if output_logits:
|
| 349 |
# Copy is needed to avoid keeping a hanging ref to outputs.logits which may be very large for first iteration
|
| 350 |
# (the clone itself is always small)
|
|
@@ -372,9 +429,12 @@ def _group_beam_search(
|
|
| 372 |
# select outputs of beams of current group only
|
| 373 |
# No need to clone() the logits here as they will not retain outputs.logits at the end of the loop
|
| 374 |
# .float() is needed to retain precision for later logits manipulations
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
|
|
|
|
|
|
|
|
|
|
| 378 |
|
| 379 |
next_token_scores = nn.functional.log_softmax(
|
| 380 |
next_token_logits, dim=-1
|
|
@@ -483,8 +543,16 @@ def _group_beam_search(
|
|
| 483 |
# (that way the memory peak does not include outputs.logits)
|
| 484 |
del outputs
|
| 485 |
|
| 486 |
-
# NOTE: we need to check if `model._reorder_cache` exists for special
|
|
|
|
| 487 |
if model_kwargs.get("past_key_values", None) is not None:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 488 |
if hasattr(model, "_reorder_cache"):
|
| 489 |
model_kwargs["past_key_values"] = model._reorder_cache(
|
| 490 |
model_kwargs["past_key_values"], reordering_indices
|
|
|
|
| 1 |
import torch
|
| 2 |
from transformers import LogitsProcessor, LogitsProcessorList, StoppingCriteriaList, GenerationConfig
|
| 3 |
+
from transformers.cache_utils import DynamicCache
|
| 4 |
from transformers.generation.utils import (
|
| 5 |
GenerationMixin,
|
| 6 |
GenerateBeamDecoderOnlyOutput,
|
|
|
|
| 242 |
device = input_ids.device
|
| 243 |
|
| 244 |
batch_beam_size, cur_len = input_ids.shape
|
| 245 |
+
cache = model_kwargs.get("past_key_values")
|
| 246 |
+
use_cache = model_kwargs.get("use_cache", True)
|
| 247 |
+
|
| 248 |
+
# Shared prefill is safe only when the generation state follows the
|
| 249 |
+
# standard contracts that this optimization knows how to reverse.
|
| 250 |
+
can_share_prefill = (
|
| 251 |
+
not model.training
|
| 252 |
+
and type(model)._expand_inputs_for_generation
|
| 253 |
+
is GenerationMixin._expand_inputs_for_generation
|
| 254 |
+
and type(model)._update_model_kwargs_for_generation
|
| 255 |
+
is GenerationMixin._update_model_kwargs_for_generation
|
| 256 |
+
and (
|
| 257 |
+
(not use_cache and cache is None)
|
| 258 |
+
or (
|
| 259 |
+
use_cache
|
| 260 |
+
and isinstance(cache, DynamicCache)
|
| 261 |
+
and not cache.is_compileable
|
| 262 |
+
and cache.get_seq_length() == 0
|
| 263 |
+
)
|
| 264 |
+
)
|
| 265 |
+
and all(
|
| 266 |
+
not isinstance(value, torch.Tensor)
|
| 267 |
+
or value.ndim == 0
|
| 268 |
+
or value.shape[0] == batch_beam_size
|
| 269 |
+
for value in model_kwargs.values()
|
| 270 |
+
)
|
| 271 |
+
)
|
| 272 |
+
|
| 273 |
# Does not exist anymore in recent versions!
|
| 274 |
if hasattr(model, "_get_initial_cache_position"):
|
| 275 |
model_kwargs = model._get_initial_cache_position(cur_len, input_ids.device, model_kwargs)
|
|
|
|
| 342 |
else 1
|
| 343 |
)
|
| 344 |
|
| 345 |
+
# prefill one prompt per batch item before beams diverge
|
| 346 |
+
# keep the original path when beam expansion cannot be safely undone
|
| 347 |
+
shared_prefill = (
|
| 348 |
+
is_first_iteration
|
| 349 |
+
and can_share_prefill
|
| 350 |
+
and not model.config.is_encoder_decoder
|
| 351 |
+
and not (output_attentions or output_hidden_states or output_logits)
|
| 352 |
+
)
|
| 353 |
+
|
| 354 |
+
# keep the beam-shaped search state; reduce only the first model forward
|
| 355 |
+
forward_input_ids = input_ids
|
| 356 |
+
forward_model_kwargs = model_kwargs
|
| 357 |
+
|
| 358 |
+
if shared_prefill:
|
| 359 |
+
# undo generate()'s beam expansion for model inputs
|
| 360 |
+
forward_input_ids = input_ids[::num_beams]
|
| 361 |
+
forward_model_kwargs = {
|
| 362 |
+
key: value[::num_beams]
|
| 363 |
+
if isinstance(value, torch.Tensor)
|
| 364 |
+
and value.ndim > 0
|
| 365 |
+
and value.shape[0] == batch_beam_size
|
| 366 |
+
else value
|
| 367 |
+
for key, value in model_kwargs.items()
|
| 368 |
+
}
|
| 369 |
+
|
| 370 |
# do one decoder step on all beams of all sentences in batch
|
| 371 |
model_inputs = model.prepare_inputs_for_generation(
|
| 372 |
+
forward_input_ids,
|
| 373 |
next_sequence_length=next_sequence_length,
|
| 374 |
is_first_iteration=is_first_iteration,
|
| 375 |
+
**forward_model_kwargs,
|
| 376 |
)
|
| 377 |
|
| 378 |
# prepare variable output controls (note: some models won't accept all output controls)
|
|
|
|
| 398 |
continue
|
| 399 |
|
| 400 |
if output_scores:
|
| 401 |
+
# scores remain beam-shaped although the first model output is shared
|
| 402 |
+
processed_score = outputs.logits.new_zeros(
|
| 403 |
+
(batch_beam_size, outputs.logits.shape[-1])
|
| 404 |
+
)
|
| 405 |
if output_logits:
|
| 406 |
# Copy is needed to avoid keeping a hanging ref to outputs.logits which may be very large for first iteration
|
| 407 |
# (the clone itself is always small)
|
|
|
|
| 429 |
# select outputs of beams of current group only
|
| 430 |
# No need to clone() the logits here as they will not retain outputs.logits at the end of the loop
|
| 431 |
# .float() is needed to retain precision for later logits manipulations
|
| 432 |
+
# reuse the common raw distribution; diversity is still applied below per group
|
| 433 |
+
next_token_logits = (
|
| 434 |
+
outputs.logits[:, -1, :].repeat_interleave(group_size, dim=0)
|
| 435 |
+
if shared_prefill
|
| 436 |
+
else outputs.logits[batch_group_indices, -1, :]
|
| 437 |
+
).to(dtype=torch.float32, device=input_ids.device)
|
| 438 |
|
| 439 |
next_token_scores = nn.functional.log_softmax(
|
| 440 |
next_token_logits, dim=-1
|
|
|
|
| 543 |
# (that way the memory peak does not include outputs.logits)
|
| 544 |
del outputs
|
| 545 |
|
| 546 |
+
# NOTE: we need to check if `model._reorder_cache` exists for special
|
| 547 |
+
# models like RAG, RecurrentGemma etc.
|
| 548 |
if model_kwargs.get("past_key_values", None) is not None:
|
| 549 |
+
if shared_prefill:
|
| 550 |
+
# Expand the shared prefill cache to the normal beam-shaped
|
| 551 |
+
# state before applying the standard beam reordering.
|
| 552 |
+
model_kwargs["past_key_values"].batch_repeat_interleave(
|
| 553 |
+
num_beams
|
| 554 |
+
)
|
| 555 |
+
|
| 556 |
if hasattr(model, "_reorder_cache"):
|
| 557 |
model_kwargs["past_key_values"] = model._reorder_cache(
|
| 558 |
model_kwargs["past_key_values"], reordering_indices
|