Repository navigation
[Feat] diffusion: support BRIA Fibo 2.0 generation and editing - #47831
liquanfeng wants to merge 4 commits into
Conversation
Preview approval requiredThis pull request comes from a fork, so Mintlify won't build a preview until someone with write access approves commit |
|
[BBuf Review Agent] Could you split it below 2500 changed lines (now 4456)? |
45b3a33 to
afe7c64
Compare
@BBuf Done — rebased onto Local checks on this branch: |
…nditioning Fibo 2.0 is an 8B flow-matching model that generates and edits images in the FLUX.2 VAE latent space. This adds its transformer and the text conditioning it expects; the pipeline that drives them follows in the next PR. * `BriaFibo2Transformer2DModel` keeps the Z-Image single-stream block and adds a Perceiver resampler that turns the text features into 256-512 "gist" tokens, five blocks that also cross-attend to their own text bundle, and per-token noisy/clean modulation, which is how the clean latents of the images to edit condition the generation. * Three-axis RoPE places the gist tokens, the image and every context image on their own plane; the image always sits on plane `max_num_gist_tokens + 1`. * The Qwen3-VL text tower feeds six bundles built from fifteen hidden states, each normalized to unit RMS per token before concatenation. The in-tree tower collects one state per decoder layer, one fewer than the reference, so the reference indices are shifted and a length assertion turns any upstream change in that collection into an error instead of silently wrong weights. The parameter names match the checkpoint one to one, including the separate q/k/v projections that cannot be fused because a cross-attention block reads a 7680-wide text bundle through a 3584-wide query.
…its API `POST /v1/images/edits` has always accepted a `mask` upload, but nothing read it: the parameter was declared and dropped. A masked edit therefore ran as a plain edit with no error, which is the worst of both worlds. The mask is now saved next to the uploaded images and forwarded to the request as `SamplingParams.mask_path`, the counterpart of `image_path`. Models that do not read it keep behaving as before, and the field is per-request like `image_path`, so image-conditioned requests still group.
One checkpoint serves both paths and sglang picks the pipeline class from `model_index.json`, so that class carries the image-aware text encoding and the reference-image latent stage; both fall back to the generation path when the request has no image. Prompt handling mirrors the reference: the caption is cleaned the way training cleaned it, serialized compactly, and an edit turns into one JSON object holding a vision marker per image plus the instruction. Qwen3-VL then sees the same crops the VAE encodes, shrunk to 768 pixels on the long side, and the images become one clean latent per image in `batch.source_latents`, the field the in-tree LLaDA edit model already uses. A repaint mask carried by the request greys out the marked region on the original image, in `preprocess_vae_image`: the first hook that receives the batch, and the one that runs before the crops are taken. Decoding reuses the FLUX.2 VAE chain, including its BatchNorm latent statistics, and the timestep schedule uses the FLUX linear shift computed from the image token count. The released checkpoints ship no separate `tokenizer` component, so the pipeline exposes the tokenizer its processor carries, and the transformer is handed timesteps in the schedule's own units rather than the reference's [0, 1]. The opt-in end-to-end test is gated on `SGLANG_FIBO2_TEST_MODEL` because the weights are released under a license that has to be accepted on Hugging Face.
Covers the turbo editing checkpoint (4 steps, guidance off) and the dev checkpoint (30 steps, guidance 5), with a command builder, the editing, masked and multi-reference requests, the structured-caption prompt format and the current limitations.
afe7c64 to
ac6e451
Compare
|
Agreed with the revert in #48054 — the model half was unusable on its own, so the transformer and the pipeline are back in one PR here (21 files, +4472). This branch is rebased onto current Rebasing onto current
Verified on current On the size: splitting at the model/pipeline boundary is what made the model dead code. If you still want smaller PRs, the split that keeps each one working is (1) model + pipeline + the generation path, (2) editing, mask and docs — say the word and I will reshape it that way. |
Motivation
Add BRIA Fibo 2.0 to SGLang Diffusion. Fibo 2.0 is an 8B flow-matching model that both generates and edits images in the FLUX.2 VAE latent space: Qwen3-VL-4B encodes structured JSON captions, a two-layer Perceiver resamples those features into 256-512 "gist" tokens, and five transformer blocks additionally cross-attend to Qwen3-VL's internal layers.
Fibo-2.0-edit-turbois distilled for 4-step, guidance-free editing;Fibo-2.0-devserves 30-step generation and editing with classifier-free guidance.The weights are released under CC BY-NC 4.0 and require accepting BRIA's license on Hugging Face, which is why the end-to-end test is opt-in.
Modifications
Model
runtime/models/dits/bria_fibo2.py: the Fibo 2.0 transformer. It keeps the Z-Image single-stream block and adds a Perceiver resampler, five injection blocks with gated cross-attention, per-token noisy/clean modulation, three-axis RoPE over the gist, image and context-image planes, and patchify/unpatchify around the FLUX.2 latent layout.configs/models/encoders/bria_fibo2.py: builds the six text bundles from fifteen Qwen3-VL hidden states, each normalized to unit RMS per token before concatenation. The in-tree text tower returns one hidden state per decoder layer, one fewer than the reference, so the reference layer indices are shifted and the tuple length is asserted, turning a future collection change into an error instead of silently wrong conditioning.Pipeline and serving
configs/pipeline_configs/bria_fibo2.py+runtime/pipelines/bria_fibo2_pipeline.py: one pipeline serves both paths, since sglang resolves the pipeline class frommodel_index.jsonand both checkpoints declare the same one.model_specific_stages/bria_fibo2/source.py: VAE-encodes every reference image into its own clean latent inbatch.source_latents, the field the in-tree LLaDA edit model already uses; the images can have different sizes, so they cannot be concatenated onto the sequence.model_specific_stages/bria_fibo2/condition_encoding.py: two stages, one text-only and one image-aware, each stepping aside for the other's requests. They stay separate stages so each keeps its own name and component-residency bookkeeping; wrapping one inside the other left the inner stage unregistered and its encoder on the CPU.TI2Iinresolve_task_type: images plus an instruction fit both I2I and TI2I, and the shared resolver otherwise refuses to choose.preprocess_vae_image: the first hook that receives the batch, and the one that runs before the crops are taken. A mask applies to one image and must match its size; both are rejected otherwise.tokenizer, so the pipeline exposes the one its processor carries.API
POST /v1/images/editsdeclared amaskupload and dropped it, so a masked edit silently ran as a plain edit. It is now saved and forwarded asSamplingParams.mask_path, the counterpart ofimage_path.Docs
docs/cookbook/diffusion/Fibo/Fibo-2.0.mdxwith a command builder and the editing, masked and multi-reference requests.Validation
Measured on one H100-80GB with the released weights:
Fibo-2.0-dev)[1.0, 0.902405, 0.755031, 0.506753, 0.0]for a 1216x832 canvas, identical to the referenceOn current
main, the opt-in end-to-end file runs green with real weights:3 passed(turbo generation, turbo editing, dev generation with CFG). The rest:178 passed, 3 skippedacross the unit files (the skips are the diffusers-parity tests, which needdiffusers>=0.42),node --test docs/scripts/tests/*.test.mjs52/52,pre-commit run --all-filesclean.Limitations
text_images/fonts) are not supported yet; captions carryingtext_renderentries are accepted, they are just not turned into images.On the size
This is 21 files / +4472. The earlier attempt split it at the model/pipeline boundary and that left the model unusable on its own (#48054). If a smaller PR is still preferred, the split that keeps each part working is: (1) model + pipeline + generation path, (2) editing, mask and docs — I can reshape it that way instead.
CI States
Latest PR Test (Base): ❌ Run #41610269241
Latest PR Test (Extra): ❌ Run #41610269162
Latest PR Test (AMD ROCm 10): ❌ Run #41610269154
Tip
Base CI only covers the core cases, and its workload may not exercise your change. Use
/rerun-testto run the tests your change touches, or copy this prompt for an agent: