Repository navigation
feat(imagegen): add shared image generation runtime and APIs - #2497
Conversation
Add `src/imagegen/` with the model-independent pieces shared by every text-to-image and image-editing family: request and result types, the checkpoint family probe, the flow-match Euler scheduler (dynamic and static shift), latent patching and packing, the FLUX.2 VAE, the Z-Image DiT blocks, the Qwen3 hidden-state conditioner, PNG output, and the family registry (empty until a model issue registers a row). Surfaces: - `mlxcel generate-image` (generate and edit, -n, --seed, --gen-kwargs) - `mlxcel-server --image-model` with `POST /v1/images/generations` and `POST /v1/images/edits`, served by a dedicated worker; without the flag both routes answer 501 naming it - `Runtime::ImageGenerate` and `OutputKind::Image` in the registry - `generate`/`serve` on an image checkpoint now point at `mlxcel generate-image` instead of failing with `model_type not found` `Qwen3Model` gains `forward_all_hidden`, one added method that reuses the existing blocks. Teacher-forced logit traces on Qwen3-0.6B-4bit before and after are byte-identical. Tests compare against the upstream Python (Blaizzy/mlx-vlm) through committed fixtures; `tests/fixtures/generate_imagegen_fixtures.py` regenerates them exactly. The real ERNIE-Image-Turbo VAE matches upstream f32 to a relative RMS of 3e-6 (decode), 1.2e-6 (packed decode) and 3e-6 (encode). Upstream's `_match_conv_layout` leaves the encoder's RGB `conv_in` in PyTorch layout, which breaks its encoder; this port decides the layout once per checkpoint. Refs lablup#2341
Add docs/image-generation.md (CLI, server routes, probe, shared building blocks, precision decision, family registration, verification) and point to it from the README and the environment variable reference. Refs lablup#2341
Discard expired queued requests before GPU execution, cap output pixel counts and explicit diffusion steps, and replace the predictable output probe with atomic exclusive creation. Add regression coverage for deadline handling, request limits, existing files and symlinks. Declare the four reproducible numerical fixtures with individual size ceilings and an explicit aggregate binary budget. Document the limits and the remaining inability to interrupt an already-running generation. Refs lablup#2341 Refs lablup#2497
Document the test-only checkpoint directory, default lookup path, skip behavior and ignored-test invocation. Validate the current main merge tree with the environment-variable documentation guard and all 15 guard tests. Refs lablup#2341 Refs lablup#2497
|
Reviewed PR #2497 against issue #2341 and its accepted scope amendments, including the Qwen3 conditioner, static scheduler, model probing, CLI, HTTP aliases and authentication. Fixed four findings in 0de942c: expired queued requests could still start GPU work after the caller timed out; output dimensions and explicit diffusion steps had no shared resource ceiling; the predictable directory probe could truncate an existing file or follow a symlink; and the four numerical fixtures were undeclared in the binary-asset gate. Requests now cap each output at 16,777,216 pixels and explicit steps at 1–1,000, queued expiration is checked before execution, and probes use atomic exclusive creation. Fixture declarations have individual size limits and a bounded aggregate budget. Added focused regressions and documented the behavior. Commit 2fea6a6 documents the new Qwen3 checkpoint override, resolving the environment-documentation and Python-tooling CI failures. Validation on Linux/aarch64 NVIDIA GB10: CUDA library selection Authentication and route-prefix regressions passed. Already-running generation remains non-interruptible through the current model trait; expired queued work is now discarded. The real ERNIE VAE checkpoint was unavailable locally. As agreed in #2341, this infrastructure PR has no registered production image family; model-family wiring remains follow-up work. CI completion is still required before merge. Refs #2341 |
Summary
Adds the shared image generation runtime: the
generate-imageCLI,/v1/images/generationsand/v1/images/editsroutes behind--image-model, the family probe, a PNG writer, the FLUX.2 VAE, the flow-match schedulers, Z-Image DiT blocks, and a Qwen3 hidden-state conditioner. The family registry ships empty; model-family issues register their constructors on top of this.Related issues
Closes #2341
Part of #2348. Unblocks #2424, #2425, #2426, #2427 and #2428.
Type of change
feat— new user-visible featuredocs— documentation (docs/image-generation.md, README,MLXCEL_IMAGE_MODEL)Test plan
Everything below ran on the CPU MLX backend (
MLXCEL_BUILD_METAL=OFF,--features accelerate), because the Metal toolchain is not installed on the author's machine.cargo fmt --all -- --check: cleancargo clippy --workspace --all-targets -D warnings(CPU backend): exit 0upstream/mainworktree;mlxcel-coreis untouched.tests/fixtures/generate_imagegen_fixtures.pyreproduces the committed fixtures exactly):mlx-community/Qwen3-0.6B-4bit: conditioner last hidden state reproduces the generation-path logits exactly (rel-RMS 0)examples/logit_trace, Qwen3-0.6B-4bit, 96 positions, 12 chunks of 8 tokens. Baseline and branch traces are byte-identical, 0 disagreements, perplexity 80.1327 for both. The only change toQwen3Modelis one added method,forward_all_hidden.generate-imageon an empty dir and on an unported family prints clear errors;generate/serve/mlxcel-serveron an image checkpoint print "use mlxcel generate-image"; a real SmolLM2 server without--image-modelreturns 501 naming the flag on both routes and the/images/*aliases.cargo test --workspace --profile test-fast --features metal,accelerate: not run (no Metal toolchain)make verify/ Metal numerics: not runcargo deny check: not runNotes for reviewers
_match_conv_layoutin mlx-vlm leaves the encoder's RGBconv_in(128,3,3,3) in PyTorch layout; encode-decode reconstruction rel-RMS is 0.96 there versus 0.096 when transposed. This port decides the conv layout once per checkpoint (detect_conv_layout) and is not affected. Not reported upstream.-30000instead of-infso a fully blocked row averages instead of producing NaN; scheduler sigmas are computed on the CPU in f32.image_model_pathlives only inServerStartupConfig, notServerConfig, to avoid the runtime-settings schema and webui label cascade.mlxcel run <image dir>fails earlier with "No tokenizer found";mlxcel arch --jsonhas noImageGeneraterow until a family registers, so only the serialization is pinned by tests.Checklist
docs/(newdocs/image-generation.md, README, env-var table)// Used by: ...comments on any shared function I modified (only an added method onQwen3Model).envfiles committed