Commit 25bbf32
feat(model): Add ER SDE / DPM++ 2M Scheduler Support For Anima (invoke-ai#9125)
* refactor(anima): reshape ANIMA_SCHEDULER_MAP to (class, kwargs) tuples
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(anima): address Task 1 review feedback
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(anima): add dpmpp_2m and dpmpp_2m_sde schedulers
* refactor(anima): unify ANIMA_SHIFT in schedulers.py and add Literal-coverage test
* fix(anima): seed generator into scheduler.step for SDE reproducibility
* feat(anima): add pure ancestral-Euler step helper
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs(anima): fix _anima_euler_ancestral_step docstring formula to match code
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* refactor(anima): address Task 4 review feedback
* feat(anima): add euler_a (rectified-flow ancestral Euler) scheduler
* fix(anima): sample euler_a noise in float32 to avoid bfloat16 quantization
* chore(anima): bump anima_denoise to v1.3.0 and regen schema
* fix(frontend): revert Windows path-separator drift in schema regen
* fix(anima): gate step_generator construction to schedulers that need it
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore(anima): apply ruff lint and format fixes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(frontend): expose new Anima schedulers in dropdown and metadata recall
* chore(frontend): apply prettier wrap to setAnimaScheduler PayloadAction
* fix(anima): correct euler_a math — variance-preserving noise mix, not biased Euler
* revert(anima): remove euler_a scheduler — quality not worth the complexity
* chore(anima): apply ruff format (trim trailing blank lines)
* feat(rectified-flow): add order-1 ER-SDE stepper for rectified flow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs(rectified-flow): document lambda_next>0 precondition; tighten terminal-step test
Address code review feedback on order-1 ER-SDE stepper:
- Add docstring preconditions to integral helpers noting the logarithmic
singularity at lam=0 (callers must guard sigma_next>0).
- Tighten terminal-step test from atol=1e-5 to torch.equal — the algebra
is exact when sigma_next=0, not approximate.
* feat(rectified-flow): add 2nd-order Taylor extension to ER-SDE stepper
* test(rectified-flow): tighten Task 2 state-mutation test with value assertion
Address code review feedback on the 2nd-order Taylor extension tests:
- Assert state.old_d_x0 equals the analytically-computed d_x0 = 0.2v / (1.5 - 4.0)
rather than just checking it's non-None.
- Document that x_t is intentionally re-used across calls (state threading
test, not trajectory correctness).
- Document the order-2 correction coefficient magnitude that justifies the
atol=1e-3 threshold in the engagement test.
* feat(rectified-flow): add 3rd-order Taylor extension to ER-SDE stepper
* docs(rectified-flow): document have_two_back invariant + order-3 test margin
Address code review feedback on Task 3:
- Comment why have_two_back checks both old_d_x0 and sigma_prev_prev
(the sigma~=1 boundary path can break the joint invariant).
- Document the analytically verified ~0.0004 per-element correction
magnitude that justifies the atol=1e-3 threshold in the order-3 test.
* feat(anima): register er_sde scheduler choice
* docs(anima): document custom-code-path scheduler convention; tighten test
Address code review feedback on Task 4:
- Add an in-file comment above ANIMA_SCHEDULER_MAP explaining the
convention: schedulers with custom code paths (er_sde) live in the
Literal+labels only, not the map.
- Hoist `import typing` to module-level in test_anima_schedulers.py
(was inline-imported in two test functions).
- Pin the er_sde label value (== "ER-SDE"), not just key existence.
* feat(anima): wire er_sde scheduler into denoise loop
* docs(anima): document float32 noise dtype and sigma_next/sigma_prev naming
Address code review feedback on Task 5:
- Comment explaining why fresh_noise is float32 (matches er_sde_rf_step's
dtype contract with x_t.to(float32)).
- Bridging comment at the inpaint extension call clarifying that
sigma_next here means the same thing as sigma_prev in the Euler branch
and the AnimaInpaintExtension API.
* chore(anima): bump anima_denoise to v1.4.0 and regen schema
* feat(frontend): expose er_sde scheduler in dropdown and metadata recall
Address code review on Task 6 — er_sde was registered in the OpenAPI
schema but missing from the frontend's own Zod enums and Redux
PayloadAction types, so:
- The combobox dropdown didn't list it.
- setAnimaScheduler('er_sde') would fail TypeScript at the call site.
- Metadata recall for er_sde-generated images would silently no-op
(the scheduler value couldn't pass zParameterScheduler validation).
Changes:
- Add er_sde to zAnimaSchedulerField (the per-Anima Zod enum).
- Add er_sde to the animaScheduler state-shape Zod enum.
- Widen setAnimaScheduler's PayloadAction union.
- Add ER-SDE option to the ParamAnimaScheduler combobox.
- Make the metadata Scheduler handler accept ParameterAnimaScheduler too,
with a fallback parse and a narrowing guard before the SD/SDXL dispatch.
* fix(rectified-flow): guard 2nd-order branch against sigma_prev_curr=1.0
When step 0 goes through the sigma_curr=1 closed-form limit branch it
writes state.sigma_prev_curr=1.0. On step 1, have_one_back was True and
the 2nd-order path called _lambda(1.0) = 1.0/(1.0-1.0), crashing with
ZeroDivisionError in every real denoise run.
Fix: extend the have_one_back guard to require that sigma_prev_curr is
more than _SIGMA_ONE_TOLERANCE below 1.0. The finite-difference derivative
across the limit step is not meaningful, so skipping the 2nd-order term on
that transition is correct. Order-3 is already gated behind old_d_x0 being
set, which this path never sets, so no additional guard is needed there.
Adds a regression test that runs the full sigma=1.0->0.9->0.7->0.0
sequence and asserts no ZeroDivisionError and all-finite output.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(scheduler): add ERSDEScheduler available to SD/SDXL
ER-SDE solver (Cui et al., arXiv:2309.06169) usable across SD/SDXL
(VP-SDE) and rectified-flow models. Anima migration follows in
subsequent commits.
- ERSDEScheduler(SchedulerMixin, ConfigMixin) with prediction_type
(epsilon | v_prediction | flow_prediction), use_flow_sigmas,
solver_order (1/2/3 with auto-warmup), and stochastic toggle
- set_timesteps(sigmas=) for pre-shifted Anima/FLUX/Z-Image schedules
- Closed-form limit at sigma=1 in flow mode
- Unit tests + VP smoke + 5/5 Anima parity vs er_sde_rf_step
(worst delta 5.137e-07)
- Frontend wiring: zSchedulerField, SCHEDULER_OPTIONS, OpenAPI regen
- parsing.tsx cleanup: removes the AnyScheduler widening since
er_sde is now a first-class general scheduler
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* feat(anima): wire ERSDEScheduler into ANIMA_SCHEDULER_MAP
Adds er_sde to the standard scheduler dispatch map with rectified-flow
kwargs (flow_prediction, use_flow_sigmas=True, flow_shift=3.0,
solver_order=3, stochastic=True). Anima still routes through the
legacy elif is_er_sde: branch — that's removed in a follow-up commit.
This is the additive prerequisite that lets the cutover happen without
a window where Anima can't use ER-SDE.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* test(anima): add ER-SDE dispatch integration tests
Verifies the ANIMA_SCHEDULER_MAP['er_sde'] entry instantiates correctly,
accepts pre-shifted sigmas via set_timesteps(sigmas=...), and resets
multistep state. Catches wiring regressions that the algorithm-level
parity test cannot.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* refactor(anima): remove elif is_er_sde branch, dispatch through ANIMA_SCHEDULER_MAP
Anima ER-SDE now flows through the same standard scheduler path as
dpmpp_2m_sde — pre-shifted sigmas via scheduler.set_timesteps(sigmas=...),
inpaint extension via inpaint_extension.merge_intermediate_latents_with_init_latents,
step_callback per-step. The custom code path was the only thing keeping
ER-SDE off the universal pipeline.
Bumps invocation version to 1.5.0.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* docs(er_sde): mark module as internal reference and parity oracle
ERSDEScheduler is now the production code path. er_sde_rf_step is kept
as the comparison oracle for the scheduler's parity test, and as a
self-contained mathematical reference for the rectified-flow algebra.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore(rectified-flow): remove er_sde.py reference helper
ERSDEScheduler is the production code path. The pure-function helper
was retained as a parity oracle but YAGNI — keeping ~200 lines of code
purely as a regression net for hypothetical future drift isn't worth
the maintenance signal it generates.
Removes:
- invokeai/backend/rectified_flow/er_sde.py
- tests/backend/rectified_flow/test_er_sde.py
- tests/backend/rectified_flow/test_er_sde_scheduler_anima_parity.py
ERSDEScheduler's own tests (test_er_sde_scheduler.py) remain — they
exercise both VP-SDE and rectified-flow paths directly.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(schema): restore forward slashes in @default cache dir paths
Windows-side typegen run flipped these to backslashes. Restore the
canonical forward-slash form to match upstream.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* style: apply ruff lint and format to ER-SDE files
Sort imports + format per project ruff config (line-length 120).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* refactor(state): use zParameterAnimaScheduler in state shape
The animaScheduler field inlined its enum (originally to add er_sde
when the shared schema didn't have it yet). Now that zAnimaSchedulerField
already includes er_sde, reference the shared zParameterAnimaScheduler
to match the pattern used by scheduler/fluxScheduler/zImageScheduler.
Drops the redundant .default('euler') — initial value comes from
getInitialParamsState.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* style(types): sort imports per simple-import-sort
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(anima): honour clipped sigma schedule for DPM++ img2img/inpaint
DPMSolverMultistepScheduler doesn't accept sigmas= in diffusers 0.35.1,
so the fallback previously called set_timesteps(num_inference_steps=total_steps)
which regenerated a full schedule from sigma_max, ignoring denoising_start/end.
When the scheduler supports set_begin_index, call set_timesteps with the
full step count and offset into it, so the internal flow_shift applies
correctly and denoising starts at the right sigma.
Also fixes the inpaint sigma_prev lookup and the timestep loop to use the
same offset, and corrects the false parity-test reference in the ER-SDE
dispatch test docstring.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* style: apply ruff format to anima_denoise dispatch block
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(anima): extract scheduler driver and fix Heun progress/inpaint bugs
Encapsulate per-scheduler dispatch quirks (sigmas= vs num_inference_steps=,
Heun's doubled-array index, set_begin_index path) in AnimaSchedulerDriver
and tighten two latent bugs in the Heun path of anima_denoise:
* Heun's terminal first-order step never reported a user-step completion,
so progress capped at N-1 of N. The driver now flags it via sigma_prev==0,
and the <= total_steps clamp that papered over the off-by-one is gone.
* The inpaint mix ran after every Heun half-step, corrupting the second-order
corrector's input (RectifiedFlowInpaintExtension's docstring says it should
be called after each denoising step — i.e. once per user step). Mix is now
gated on completes_user_step, which is unconditionally True for non-Heun.
Also: Heun shift kwarg switched to ANIMA_SHIFT (its set_timesteps doesn't
accept sigmas=, so it builds its own internal schedule); narrative comments
in scheduler_driver and er_sde_scheduler trimmed; new tests covering driver
iteration counts, terminal sigma_prev, seed determinism, and the begin_index
fallback for clipped DPM++ schedules.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* style: apply ruff lint and format to anima scheduler driver
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* ci: re-run after flaky token-expiration test
The 1-second JWT token-expiration test in test_token_service.py is timing
sensitive — passes locally on retry. Empty commit to retrigger CI.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Your Name <you@example.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com>1 parent fcc0881 commit 25bbf32
17 files changed
Lines changed: 1765 additions & 93 deletions
File tree
- invokeai
- app/invocations
- backend
- anima
- flux
- rectified_flow
- stable_diffusion/schedulers
- frontend/web
- src
- features
- controlLayers/store
- metadata
- nodes/types
- parameters
- components/Core
- types
- services/api
- tests
- app/invocations
- backend
- anima
- flux
- rectified_flow
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
19 | | - | |
20 | 19 | | |
21 | 20 | | |
22 | 21 | | |
23 | 22 | | |
24 | 23 | | |
25 | 24 | | |
26 | | - | |
27 | 25 | | |
28 | 26 | | |
29 | 27 | | |
| |||
42 | 40 | | |
43 | 41 | | |
44 | 42 | | |
45 | | - | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
46 | 49 | | |
47 | 50 | | |
48 | 51 | | |
| |||
59 | 62 | | |
60 | 63 | | |
61 | 64 | | |
62 | | - | |
63 | | - | |
64 | 65 | | |
65 | 66 | | |
66 | 67 | | |
| |||
165 | 166 | | |
166 | 167 | | |
167 | 168 | | |
168 | | - | |
| 169 | + | |
169 | 170 | | |
170 | 171 | | |
171 | 172 | | |
| |||
491 | 492 | | |
492 | 493 | | |
493 | 494 | | |
494 | | - | |
495 | | - | |
| 495 | + | |
496 | 496 | | |
497 | | - | |
| 497 | + | |
498 | 498 | | |
499 | | - | |
500 | | - | |
501 | | - | |
502 | | - | |
503 | | - | |
504 | | - | |
505 | | - | |
506 | | - | |
507 | | - | |
508 | | - | |
509 | | - | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
510 | 508 | | |
511 | 509 | | |
512 | 510 | | |
| |||
587 | 585 | | |
588 | 586 | | |
589 | 587 | | |
590 | | - | |
591 | | - | |
| 588 | + | |
592 | 589 | | |
593 | 590 | | |
594 | | - | |
595 | | - | |
596 | | - | |
597 | | - | |
598 | | - | |
599 | | - | |
600 | | - | |
| 591 | + | |
601 | 592 | | |
602 | | - | |
| 593 | + | |
603 | 594 | | |
604 | 595 | | |
605 | 596 | | |
| |||
610 | 601 | | |
611 | 602 | | |
612 | 603 | | |
613 | | - | |
614 | | - | |
615 | | - | |
616 | | - | |
617 | | - | |
618 | | - | |
619 | | - | |
| 604 | + | |
620 | 605 | | |
621 | | - | |
622 | | - | |
623 | | - | |
624 | | - | |
625 | | - | |
626 | | - | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
627 | 616 | | |
628 | | - | |
629 | | - | |
630 | | - | |
631 | | - | |
632 | | - | |
633 | | - | |
634 | | - | |
635 | | - | |
636 | | - | |
637 | | - | |
638 | | - | |
639 | | - | |
640 | | - | |
641 | | - | |
642 | | - | |
643 | 617 | | |
644 | | - | |
645 | | - | |
646 | | - | |
647 | | - | |
648 | | - | |
649 | | - | |
650 | | - | |
651 | | - | |
652 | | - | |
653 | | - | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
654 | 626 | | |
| 627 | + | |
655 | 628 | | |
656 | 629 | | |
657 | 630 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
0 commit comments