[Feature][MiniMax-H3] Support diffusion continuous batching (#5810)
Signed-off-by: princepride <wangzhipeng628@gmail.com> Signed-off-by: lishunyang12 <lishunyang12@163.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: lishunyang12 <lishunyang12@163.com> Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
15 files changed
+1834
-140
No files matched your search
@@ -47,6 +47,7 @@ from vllm_omni.diffusion.worker.diffusion_worker import DiffusionWorker
|
||||
from vllm_omni.diffusion.worker.input_batch import InputBatch
|
||||
from vllm_omni.diffusion.worker.utils import RunnerOutput, StepRequestState
|
||||
from vllm_omni.engine.async_omni_engine import AsyncOmniEngine
|
||||
from vllm_omni.errors import OmniClientError
|
||||
from vllm_omni.inputs.data import OmniDiffusionSamplingParams
|
||||
from vllm_omni.platforms import current_omni_platform
|
||||
|
||||
@@ -102,6 +103,22 @@ class _StepPipeline:
|
||||
return DiffusionOutput(output=torch.tensor([state.step_index], dtype=torch.float32))
|
||||
|
||||
|
||||
class _PerRequestErrorStepPipeline(_StepPipeline):
|
||||
def prepare_encode(self, state, **kwargs):
|
||||
if state.prompt == "fail-prepare":
|
||||
raise OmniClientError(
|
||||
"invalid request input",
|
||||
status_code=422,
|
||||
error_type="UnprocessableEntityError",
|
||||
)
|
||||
return super().prepare_encode(state, **kwargs)
|
||||
|
||||
def denoise_step(self, input_batch, **kwargs):
|
||||
del kwargs
|
||||
self.denoise_calls += 1
|
||||
return torch.ones_like(input_batch.latents)
|
||||
|
||||
|
||||
class _ProfilingStepPipeline(_StepPipeline):
|
||||
enable_diffusion_pipeline_profiler = True
|
||||
|
||||
@@ -697,6 +714,72 @@ class TestRunner:
|
||||
result = DiffusionModelRunner.execute_stepwise(runner, scheduler_output)
|
||||
assert len(result) == 2
|
||||
|
||||
def test_prepare_error_isolated_from_healthy_request(self, monkeypatch):
|
||||
runner = _make_runner()
|
||||
runner.pipeline = _PerRequestErrorStepPipeline()
|
||||
bad_req = _make_step_request()
|
||||
bad_req.request_id = "req-bad"
|
||||
bad_req.prompt = "fail-prepare"
|
||||
good_req = _make_step_request()
|
||||
good_req.request_id = "req-good"
|
||||
good_req.prompt = "valid"
|
||||
monkeypatch.setattr(model_runner_module, "set_forward_context", _noop_forward_context)
|
||||
|
||||
result = DiffusionModelRunner.execute_stepwise(
|
||||
runner,
|
||||
_make_batch_scheduler_output([bad_req, good_req]),
|
||||
)
|
||||
|
||||
bad_output = result.get_request_output("req-bad")
|
||||
assert bad_output.finished is True
|
||||
assert bad_output.result is not None
|
||||
assert bad_output.result.error == "invalid request input"
|
||||
assert bad_output.result.error_status_code == 422
|
||||
assert bad_output.result.error_type == "UnprocessableEntityError"
|
||||
good_output = result.get_request_output("req-good")
|
||||
assert good_output.finished is False
|
||||
assert good_output.step_index == 1
|
||||
assert good_output.result is None
|
||||
assert set(runner.state_cache) == {"req-good"}
|
||||
assert runner.pipeline.denoise_calls == 1
|
||||
assert runner.pipeline.scheduler_calls == 1
|
||||
|
||||
def test_prepare_error_on_other_rank_is_isolated_via_all_reduce(self, monkeypatch):
|
||||
"""P1-B: rank-0-only pipeline work (e.g. H3 reference-video prep)
|
||||
can raise on rank 0 while non-zero ranks return cleanly and then hang
|
||||
on a downstream ``dist.broadcast``. Beyond the pipeline-side guard,
|
||||
the runner all-reduces a per-request failure flag across the DiT
|
||||
group so a rank that ``prepare_encode`` returned cleanly on still
|
||||
skips the request and does not enter the denoise step batch.
|
||||
"""
|
||||
runner = _make_runner()
|
||||
runner.pipeline = _StepPipeline() # locally always succeeds
|
||||
monkeypatch.setattr(model_runner_module, "set_forward_context", _noop_forward_context)
|
||||
|
||||
# Simulate a peer DiT rank having reported failure. We patch the
|
||||
# helper directly (rather than ``torch.distributed`` broadly) because
|
||||
# ``execute_stepwise`` also queries ``torch.distributed.get_rank``.
|
||||
monkeypatch.setattr(
|
||||
model_runner_module,
|
||||
"_dit_any_rank_failed",
|
||||
lambda local_failed: True,
|
||||
)
|
||||
|
||||
req = _make_step_request(num_inference_steps=1)
|
||||
result = DiffusionModelRunner.execute_stepwise(
|
||||
runner,
|
||||
_make_scheduler_output(req),
|
||||
)
|
||||
|
||||
output = result.get_request_output("req-1")
|
||||
assert output.finished is True
|
||||
assert output.result is not None
|
||||
assert output.result.error is not None
|
||||
assert "another DiT rank" in output.result.error
|
||||
# A rank that skipped the request must not have driven a denoise step.
|
||||
assert runner.pipeline.denoise_calls == 0
|
||||
assert runner.state_cache == {}
|
||||
|
||||
def test_receives_kv_payload_before_prepare_encode(self, monkeypatch):
|
||||
runner = _make_runner()
|
||||
captured: dict[str, object] = {}
|
||||
|
||||
Reference in new issue
Block a user