Update vLLM precompiled wheel version and refactor various components for improved functionality and error handling. Changes include modifying the get_name method in DiffusionQuantizationConfig to use class-level attributes, enhancing metadata handling in StageEngineCoreClient, and adjusting the AsyncOmni class constructor for better parameter management. Additionally, improved error handling in omni_snapshot_download and optimized initial chunk size computation in talker2code2wav_async_chunk for dynamic load adaptation.

Signed-off-by: tzhouam <tzhouam@connect.ust.hk>
This commit is contained in:
tzhouam committed 2026-03-19 05:14:34 +00:00
1 parent 4f75cccacc
commit 034d579d77
7 files changed
+61 -42

No files matched your search

+1 -1
View File
@@ -16,7 +16,7 @@ RUN uv pip uninstall --system -y vllm || true
# Install vLLM from precompiled wheel at the selected commit. # Install vLLM from precompiled wheel at the selected commit.
# Must use direct URL because the wheel has a PEP 440 local version identifier # Must use direct URL because the wheel has a PEP 440 local version identifier
# (e.g. +g0a0a1a198) which pip/uv refuse to install from a PEP 503 package index. # (e.g. +g0a0a1a198) which pip/uv refuse to install from a PEP 503 package index.
ENV VLLM_PRECOMPILED_WHEEL_COMMIT=0a0a1a198be88e1782b52fa31738896468200a76 ENV VLLM_PRECOMPILED_WHEEL_COMMIT=89138b21cc246ae944c741d5c399c148e2b770ab
RUN VLLM_WHEEL_URL=$(python3 -c "import urllib.request,re; \ RUN VLLM_WHEEL_URL=$(python3 -c "import urllib.request,re; \
html=urllib.request.urlopen('https://wheels.vllm.ai/${VLLM_PRECOMPILED_WHEEL_COMMIT}/vllm/').read().decode(); \ html=urllib.request.urlopen('https://wheels.vllm.ai/${VLLM_PRECOMPILED_WHEEL_COMMIT}/vllm/').read().decode(); \
m=re.search(r'>(\S+x86_64\.whl)<',html); \ m=re.search(r'>(\S+x86_64\.whl)<',html); \
+6 -5
View File
@@ -31,14 +31,15 @@ class DiffusionQuantizationConfig(ABC):
# The underlying vLLM config instance # The underlying vLLM config instance
_vllm_config: "QuantizationConfig | None" = None _vllm_config: "QuantizationConfig | None" = None
def get_name(self) -> str: @classmethod
def get_name(cls) -> str:
"""Return the quantization method name (e.g., 'fp8', 'int8'). """Return the quantization method name (e.g., 'fp8', 'int8').
By default, delegates to the underlying vLLM config instance. Delegates to the underlying vLLM config class's get_name().
""" """
if self._vllm_config is not None: if cls.quant_config_cls is not None:
return self._vllm_config.get_name() return cls.quant_config_cls.get_name()
raise NotImplementedError("Subclass must initialize _vllm_config or override get_name().") raise NotImplementedError("Subclass must set quant_config_cls or override get_name().")
def get_vllm_quant_config(self) -> "QuantizationConfig | None": def get_vllm_quant_config(self) -> "QuantizationConfig | None":
"""Return the underlying vLLM QuantizationConfig for linear layers.""" """Return the underlying vLLM QuantizationConfig for linear layers."""
+20 -13
View File
@@ -38,8 +38,12 @@ class StageEngineCoreClient(AsyncMPClient):
self, self,
vllm_config: Any, vllm_config: Any,
executor_class: type, executor_class: type,
metadata: StageMetadata, log_stats: bool = False,
client_addresses: dict[str, str] | None = None, client_addresses: dict[str, str] | None = None,
client_count: int = 1,
client_index: int = 0,
*,
metadata: StageMetadata | None = None,
engine_manager: Any = None, engine_manager: Any = None,
coordinator: Any = None, coordinator: Any = None,
): ):
@@ -51,17 +55,18 @@ class StageEngineCoreClient(AsyncMPClient):
and calls super().__init__(). and calls super().__init__().
""" """
# -------- Stage metadata (public fields used at runtime) -------- # -------- Stage metadata (public fields used at runtime) --------
self.stage_id = metadata.stage_id if metadata is not None:
self.stage_type = metadata.stage_type self.stage_id = metadata.stage_id
self.engine_output_type = metadata.engine_output_type self.stage_type = metadata.stage_type
self.is_comprehension = metadata.is_comprehension self.engine_output_type = metadata.engine_output_type
self.requires_multimodal_data = metadata.requires_multimodal_data self.is_comprehension = metadata.is_comprehension
self.engine_input_source = metadata.engine_input_source self.requires_multimodal_data = metadata.requires_multimodal_data
self.final_output = metadata.final_output self.engine_input_source = metadata.engine_input_source
self.final_output_type = metadata.final_output_type self.final_output = metadata.final_output
self.default_sampling_params = metadata.default_sampling_params self.final_output_type = metadata.final_output_type
self.custom_process_input_func = metadata.custom_process_input_func self.default_sampling_params = metadata.default_sampling_params
self.model_stage = metadata.model_stage self.custom_process_input_func = metadata.custom_process_input_func
self.model_stage = metadata.model_stage
self.engine_outputs: Any = None self.engine_outputs: Any = None
@@ -73,8 +78,10 @@ class StageEngineCoreClient(AsyncMPClient):
super().__init__( super().__init__(
vllm_config, vllm_config,
executor_class, executor_class,
log_stats=False, log_stats=log_stats,
client_addresses=client_addresses, client_addresses=client_addresses,
client_count=client_count,
client_index=client_index,
) )
if engine_manager is not None: if engine_manager is not None:
self.resources.engine_manager = engine_manager self.resources.engine_manager = engine_manager
+16 -5
View File
@@ -29,6 +29,7 @@ from vllm_omni.outputs import OmniRequestOutput
if TYPE_CHECKING: if TYPE_CHECKING:
from vllm.inputs.preprocess import InputPreprocessor from vllm.inputs.preprocess import InputPreprocessor
from vllm.tokenizers import TokenizerLike from vllm.tokenizers import TokenizerLike
from vllm.v1.engine import PauseMode
from vllm_omni.inputs.data import OmniPromptType, OmniSamplingParams from vllm_omni.inputs.data import OmniPromptType, OmniSamplingParams
@@ -66,7 +67,7 @@ class AsyncOmni(EngineClient, OmniBase):
... print(output) ... print(output)
""" """
def __init__(self, model: str, **kwargs: Any) -> None: def __init__(self, *args: Any, model: str = "", **kwargs: Any) -> None:
OmniBase.__init__(self, model=model, **kwargs) OmniBase.__init__(self, model=model, **kwargs)
self._pause_cond: asyncio.Condition = asyncio.Condition() self._pause_cond: asyncio.Condition = asyncio.Condition()
self._paused: bool = False self._paused: bool = False
@@ -130,9 +131,17 @@ class AsyncOmni(EngineClient, OmniBase):
async def generate( async def generate(
self, self,
prompt: OmniPromptType, prompt: OmniPromptType,
request_id: str, sampling_params: Any = None,
sampling_params_list: Sequence[OmniSamplingParams] | None = None, request_id: str = "",
*, *,
prompt_text: str | None = None,
lora_request: Any = None,
tokenization_kwargs: dict[str, Any] | None = None,
trace_headers: Any = None,
priority: int = 0,
data_parallel_rank: int | None = None,
reasoning_ended: bool | None = None,
sampling_params_list: Sequence[OmniSamplingParams] | None = None,
output_modalities: list[str] | None = None, output_modalities: list[str] | None = None,
) -> AsyncGenerator[OmniRequestOutput, None]: ) -> AsyncGenerator[OmniRequestOutput, None]:
"""Generate outputs for the given prompt asynchronously. """Generate outputs for the given prompt asynchronously.
@@ -226,6 +235,7 @@ class AsyncOmni(EngineClient, OmniBase):
trace_headers: dict[str, str] | None = None, trace_headers: dict[str, str] | None = None,
priority: int = 0, priority: int = 0,
tokenization_kwargs: dict[str, Any] | None = None, tokenization_kwargs: dict[str, Any] | None = None,
reasoning_ended: bool | None = None,
) -> AsyncGenerator[PoolingRequestOutput, None]: ) -> AsyncGenerator[PoolingRequestOutput, None]:
"""EngineClient.encode() stub. """EngineClient.encode() stub.
@@ -396,6 +406,7 @@ class AsyncOmni(EngineClient, OmniBase):
async def pause_generation( async def pause_generation(
self, self,
*, *,
mode: PauseMode = "abort",
wait_for_inflight_requests: bool = False, wait_for_inflight_requests: bool = False,
clear_cache: bool = True, clear_cache: bool = True,
) -> None: ) -> None:
@@ -467,7 +478,7 @@ class AsyncOmni(EngineClient, OmniBase):
logger.warning("[AsyncOmni] reset_prefix_cache not yet supported with Orchestrator process") logger.warning("[AsyncOmni] reset_prefix_cache not yet supported with Orchestrator process")
return True return True
async def sleep(self, level: int = 1) -> None: async def sleep(self, level: int = 1, mode: PauseMode = "abort") -> None:
"""Sleep all stages. """Sleep all stages.
Best-effort: unsupported stages will emit a TODO result. Best-effort: unsupported stages will emit a TODO result.
@@ -584,7 +595,7 @@ class AsyncOmni(EngineClient, OmniBase):
# ==================== Shutdown ==================== # ==================== Shutdown ====================
def shutdown(self) -> None: def shutdown(self, timeout: float | None = None) -> None:
"""Shutdown the engine.""" """Shutdown the engine."""
if self.final_output_task is not None: if self.final_output_task is not None:
self.final_output_task.cancel() self.final_output_task.cancel()
+5
View File
@@ -53,6 +53,11 @@ def omni_snapshot_download(model_id: str) -> str:
) )
except huggingface_hub.errors.RepositoryNotFoundError: except huggingface_hub.errors.RepositoryNotFoundError:
logger.warning("Repository not found for '%s'.", model_id) logger.warning("Repository not found for '%s'.", model_id)
except PermissionError:
logger.warning(
"Permission denied when downloading '%s'. Assuming the model is already cached locally.",
model_id,
)
return model_id return model_id
@@ -155,8 +155,7 @@ class Qwen3Omni_VisionTransformer(_Qwen3Omni_VisionTransformer):
cu_seqlens = F.pad(cu_seqlens, (1, 0), value=0) cu_seqlens = F.pad(cu_seqlens, (1, 0), value=0)
except RuntimeError: except RuntimeError:
logger.warning( logger.warning(
"torch.repeat_interleave not executable, " "torch.repeat_interleave not executable, switching to vectorized searchsorted implementation."
"switching to vectorized searchsorted implementation."
) )
repeat_counts = grid_thw_tensor[:, 0] repeat_counts = grid_thw_tensor[:, 0]
values = grid_thw_tensor[:, 1] * grid_thw_tensor[:, 2] values = grid_thw_tensor[:, 1] * grid_thw_tensor[:, 2]
@@ -179,9 +178,9 @@ class Qwen3Omni_VisionTransformer(_Qwen3Omni_VisionTransformer):
max_seqlen = self.compute_attn_mask_seqlen(cu_seqlens) max_seqlen = self.compute_attn_mask_seqlen(cu_seqlens)
grid_thw_np = grid_thw_tensor.cpu().numpy().astype(np.int32) grid_thw_np = grid_thw_tensor.cpu().numpy().astype(np.int32)
cu_seqlens_np = np.repeat( cu_seqlens_np = np.repeat(grid_thw_np[:, 1] * grid_thw_np[:, 2], grid_thw_np[:, 0]).cumsum(
grid_thw_np[:, 1] * grid_thw_np[:, 2], grid_thw_np[:, 0] axis=0, dtype=np.int32
).cumsum(axis=0, dtype=np.int32) )
cu_seqlens_np = np.concatenate([np.zeros(1, dtype=np.int32), cu_seqlens_np]) cu_seqlens_np = np.concatenate([np.zeros(1, dtype=np.int32), cu_seqlens_np])
sequence_lengths = MMEncoderAttention.maybe_compute_seq_lens( sequence_lengths = MMEncoderAttention.maybe_compute_seq_lens(
self.attn_backend, self.attn_backend,
@@ -116,18 +116,12 @@ def talker2code2wav_async_chunk(
initial_chunk_size = int(entry.list_data[0]) initial_chunk_size = int(entry.list_data[0])
per_request_override = True per_request_override = True
# Dynamic IC: cache per request so boundaries stay stable for its lifetime. # Dynamic IC: recalculate each call so IC adapts to current load.
if not per_request_override: if not per_request_override:
_ic_cache = getattr(transfer_manager, "_cached_ic", None) max_ic = max_ic_for_chunk_size(chunk_size)
if _ic_cache is None: active = sum(1 for v in transfer_manager.code_prompt_token_ids.values() if len(v) > 0)
_ic_cache = {} capacity = getattr(transfer_manager, "scheduler_max_num_seqs", 1)
transfer_manager._cached_ic = _ic_cache initial_chunk_size = compute_dynamic_initial_chunk_size(active, capacity, max_ic)
if request_id not in _ic_cache:
max_ic = max_ic_for_chunk_size(chunk_size)
active = sum(1 for v in transfer_manager.code_prompt_token_ids.values() if len(v) > 0)
capacity = getattr(transfer_manager, "scheduler_max_num_seqs", 1)
_ic_cache[request_id] = compute_dynamic_initial_chunk_size(active, capacity, max_ic)
initial_chunk_size = _ic_cache[request_id]
if chunk_size <= 0 or left_context_size_config < 0 or initial_chunk_size < 0: if chunk_size <= 0 or left_context_size_config < 0 or initial_chunk_size < 0:
raise ValueError( raise ValueError(
@@ -145,11 +139,13 @@ def talker2code2wav_async_chunk(
initial_chunk_size = chunk_size initial_chunk_size = chunk_size
length = len(transfer_manager.code_prompt_token_ids[request_id]) length = len(transfer_manager.code_prompt_token_ids[request_id])
finished_tensor = torch.tensor(finished, dtype=torch.bool)
if length <= 0: if length <= 0:
if finished: if finished:
return { return {
"code_predictor_codes": [], "code_predictor_codes": [],
"finished": True, "finished": finished_tensor,
} }
return None return None
@@ -197,5 +193,5 @@ def talker2code2wav_async_chunk(
return { return {
"code_predictor_codes": code_predictor_codes, "code_predictor_codes": code_predictor_codes,
"left_context_size": left_context_size, "left_context_size": left_context_size,
"finished": finished, "finished": finished_tensor,
} }