Files
vllm-omni/vllm_omni/diffusion/sched/step_scheduler.py
T
e49fbd8a2d [Feat] DiffusionEngine Support async batch infer (#2729)
Signed-off-by: Semmer <semmer@live.cn>
Signed-off-by: jader <yjader@foxmail.com>
Signed-off-by: asukaqaq-s <1311722138@qq.com>
Co-authored-by: asukaqaq-s <1311722138@qq.com>
Co-authored-by: jader <yjader@foxmail.com>
Co-authored-by: Hongsheng Liu <liuhongsheng4@huawei.com>
Co-authored-by: Gao Han <hgaoaf@connect.ust.hk>
2026-05-06 09:47:13 +12:00

140 lines
5.3 KiB
Python

# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
from __future__ import annotations
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any
from vllm.logger import init_logger
from vllm_omni.diffusion.request import OmniDiffusionRequest
from vllm_omni.diffusion.sched.base_scheduler import _BaseScheduler
from vllm_omni.diffusion.sched.interface import (
DiffusionRequestStatus,
DiffusionSchedulerOutput,
)
if TYPE_CHECKING:
from vllm_omni.diffusion.worker.utils import RunnerOutput
logger = init_logger(__name__)
@dataclass
class _StepProgress:
current_step: int
total_steps: int
class StepScheduler(_BaseScheduler):
"""Placeholder scheduler that advances a request one denoise step per update."""
def __init__(self) -> None:
super().__init__()
self._request_progress: dict[str, _StepProgress] = {}
def _reset_scheduler_state(self) -> None:
self._request_progress.clear()
def add_request(self, request: OmniDiffusionRequest) -> str:
sched_req_id = self._make_sched_req_id(request)
total_steps = self._get_total_steps(request)
if total_steps <= 0:
raise ValueError(f"Diffusion request {sched_req_id} must have positive total_steps, got {total_steps}")
current_step = request.sampling_params.step_index or 0
if current_step < 0 or current_step >= total_steps:
raise ValueError(
f"Diffusion request {sched_req_id} has invalid initial step_index {current_step} "
f"for total_steps={total_steps}"
)
request.sampling_params.step_index = current_step
sched_req_id = self._add_request_with_sched_req_id(sched_req_id, request)
self._request_progress[sched_req_id] = _StepProgress(current_step=current_step, total_steps=total_steps)
logger.debug(
"StepScheduler add_request: %s (step=%d/%d, waiting=%d)",
sched_req_id,
current_step,
total_steps,
len(self._waiting),
)
return sched_req_id
def schedule(self) -> DiffusionSchedulerOutput:
return super().schedule()
def update_from_output(self, sched_output: DiffusionSchedulerOutput, output: RunnerOutput) -> set[str]:
scheduled_req_ids = sched_output.scheduled_req_ids
if not scheduled_req_ids:
return set()
terminal_statuses: dict[str, DiffusionRequestStatus] = {}
terminal_errors: dict[str, str | None] = {}
for sched_req_id in scheduled_req_ids:
state = self._request_states.get(sched_req_id)
progress = self._request_progress.get(sched_req_id)
if state is None or progress is None or state.is_finished():
continue
req_output = output.get_req_output(sched_req_id)
if req_output is None:
logger.warning(
"No RunnerOutput for request %s, treating as error",
sched_req_id,
)
terminal_statuses[sched_req_id] = DiffusionRequestStatus.FINISHED_ERROR
terminal_errors[sched_req_id] = "No output for request"
continue
req_result = req_output.result
output_error = req_result.error if req_result is not None else None
if output_error is not None:
terminal_statuses[sched_req_id] = DiffusionRequestStatus.FINISHED_ERROR
terminal_errors[sched_req_id] = output_error
continue
if req_output.step_index is None:
logger.warning(
"Received RunnerOutput with no step_index for request %s, treating as error",
sched_req_id,
)
terminal_statuses[sched_req_id] = DiffusionRequestStatus.FINISHED_ERROR
terminal_errors[sched_req_id] = "Missing step_index in RunnerOutput"
continue
# We assume that the decoding stage is executed immediately after the denoising stage completes.
progress.current_step = req_output.step_index
state.req.sampling_params.step_index = req_output.step_index
if req_output.finished:
terminal_statuses[sched_req_id] = DiffusionRequestStatus.FINISHED_COMPLETED
terminal_errors[sched_req_id] = None
else:
state.error = None
return self._finalize_update_from_output(sched_output, terminal_statuses, terminal_errors)
def _pop_extra_request_state(self, sched_req_id: str) -> None:
self._request_progress.pop(sched_req_id, None)
def _get_total_steps(self, request: OmniDiffusionRequest) -> int:
sampling = request.sampling_params
if sampling.timesteps is not None:
return self._sequence_length(sampling.timesteps)
if sampling.sigmas is not None:
return len(sampling.sigmas)
return int(sampling.num_inference_steps)
@staticmethod
def _sequence_length(values: Any) -> int:
ndim = getattr(values, "ndim", None)
if ndim == 0:
return 1
shape = getattr(values, "shape", None)
if shape is not None:
return int(shape[0])
return len(values)