chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:17:40 +08:00
commit f1825c8ceb
10096 changed files with 2364182 additions and 0 deletions
@@ -0,0 +1,79 @@
# flake8: noqa
# fmt: off
from typing import Iterator, Union, List
import pyarrow
from ray.data.block import Block
# __datasource_constructor_start__
from ray.data.datasource import FileBasedDatasource
class ImageDatasource(FileBasedDatasource):
def __init__(self, paths: Union[str, List[str]], *, mode: str):
super().__init__(
paths,
file_extensions=["png", "jpg", "jpeg", "bmp", "gif", "tiff"],
)
self.mode = mode # Specify read options in the constructor
# __datasource_constructor_end__
# __read_stream_start__
def _read_stream(self, f: "pyarrow.NativeFile", path: str) -> Iterator[Block]:
import io
import numpy as np
from PIL import Image
from ray.data._internal.delegating_block_builder import DelegatingBlockBuilder
data = f.readall()
image = Image.open(io.BytesIO(data))
image = image.convert(self.mode)
# Each block contains one row
builder = DelegatingBlockBuilder()
array = np.asarray(image)
item = {"image": array}
builder.add(item)
yield builder.build()
# __read_stream_end__
# __read_datasource_start__
import ray
ds = ray.data.read_datasource(
ImageDatasource("s3://anonymous@ray-example-data/batoidea", mode="RGB")
)
# __read_datasource_end__
from typing import Any, Dict
import pyarrow
# __datasink_constructor_start__
from ray.data.datasource import RowBasedFileDatasink
class ImageDatasink(RowBasedFileDatasink):
def __init__(self, path: str, column: str, file_format: str):
super().__init__(path, file_format=file_format)
self.column = column
self.file_format = file_format # Specify write options in the constructor
# __datasink_constructor_end__
# __write_row_to_file_start__
def write_row_to_file(self, row: Dict[str, Any], file: pyarrow.NativeFile):
import io
from PIL import Image
# PIL can't write to a NativeFile, so we have to write to a buffer first.
image = Image.fromarray(row[self.column])
buffer = io.BytesIO()
image.save(buffer, format=self.file_format)
file.write(buffer.getvalue())
# __write_row_to_file_end__
# __write_datasink_start__
ds.write_datasink(ImageDatasink("/tmp/results", column="image", file_format="png"))
# __write_datasink_end__
+27
View File
@@ -0,0 +1,27 @@
# flake8: noqa
# fmt: off
# __resource_allocation_1_begin__
import ray
from ray import tune
# This workload will use spare cluster resources for execution.
def objective(*args):
ray.data.range(10).show()
# Create a cluster with 4 CPU slots available.
ray.init(num_cpus=4)
# By setting `max_concurrent_trials=3`, this ensures the cluster will always
# have a sparse CPU for Dataset. Try setting `max_concurrent_trials=4` here,
# and notice that the experiment will appear to hang.
tuner = tune.Tuner(
tune.with_resources(objective, {"cpu": 1}),
tune_config=tune.TuneConfig(
num_samples=1,
max_concurrent_trials=3
)
)
tuner.fit()
# __resource_allocation_1_end__
# fmt: on
@@ -0,0 +1,462 @@
"""
This file serves as a documentation example and CI test for basic LLM batch inference.
"""
# __basic_llm_example_start__
import os
import shutil
import ray
from ray.data.llm import vLLMEngineProcessorConfig, build_processor
# __basic_config_example_start__
# Basic vLLM configuration
config = vLLMEngineProcessorConfig(
model_source="unsloth/Llama-3.1-8B-Instruct",
engine_kwargs={
"enable_chunked_prefill": True,
"max_num_batched_tokens": 4096, # Reduce if CUDA OOM occurs
"max_model_len": 4096, # Constrain to fit test GPU memory
},
concurrency=1,
batch_size=64,
)
# __basic_config_example_end__
processor = build_processor(
config,
preprocess=lambda row: dict(
messages=[
{"role": "system", "content": "You are a bot that responds with haikus."},
{"role": "user", "content": row["item"]},
],
sampling_params=dict(
temperature=0.3,
max_tokens=250,
),
),
postprocess=lambda row: dict(
answer=row["generated_text"],
**row, # This will return all the original columns in the dataset.
),
)
ds = ray.data.from_items(["Start of the haiku is: Complete this for me..."])
if __name__ == "__main__":
try:
import torch
if torch.cuda.is_available():
ds = processor(ds)
ds.show(limit=1)
else:
print("Skipping basic LLM run (no GPU available)")
except Exception as e:
print(f"Skipping basic LLM run due to environment error: {e}")
# __hf_token_config_example_start__
# Configuration with Hugging Face token
config_with_token = vLLMEngineProcessorConfig(
model_source="unsloth/Llama-3.1-8B-Instruct",
runtime_env={"env_vars": {"HF_TOKEN": "your_huggingface_token"}},
concurrency=1,
batch_size=64,
)
# __hf_token_config_example_end__
# __parallel_config_example_start__
# Model parallelism configuration for larger models
# tensor_parallel_size=2: Split model across 2 GPUs for tensor parallelism
# pipeline_parallel_size=2: Use 2 pipeline stages (total 4 GPUs needed)
# Total GPUs required = tensor_parallel_size * pipeline_parallel_size = 4
config = vLLMEngineProcessorConfig(
model_source="unsloth/Llama-3.1-8B-Instruct",
engine_kwargs={
"max_model_len": 16384,
"tensor_parallel_size": 2,
"pipeline_parallel_size": 2,
"enable_chunked_prefill": True,
"max_num_batched_tokens": 2048,
},
concurrency=1,
batch_size=32,
accelerator_type="L4",
)
# __parallel_config_example_end__
# __runai_config_example_start__
# RunAI streamer configuration for optimized model loading
# Note: Install vLLM with runai dependencies: pip install -U "vllm[runai]>=0.10.1"
config = vLLMEngineProcessorConfig(
model_source="unsloth/Llama-3.1-8B-Instruct",
engine_kwargs={
"load_format": "runai_streamer",
"max_model_len": 16384,
},
concurrency=1,
batch_size=64,
)
# __runai_config_example_end__
# __lora_config_example_start__
# Multi-LoRA configuration
config = vLLMEngineProcessorConfig(
model_source="unsloth/Llama-3.1-8B-Instruct",
engine_kwargs={
"enable_lora": True,
"max_lora_rank": 32,
"max_loras": 1,
"max_model_len": 16384,
},
concurrency=1,
batch_size=32,
)
# __lora_config_example_end__
# __s3_config_example_start__
# S3 hosted model configuration
s3_config = vLLMEngineProcessorConfig(
model_source="s3://your-bucket/your-model-path/",
engine_kwargs={
"load_format": "runai_streamer",
"max_model_len": 16384,
},
concurrency=1,
batch_size=64,
)
# __s3_config_example_end__
base_dir = "/tmp/llm_checkpoint_demo"
input_path = os.path.join(base_dir, "input")
output_path = os.path.join(base_dir, "output")
checkpoint_path = os.path.join(base_dir, "checkpoint")
# Reset directories
for path in (input_path, output_path, checkpoint_path):
shutil.rmtree(path, ignore_errors=True)
os.makedirs(path)
# __row_level_fault_tolerance_config_example_start__
# Row-level fault tolerance configuration
config = vLLMEngineProcessorConfig(
model_source="unsloth/Llama-3.1-8B-Instruct",
concurrency=1,
batch_size=64,
should_continue_on_error=True,
)
# __row_level_fault_tolerance_config_example_end__
# Seed the input directory because Ray Data V2's `read_parquet` errors on empty dirs
ray.data.from_items(
[{"id": i, "message": f"Question {i}: What is 2 + 2?"} for i in range(4)]
).write_parquet(input_path)
# __checkpoint_config_setup_example_start__
from ray.data.checkpoint import CheckpointConfig
ctx = ray.data.DataContext.get_current()
ctx.checkpoint_config = CheckpointConfig(
id_column="id",
checkpoint_path=checkpoint_path,
delete_checkpoint_on_success=False,
)
# __checkpoint_config_setup_example_end__
# __checkpoint_usage_example_start__
processor_config = vLLMEngineProcessorConfig(
model_source="unsloth/Llama-3.1-8B-Instruct",
engine_kwargs={
"max_num_batched_tokens": 4096,
"max_model_len": 4096,
},
concurrency=1,
batch_size=16,
)
processor = build_processor(
processor_config,
preprocess=lambda row: dict(
id=row["id"], # Preserve the ID column for checkpointing
messages=[{"role": "user", "content": row["message"]}],
sampling_params=dict(
temperature=0.3,
max_tokens=10,
),
),
postprocess=lambda row: {
"id": row["id"], # Preserve the ID column for checkpointing
"answer": row.get("generated_text"),
},
)
ds = ray.data.read_parquet(input_path)
ds = processor(ds)
ds.write_parquet(output_path)
# __checkpoint_usage_example_end__
# __gpu_memory_config_example_start__
# GPU memory management configuration
# If you encounter CUDA out of memory errors, try these optimizations:
config_memory_optimized = vLLMEngineProcessorConfig(
model_source="unsloth/Llama-3.1-8B-Instruct",
engine_kwargs={
"max_model_len": 8192,
"max_num_batched_tokens": 2048,
"enable_chunked_prefill": True,
"gpu_memory_utilization": 0.85,
"block_size": 16,
},
concurrency=1,
batch_size=16,
)
# For very large models or limited GPU memory:
config_minimal_memory = vLLMEngineProcessorConfig(
model_source="unsloth/Llama-3.1-8B-Instruct",
engine_kwargs={
"max_model_len": 4096,
"max_num_batched_tokens": 1024,
"enable_chunked_prefill": True,
"gpu_memory_utilization": 0.75,
},
concurrency=1,
batch_size=8,
)
# __gpu_memory_config_example_end__
# __embedding_config_example_start__
# Embedding model configuration
embedding_config = vLLMEngineProcessorConfig(
model_source="sentence-transformers/all-MiniLM-L6-v2",
task_type="embed",
engine_kwargs=dict(
enable_prefix_caching=False,
enable_chunked_prefill=False,
max_model_len=256,
enforce_eager=True,
),
batch_size=32,
concurrency=1,
chat_template_stage=False, # Skip chat templating for embeddings
detokenize_stage=False, # Skip detokenization for embeddings
)
# Example usage for embeddings
def create_embedding_processor():
return build_processor(
embedding_config,
preprocess=lambda row: dict(prompt=row["text"]),
postprocess=lambda row: {
"text": row["prompt"],
"embedding": row["embeddings"],
},
)
# __embedding_config_example_end__
# __classification_config_example_start__
# Sequence classification model configuration
# Use task_type="classify" for classification models (e.g., sentiment, quality scoring)
# Use task_type="score" for cross-encoder scoring models
classification_config = vLLMEngineProcessorConfig(
model_source="nvidia/nemocurator-fineweb-nemotron-4-edu-classifier",
task_type="classify",
engine_kwargs=dict(
max_model_len=512,
enforce_eager=True,
),
batch_size=8,
concurrency=1,
chat_template_stage=False,
detokenize_stage=False,
)
# Example usage for classification
def create_classification_processor():
return build_processor(
classification_config,
preprocess=lambda row: dict(prompt=row["text"]),
postprocess=lambda row: {
"text": row["prompt"],
# Classification models return logits in the 'embeddings' field
"score": float(row["embeddings"][0])
if row.get("embeddings") is not None and len(row["embeddings"]) > 0
else None,
},
)
# __classification_config_example_end__
# __shared_vllm_engine_config_example_start__
import ray
from ray import serve
from ray.data.llm import ServeDeploymentProcessorConfig, build_processor
from ray.serve.llm import (
LLMConfig,
ModelLoadingConfig,
build_llm_deployment,
)
from ray.serve.llm.openai_api_models import CompletionRequest
llm_config = LLMConfig(
model_loading_config=ModelLoadingConfig(
model_id="facebook/opt-1.3b",
model_source="facebook/opt-1.3b",
),
deployment_config=dict(
name="demo_deployment_config",
autoscaling_config=dict(
min_replicas=1,
max_replicas=1,
),
),
engine_kwargs=dict(
enable_prefix_caching=True,
enable_chunked_prefill=True,
max_num_batched_tokens=4096,
),
)
APP_NAME = "demo_app"
DEPLOYMENT_NAME = "demo_deployment"
override_serve_options = dict(name=DEPLOYMENT_NAME)
llm_app = build_llm_deployment(
llm_config, override_serve_options=override_serve_options
)
app = serve.run(llm_app, name=APP_NAME)
config = ServeDeploymentProcessorConfig(
deployment_name=DEPLOYMENT_NAME,
app_name=APP_NAME,
dtype_mapping={
"CompletionRequest": CompletionRequest,
},
concurrency=1,
batch_size=64,
)
processor1 = build_processor(
config,
preprocess=lambda row: dict(
method="completions",
dtype="CompletionRequest",
request_kwargs=dict(
model="facebook/opt-1.3b",
prompt=f"This is a prompt for {row['id']}",
stream=False,
),
),
postprocess=lambda row: dict(
prompt=row["choices"][0]["text"],
),
)
processor2 = build_processor(
config,
preprocess=lambda row: dict(
method="completions",
dtype="CompletionRequest",
request_kwargs=dict(
model="facebook/opt-1.3b",
prompt=row["prompt"],
stream=False,
),
),
postprocess=lambda row: row,
)
ds = ray.data.range(10)
ds = processor2(processor1(ds))
print(ds.take_all())
# __shared_vllm_engine_config_example_end__
# __cross_node_parallelism_config_example_start__
config = vLLMEngineProcessorConfig(
model_source="unsloth/Llama-3.1-8B-Instruct",
engine_kwargs={
"enable_chunked_prefill": True,
"max_num_batched_tokens": 4096,
"max_model_len": 16384,
"pipeline_parallel_size": 4,
"tensor_parallel_size": 4,
"distributed_executor_backend": "ray",
},
batch_size=32,
concurrency=1,
)
# __cross_node_parallelism_config_example_end__
# __custom_placement_group_strategy_config_example_start__
# Simple: specify resources per worker, auto-replicated by TP*PP (4 workers here)
# Alternative: use "bundles": [{"GPU": 1}] * 4 for explicit bundle control
config = vLLMEngineProcessorConfig(
model_source="unsloth/Llama-3.1-8B-Instruct",
engine_kwargs={
"enable_chunked_prefill": True,
"max_num_batched_tokens": 4096,
"max_model_len": 16384,
"pipeline_parallel_size": 2,
"tensor_parallel_size": 2,
"distributed_executor_backend": "ray",
},
batch_size=32,
concurrency=1,
placement_group_config={
"bundle_per_worker": {"GPU": 1},
"strategy": "STRICT_PACK",
},
)
# __custom_placement_group_strategy_config_example_end__
# __concurrent_config_example_start__
config = vLLMEngineProcessorConfig(
model_source="unsloth/Llama-3.1-8B-Instruct",
engine_kwargs={
"enable_chunked_prefill": True,
"max_num_batched_tokens": 4096,
"max_model_len": 16384,
},
concurrency=10,
batch_size=64,
)
# __concurrent_config_example_end__
# __concurrent_config_fixed_pool_example_start__
config = vLLMEngineProcessorConfig(
model_source="unsloth/Llama-3.1-8B-Instruct",
engine_kwargs={
"enable_chunked_prefill": True,
"max_num_batched_tokens": 4096,
"max_model_len": 16384,
},
concurrency=(10, 10),
batch_size=64,
)
# __concurrent_config_fixed_pool_example_end__
# __concurrent_batches_tuning_example_start__
# Tuning concurrent batch processing
# Configure both parameters together for optimal throughput
config = vLLMEngineProcessorConfig(
model_source="unsloth/Llama-3.1-8B-Instruct",
engine_kwargs={
"enable_chunked_prefill": True,
"max_num_batched_tokens": 4096,
},
batch_size=64,
# Dataset-level concurrency (number of actor replicas)
concurrency=1,
# Number of batches that can run concurrently per actor (default: 8)
max_concurrent_batches=8,
# Number of tasks Ray Data queues per actor (default: 16)
# Increase to keep actor task queue saturated
experimental={"max_tasks_in_flight_per_actor": 16},
)
# __concurrent_batches_tuning_example_end__
# __basic_llm_example_end__
@@ -0,0 +1,69 @@
"""
Classification batch inference with Ray Data LLM.
Uses sequence classification models for content classifiers and sentiment analyzers.
"""
# Dependency setup
import subprocess
import sys
subprocess.check_call([sys.executable, "-m", "pip", "install", "--upgrade", "ray[llm]"])
subprocess.check_call(
[sys.executable, "-m", "pip", "install", "--upgrade", "transformers"]
)
subprocess.check_call([sys.executable, "-m", "pip", "install", "numpy==1.26.4"])
# __classification_example_start__
import ray
from ray.data.llm import vLLMEngineProcessorConfig, build_processor
# Configure vLLM for a sequence classification model
classification_config = vLLMEngineProcessorConfig(
model_source="nvidia/nemocurator-fineweb-nemotron-4-edu-classifier",
task_type="classify", # Use 'classify' for sequence classification models
engine_kwargs=dict(
max_model_len=512,
enforce_eager=True,
),
batch_size=8,
concurrency=1,
chat_template_stage=False,
detokenize_stage=False,
)
classification_processor = build_processor(
classification_config,
preprocess=lambda row: dict(prompt=row["text"]),
postprocess=lambda row: {
"text": row["prompt"],
# Classification models return logits in the 'embeddings' field
"edu_score": float(row["embeddings"][0])
if row.get("embeddings") is not None and len(row["embeddings"]) > 0
else None,
},
)
# Sample texts with varying educational quality
texts = [
"lol that was so funny haha",
"Photosynthesis converts light energy into chemical energy.",
"Newton's laws describe the relationship between forces and motion.",
]
ds = ray.data.from_items([{"text": text} for text in texts])
if __name__ == "__main__":
try:
import torch
if torch.cuda.is_available():
classified_ds = classification_processor(ds)
classified_ds.show(limit=3)
else:
print("Skipping classification run (no GPU available)")
except Exception as e:
print(f"Skipping classification run due to environment error: {e}")
# __classification_example_end__
@@ -0,0 +1,195 @@
"""
Documentation example and test for custom tokenizer batch inference.
Demonstrates how to use vLLM's tokenizer infrastructure for models whose
tokenizers are not natively supported by HuggingFace (e.g. Mistral Tekken,
DeepSeek-V3.2, Grok-2 tiktoken).
This example uses a standard model to demonstrate the pattern. For models
that truly require vLLM's custom tokenizer (e.g. deepseek-ai/DeepSeek-V3-0324),
replace the model ID and adjust tokenizer_mode accordingly.
"""
# __custom_chat_template_start__
from typing import Any, Dict, List
from vllm.tokenizers import get_tokenizer
class VLLMChatTemplate:
"""Apply a chat template using vLLM's tokenizer."""
def __init__(self, model_id: str, tokenizer_mode: str = "auto"):
self.tokenizer = get_tokenizer(
model_id,
tokenizer_mode=tokenizer_mode,
trust_remote_code=True,
)
async def __call__(self, batch: Dict[str, Any]) -> Dict[str, Any]:
prompts: List[str] = []
all_messages: List[List[Dict[str, Any]]] = []
for messages in batch["messages"]:
if hasattr(messages, "tolist"):
messages = messages.tolist()
all_messages.append(messages)
add_generation_prompt = messages[-1]["role"] == "user"
prompt = self.tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=add_generation_prompt,
continue_final_message=not add_generation_prompt,
)
prompts.append(prompt)
return {
"prompt": prompts,
"messages": all_messages,
"sampling_params": batch["sampling_params"],
}
# __custom_chat_template_end__
# __custom_tokenize_start__
class VLLMTokenize:
"""Tokenize text prompts using vLLM's tokenizer."""
def __init__(self, model_id: str, tokenizer_mode: str = "auto"):
self.tokenizer = get_tokenizer(
model_id,
tokenizer_mode=tokenizer_mode,
trust_remote_code=True,
)
async def __call__(self, batch: Dict[str, Any]) -> Dict[str, Any]:
all_tokenized: List[List[int]] = [
self.tokenizer.encode(prompt) for prompt in batch["prompt"]
]
return {
"tokenized_prompt": all_tokenized,
"messages": batch["messages"],
"sampling_params": batch["sampling_params"],
}
# __custom_tokenize_end__
# __custom_detokenize_start__
class VLLMDetokenize:
"""Detokenize generated token IDs using vLLM's tokenizer."""
def __init__(self, model_id: str, tokenizer_mode: str = "auto"):
self.tokenizer = get_tokenizer(
model_id,
tokenizer_mode=tokenizer_mode,
trust_remote_code=True,
)
async def __call__(self, batch: Dict[str, Any]) -> Dict[str, Any]:
decoded: List[str] = []
for tokens in batch["generated_tokens"]:
if hasattr(tokens, "tolist"):
tokens = tokens.tolist()
decoded.append(self.tokenizer.decode(tokens, skip_special_tokens=True))
return {
**batch,
"generated_text_custom": decoded,
}
# __custom_detokenize_end__
def run_custom_tokenizer_example():
import ray
from ray.data.llm import vLLMEngineProcessorConfig, build_processor
# Input dataset with sampling_params per row.
ds = ray.data.from_items(
[
{
"messages": [
{"role": "user", "content": "What is the capital of France?"}
],
"sampling_params": {"max_tokens": 256, "temperature": 0.7},
},
{
"messages": [
{"role": "user", "content": "Write a haiku about computing."}
],
"sampling_params": {"max_tokens": 256, "temperature": 0.7},
},
]
)
# __custom_tokenizer_pipeline_start__
MODEL_ID = "unsloth/Llama-3.1-8B-Instruct"
config = vLLMEngineProcessorConfig(
model_source=MODEL_ID,
engine_kwargs=dict(
max_model_len=4096,
trust_remote_code=True,
tokenizer_mode="auto",
),
batch_size=4,
concurrency=1,
# Disable built-in stages -- we handle them via map_batches.
chat_template_stage=False,
tokenize_stage=False,
detokenize_stage=False,
)
processor = build_processor(
config,
postprocess=lambda row: {
"generated_text": row.get("generated_text", ""),
"generated_tokens": row.get("generated_tokens", []),
"num_input_tokens": row.get("num_input_tokens", 0),
"num_generated_tokens": row.get("num_generated_tokens", 0),
},
)
ds = ds.map_batches(
VLLMChatTemplate,
fn_constructor_kwargs={"model_id": MODEL_ID},
concurrency=1,
batch_size=4,
)
ds = ds.map_batches(
VLLMTokenize,
fn_constructor_kwargs={"model_id": MODEL_ID},
concurrency=1,
batch_size=4,
)
ds = processor(ds)
ds = ds.map_batches(
VLLMDetokenize,
fn_constructor_kwargs={"model_id": MODEL_ID},
concurrency=1,
batch_size=4,
)
# __custom_tokenizer_pipeline_end__
ds.show(limit=2)
if __name__ == "__main__":
try:
import torch
if torch.cuda.is_available():
run_custom_tokenizer_example()
else:
print("Skipping custom tokenizer example (no GPU available)")
except Exception as e:
print(f"Skipping custom tokenizer example: {e}")
@@ -0,0 +1,63 @@
"""
Documentation example and test for embedding model batch inference.
"""
import subprocess
import sys
subprocess.check_call([sys.executable, "-m", "pip", "install", "--upgrade", "ray[llm]"])
subprocess.check_call([sys.executable, "-m", "pip", "install", "numpy==1.26.4"])
def run_embedding_example():
# __embedding_example_start__
import ray
from ray.data.llm import vLLMEngineProcessorConfig, build_processor
embedding_config = vLLMEngineProcessorConfig(
model_source="sentence-transformers/all-MiniLM-L6-v2",
task_type="embed",
engine_kwargs=dict(
enable_prefix_caching=False,
enable_chunked_prefill=False,
max_model_len=256,
enforce_eager=True,
),
batch_size=32,
concurrency=1,
chat_template_stage=False, # Skip chat templating for embeddings
detokenize_stage=False, # Skip detokenization for embeddings
)
embedding_processor = build_processor(
embedding_config,
preprocess=lambda row: dict(prompt=row["text"]),
postprocess=lambda row: {
"text": row["prompt"],
"embedding": row["embeddings"],
},
)
texts = [
"Hello world",
"This is a test sentence",
"Embedding models convert text to vectors",
]
ds = ray.data.from_items([{"text": text} for text in texts])
embedded_ds = embedding_processor(ds)
embedded_ds.show(limit=1)
# __embedding_example_end__
if __name__ == "__main__":
try:
import torch
if torch.cuda.is_available():
run_embedding_example()
else:
print("Skipping embedding example (no GPU available)")
except Exception as e:
print(f"Skipping embedding example: {e}")
@@ -0,0 +1,62 @@
"""
Quickstart: vLLM + Ray Data batch inference.
1. Installation
2. Dataset creation
3. Processor configuration
4. Running inference
5. Getting results
"""
# __minimal_vllm_quickstart_start__
import ray
from ray.data.llm import vLLMEngineProcessorConfig, build_processor
# Initialize Ray
ray.init()
# simple dataset
ds = ray.data.from_items([
{"prompt": "What is machine learning?"},
{"prompt": "Explain neural networks in one sentence."},
])
# Minimal vLLM configuration
config = vLLMEngineProcessorConfig(
model_source="unsloth/Llama-3.1-8B-Instruct",
concurrency=1, # 1 vLLM engine replica
batch_size=32, # 32 samples per batch
engine_kwargs={
"max_model_len": 4096, # Fit into test GPU memory
}
)
# Build processor
# preprocess: converts input row to format expected by vLLM (OpenAI chat format)
# postprocess: extracts generated text from vLLM output
processor = build_processor(
config,
preprocess=lambda row: {
"messages": [{"role": "user", "content": row["prompt"]}],
"sampling_params": {"temperature": 0.7, "max_tokens": 100},
},
postprocess=lambda row: {
"prompt": row["prompt"],
"response": row["generated_text"],
},
)
# inference
ds = processor(ds)
# iterate through the results
for result in ds.iter_rows():
print(f"Q: {result['prompt']}")
print(f"A: {result['response']}\n")
# Alternative ways to get results:
# results = ds.take(10) # Get first 10 results
# ds.show(limit=5) # Print first 5 results
# ds.write_parquet("output.parquet") # Save to file
# __minimal_vllm_quickstart_end__
@@ -0,0 +1,212 @@
"""
This file serves as a documentation example and CI test for VLM batch inference with audio.
Structure:
1. Infrastructure setup: Dataset compatibility patches, dependency handling
2. Docs example (between __vlm_audio_example_start/end__): Embedded in Sphinx docs via literalinclude
3. Test validation and cleanup
"""
'''
# __audio_message_format_example_start__
"""Supported audio input formats: audio URL, audio binary data"""
{
"messages": [
{
"role": "system",
"content": "Provide a detailed description of the audio."
},
{
"role": "user",
"content": [
{"type": "text", "text": "Describe what happens in this audio."},
# Option 1: Provide audio URL
{"type": "audio_url", "audio_url": {"url": "https://example.com/audio.wav"}},
# Option 2: Provide audio binary data
{"type": "input_audio", "input_audio": {"data": audio_base64, "format": "wav"}},
]
},
]
}
# __audio_message_format_example_end__
'''
# __omni_audio_example_start__
import ray
from ray.data.llm import (
vLLMEngineProcessorConfig,
build_processor,
)
# __omni_audio_config_example_start__
audio_processor_config = vLLMEngineProcessorConfig(
model_source="Qwen/Qwen2.5-Omni-3B",
task_type="generate",
engine_kwargs=dict(
limit_mm_per_prompt={"audio": 1},
),
batch_size=16,
accelerator_type="L4",
concurrency=1,
prepare_multimodal_stage={
"enabled": True,
"chat_template_content_format": "openai",
},
chat_template_stage=True,
tokenize_stage=True,
detokenize_stage=True,
)
# __omni_audio_config_example_end__
# __omni_audio_preprocess_example_start__
def audio_preprocess(row: dict) -> dict:
"""
Preprocessing function for audio-language model inputs.
Converts dataset rows into the format expected by the Omni model:
- System prompt for analysis instructions
- User message with text and audio content
- Sampling parameters
"""
return {
"messages": [
{
"role": "system",
"content": "You are a helpful assistant that analyzes audio. "
"Listen to the audio carefully and provide detailed descriptions.",
},
{
"role": "user",
"content": [
{
"type": "text",
"text": row["text"],
},
{
"type": "input_audio",
"input_audio": {
"data": row["audio_data"],
"format": "wav",
},
},
],
},
],
"sampling_params": {
"temperature": 0.3,
"max_tokens": 150,
"detokenize": False,
},
}
def audio_postprocess(row: dict) -> dict:
return {
"resp": row["generated_text"],
}
# __omni_audio_preprocess_example_end__
def load_audio_dataset():
# __omni_audio_load_dataset_example_start__
"""
Load audio dataset from MRSAudio Hugging Face dataset.
"""
try:
from datasets import load_dataset
from huggingface_hub import hf_hub_download
import base64
dataset_name = "MRSAudio/MRSAudio"
dataset = load_dataset(dataset_name, split="train")
audio_items = []
# Limit to first 10 samples for the example
num_samples = min(10, len(dataset))
for i in range(num_samples):
item = dataset[i]
audio_path = hf_hub_download(
repo_id=dataset_name, filename=item["path"], repo_type="dataset"
)
with open(audio_path, "rb") as f:
audio_bytes = f.read()
audio_base64 = base64.b64encode(audio_bytes).decode("utf-8")
audio_items.append(
{
"audio_data": audio_base64,
"text": item.get("text", "Describe this audio."),
}
)
audio_dataset = ray.data.from_items(audio_items)
return audio_dataset
except Exception as e:
print(f"Error loading dataset: {e}")
return None
# __omni_audio_load_dataset_example_end__
def create_omni_audio_config():
"""Create Omni audio configuration."""
return vLLMEngineProcessorConfig(
model_source="Qwen/Qwen2.5-Omni-3B",
task_type="generate",
engine_kwargs=dict(
enforce_eager=True,
limit_mm_per_prompt={"audio": 1},
),
batch_size=16,
accelerator_type="L4",
concurrency=1,
prepare_multimodal_stage={
"enabled": True,
"chat_template_content_format": "openai",
},
chat_template_stage=True,
tokenize_stage=True,
detokenize_stage=True,
)
def run_omni_audio_example():
# __omni_audio_run_example_start__
"""Run the complete Omni audio example workflow."""
config = create_omni_audio_config()
audio_dataset = load_audio_dataset()
if audio_dataset:
# Build processor with preprocessing and postprocessing
processor = build_processor(
config, preprocess=audio_preprocess, postprocess=audio_postprocess
)
print("Omni audio processor configured successfully")
print(f"Model: {config.model_source}")
print(f"Has multimodal support: {config.prepare_multimodal_stage.get('enabled', False)}")
result = processor(audio_dataset).take_all()
return config, processor, result
# __omni_audio_run_example_end__
return None, None, None
# __omni_audio_example_end__
if __name__ == "__main__":
# Run the example Omni audio workflow only if GPU is available
try:
import torch
if torch.cuda.is_available():
run_omni_audio_example()
else:
print("Skipping Omni audio example run (no GPU available)")
except Exception as e:
print(f"Skipping Omni audio example run due to environment error: {e}")
@@ -0,0 +1,99 @@
"""
This file serves as a documentation example and CI test for OpenAI API batch inference.
"""
import os
from ray.data.llm import HttpRequestProcessorConfig, build_processor
def run_openai_example():
# __openai_example_start__
import ray
OPENAI_KEY = os.environ["OPENAI_API_KEY"]
ds = ray.data.from_items(["Hand me a haiku."])
config = HttpRequestProcessorConfig(
url="https://api.openai.com/v1/chat/completions",
headers={"Authorization": f"Bearer {OPENAI_KEY}"},
qps=1,
)
processor = build_processor(
config,
preprocess=lambda row: dict(
payload=dict(
model="gpt-4o-mini",
messages=[
{
"role": "system",
"content": "You are a bot that responds with haikus.",
},
{"role": "user", "content": row["item"]},
],
temperature=0.0,
max_tokens=150,
),
),
postprocess=lambda row: dict(
response=row["http_response"]["choices"][0]["message"]["content"]
),
)
ds = processor(ds)
print(ds.take_all())
# __openai_example_end__
def run_openai_demo():
"""Run the OpenAI API configuration demo."""
print("OpenAI API Configuration Demo")
print("=" * 30)
print("\nExample configuration:")
print("config = HttpRequestProcessorConfig(")
print(" url='https://api.openai.com/v1/chat/completions',")
print(" headers={'Authorization': f'Bearer {OPENAI_KEY}'},")
print(" qps=1,")
print(")")
print("\nThe processor handles:")
print("- Preprocessing: Convert text to OpenAI API format")
print("- HTTP requests: Send batched requests to OpenAI")
print("- Postprocessing: Extract response content")
def preprocess_for_openai(row):
"""Preprocess function for OpenAI API requests."""
return dict(
payload=dict(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": row["item"]},
],
temperature=0.0,
max_tokens=150,
)
)
def postprocess_openai_response(row):
"""Postprocess function for OpenAI API responses."""
return dict(response=row["http_response"]["choices"][0]["message"]["content"])
if __name__ == "__main__":
# Run live call if API key is set; otherwise show demo with mock output
if "OPENAI_API_KEY" in os.environ:
run_openai_example()
else:
# Mock response without API key
print(
[
{
"response": (
"Autumn leaves whisper\nSoft code flows in quiet lines\nBugs fall one by one"
)
}
]
)
@@ -0,0 +1,53 @@
"""
This file serves as a documentation example for aggregated tokenization.
"""
import ray
from ray.data.llm import (
vLLMEngineProcessorConfig,
build_processor,
TokenizerStageConfig,
DetokenizeStageConfig,
)
# __aggregated_tokenization_start__
config = vLLMEngineProcessorConfig(
model_source="unsloth/Llama-3.1-8B-Instruct",
engine_kwargs={"max_model_len": 4096},
concurrency=1,
batch_size=64,
tokenize_stage=TokenizerStageConfig(enabled=False),
detokenize_stage=DetokenizeStageConfig(enabled=False),
)
processor = build_processor(
config,
preprocess=lambda row: dict(
messages=[
{"role": "user", "content": row["item"]},
],
sampling_params=dict(
temperature=0.3,
max_tokens=250,
# Let the vLLM engine handle detokenization
detokenize=True,
),
),
postprocess=lambda row: dict(resp=row["generated_text"]),
)
# __aggregated_tokenization_end__
ds = ray.data.from_items(["Hello world!"])
if __name__ == "__main__":
try:
import torch
if torch.cuda.is_available():
ds = processor(ds)
ds.show(limit=1)
else:
print("Skipping aggregated run (no GPU available)")
except Exception as e:
print(f"Skipping aggregated run due to environment error: {e}")
@@ -0,0 +1,48 @@
"""
This file serves as a documentation example for disaggregated tokenization.
"""
import ray
from ray.data.llm import vLLMEngineProcessorConfig, build_processor
# __disaggregated_tokenization_start__
config = vLLMEngineProcessorConfig(
model_source="unsloth/Llama-3.1-8B-Instruct",
engine_kwargs={"max_model_len": 4096},
concurrency=1,
batch_size=64,
tokenize_stage=True,
detokenize_stage=True,
)
processor = build_processor(
config,
preprocess=lambda row: dict(
messages=[
{"role": "user", "content": row["item"]},
],
sampling_params=dict(
temperature=0.3,
max_tokens=250,
# Let the vLLMEngineProcessor's CPU detokenize stage handle detokenization
detokenize=False,
),
),
postprocess=lambda row: dict(resp=row["generated_text"]),
)
# __disaggregated_tokenization_end__
ds = ray.data.from_items(["Hello world!"])
if __name__ == "__main__":
try:
import torch
if torch.cuda.is_available():
ds = processor(ds)
ds.show(limit=1)
else:
print("Skipping disaggregated run (no GPU available)")
except Exception as e:
print(f"Skipping disaggregated run due to environment error: {e}")
@@ -0,0 +1,217 @@
"""
This file serves as a documentation example and CI test for VLM batch inference with images.
Structure:
1. Infrastructure setup: Dataset compatibility patches, dependency handling
2. Docs example (between __vlm_image_example_start/end__): Embedded in Sphinx docs via literalinclude
3. Test validation and cleanup
"""
'''
# __image_message_format_example_start__
"""Supported image input formats: image URL, PIL Image object"""
{
"messages": [
{
"role": "system",
"content": "Provide a detailed description of the image."
},
{
"role": "user",
"content": [
{"type": "text", "text": "Describe what happens in this image."},
# Option 1: Provide image URL
{"type": "image_url", "image_url": {"url": "https://example.com/image.jpg"}},
# Option 2: Provide PIL Image object
{"type": "image_pil", "image_pil": PIL.Image.open("path/to/image.jpg")}
]
},
]
}
# __image_message_format_example_end__
'''
# __vlm_image_example_start__
import ray
from PIL import Image
from io import BytesIO
from ray.data.llm import (
vLLMEngineProcessorConfig,
build_processor,
)
from huggingface_hub import HfFileSystem
# Load "LMMs-Eval-Lite" dataset from Hugging Face using HfFileSystem
path = "hf://datasets/lmms-lab/LMMs-Eval-Lite/coco2017_cap_val/"
fs = HfFileSystem()
vision_dataset = ray.data.read_parquet(path, filesystem=fs)
# __vlm_config_example_start__
vision_processor_config = vLLMEngineProcessorConfig(
model_source="Qwen/Qwen2.5-VL-3B-Instruct",
engine_kwargs=dict(
tensor_parallel_size=1,
pipeline_parallel_size=1,
max_model_len=4096,
trust_remote_code=True,
limit_mm_per_prompt={"image": 1},
),
batch_size=16,
concurrency=1,
prepare_multimodal_stage=True,
)
# __vlm_config_example_end__
# __vlm_preprocess_example_start__
def vision_preprocess(row: dict) -> dict:
"""
Preprocessing function for vision-language model inputs.
Converts dataset rows into the format expected by the VLM:
- System prompt for analysis instructions
- User message with text and image content
- Multiple choice formatting
- Sampling parameters
"""
choice_indices = ["A", "B", "C", "D", "E", "F", "G", "H"]
return {
"messages": [
{
"role": "system",
"content": (
"Analyze the image and question carefully, using step-by-step reasoning. "
"First, describe any image provided in detail. Then, present your reasoning. "
"And finally your final answer in this format: Final Answer: <answer> "
"where <answer> is: The single correct letter choice A, B, C, D, E, F, etc. when options are provided. "
"Only include the letter. Your direct answer if no options are given, as a single phrase or number. "
"IMPORTANT: Remember, to end your answer with Final Answer: <answer>."
),
},
{
"role": "user",
"content": [
{"type": "text", "text": row["question"] + "\n\n"},
{
"type": "image_pil",
"image_pil": Image.open(BytesIO(row["image"]["bytes"])),
},
{
"type": "text",
"text": "\n\nChoices:\n"
+ "\n".join(
[
f"{choice_indices[i]}. {choice}"
for i, choice in enumerate(row["answer"])
]
),
},
],
},
],
"sampling_params": {
"temperature": 0.3,
"max_tokens": 150,
"detokenize": False,
},
# Include original data for reference
"original_data": {
"question": row["question"],
"answer_choices": row["answer"],
"image_size": row["image"].get("width", 0) if row["image"] else 0,
},
}
def vision_postprocess(row: dict) -> dict:
return {
"resp": row["generated_text"],
}
# __vlm_preprocess_example_end__
def load_vision_dataset():
# __vlm_image_load_dataset_example_start__
"""
Load vision dataset from Hugging Face.
This function loads the LMMs-Eval-Lite dataset which contains:
- Images with associated questions
- Multiple choice answers
- Various visual reasoning tasks
"""
try:
from huggingface_hub import HfFileSystem
# Load "LMMs-Eval-Lite" dataset from Hugging Face using HfFileSystem
path = "hf://datasets/lmms-lab/LMMs-Eval-Lite/coco2017_cap_val/"
fs = HfFileSystem()
vision_dataset = ray.data.read_parquet(path, filesystem=fs)
return vision_dataset
except ImportError:
print(
"huggingface_hub package not available. Install with: pip install huggingface_hub"
)
return None
except Exception as e:
print(f"Error loading dataset: {e}")
return None
# __vlm_image_load_dataset_example_end__
def create_vlm_config():
"""Create VLM configuration."""
return vLLMEngineProcessorConfig(
model_source="Qwen/Qwen2.5-VL-3B-Instruct",
engine_kwargs=dict(
tensor_parallel_size=1,
pipeline_parallel_size=1,
max_model_len=4096,
trust_remote_code=True,
limit_mm_per_prompt={"image": 1},
),
batch_size=1,
concurrency=1,
prepare_multimodal_stage=True,
)
def run_vlm_example():
# __vlm_run_example_start__
"""Run the complete VLM example workflow."""
config = create_vlm_config()
vision_dataset = load_vision_dataset()
if vision_dataset:
# Build processor with preprocessing and postprocessing
processor = build_processor(
config, preprocess=vision_preprocess, postprocess=vision_postprocess
)
print("VLM processor configured successfully")
print(f"Model: {config.model_source}")
result = processor(vision_dataset).take_all()
return config, processor, result
# __vlm_run_example_end__
return None, None, None
# __vlm_image_example_end__
if __name__ == "__main__":
# Run the example VLM workflow only if GPU is available
try:
import torch
if torch.cuda.is_available():
run_vlm_example()
else:
print("Skipping VLM example run (no GPU available)")
except Exception as e:
print(f"Skipping VLM example run due to environment error: {e}")
@@ -0,0 +1,241 @@
"""
This file serves as a documentation example and CI test for VLM batch inference with videos.
Structure:
1. Infrastructure setup: Dataset compatibility patches, dependency handling
2. Docs example (between __vlm_video_example_start/end__): Embedded in Sphinx docs via literalinclude
3. Test validation and cleanup
"""
import os
'''
# __video_message_format_example_start__
"""Supported video input formats: video URL"""
{
"messages": [
{
"role": "system",
"content": "Provide a detailed description of the video."
},
{
"role": "user",
"content": [
{"type": "text", "text": "Describe what happens in this video."},
# Provide video URL
{"type": "video_url", "video_url": {"url": "https://example.com/video.mp4"}},
]
},
]
}
# __video_message_format_example_end__
'''
# __vlm_video_example_start__
import ray
from ray.data.llm import (
vLLMEngineProcessorConfig,
build_processor,
)
# __vlm_video_config_example_start__
video_processor_config = vLLMEngineProcessorConfig(
model_source="Qwen/Qwen3-VL-4B-Instruct",
engine_kwargs=dict(
tensor_parallel_size=4,
pipeline_parallel_size=1,
trust_remote_code=True,
limit_mm_per_prompt={"video": 1},
mm_processor_kwargs={
"size": {
"shortest_edge": 65536,
"longest_edge": 20 * 1088 * 1920,
},
"do_sample_frames": False,
},
),
batch_size=1,
accelerator_type="L4",
concurrency=1,
prepare_multimodal_stage={
"enabled": True,
"model_config_kwargs": dict(
# See available model config kwargs at https://docs.vllm.ai/en/latest/api/vllm/config/#vllm.config.ModelConfig
allowed_local_media_path="/tmp",
media_io_kwargs={"video": {"num_frames": 20, "fps": 2}},
),
},
chat_template_stage=True,
tokenize_stage=True,
detokenize_stage=True,
)
# __vlm_video_config_example_end__
# __vlm_video_preprocess_example_start__
def video_preprocess(row: dict) -> dict:
"""
Preprocessing function for video-language model inputs.
Converts dataset rows into the format expected by the VLM:
- System prompt for analysis instructions
- User message with text and video content
- Sampling parameters
- Multimodal processor kwargs for video processing
"""
return {
"messages": [
{
"role": "system",
"content": (
"You are a helpful assistant that analyzes videos. "
"Watch the video carefully and provide detailed descriptions."
),
},
{
"role": "user",
"content": [
{
"type": "text",
"text": row["text"],
},
{
"type": "video_url",
"video_url": {"url": row["video_url"]},
},
],
},
],
"sampling_params": {
"temperature": 0.3,
"max_tokens": 150,
"detokenize": False,
},
}
def video_postprocess(row: dict) -> dict:
return {
"resp": row["generated_text"],
}
# __vlm_video_preprocess_example_end__
def load_video_dataset():
# __vlm_video_load_dataset_example_start__
"""
Load video dataset from ShareGPTVideo Hugging Face dataset.
"""
try:
from huggingface_hub import hf_hub_download
import tarfile
from pathlib import Path
dataset_name = "ShareGPTVideo/train_raw_video"
tar_path = hf_hub_download(
repo_id=dataset_name,
filename="activitynet/chunk_0.tar.gz",
repo_type="dataset",
)
extract_dir = "/tmp/sharegpt_videos"
os.makedirs(extract_dir, exist_ok=True)
if not any(Path(extract_dir).glob("*.mp4")):
with tarfile.open(tar_path, "r:gz") as tar:
tar.extractall(extract_dir)
video_files = list(Path(extract_dir).rglob("*.mp4"))
# Limit to first 10 videos for the example
video_files = video_files[:10]
video_dataset = ray.data.from_items(
[
{
"video_path": str(video_file),
"video_url": f"file://{video_file}",
"text": "Describe what happens in this video.",
}
for video_file in video_files
]
)
return video_dataset
except Exception as e:
print(f"Error loading dataset: {e}")
return None
# __vlm_video_load_dataset_example_end__
def create_vlm_video_config():
"""Create VLM video configuration."""
return vLLMEngineProcessorConfig(
model_source="Qwen/Qwen3-VL-4B-Instruct",
engine_kwargs=dict(
tensor_parallel_size=4,
pipeline_parallel_size=1,
trust_remote_code=True,
limit_mm_per_prompt={"video": 1},
mm_processor_kwargs={
"size": {
"shortest_edge": 65536,
"longest_edge": 20 * 1088 * 1920,
},
"do_sample_frames": False,
},
),
batch_size=1,
accelerator_type="L4",
concurrency=1,
prepare_multimodal_stage={
"enabled": True,
"model_config_kwargs": dict(
# See available model config kwargs at https://docs.vllm.ai/en/latest/api/vllm/config/#vllm.config.ModelConfig
allowed_local_media_path="/tmp",
media_io_kwargs={"video": {"num_frames": 20, "fps": 2}},
),
},
chat_template_stage=True,
tokenize_stage=True,
detokenize_stage=True,
)
def run_vlm_video_example():
# __vlm_video_run_example_start__
"""Run the complete VLM video example workflow."""
config = create_vlm_video_config()
video_dataset = load_video_dataset()
if video_dataset:
# Build processor with preprocessing and postprocessing
processor = build_processor(
config, preprocess=video_preprocess, postprocess=video_postprocess
)
print("VLM video processor configured successfully")
print(f"Model: {config.model_source}")
print(f"Has multimodal support: {config.prepare_multimodal_stage.get('enabled', False)}")
result = processor(video_dataset).take_all()
return config, processor, result
# __vlm_video_run_example_end__
return None, None, None
# __vlm_video_example_end__
if __name__ == "__main__":
# Run the example VLM video workflow only if GPU is available
try:
import torch
if torch.cuda.is_available():
run_vlm_video_example()
else:
print("Skipping VLM video example run (no GPU available)")
except Exception as e:
print(f"Skipping VLM video example run due to environment error: {e}")