Skip to content

fix(qwen-image-2-1): hold the base model's shift at the end of its fit - #9902

Merged
joshistoast merged 5 commits into
invoke-ai:mainfrom
Pfannkuchensack:fix/qwen-image-2-1-shift-hold
Oct 19, 2026
Merged

joshistoast merged 5 commits into
invoke-ai:mainfrom
Pfannkuchensack:fix/qwen-image-2-1-shift-hold

Conversation

@Pfannkuchensack

@Pfannkuchensack Pfannkuchensack commented Oct 17, 2026 •

Copy link
Copy Markdown
Member

Summary

Qwen-Image-2.1's base model set its noise-schedule shift (mu) from the image's token count along a line through its scheduler config: 256 tokens give 0.5, and 8192 tokens give 0.9 (about 1448×1448 of area, 2.1 MP). Above 8192 tokens the line kept climbing.

Image mu before mu after 40-step img2img at strength 0.5 starts at sigma
1024² 0.69 0.69 0.66, unchanged
2048² 1.31 0.90 0.77 → 0.70
4096² 3.79 0.90 0.95 → 0.70

calculate_mu now holds mu at the end of its fit. Qwen-Image (#9892), Krea-2 Raw (#9887), FLUX.1 and Z-Image already do the same.

  • Turbo samples its own fixed table, so it is unaffected.
  • The qwen_image_2_1_denoise node goes from 1.0.0 to 1.0.1; its inputs are unchanged.
  • The docstrings of calculate_mu and build_sigmas say the schedule matches the pipeline only up to the end of the fit.

Why: at 4096², an image-to-image pass at strength 0.5 started from almost pure noise, so it replaced the image instead of refining it.

How the reference implementations handle this:

  • diffusers QwenImage21Pipeline extrapolates like the old code.
  • ComfyUI samples Qwen-Image-2.1 at a constant mu of 0.69 (supported_models.py, QwenImage21.sampling_settings).

Related Issues / Discussions

Follow-up to #9784. The same fix for Qwen-Image is #9892, and for Krea-2 Raw it is #9887.

QA Instructions

Automated

  • pytest tests/backend/qwen_image_2_1 tests/app/invocations/test_qwen_image_2_1_nodes.py: 57 passed.
    • Pipeline parity: the parity test against QwenImage21Pipeline recordings now keeps only cases within the fit. The 2048² recording was the extrapolated schedule, so it was removed.
    • Above the fit: new cases check that 8192, 16384 and 65536 tokens all give the 8192-token schedule. The expected head and tail sigmas were computed with diffusers' FlowMatchEulerDiscreteScheduler at mu 0.9, outside the code under test.
    • Below the end: 1440² (8100 tokens) still follows the line.
    • Mutation probes: each of these fails at least one test: removing the hold; holding at 8191, 8193, 4096 or 16384 tokens; a constant mu of 0.69.
  • ruff@0.11.2 check / format --check: pass. openapi.json is regenerated; only the node version changes.

GPU A/B (RTX 4090, Qwen-Image-2.1 base Q4_K_M GGUF, Qwen3-VL 8B fp8 encoder, 40 steps, CFG 1, model cache emptied before each run). Main's code and this branch ran the same graphs:

Graph Result main / this PR
text-to-image 1024² bit-identical 66 s / 53 s (first, cold run)
text-to-image 2048², seed 1234 Same composition, lettering, lighthouse and house; waves and rocks differ in detail 183 s / 170 s
text-to-image 2048², seed 99 Same scene; the sun sits on the horizon and the sky is crisper with the hold 203 s / 174 s
image-to-image 2048², strength 0.5 Both keep the source's composition and lettering; the held run changes a little less 104 s / 96 s

No image shows doubled subjects, broken lettering or a damaged composition.

Review

No material findings. Resolved:

  • The build_sigmas docstring still claimed exact parity with the pipeline; it now scopes that to within the fit.
  • The docs now say that text-to-image above about 1448×1448 changes too.

Compatibility / Rollout

  • Same seed, different image: base-model images above about 1448×1448 of area no longer reproduce with the same seed, and they differ from diffusers' QwenImage21Pipeline there.
    • The node has no Shift input, so the old schedule cannot be selected.
    • Image metadata does not record mu.
  • Unchanged: Turbo, and base images at or below that area.
  • Saved workflows: the 1.0.1 node has the same fields as 1.0.0. The editor offers to update 1.0.0 nodes, and running them is not blocked.

Checklist

  • The PR has a short but descriptive title, suitable for a changelog
  • Meaningful regression coverage added / updated where needed; obsolete tests/code removed
  • Persisted-state and API changes include required migrations / compatibility validation
  • Relevant performance/efficiency opportunities considered; material claims have evidence
  • Material review findings resolved and relevant checks rerun
  • Documentation added / updated (if applicable)
  • Updated What's New copy (if doing a release after this PR)

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

Above 8192 image tokens (about 1448x1448) mu stays at 0.9 instead of extrapolating; Turbo's fixed table is unchanged.
The Qwen-Image-2.1 docs explain the hold and that large base-model images no longer match the diffusers pipeline.
@github-actions github-actions Bot added python PRs that change python files invocations PRs that change invocations backend PRs that change backend files python-tests PRs that change python tests docs PRs that change docs labels Oct 17, 2026
@joshistoast joshistoast self-assigned this Oct 19, 2026
@joshistoast
joshistoast enabled auto-merge (squash) October 19, 2026 01:17
@joshistoast
joshistoast merged commit 5582a8d into invoke-ai:main Oct 19, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend PRs that change backend files docs PRs that change docs invocations PRs that change invocations python PRs that change python files python-tests PRs that change python tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants