dikdimon commited on
Commit
08a6d74
·
verified ·
1 Parent(s): 03aa198

Upload adept_scheduler_pack.py

Browse files
adept-sampler-v6/scripts/adept_scheduler_pack.py ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Adept Scheduler Pack for Automatic1111 WebUI
3
+ Registers Adept Sampler's scheduler algorithms into A1111's native
4
+ "Schedule type" dropdown (the one next to "Sampling method"), so they
5
+ become usable with ANY sampler -- not only when the Adept Sampler script
6
+ itself is active via its own "Scheduler Type" dropdown.
7
+
8
+ Companion file to adept_sampler_v5.py: it must be installed in the same
9
+ scripts/ folder. This file reads Adept's scheduler functions directly off
10
+ the loaded adept_sampler_v5 module (no duplicated formulas), so any future
11
+ tweak to those functions is picked up automatically -- nothing here needs
12
+ updating when Adept's own schedulers change.
13
+
14
+ If adept_sampler_v5.py isn't found (not installed, or failed to load for
15
+ some other reason), this file logs a message and does nothing further; it
16
+ never raises, so a missing companion file can't break WebUI startup.
17
+ """
18
+
19
+ import os
20
+ import torch
21
+ from modules import scripts, script_callbacks
22
+ import modules.sd_schedulers as sd_schedulers
23
+
24
+ _ADEPT_SCRIPT_FILENAME = "adept_sampler_v5.py"
25
+
26
+ # (label shown in the Schedule-type dropdown, internal name, function name on
27
+ # the adept_sampler_v5 module). Mirrors apply_custom_scheduler's own
28
+ # scheduler_map in adept_sampler_v5.py exactly -- kept as literal strings
29
+ # (not imported) so this file has no hard import-time dependency on that
30
+ # module actually existing.
31
+ _ADEPT_SCHEDULER_SPECS = [
32
+ ("Adept: AOS-V", "adept_aos_v", "create_aos_v_sigmas"),
33
+ ("Adept: AOS-Epsilon", "adept_aos_epsilon", "create_aos_e_sigmas"),
34
+ ("Adept: AkashicAOS", "adept_akashic_aos", "create_aos_akashic_sigmas"),
35
+ ("Adept: Entropic", "adept_entropic", "create_entropic_sigmas"),
36
+ ("Adept: SNR-Optimized", "adept_snr_optimized", "create_snr_optimized_sigmas"),
37
+ ("Adept: Constant-Rate", "adept_constant_rate", "create_constant_rate_sigmas"),
38
+ ("Adept: Adaptive-Optimized", "adept_adaptive_optimized", "create_adaptive_optimized_sigmas"),
39
+ ("Adept: Cosine-Annealed", "adept_cosine_annealed", "create_cosine_sigmas"),
40
+ ("Adept: LogSNR-Uniform", "adept_logsnr_uniform", "create_logsnr_uniform_sigmas"),
41
+ ("Adept: Tanh Mid-Boost", "adept_tanh_midboost", "create_tanh_midboost_sigmas"),
42
+ ("Adept: Exponential Tail", "adept_exponential_tail", "create_exponential_tail_sigmas"),
43
+ ("Adept: Jittered-Karras", "adept_jittered_karras", "create_jittered_karras_sigmas"),
44
+ ("Adept: Stochastic", "adept_stochastic", "create_stochastic_sigmas"),
45
+ ("Adept: JYS (Dynamic)", "adept_jys", "create_jys_sigmas"),
46
+ ("Adept: Hybrid JYS-Karras", "adept_hybrid_jys_karras", "create_hybrid_jys_karras_sigmas"),
47
+ ("Adept: AYS-SDXL", "adept_ays_sdxl", "create_ays_sdxl_sigmas"),
48
+ ("Adept: AkashicAOS Alt", "adept_akashic_aos_alt", "create_aos_akashic_alt_sigmas"),
49
+ ("Adept: AkashicEQFlow", "adept_akashic_eqflow", "create_akashic_eqflow_sigmas"),
50
+ ]
51
+
52
+
53
+ def _find_adept_module():
54
+ """Locate the already-loaded adept_sampler_v5 module via A1111's own
55
+ script registry (scripts.scripts_data), the same technique Adept itself
56
+ uses to find xyz_grid.py. Deferred to on_before_ui time so load order
57
+ between the two files never matters -- every script's top-level code
58
+ has already run by the time on_before_ui callbacks fire."""
59
+ for data in scripts.scripts_data:
60
+ if os.path.basename(data.path) == _ADEPT_SCRIPT_FILENAME:
61
+ return data.module
62
+ return None
63
+
64
+
65
+ def _make_adapter(adept_fn, label):
66
+ """
67
+ Wrap one of Adept's create_*_sigmas(sigma_max, sigma_min, num_steps,
68
+ device, ...) functions to match A1111's native scheduler signature:
69
+ function(n, sigma_min, sigma_max, device, **extra). A1111 calls this
70
+ with keyword arguments (n=steps, sigma_min=..., sigma_max=...,
71
+ device=...), never positionally, so only the parameter *names* need to
72
+ line up -- the underlying function's extra optional kwargs (Entropic's
73
+ `power`, Stochastic's `noise_type`, etc.) keep their own defaults since
74
+ A1111 has no UI for them and won't pass them.
75
+ """
76
+ def adapter(n, sigma_min, sigma_max, device='cpu', **_ignored):
77
+ try:
78
+ # A1111's native scheduler API passes sigma_min/sigma_max as
79
+ # plain Python floats (via .item()); Adept's own internal call
80
+ # path (apply_custom_scheduler) always passes tensor elements
81
+ # instead. A few of Adept's scheduler functions call torch.log()
82
+ # directly on these arguments, which requires a tensor -- so we
83
+ # convert here, at the compatibility boundary, rather than
84
+ # touching the already-shipped, tested adept_sampler_v5.py.
85
+ sigma_min_t = torch.as_tensor(sigma_min, dtype=torch.float32, device=device)
86
+ sigma_max_t = torch.as_tensor(sigma_max, dtype=torch.float32, device=device)
87
+ result = adept_fn(sigma_max_t, sigma_min_t, n, device=device)
88
+ if result is None or len(result) != n + 1:
89
+ raise ValueError(f"unexpected shape from {label}")
90
+ if torch.isnan(result).any() or torch.isinf(result).any():
91
+ raise ValueError(f"NaN/Inf from {label}")
92
+ return result
93
+ except Exception as e:
94
+ print(f"⚠️ Adept Scheduler Pack: '{label}' failed ({e}), falling back to Karras")
95
+ import k_diffusion.sampling as k_diff
96
+ return k_diff.get_sigmas_karras(n, sigma_min, sigma_max, device=device)
97
+ return adapter
98
+
99
+
100
+ def register_adept_schedulers():
101
+ adept_mod = _find_adept_module()
102
+ if adept_mod is None:
103
+ print("⚠️ Adept Scheduler Pack: adept_sampler_v5.py not found -- "
104
+ "install it alongside this file to enable Adept schedulers "
105
+ "in the native Schedule type dropdown.")
106
+ return
107
+
108
+ # Dedup guard: safe to call more than once (e.g. UI reload).
109
+ if any(getattr(s, "name", "").startswith("adept_") for s in sd_schedulers.schedulers):
110
+ return
111
+
112
+ registered = 0
113
+ for label, name, fn_name in _ADEPT_SCHEDULER_SPECS:
114
+ adept_fn = getattr(adept_mod, fn_name, None)
115
+ if adept_fn is None:
116
+ print(f"⚠️ Adept Scheduler Pack: {fn_name} not found on adept_sampler_v5 "
117
+ f"(version mismatch?), skipping '{label}'")
118
+ continue
119
+
120
+ sched = sd_schedulers.Scheduler(
121
+ name=name,
122
+ label=label,
123
+ function=_make_adapter(adept_fn, label),
124
+ default_rho=-1,
125
+ need_inner_model=False,
126
+ )
127
+ sd_schedulers.schedulers.append(sched)
128
+ # schedulers_map is built once (as a dict comprehension) right after
129
+ # the schedulers list at sd_schedulers.py's own import time -- it
130
+ # does NOT update itself when the list is appended to afterwards.
131
+ # Both the name and label must be added, matching how the map is
132
+ # originally built, or lookups by either key at generation time
133
+ # would fail to find these newly-registered entries.
134
+ sd_schedulers.schedulers_map[sched.name] = sched
135
+ sd_schedulers.schedulers_map[sched.label] = sched
136
+ registered += 1
137
+
138
+ print(f"✅ Adept Scheduler Pack: registered {registered}/{len(_ADEPT_SCHEDULER_SPECS)} "
139
+ f"schedulers into the native Schedule type dropdown")
140
+
141
+
142
+ def on_before_ui():
143
+ try:
144
+ register_adept_schedulers()
145
+ except Exception:
146
+ import traceback
147
+ print(f"⚠️ Adept Scheduler Pack: registration failed:\n{traceback.format_exc()}")
148
+
149
+
150
+ script_callbacks.on_before_ui(on_before_ui)