This repository was archived by the owner on Oct 4, 2026. It is now read-only.
Repository navigation
fix(z-image): hold the schedule shift at the end of its fit - #378
Merged
Merged
Conversation
Clamp `_calculate_shift` at 4096 image tokens, the upper point of the two-point fit it is built on. Extrapolated, the shift reached 25 at 2048px and 103_777 at 4096px, and because `denoising_start` is clipped by index the entry sigma moved to 0.97 and 1.0000 instead of the step count collapsing -- an img2img pass asked to refine an image started from noise and generated a new one. Correct the `shift` field description, which documented mu units for a field consumed as exp(mu), and bump the invocation to 1.6.1.
Pfannkuchensack
requested review from
JPPhoto,
blessedcoolant and
lstein
as code owners
September 30, 2026 03:50
Correct the entry sigma quoted for a canvas img2img pass: 0.88 at 1536px and 0.96 at 2048px, not the values that belonged to a different denoising_start. Replace the step-count parametrisation, which read one number twice over, with a single cell for step-count invariance, and drop an inert patch.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ZImageDenoiseInvocation._calculate_shiftbuilds a straight line through two points — 256 image tokens to mu 0.5, 4096 tokens (a 1024×1024 frame) to mu 1.15 — and evaluated it past the second one. Extrapolated, the shift reaches 25 at 2048px, 810 at 3072px and 103 777 at 4096px, and_get_sigmasflattens with it.Because
denoising_startis clipped here by index (start_idx = int(denoising_start * (total_sigmas - 1))), the step count survives and the entry sigma moves instead. A canvas img2img pass at strength 0.5 entered at:At 4096px the blend
s · noise + (1 − s) · initkept nothing of the input, so a pass asked to refine an image generated a new one instead. This clamps the fit at its upper anchor. Below one megapixel nothing changes, the fit stays live there, and an explicitshifton the invocation still overrides it.This is the same defect and the same fix as #359 for FLUX.1, which cited the identical two-point fit.
Related Issues / Discussions
Follows #359 (the FLUX.1 clamp). The underlying reason this was reachable at all — Z-Image and Anima clip
denoising_startby index where FLUX.1, FLUX.2, SD3 and CogView4 use the shared value-basedclip_timestep_schedule_fractional— is a separate change and is not in this PR.QA Instructions
Reproduce on
main: a Z-Image img2img pass at 2048×2048 withdenoising_start0.5 returns an image unrelated to its input. With this change it refines the input.Checks run:
pytest tests/app/invocations/test_z_image_schedule_shift.py— 14 passedpytest tests/app/invocations -n 4— 2046 passed, 3 skipped, 6 xfailedpytest -k "z_image or zimage"— 192 passedpytest tests/app tests/backend/flux -n 4— 6752 passed, 9 failed; all 9 are pre-existing local download/install failures caused by anHF_ENDPOINTproxy in this environment and pass underenv -u HF_ENDPOINT(45 passed)ruff checkandruff format --checkon the touched paths — cleanmake frontend-openapiandmake frontend-typegen— regenerated, diff limited to the two intended changesThe new cells drive the real
_run_diffusionas far as the img2img blend and read the entry sigma back out of the blended tensor rather than recomputing the schedule, so they fail if the node stops honouring the clamp, the override, or the clipping. Each was run against a deliberately broken copy of the node; seven mutations, all caught, including deletion of theshiftoverride.Review
The first version of the override cell recomputed the schedule itself and stayed green when the override branch was deleted — it was replaced with the harness described above, which also closes the previously untested index-clipping path. Two further items were found and fixed: the
shiftfield description documented mu units for a field consumed asexp(mu), and a function-localimport mathshadowed the module import.Remaining limitation: this corrects where the pass starts, not the fact that Z-Image measures
denoising_starton a different scale from FLUX.1. At the same slider value Z-Image still enters at more noise than FLUX.1 does. That is the value-based clipping change, deliberately kept separate because it alters the meaning of every saved Z-Image setting.Compatibility / Rollout
Invocation version 1.6.0 → 1.6.1;
openapi.jsonand the generatedschema.tsregenerated.Existing workflows keep working and are unaffected at or below one megapixel. Above it, a partial denoise becomes more conservative — which is the point of the fix — so a saved workflow that relied on the runaway shift to produce near-txt2img output at high resolutions will now refine its input instead.
shiftcan be set explicitly to restore the previous value.Full denoises (
denoising_start = 0) still enter at sigma 1.0 at every resolution, but the intermediate sigmas above one megapixel do change, so a txt2img generation there will differ from 1.6.0 at the same seed. That is the intended consequence of holding the fit; it is the same trade #359 made for FLUX.1.Checklist
What's Newcopy (if doing a release after this PR)