[Feature] Add HunyuanImage3 DiT grouped step batching (#4041)
Signed-off-by: TaffyOfficial <2324465096@qq.com> Signed-off-by: zuiho <2324465096@qq.com> Co-authored-by: TaffyOfficial <2324465096@qq.com> Co-authored-by: Gao Han <hgaoaf@connect.ust.hk> Co-authored-by: Hongsheng Liu <liuhongsheng4@huawei.com>
This commit is contained in:
7 files changed
+1337
-76
No files matched your search
File diff suppressed because it is too large.
Load diff
@@ -16,6 +16,7 @@ if TYPE_CHECKING:
|
||||
import torch
|
||||
|
||||
from vllm_omni.diffusion.data import DiffusionOutput
|
||||
from vllm_omni.diffusion.worker.input_batch import InputBatch
|
||||
from vllm_omni.diffusion.worker.utils import DiffusionRequestState
|
||||
|
||||
|
||||
@@ -56,8 +57,8 @@ class SupportsStepExecution(Protocol):
|
||||
def prepare_encode(self, state: DiffusionRequestState, **kwargs: Any) -> DiffusionRequestState:
|
||||
"""Prepare request-level inputs and return initialized state."""
|
||||
|
||||
def denoise_step(self, state: DiffusionRequestState, **kwargs: Any) -> torch.Tensor | None:
|
||||
"""Run one denoise step."""
|
||||
def denoise_step(self, input_batch: InputBatch, **kwargs: Any) -> torch.Tensor | None:
|
||||
"""Run one denoise forward on the runner-assembled batch."""
|
||||
|
||||
def step_scheduler(self, state: DiffusionRequestState, noise_pred: torch.Tensor, **kwargs: Any) -> None:
|
||||
"""Run one scheduler step."""
|
||||
|
||||
@@ -374,6 +374,13 @@ class DiffusionModelRunner(OmniConnectorModelRunnerMixin):
|
||||
sampling=copy.deepcopy(req.sampling_params),
|
||||
prompts=req.prompts,
|
||||
)
|
||||
state_req = copy.copy(req)
|
||||
state_req.sampling_params = new_state.sampling
|
||||
self.kv_transfer_manager.receive_multi_kv_cache_distributed(
|
||||
state_req,
|
||||
cfg_kv_collect_func=getattr(self.od_config, "cfg_kv_collect_func", None),
|
||||
target_device=getattr(self.pipeline, "device", None),
|
||||
)
|
||||
self.state_cache[request_id] = new_state
|
||||
resolved.append(new_state)
|
||||
|
||||
@@ -452,8 +459,8 @@ class DiffusionModelRunner(OmniConnectorModelRunnerMixin):
|
||||
if not self.supports_step_mode():
|
||||
raise ValueError("Current pipeline does not support step execution.")
|
||||
# Stepwise mode only supports the basic state-driven denoise path for now.
|
||||
# Request-mode extras such as cache backends, KV transfer, editing inputs,
|
||||
# and similar features are not supported here yet.
|
||||
# Request-mode extras such as cache backends, editing inputs, and
|
||||
# similar features are not supported here yet.
|
||||
if self.od_config.cache_backend not in (None, "none"):
|
||||
raise ValueError("Step mode does not support cache_backend yet.")
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ step, and step outputs are scattered back into request states by
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Sequence
|
||||
from dataclasses import dataclass
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
import numpy as np
|
||||
import torch
|
||||
@@ -496,7 +496,7 @@ def _prepare_prompt_embeds(
|
||||
*,
|
||||
embeds_out: torch.Tensor | None = None,
|
||||
mask_out: torch.Tensor | None = None,
|
||||
) -> tuple[torch.Tensor, torch.Tensor | None]:
|
||||
) -> tuple[torch.Tensor | None, torch.Tensor | None]:
|
||||
prompt_embeds, prompt_embeds_mask = _prepare_padded_prompt_fields(
|
||||
states,
|
||||
embeds_attr="prompt_embeds",
|
||||
@@ -505,8 +505,6 @@ def _prepare_prompt_embeds(
|
||||
embeds_out=embeds_out,
|
||||
mask_out=mask_out,
|
||||
)
|
||||
if prompt_embeds is None:
|
||||
raise ValueError("All requests must have `prompt_embeds` initialized.")
|
||||
return prompt_embeds, prompt_embeds_mask
|
||||
|
||||
|
||||
@@ -581,6 +579,10 @@ class InputBatch:
|
||||
source of truth. ``InputBatch`` only assembles a contiguous view for the
|
||||
current step and refreshes dynamic fields in-place when composition is
|
||||
unchanged.
|
||||
|
||||
``states`` is a narrow escape hatch for Hunyuan-style state-driven
|
||||
pipelines that need request-private KV/cache metadata during denoise.
|
||||
Other pipelines should continue to use the standard batch fields.
|
||||
"""
|
||||
|
||||
request_ids: list[str]
|
||||
@@ -591,7 +593,7 @@ class InputBatch:
|
||||
|
||||
latents: torch.Tensor
|
||||
timesteps: torch.Tensor
|
||||
prompt_embeds: torch.Tensor
|
||||
prompt_embeds: torch.Tensor | None
|
||||
prompt_embeds_mask: torch.Tensor | None
|
||||
negative_prompt_embeds: torch.Tensor | None
|
||||
negative_prompt_embeds_mask: torch.Tensor | None
|
||||
@@ -604,6 +606,7 @@ class InputBatch:
|
||||
img_shapes: list | None = None
|
||||
txt_seq_lens: list[int] | None = None
|
||||
negative_txt_seq_lens: list[int] | None = None
|
||||
states: Sequence[DiffusionRequestState] = field(default_factory=tuple)
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if len(self.request_ids) != int(self.idx_mapping.numel()):
|
||||
@@ -648,6 +651,9 @@ class InputBatch:
|
||||
self,
|
||||
selected_states: Sequence[DiffusionRequestState],
|
||||
) -> None:
|
||||
# Same-composition cache hits reuse static prompt fields; request ids
|
||||
# must keep the same encoded prompt metadata for the batch lifetime.
|
||||
self.states = tuple(selected_states)
|
||||
self._refresh_dynamic_fields(selected_states)
|
||||
|
||||
def _rebuild(
|
||||
@@ -662,6 +668,7 @@ class InputBatch:
|
||||
self.num_reqs_after_padding = len(request_ids)
|
||||
self.idx_mapping = idx_mapping
|
||||
self.idx_mapping_np = idx_mapping_np
|
||||
self.states = tuple(selected_states)
|
||||
self.latents = _prepare_latents(selected_states, out=self.latents)
|
||||
self.timesteps = _prepare_timesteps(selected_states, out=self.timesteps)
|
||||
self._refresh_static_fields(selected_states)
|
||||
@@ -718,6 +725,7 @@ class InputBatch:
|
||||
selected_states,
|
||||
"negative_txt_seq_lens",
|
||||
),
|
||||
states=tuple(selected_states),
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user