fix(nodes): blend latents with weight=0 with DPMSolverSDEScheduler #6482
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
latents_a
to the output latents. Fixed an issue where usingBlendLatentsInvocation
could result in different outputs during denoising even when the alpha or slerp weight was 0.Explanation
LatentsField
has an optionalseed
field. During denoising, if thisseed
field is not present, we fall back to 0 for the seed. The seed is used during denoising in a few ways:Initializing the scheduler.
The seed is used in two places in
invokeai/app/invocations/latent.py
.The
get_scheduler()
utility function has special handling forDPMSolverSDEScheduler
, which appears to need a seed for deterministic outputs.DenoiseLatentsInvocation.init_scheduler()
has special handling for schedulers that accept a generator - the generator needs to be seeded in a particular way. At the time of this commit, these are the Invoke-supported schedulers that need this seed:Adding noise during inpainting.
If a mask is used for denoising, and we are not using an inpainting model, we add noise to the unmasked area. If, for some reason, we have a mask but no noise, the seed is used to add noise.
I wonder if we should instead assert that if a mask is provided, we also have noise.
This is done in
invokeai/backend/stable_diffusion/diffusers_pipeline.py
inStableDiffusionGeneratorPipeline.latents_from_embeddings()
.The problem
When we create noise to be used in denoising, we are expected to set
LatentsField.seed
to the seed used to create the noise. This introduces some awkwardness when we manipulate any "latents" that will be used for denoising. We have to pass the seed along for every operation.If the wrong seed or no seed is passed along, we can get unexpected outputs during denoising. One notable case relates to blending latents (slerping tensors).
If we slerp two noise tensors (
LatentsField
s) without passing along the seed from the source latents, when we denoise with a seed-dependent scheduler*, the schedulers use the fallback seed of 0 and we get the wrong output. This is most obvious when slerping with a weight of 0, in which case we expect the exact same output after denoising.*It looks like only the DPMSolver- schedulers are affected, but I haven't tested all of them.
Passing the seed along in the output fixes this issue.
Related Issues / Discussions
QA Instructions
Repro steps:
DPM++ SDE Karras
On
main
, we expect:On this PR, we expect:
Merge Plan
n/a
Checklist