Skip to content

[Model] Add HiDream-O1-Image support (text-to-image, editing, personalization, layout-bbox) - #5306

Closed
SOKOUDJOU-LEOPOLD wants to merge 19 commits into
vllm-project:mainfrom
SOKOUDJOU-LEOPOLD:leopold/Add-HiDream-O1-Image
Closed

SOKOUDJOU-LEOPOLD wants to merge 19 commits into
vllm-project:mainfrom
SOKOUDJOU-LEOPOLD:leopold/Add-HiDream-O1-Image

Conversation

@SOKOUDJOU-LEOPOLD

Copy link
Copy Markdown

Purpose

This PR adds support for HiDream-O1-Image (HiDream-ai/HiDream-O1-Image and HiDream-ai/HiDream-O1-Image-Dev), a ~8B-parameter image generation model from HiDream.ai. It supports text-to-image, instruction-based image editing, multi-reference subject personalization, and layout-bbox spatial conditioning — all in a single model with no VAE and no separate text encoder.

Why

HiDream-O1-Image has an architecture that nothing in vLLM-Omni currently handles:

  • No VAE. The model diffuses directly on raw 32×32 pixel patches. Output is assembled from final hidden states with no latent encoder/decoder.
  • No separate text encoder. A single Qwen3-VL backbone handles everything — causal attention over text for conditioning, bidirectional attention over image tokens for the diffusion pass. This is called a Pixel-level Unified Transformer (UiT).
  • Timestep conditioning via token substitution, not AdaLN. A special <|tms_token|> placeholder has its embedding swapped for the sinusoidal timestep embedding at every step.
  • Mixed causal/bidirectional attention in one forward call. Text tokens are causal; image tokens attend bidirectionally over the full sequence. Expressed through AttentionMetadata + full_attn_spans.
  • 3D MRoPE with fix_point anchoring. Custom get_rope_index_fix_point pins reference image positions at a fixed offset to avoid RoPE extrapolation.

What

New files — vllm_omni/diffusion/models/hidream_o1_image/ (4 files):

  • qwen3_vl_uit_transformer.py — HiDreamO1UiTModel backbone. Lazy-imports HF Qwen3-VL (gated on transformers >= 4.57.1). Overrides attention/MLP projections with TP-capable parallel linears via _build_attention_subclasses(quant_config) closure. Carries _cache_dit_adapter_config, _sp_plan, _hsdp_shard_conditions, _layerwise_offload_blocks_attrs.
  • pipeline_hidream_o1_image.py — HiDreamO1ImagePipeline denoise loop. Handles T2I, editing, personalization, layout-bbox. Implements SupportsComponentDiscovery (empty _vae_modules, nested _encoder_modules = ["transformer.visual"]), DiffusionPipelineProfilerMixin, CFGParallelMixin.
  • utils_hidream_o1.py — pure utilities: build_packed_attention_metadata (builds both full_attn_spans and dense attn_mask), get_rope_index_fix_point, patchify/depatchify, layout-bbox rendering.
  • __init__.py — module exports.

Parallelism — all wired in the model files above:

Strategy Implementation
Tensor Parallel QKVParallelLinear (fused Q/K/V), MergedColumnParallelLinear (gate+up), RowParallelLinear (o_proj, down_proj). stacked_params_mapping in load_weights() remaps split checkpoint weights into fused params.
Sequence Parallel (Ulysses + Ring) _sp_plan splits inputs_embeds/position_ids before decoder stack, gathers final_layer2 after. attn_metadata excluded — Ulysses AllToAll restores full sequence before attention. T2I only; editing path documented as known SP limitation.
CFG-Parallel Zero code — inherited from CFGParallelMixin.
HSDP _hsdp_shard_conditions = [_is_transformer_block] — each Qwen3VLTextDecoderLayer is a shard unit.
Cache-DiT _cache_dit_adapter_config with ForwardPattern.Pattern_0, has_separate_cfg=True, check_forward_pattern=False. Added layers property alias on HiDreamO1UiTModel pointing to language_model.layers for cache-dit auto-detection.
CPU Offload SupportsComponentDiscovery. _vae_modules = [] (no VAE). _encoder_modules = ["transformer.visual"] — first nested encoder path in the codebase, resolved via operator.attrgetter.
Layerwise Offload _layerwise_offload_blocks_attrs = ["language_model.layers"]

Integration:

  • vllm_omni/diffusion/registry.py — registered with get_hidream_o1_image_post_process_func ([-1, 1] → uint8, no VAE decode).
  • docs/models/supported_models.md, docs/user_guide/diffusion_features.md, docs/user_guide/diffusion/cpu_offload_diffusion.md — rows added.
  • .buildkite/cuda/test-ready.yml, test-merge.yml, test-nightly.yml — CI entries added.
  • examples/offline_inference/hidream_o1_image/, examples/online_serving/hidream_o1_image/ — runnable examples with READMEs.
  • recipes/HiDream/HiDream-O1-Image.md — full serving recipe with two-bucket performance methodology.

Test Plan

Unit tests (47 tests, CPU-only, pytest -m core_model):

File Coverage
tests/diffusion/models/hidream_o1_image/test_packed_sequence.py build_packed_attention_metadata for T2I, editing, multi-ref, layout-bbox. Verifies full_attn_spans coordinates, attn_mask, token types, causal vs bidirectional pattern.
tests/diffusion/models/hidream_o1_image/test_embed_cache.py Vision-tower called exactly once per request across all denoising steps.
tests/diffusion/models/hidream_o1_image/test_layout_bbox_utils.py Bbox parsing, layout image rendering, coordinate clamping, batch handling.

E2E offline (tests/e2e/offline_inference/test_hidream_o1_image.py): full pipeline forward pass, output shape and pixel range verified.

E2E online (tests/e2e/online_serving/test_hidream_o1_image.py): T2I (Dev + Full variants), image editing, multi-reference personalization, layout-bbox.

Nightly expansion (tests/e2e/online_serving/test_hidream_o1_image_expansion.py): 8 parametrized server configs:

id flags GPUs
default — 1× H100
cache_dit --cache-backend cache_dit 1× H100
tp2 --tensor-parallel-size 2 2× H100
ulysses2 --ulysses-degree 2 2× H100
cfg_parallel2 --cfg-parallel-size 2 2× H100
hsdp --use-hsdp 1× H100
cpu_offload --enable-cpu-offload 1× H100
layerwise_offload --enable-layerwise-offload 1× H100

vLLM Version: 0.23.0

vLLM-Omni Commit: 1ff2f22

Test Result

Unit tests (47): all passed on CPU.

image

E2E and expansion tests require H100 hardware, tracked through CI (test-merge and test-nightly pipelines).

Pixel-level output comparison against the HiDream reference repo is explicitly deferred and tracked in #5304 .
H100 benchmark numbers are explicitly deferred and tracked in #5305 .

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class vLLM-Omni diffusion support for HiDream-O1-Image (Qwen3-VL–based Pixel-level Unified Transformer) including text-to-image, reference-image editing/personalization, and layout-bbox conditioning, plus integration into registry/docs/CI and a test+example suite.

Changes:

  • Introduces a new HiDream-O1-Image model implementation (UiT backbone + diffusion pipeline) and registers it in the diffusion registry/post-processing map.
  • Adds utilities for packed attention metadata, MRoPE position id construction, patchify/depatchify, and layout-bbox rendering.
  • Adds unit + E2E tests, Buildkite coverage, docs updates, and offline/online runnable examples + a serving recipe.

Reviewed changes

Copilot reviewed 26 out of 27 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
vllm_omni/diffusion/registry.py Registers HiDreamO1ImagePipeline and its post-process function.
vllm_omni/diffusion/models/hidream_o1_image/utils_hidream_o1.py Adds core tensor/PIL utilities (masking, MRoPE indices, patch ops, layout-bbox helpers).
vllm_omni/diffusion/models/hidream_o1_image/qwen3_vl_uit_transformer.py Implements the Qwen3-VL–based UiT backbone with vLLM-Omni attention + TP-capable linears.
vllm_omni/diffusion/models/hidream_o1_image/pipeline_hidream_o1_image.py Implements denoising pipeline for T2I/editing/personalization/layout-bbox + weight loading and caching.
vllm_omni/diffusion/models/hidream_o1_image/init.py Exposes lazy imports for pipeline and post-processing function.
tests/e2e/online_serving/test_hidream_o1_image.py Adds L2/L3 online-serving smoke tests for T2I, editing, and multi-ref.
tests/e2e/online_serving/test_hidream_o1_image_expansion.py Adds L4 nightly expansion matrix (cache_dit/tp/sp/cfg-parallel/hsdp/offload).
tests/e2e/offline_inference/test_hidream_o1_image.py Adds offline inference smoke test.
tests/diffusion/models/hidream_o1_image/test_packed_sequence.py Unit tests for packed sequence masking, MRoPE, patchify/depatchify, ref preprocessing.
tests/diffusion/models/hidream_o1_image/test_layout_bbox_utils.py Unit tests for bbox parsing/rendering and ref/layout image generation.
tests/diffusion/models/hidream_o1_image/test_embed_cache.py Unit tests for vision-embed caching contract.
tests/diffusion/models/hidream_o1_image/init.py Package marker for hidream_o1_image diffusion tests.
recipes/HiDream/HiDream-O1-Image.md Adds a full serving recipe and profiling methodology placeholders.
examples/online_serving/hidream_o1_image/run_server.sh Adds a convenience script to start the server.
examples/online_serving/hidream_o1_image/run_curl_hidream_o1.sh Adds a curl example for /v1/images/generations.
examples/online_serving/hidream_o1_image/README.md Documents online-serving usage for HiDream-O1-Image.
examples/online_serving/hidream_o1_image/openai_client_hidream_o1.py Adds a simple OpenAI-compatible Python client example.
examples/offline_inference/hidream_o1_image/text_to_image_hidream_o1.py Adds an offline T2I driver with full/dev presets.
examples/offline_inference/hidream_o1_image/README.md Documents offline scripts and arguments for T2I/edit/layout control.
examples/offline_inference/hidream_o1_image/layout_control_hidream_o1.py Adds an offline layout-bbox controlled generation script.
examples/offline_inference/hidream_o1_image/image_edit_hidream_o1.py Adds an offline editing/multi-ref personalization script.
docs/user_guide/diffusion/cpu_offload_diffusion.md Documents CPU/layerwise offload support for the new pipeline.
docs/user_guide/diffusion_features.md Updates diffusion feature support matrix to include HiDream-O1-Image.
docs/models/supported_models.md Adds HiDream-O1-Image to supported models list.
.buildkite/cuda/test-ready.yml Adds L2 test-ready step for HiDream-O1-Image serving.
.buildkite/cuda/test-nightly.yml Adds nightly expansion test entry for HiDream-O1-Image.
.buildkite/cuda/test-merge.yml Adds L3 test-merge step for HiDream-O1-Image serving.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +266 to +270
is_gen = token_types > 0
for b in range(batch_size):
dense_mask[b, is_gen[b]] = True # gen rows attend to everything (incl. future gen positions)
row = is_gen[b]
idx = torch.nonzero(row, as_tuple=False).squeeze(-1)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid.

It would add a redundant operation (dense_mask[b, ~gen] &= (~gen).unsqueeze(0)) that zeroes bits already guaranteed to be zero by construction. The docstring phrase "causal-only-over-text" is accurate as is, text tokens already only see text columns because the layout puts all gen tokens at the tail of every sequence.

Comment on lines +3 to +6
"""HiDream-O1-Image pipeline — Phase 3 (text-to-image + image editing +
multi-reference personalization + layout-bbox conditioning, single GPU,
no Cache-DiT / TP / SP yet).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid.
The docstring was written at the end of Phase 3 and still says "single GPU, no Cache-DiT / TP / SP yet", but Phases 5–8 added all of those. It's now stale and misleading.

Comment on lines +391 to +398
ref_pixel_grid_thw = torch.tensor(
[[1, pil.size[1] // PATCH_SIZE, pil.size[0] // PATCH_SIZE]
for pil, n in zip(ref_pils, ref_image_lens)
for _ in [resize_pilimage(pil, ref_max)]],
dtype=torch.int64,
device=self.device,
)
# Build per-ref pixel grid from actual resized dimensions.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid.

  • Lines 388–394 build ref_pixel_grid_thw but with a subtle bug: it calls resize_pilimage(pil, ref_max) inside the comprehension expression (for _ in [resize_pilimage(...)]) but then reads pil.size (the original unresized dimensions), not the resized ones. This produces wrong grid values AND does a wasted resize call.
  • Lines 396–401 immediately overwrite ref_pixel_grid_thw correctly: it resizes, captures pil_r.size, and uses rw, rh.

"--model-type",
choices=["full", "dev"],
default="full",
help="full: 50 steps, guidance 5.0, shift 3.0. dev: 28 steps, guidance 0.0 (no CFG), shift 1.0.",

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

valid

Comment on lines +666 to +669
raw_layout = mm_data.get("layout_bboxes")
if raw_layout is not None and ref_pils is not None:
layout_data = load_layout_bboxes(raw_layout) if isinstance(raw_layout, str) else raw_layout
ref_pils = create_layout_reference_images(ref_pils, layout_data, width, height)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid.
load_layout_bboxes calls os.path.exists() on any user-supplied string in online serving a remote client controls multi_modal_data["layout_bboxes"], so they can probe server-local file existence and read arbitrary JSON files from disk.
To fix:

  • use json.loads() directly, only accept inline JSON, never read files from user data.
  • preload the file with load_layout_bboxes() before putting data in multi_modal_data, since that's operator-controlled code anyway.

@hsliuustc0106 hsliuustc0106 added new model add new model diffusion codes related to diffusion models labels Jul 22, 2026
lsokoudj and others added 11 commits July 28, 2026 20:29
Starting work on HiDream-O1-Image. This is the first piece: plain
text-to-image generation, nothing else yet.

This model works differently from everything else already in the repo.
Instead of a VAE plus a separate transformer, it's one Qwen3-VL-based
transformer that does the diffusion denoising directly on raw pixels.
Text and image tokens get packed into a single sequence, and the tricky
part is that attention has to be causal for the text but bidirectional
for the image/timestep tokens, all within the same forward pass.

I tested this for real on GPU against the actual HiDream-O1-Image-Dev
checkpoint, not just unit tests: weight loading, the attention masking,
the position ids, and the denoising loop (with and without
classifier-free guidance) all produce correct images when run through
the normal Omni() serving path.

Editing, personalization, layout/skeleton conditioning, caching and
multi-GPU support are not in this commit, those are next.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Leopold Sokoudjou <leopoldgatsing@gmail.com>
…sonalization

Extends the Phase 1 packed-sequence machinery with dual-pathway reference
image conditioning for instruction-based editing (1 ref) and subject-driven
personalization (N refs):

- utils_hidream_o1: add adaptive_ref_max_size() and preprocess_ref_patches()
  for pixel-patch pathway preprocessing
- qwen3_vl_uit_transformer: add _deepstack_process() static method to
  Qwen3VLTextModel; fix get_image_features() to extract from
  BaseModelOutputWithDeepstackFeatures; fix forward_generation() bug
  (removed erroneous torch.cat on already-merged image_embeds tensor)
- pipeline_hidream_o1_image: add SupportImageInput protocol, _build_edit_sample()
  for dual-pathway conditioning (VLM semantic path + pixel-patch path),
  embed caching via mutable dict side-channel (_embed_storage) to call the
  vision tower exactly once per request, ref_patches concatenation in diffuse()
- test_packed_sequence: add Phase 2 test classes (TestAdaptiveRefMaxSize,
  TestPreprocessRefPatches, TestEditSampleTokenTypes)
- test_embed_cache: new file verifying vision tower is called exactly once
  regardless of num_inference_steps or CFG
- image_edit_hidream_o1.py: example script for editing (1 ref) and
  personalization (2+ refs)

All 23 CPU unit tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Leopold Sokoudjou <leopoldgatsing@gmail.com>
Adds spatially-grounded layout conditioning via bounding boxes. The layout
pipeline reuses Phase 2's ref-image path unchanged: bboxes are rendered into
a synthetic layout image (black background, colored box outlines), and each
reference image gets a matching-colored border. The augmented ref list is
passed to _build_edit_sample() as regular token_type=2 conditioning tokens.

- utils_hidream_o1: add load_layout_bboxes, parse_layout_bboxes,
  draw_bbox_layout, add_outer_border_keep_size, create_layout_reference_images
  and their helpers; accepts xxyy relative/percentage coords, three input
  formats (list, list-of-dicts, dict wrapper), auto-loads JSON strings/files
- pipeline_hidream_o1_image: forward() extracts layout_bboxes from
  multi_modal_data and calls create_layout_reference_images before diffuse();
  no changes needed to _build_edit_sample() or diffuse()
- test_layout_bbox_utils: 24 CPU-only tests covering all new functions
- layout_control_hidream_o1.py: example script with --layout-bboxes argument

All 47 CPU unit tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Leopold Sokoudjou <leopoldgatsing@gmail.com>
…sts, CI wiring

- docs/models/supported_models.md: add HiDreamO1ImagePipeline row
- recipes/HiDream/HiDream-O1-Image.md: new recipe with Dev/Full variants,
  offline t2i/editing/layout commands, online serving verification
- examples/offline_inference/hidream_o1_image/README.md: updated to Phase 3,
  scripts table, editing/personalization/layout-bbox sections
- examples/online_serving/hidream_o1_image/: run_server.sh, run_curl, Python
  client, README
- tests/e2e/online_serving/test_hidream_o1_image.py: L2+L3 online tests
  (t2i baseline dual-marked core+advanced; editing/personalization advanced)
- tests/e2e/offline_inference/test_hidream_o1_image.py: L3 offline smoke
- tests/e2e/online_serving/test_hidream_o1_image_expansion.py: L4 skeleton
- .buildkite/test-ready.yml: L2 step (core_model, H100)
- .buildkite/test-merge.yml: L3 step (advanced_model and cuda, H100)
- .buildkite/test-nightly.yml: add expansion file to Single-GPU shard

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Leopold Sokoudjou <leopoldgatsing@gmail.com>
Add Cache-DiT support to HiDreamO1UiTModel via the standard
_cache_dit_adapter_config / layers-property pattern (no custom
CUSTOM_DIT_ENABLERS entry needed):

- _cache_dit_adapter_config: Pattern_0 blocks, has_separate_cfg=True
  (cond/uncond are separate pipeline.forward() calls via CFGParallelMixin),
  check_forward_pattern=False (block sig has attn_metadata kwargs)
- layers property: aliases self.language_model.layers so the framework's
  direct-attribute block discovery works without nesting
- _layerwise_offload_blocks_attrs: ["language_model.layers"] (also used
  by Phase 7 CPU offload)
- _is_transformer_block + _hsdp_shard_conditions: HSDP predicate bundled
  here (trivial addition, consumed by Phase 6d)

docs: add HiDream-O1-Image row to diffusion_features.md ImageGen table
      (Cache-DiT=✅, all other acceleration features pending later phases)
tests: extend L4 expansion parametrize with cache_dit server variant
Signed-off-by: Leopold Sokoudjou <leopoldgatsing@gmail.com>
Replace plain nn.Linear q/k/v projections and MLP gate/up/down with
TP-capable parallel linears (QKVParallelLinear, MergedColumnParallelLinear,
RowParallelLinear) inside _build_attention_subclasses, so
--tensor-parallel-size ≥ 2 shards correctly across heads and intermediate
dimensions.

Key changes:
- qwen3_vl_uit_transformer.py: _build_attention_subclasses(quant_config) now
  captures quant_config via closure; Qwen3VLTextAttention replaces q/k/v/o
  plain linears with qkv_proj (QKVParallelLinear) and o_proj
  (RowParallelLinear, return_bias=False); new HiDreamO1TextMLP uses
  gate_up_proj (MergedColumnParallelLinear, return_bias=False) and down_proj
  (RowParallelLinear, return_bias=False).
- pipeline_hidream_o1_image.py: load_weights gains stacked_params_mapping to
  route checkpoint's split q/k/v and gate/up weights into fused params.
- diffusion_features.md: TP column → ✅ for HiDream-O1-Image.
- test_hidream_o1_image_expansion.py: adds tp2 L4 row (2× H100, server_args
  --tensor-parallel-size 2).

Signed-off-by: Leopold Sokoudjou <leopoldgatsing@gmail.com>
Add _sp_plan to HiDreamO1UiTModel for hook-based SP:
- Split inputs_embeds (dim 1) and position_ids (dim 2) before
  language_model.forward() so each SP rank processes its sequence shard
- Gather final_layer2 output (dim 1) to reconstruct full sequence before
  returning to the pipeline

attn_metadata is intentionally excluded from the plan: Ulysses AllToAll
reconstructs the full sequence on each rank before local attention, so
full_attn_spans global coordinates and the dense attn_mask remain correct
without modification.

Known limitation: SP with reference images (pixel_values != None) is not
yet supported — deepstack visual_pos_masks would need per-rank coordinate
adjustment. T2I usage is correct.

Also: SP column → ✅ in diffusion_features.md, ulysses2 L4 row added.
Signed-off-by: Leopold Sokoudjou <leopoldgatsing@gmail.com>
6c — CFG-Parallel: HiDreamO1ImagePipeline already inherits CFGParallelMixin;
CFGParallelMixin.predict_noise_maybe_with_cfg routes cond/uncond branches to
separate ranks and all_gathers noise predictions. No code change needed.
Note: under CFG-Parallel with reference images the uncond rank re-runs the
vision tower each step (no cross-rank embed cache); functionally correct,
a future optimisation could broadcast the precomputed embeds.

6d — HSDP: _hsdp_shard_conditions was already added in Phase 5 via
_is_transformer_block; each Qwen3VLTextDecoderLayer is a shard unit.

Both columns → ✅ in diffusion_features.md.
L4 rows: cfg_parallel2 (2× H100, --cfg-parallel-size 2) and hsdp (1× H100,
--use-hsdp).

Signed-off-by: Leopold Sokoudjou <leopoldgatsing@gmail.com>
Add SupportsComponentDiscovery to HiDreamO1ImagePipeline so the CPU-offload
framework can discover which submodules to offload:

  _dit_modules       = ["transformer"]
  _encoder_modules   = ["transformer.visual"]   # nested dotted path, safe
  _vae_modules       = []                       # no VAE; empty list is safe
  _resident_modules  = ["transformer.x_embedder",
                         "transformer.t_embedder1",
                         "transformer.final_layer2"]

Two novel cases verified against module_collector.py:
- _vae_modules=[]: offloader iterates `for vae in modules.vaes:` — zero
  iterations over an empty list, no error.
- _encoder_modules=["transformer.visual"]: resolved via operator.attrgetter
  which supports dotted paths per the SupportsComponentDiscovery docstring;
  no special framework support needed.

Both --enable-cpu-offload (sequential) and --enable-layerwise-offload
(layerwise, using the existing _layerwise_offload_blocks_attrs on
HiDreamO1UiTModel) are now active.

Other changes:
- CPU Offload column → ✅ in diffusion_features.md
- HiDreamO1ImagePipeline row added to cpu_offload_diffusion.md
- cpu_offload and layerwise_offload L4 expansion rows added

Signed-off-by: Leopold Sokoudjou <leopoldgatsing@gmail.com>
Add DiffusionPipelineProfilerMixin to HiDreamO1ImagePipeline:
- Import and add to class MRO
- Custom _PROFILER_TARGETS for the no-VAE architecture:
  transformer.get_image_features (one-time vision-tower cost),
  transformer.forward_generation (per-step cost),
  transformer.x_embedder.forward (patch embedding)
- setup_diffusion_pipeline_profiler() wired at end of __init__,
  enabled via --enable-diffusion-pipeline-profiler flag

recipes/HiDream/HiDream-O1-Image.md: add Performance section documenting
the two-bucket cost model (one-time setup vs per-step forward_generation),
benchmarking configs (baseline / Cache-DiT / TP-2 / Ulysses-2 / combined),
profiling commands, and an empty benchmark table to fill from H100 runs.

Signed-off-by: Leopold Sokoudjou <leopoldgatsing@gmail.com>
Signed-off-by: Leopold Sokoudjou <leopoldgatsing@gmail.com>
…nings

griffe (used by mkdocstrings) treats 'param_a / param_b:' as a single
parameter name, emitting 4 warnings that fail the strict mkdocs build.
Split into individual Args entries matching the actual function signature.

Signed-off-by: Leopold Sokoudjou <leopoldgatsing@gmail.com>
@SOKOUDJOU-LEOPOLD
SOKOUDJOU-LEOPOLD force-pushed the leopold/Add-HiDream-O1-Image branch from 16d38ff to 391d004 Compare July 29, 2026 01:29
SOKOUDJOU-LEOPOLD and others added 6 commits July 29, 2026 00:23
Upstream main replaced the verbose kubernetes pod-spec for Qwen Image Edit
with the shorter mirror_hardwares: h100_1. Align our new test blocks
(HiDream-O1 Image, Longcat Image Edit, Longcat Image Test) with the same
pattern to resolve the merge conflict.

Signed-off-by: Leopold Sokoudjou <leopoldgatsing@gmail.com>
Signed-off-by: SOKOUDJOU Leopold <109520753+SOKOUDJOU-LEOPOLD@users.noreply.github.com>
Remove stale 'single GPU, no Cache-DiT / TP / SP yet' claim written at
Phase 3. The pipeline now supports Cache-DiT, TP, SP (Ulysses), CFG-Parallel,
HSDP, and CPU offload added in Phases 5-8.

Signed-off-by: Leopold Sokoudjou <leopoldgatsing@gmail.com>
…d_edit_sample

The first tensor construction used pre-resize pil.size dimensions and was
immediately overwritten by the correct second construction that uses the
actual resized pil_r.size dimensions.

Signed-off-by: Leopold Sokoudjou <leopoldgatsing@gmail.com>
The actual preset uses guidance_scale=1.0 (mathematically no-CFG);
the help string incorrectly said 0.0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Leopold Sokoudjou <leopoldgatsing@gmail.com>
…online serving

In online serving, multi_modal_data is user-controlled. Using load_layout_bboxes()
in the pipeline allowed remote clients to probe os.path.exists() and read
arbitrary JSON files from the server filesystem.

Fix: pipeline now uses json.loads() directly (inline JSON only). The offline
script pre-loads file-path layouts via load_layout_bboxes() before passing
parsed data into multi_modal_data.

Signed-off-by: Leopold Sokoudjou <leopoldgatsing@gmail.com>
@SOKOUDJOU-LEOPOLD
SOKOUDJOU-LEOPOLD force-pushed the leopold/Add-HiDream-O1-Image branch from a08c4af to 566ebad Compare July 29, 2026 07:49
ruff check: remove unused variables (n_refs, z, sigma, original_color),
rename uppercase arg K→k in adaptive_ref_max_size, remove unused imports
(json, math, os, tempfile, MagicMock/patch/call from unittest.mock),
fix import ordering and UP037/UP035 style issues.

ruff format: reformat 9 files to match project style (line breaks,
trailing commas, slice spacing).

Signed-off-by: Leopold Sokoudjou <leopoldgatsing@gmail.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@SOKOUDJOU-LEOPOLD

Copy link
Copy Markdown
Author

Hi @hsliuustc0106 , Please can you review my PR?

@hsliuustc0106 hsliuustc0106 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Joint review with #5194. These are comment-only findings; no approval or change-request verdict.

echo "Model: $MODEL"
echo "Port: $PORT"

vllm serve "$MODEL" --omni \

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Add automatic model-class resolution before relying on this command. The official checkpoint config declares Qwen3VLForConditionalGeneration, but the resolver returns that unregistered architecture while the registry contains HiDreamO1ImagePipeline, so vllm serve "$MODEL" --omni will fail unless the caller supplies --model-class-name. Please add the HiDream signature mapping to both resolver/enrichment paths; carrying #5194's diffusion detector alone is not sufficient because detection does not select the pipeline class.

# Limitation: the reference-image path (pixel_values != None) uses
# visual_pos_masks for deepstack indexing into the sequence. Those
# positions may span multiple SP ranks, making gather/scatter logic
# non-trivial. For now SP is supported for text-to-image only; using

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Guard this combination before advertising sequence parallelism for the full pipeline. With reference images, visual_pos_masks remains full-length while _sp_plan splits only inputs_embeds and position_ids; _deepstack_process() then indexes local hidden states with the full mask. Edit/personalization/layout with --ulysses-degree > 1 can therefore shape-error or produce incorrect deepstack embeddings. Please either implement mask-aware split/gather or reject this mode explicitly and add a reference-image SP test.

-d '{
"prompt": "A golden retriever running through a field of sunflowers at sunset",
"size": "1024x1024",
"num_inference_steps": 28,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Apply the documented Dev sampling defaults to this online path. The server defaults to the Dev variant and this request sends 28 steps, but omits guidance and shift; the pipeline consequently substitutes guidance 5.0 and shift 3.0, enabling CFG and using the full-model shift instead of the Dev preset (1.0/1.0). Please make defaults model-variant-aware or include and enforce the Dev parameters in the server example.

"sigma": sigma,
"vinputs": neg_vinputs,
# CFG uncond branch reuses the same cached embeds (same refs)
"precomputed_image_embeds": cached_img_emb,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Refresh the vision-embedding cache before constructing the negative CFG branch. cached_img_emb and cached_ds_emb are captured before the positive branch populates embed_storage; the negative branch still receives those stale None values and _embed_storage=None, so reference-image CFG recomputes the vision tower on the first denoise step. Please refresh the cached values after the positive call and add an actual pipeline call-count test.

@vllm-omni-review-bot

Copy link
Copy Markdown

Omni ReviewBot: no human activity for 29 days

@SOKOUDJOU-LEOPOLD this pull request has had no human commit, comment or review since 2026-08-10. Per repository policy it may be closed if it stays inactive.

To keep it moving, any one of these is enough: push an update, reply to the open blocker, or post the current plan and timeline.

@vllm-omni-review-bot

Copy link
Copy Markdown

Omni ReviewBot: no human activity for 44 days

@SOKOUDJOU-LEOPOLD this pull request has had no human commit, comment or review since 2026-08-10. Please consider closing this PR if the work is no longer planned. The author or a maintainer decides whether to change the PR state.

To keep it moving, any one of these is enough: push an update, reply to the open blocker, or post the current plan and timeline.

@hsliuustc0106 hsliuustc0106 added the stale No new commits for at least 60 days label Sep 30, 2026 — with ChatGPT Codex Connector
@vllm-omni-review-bot

Copy link
Copy Markdown
Omni ReviewBot routing record

Assigned Strict on zcode (GLM-5.3-Flash) under experiment fleet-strict-cursor-grok46-zcode-glm53flash-5050-c5-z10-20261002.

@vllm-omni-review-bot

Copy link
Copy Markdown
Omni ReviewBot attempt record

Review attempt ended as timeout (Strict attempt outlived its budget; falling back to direct/cursor/auto).

@vllm-omni-review-bot vllm-omni-review-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Omni ReviewBot review

Changes since the previous review

  • 4 new inline finding(s); 0 finding(s) below.

CI at 43db9cd47b29 (2026-10-09T16:29:35.281736+00:00): required check(s) blocking: buildkite/vllm-omni (missing).

Note: The assigned review arm strict/zcode/GLM-5.3-Flash could not complete this review, so it was produced by the fallback arm direct/cursor/auto. It is excluded from the routing experiment.

Full review analysis

PR description

This PR adds HiDream-O1-Image (HiDreamO1ImagePipeline / HiDreamO1UiTModel): a Qwen3-VL pixel-space diffusion pipeline with no VAE, covering text-to-image, reference editing, multi-reference personalization, and layout-bbox conditioning. Denoising patches 32×32 pixels, swaps a <|tms_token|> embedding for the timestep, and registers a [-1, 1] to RGB post-process. Docs, examples, and Buildkite steps advertise Cache-DiT, TP, Ulysses, CFG-parallel, HSDP, and CPU/layerwise offload. The online serve script still does not select HiDreamO1ImagePipeline, and edit-plus-sequence-parallel plus the Dev sampling defaults are not actually enforced.

Change flow

flowchart LR
  req["[EXISTING] OmniDiffusionRequest"]:::existing
  reg["[CHANGED] diffusion registry"]:::changed
  pipe["[NEW] HiDreamO1ImagePipeline"]:::new
  uit["[NEW] HiDreamO1UiTModel"]:::new
  rgb["[NEW] patch RGB post-process"]:::new
  req --> reg --> pipe --> uit --> rgb
classDef existing fill:#e5e7eb,stroke:#6b7280,color:#111827
classDef changed fill:#fef3c7,stroke:#d97706,color:#451a03,stroke-width:2px
classDef new fill:#dcfce7,stroke:#16a34a,color:#052e16,stroke-width:2px
classDef removed fill:#fee2e2,stroke:#dc2626,color:#450a0a,stroke-width:2px
Loading

See inline comments below.


🤖 This review was generated by InferMatrix Copilot, an open-source repo-maintenance agent for PR review, CI debugging and issue triage. Try it on your own repo, and ⭐ star it if it helped!

"attn_metadata": attn_metadata,
"vinput_mask": vinput_mask,
"pixel_values": pixel_values_vlm,
"image_grid_thw": image_grid_thw_all,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Edit vision tower receives target and ref grids

Evidence and suggested fix

_build_edit_sample returns pixel_values from the VLM processor (K reference images) but sets image_grid_thw to image_grid_thw_all, which concatenates those VLM grids with the target patch grid and the pixel-ref grids. forward_generation passes that tensor straight into get_image_features. Qwen3-VL splits pixel_values by the product of grid_thw, so the extra rows make the vision-tower length disagree with the image-token mask and masked_scatter. Every edit, personalization, and layout request can throw or scatter the wrong embeddings. Pass only image_grid_thw_vlm into the vision tower; keep the concatenated grid for get_rope_index_fix_point.

tests/e2e/online_serving/test_krea2_expansion.py
tests/e2e/offline_inference/test_krea2_expansion.py
tests/e2e/offline_inference/test_sensenova_u1_expansion.py
tests/e2e/online_serving/test_hidream_o1_image_expansion.py

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Two-GPU HiDream rows are only on the 1-GPU nightly shard

Evidence and suggested fix

test_hidream_o1_image_expansion.py is added only to the H100 single-GPU step (.buildkite/cuda/test-nightly.yml around line 213), whose command is -m "full_model and diffusion and H100 and not distributed_cuda" and mirror_hardwares: h100_1. The tp2, ulysses2, and cfg_parallel2 params request 2 GPUs. They are either deselected by not distributed_cuda or executed on one GPU. No h100_2 step lists this file (the multi-GPU steps cover Qwen-Image, layered, and Bagel only). The PR test plan's 2×H100 rows are not what nightly runs. Put those params on a distributed_cuda / h100_2 step.

- pytest -s -v tests/e2e/online_serving/test_hidream_o1_image.py -m 'advanced_model and cuda' --run-level 'advanced_model'
mirror_hardwares: h100_1

- label: "Diffusion · Longcat Image Edit Test"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Merge CI adds unrelated Longcat and SenseNova jobs

Evidence and suggested fix

The HiDream test-merge hunk also inserts "Diffusion · Longcat Image Edit Test" and "Diffusion · Longcat Image Test", whose sources are tests/e2e/online_serving/test_longcat_image*.py and vllm_omni/diffusion/models/longcat_image/. test-nightly.yml line 228 likewise adds tests/e2e/offline_inference/test_sensenova_u1_expansion.py. Neither model is part of HiDream-O1. Those jobs add H100 time and can fail this PR for unrelated tests. Drop them from this diff.

self.cond_deepstack_image_embeds = cond_deepstack_image_embeds


class HiDreamO1UiTModel(nn.Module):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Non-test diff exceeds the size budget

Evidence and suggested fix

The supplied diff size is 2592 non-test added lines against a budget of 1000 (14 counted files, 13 exempt). The largest contributors are qwen3_vl_uit_transformer.py (694), pipeline_hidream_o1_image.py (679), and utils_hidream_o1.py (592). The PR body describes the new model and deferred pixel/benchmark follow-ups (#5304, #5305) but does not give a split plan or a concrete size exemption. Split the backbone, pipeline, and examples/CI into reviewable PRs, or state an explicit exemption for this new-model drop. Size is not itself a correctness defect.

@vllm-omni-review-bot

Copy link
Copy Markdown

Omni ReviewBot: finding feedback

[p1] Reference-image sequence parallel is not rejected — vllm_omni/diffusion/models/hidream_o1_image/qwen3_vl_uit_transformer.py:500

See the review for details. If you are the PR author and disagree, react 👎 here; the maintainer will see your disagreement.

@vllm-omni-review-bot

Copy link
Copy Markdown

Omni ReviewBot: finding feedback

[p1] Two-GPU HiDream rows are only on the 1-GPU nightly shard — .buildkite/cuda/test-nightly.yml:229

See the review for details. If you are the PR author and disagree, react 👎 here; the maintainer will see your disagreement.

@vllm-omni-review-bot

Copy link
Copy Markdown

Omni ReviewBot: finding feedback

[p1] Dev examples and nightly tests use full CFG defaults — examples/online_serving/hidream_o1_image/run_curl_hidream_o1.sh:14

See the review for details. If you are the PR author and disagree, react 👎 here; the maintainer will see your disagreement.

@vllm-omni-review-bot

Copy link
Copy Markdown

Omni ReviewBot: finding feedback

[p1] Online serve does not select the pipeline class — examples/online_serving/hidream_o1_image/run_server.sh:13

See the review for details. If you are the PR author and disagree, react 👎 here; the maintainer will see your disagreement.

@vllm-omni-review-bot

Copy link
Copy Markdown

Omni ReviewBot: finding feedback

[p1] CFG negative branch sees a stale vision cache — vllm_omni/diffusion/models/hidream_o1_image/pipeline_hidream_o1_image.py:595

See the review for details. If you are the PR author and disagree, react 👎 here; the maintainer will see your disagreement.

@vllm-omni-review-bot

Copy link
Copy Markdown

Omni ReviewBot: finding feedback

[p1] Edit vision tower receives target and ref grids — vllm_omni/diffusion/models/hidream_o1_image/pipeline_hidream_o1_image.py:445

See the review for details. If you are the PR author and disagree, react 👎 here; the maintainer will see your disagreement.

Copy link
Copy Markdown
Collaborator

@SOKOUDJOU-LEOPOLD Are you planning to continue work on this PR? Please reply by 2026-10-19 10:37:13 UTC.

A yes or a brief plan is enough; code changes do not need to be finished within these three days. If you are waiting on a review or other maintainer action, please let us know.

If there is no reply, new commit, or maintainer takeover by then, we will recheck and close this PR as inactive. It can be reopened when work resumes.

Copy link
Copy Markdown
Collaborator

Closing as inactive after the 3-day deadline with no author reply. Feel free to reopen anytime.

3 天期限已过且作者未回复,先关闭;随时可以 reopen。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

diffusion codes related to diffusion models new model add new model stale No new commits for at least 60 days

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants