Skip to content

Sync with upstream master-968-8cd731e (FLUX.3 Image Klein) - #33

Merged
danielhanchen merged 19 commits into
masterfrom
sync/upstream-flux3
Oct 17, 2026
Merged

danielhanchen merged 19 commits into
masterfrom
sync/upstream-flux3

Conversation

@danielhanchen

Copy link
Copy Markdown
Member

Syncs the fork with upstream master-968-8cd731e (2026-10-16), which adds FLUX.3 Image Klein and Klein Base (leejet#2143). The last sync, #24, brought the tree to master-951-f89d9b1, so this adds 17 upstream commits. The ggml submodule is unchanged (d25b121), and all 13 patches in scripts/unsloth/ggml-patches still apply.

Merge this with "Create a merge commit", not squash or rebase. The prebuilt workflow names a release after the highest upstream master-* tag reachable from the tree. If this PR is squashed, 8cd731e is not reachable and the next release is still named master-951-.... The upstream tag master-968-8cd731e also has to be in this repository (git push origin refs/tags/master-968-8cd731e), as master-951-f89d9b1 is today.

Upstream commits brought in

Conflicts

Two files conflicted.

  • .github/workflows/build.yml, Windows ROCm job. Took upstream's ROCm 10.1.0. Kept the fork's GPU_TARGETS env name, which is what the job's cmake line reads, and CCACHE_COMPILERCHECK: content. Kept the fork's SHA-pinned actions and the max-size: 2G comment. Added upstream's "Tune ccache for reinstalled ROCm toolchain" step. Every action in the workflows is still pinned to a commit.
  • src/core/ggml_extend_backend.cpp. An include clash: kept both <tuple> (fork) and <utility> (upstream).

Beyond the textual merge

  • MiniMax-H3 video VAE flash attention (commit ca7d7af). Upstream feat: add per-module automatic flash attention selection leejet/stable-diffusion.cpp#2132 rewrote --diffusion-fa as a module assignment and no longer sets the legacy diffusion_flash_attn flag. The fork's rule ("on CUDA and ROCm, --diffusion-fa also covers the H3 video VAE") read that flag, so it would never have fired again and H3 decode would have silently lost its flash attention. It now keys on the resolved per-module state: diffusion FA on and VAE FA off, unless the user gave an explicit vae= assignment. SD_H3_VAE_FLASH_ATTN behaves as before. The log line "Using flash attention in the MiniMax-H3 video VAE" appears in both master and this branch.
  • VAE OOM retry (fix: halve VAE decode tiles on OOM retry instead of jumping to 256px leejet/stable-diffusion.cpp#2120). Upstream's change removes a clamp inside the function the fork already uses for both decode and encode retries. The encode retry and the fork's stop rule are unchanged.

Behaviour that changes with upstream

  • sd.cpp defaults now enable flash attention and direct convolution where a probe says they work. That is CPU and CUDA flash attention, and CUDA implicit-GEMM conv. A run with no speed flags therefore differs from master: on CPU, Z-Image LPIPS 0.014 and FLUX.2 klein 0.019. Head with --flash-attn off --conv-direct off is pixel-identical to master's default (CPU and CUDA, see below), so this is the whole difference.
  • Studio passes --diffusion-fa --diffusion-conv-direct. With those flags, CPU output is pixel-identical between master and this branch. On CUDA the VAE also gets upstream's auto direct conv, which master never enabled (about 60 dB from master, LPIPS 0.0001 to 0.0002).

Verification

Builds (CUDA 13.1, sm_100, cuDNN on, shared ggml; CPU GGML_NATIVE=OFF with all CPU variants and GGML_BACKEND_DL, as the prebuilt) all succeed: sd-cli and sd-server for master 11761ef and for this branch.

The A/B compares master 11761ef against this branch on the same host and GPU, interleaved, with seed 42. Assets are those Studio ships for each family.

Assets per family:

  • Z-Image Turbo: Q8_0, unsloth/Z-Image-Turbo-ComfyUI AE + Qwen3-4B, 8 steps.
  • FLUX.2 klein 4B: Q8_0, unsloth/FLUX.2-VAE + Qwen3-4B, 4 steps.
  • Qwen-Image: Q4_K_M, unsloth/Qwen-Image-ComfyUI VAE + Qwen2.5-VL-7B Q4_K_M, euler, shift 3, 20 steps, CFG 2.5.
  • FLUX.1 schnell: Q4_K_M, unsloth/flux-text-encoders, 4 steps. The FLUX.1 AE comes from unsloth/Z-Image-Turbo-ComfyUI, because black-forest-labs/FLUX.1-schnell is gated for our token. It is the same AE.
  • MiniMax-H3: fl2va pruned Q2_K + Qwen3-VL-32B Q2_K_M + video/audio VAEs, 480x288, 22 frames, 8 steps, --diffusion-fa.

Images are 1024x1024. Every arm repeated twice and is bit-identical to itself (A/A 0) on CPU and CUDA.

CUDA (B200, shared with other jobs)

Model sd.cpp defaults, master vs branch Studio flags (--diffusion-fa --diffusion-conv-direct) Branch with --flash-attn off --conv-direct off vs master defaults Time master / branch (s, 2 runs, defaults)
Z-Image Turbo LPIPS 0.0054, 44.4 dB 0.0002, 60.6 dB identical 13.5, 17.1 / 10.6, 13.8
FLUX.2 klein 4B 0.0255, 30.4 dB 0.0001, 59.4 dB identical 7.5, 10.2 / 7.6, 6.6
Qwen-Image 0.0095, 37.6 dB 0.0002, 55.8 dB identical 102.8, 69.3 / 68.3, 56.4
FLUX.1 schnell 0.0111, 36.5 dB 0.0001, 59.6 dB identical 26.0, 19.7 / 18.8, 16.8
MiniMax-H3 (video) 0.0049, 50.9 dB; audio bit-identical (same run, it passes --diffusion-fa) identical, audio bit-identical (--conv-direct off) 30.4, 28.3 / 29.2, 25.5

CPU (32 threads, GGML_NATIVE=OFF + all CPU variants, 512x512, 4 steps)

Model sd.cpp defaults Studio flags Branch with FA and direct conv off vs master defaults
Z-Image Turbo Q4_K_S LPIPS 0.0143, 34.7 dB identical identical
FLUX.2 klein 4B Q4_K_M 0.0190, 27.3 dB identical identical

Timing is from a host shared with other GPU and CPU jobs (Qwen-Image ranged 30 to 103 s for one arm), so it only supports "no slowdown". The branch was at or below master in every pair.

FLUX.3 (this branch only): the unsloth/flux-3-image-klein[-base]-GGUF denoisers (UD-Q4_K_XL, Q4_K_M, Q8_0, BF16) load as published. The VAE is vae/diffusion_pytorch_model.safetensors from the FP8 repos and the encoder is Qwen3-VL-4B-Instruct GGUF. At 1024, 16 steps on a B200, the distilled model takes about 9 to 11 s/img and the base (25 steps, CFG 3.5) 16 to 19 s/img. A reference edit with one -r image works without the vision projector. CPU output matches CUDA (LPIPS 0.0008 to 0.006 for the same cell).

losewayy and others added 19 commits October 10, 2026 22:33
Brings in 17 upstream commits up to leejet/stable-diffusion.cpp 8cd731e (FLUX.3 Image Klein and Klein Base, leejet#2143).
…e flash attention

Upstream leejet#2132 maps --diffusion-fa to --flash-attn off,diffusion=on and no longer sets the legacy diffusion_flash_attn flag, so the H3 VAE flash-attention rule (CUDA/ROCm by default) never fired after the sync. Key it on the resolved per-module state instead: diffusion FA on, VAE FA off, and no explicit vae= assignment.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-16T12:50:25.946640Z ca7d7af PR opened
🔒 Security Review ✅ Completed 2026-10-16T12:53:12.626354Z ca7d7af PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ca7d7af876

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

sd_version_is_minimax_h3(version)) {
// Keyed on the resolved per-module state: the CLI now spells --diffusion-fa as --flash-attn off,diffusion=on and
// never sets the legacy diffusion_flash_attn flag. An explicit vae= assignment is the user's choice and wins.
const bool vae_fa_assigned = std::string(SAFE_STR(sd_ctx_params->flash_attn_mode)).find("vae=") != std::string::npos;

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 Badge Honor every parsed VAE flash-attention assignment

On MiniMax-H3 with CUDA/ROCm, this raw substring check recognizes only the exact spelling vae=. The assignment parser also accepts whitespace, case differences, and aliases such as first_stage, autoencoder, and tae, so a valid setting like --flash-attn 'off,diffusion=on,first_stage=off' is parsed as an explicit VAE disable but is not detected here; the following block then enables VAE flash attention anyway. Check the parsed flash_attn_assignment.module_names for SDBackendModule::VAE rather than searching the original string.

Useful? React with 👍 / 👎.

@danielhanchen
danielhanchen merged commit bdb47d1 into master Oct 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants