Instructions to use nebulette/moss-spectrum-diffusers with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use nebulette/moss-spectrum-diffusers with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("nebulette/moss-spectrum-diffusers", dtype=torch.bfloat16, device_map="cuda") prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k" image = pipe(prompt).images[0] - Notebooks
- Google Colab
- Kaggle
Update spectrum.py
Browse files- spectrum.py +24 -31
spectrum.py
CHANGED
|
@@ -78,7 +78,7 @@ class SpectrumConfig:
|
|
| 78 |
def window_cap(self) -> float:
|
| 79 |
return max(1.0, self.window_size, float(self.history_points))
|
| 80 |
|
| 81 |
-
def
|
| 82 |
u = torch.as_tensor(u, dtype=torch.float64).reshape(-1)
|
| 83 |
cols = [torch.ones_like(u)]
|
| 84 |
if degree >= 1:
|
|
@@ -87,7 +87,7 @@ def _cheb_basis(u, degree: int) -> torch.Tensor:
|
|
| 87 |
cols.append(2.0 * u * cols[-1] - cols[-2])
|
| 88 |
return torch.stack(cols[: degree + 1], dim=-1) # [n, P]
|
| 89 |
|
| 90 |
-
class
|
| 91 |
"""Chebyshev ridge forecaster (prediction = weighted sum of anchors)"""
|
| 92 |
def __init__(self, cfg: SpectrumConfig):
|
| 93 |
self.cfg = cfg
|
|
@@ -116,7 +116,7 @@ class _Forecaster:
|
|
| 116 |
self._chol = None
|
| 117 |
|
| 118 |
def _design(self) -> torch.Tensor:
|
| 119 |
-
return
|
| 120 |
|
| 121 |
def _factor(self) -> torch.Tensor:
|
| 122 |
if self._chol is not None:
|
|
@@ -160,7 +160,7 @@ class _Forecaster:
|
|
| 160 |
return w
|
| 161 |
|
| 162 |
def weights(self, u: float) -> torch.Tensor:
|
| 163 |
-
phi =
|
| 164 |
solved = torch.cholesky_solve(self._design().T, self._factor()) # [P, K]
|
| 165 |
spectral = (phi @ solved).reshape(-1)
|
| 166 |
bw = self.cfg.blend_weight
|
|
@@ -194,7 +194,7 @@ class _Forecaster:
|
|
| 194 |
den = actual.float().norm().clamp_min(1e-6)
|
| 195 |
return float((num / den).item())
|
| 196 |
|
| 197 |
-
class
|
| 198 |
"""Per-branch scheduler state"""
|
| 199 |
def __init__(self, cfg: SpectrumConfig):
|
| 200 |
self.cfg = cfg
|
|
@@ -202,13 +202,13 @@ class _Branch:
|
|
| 202 |
self.consecutive = 0
|
| 203 |
self.actual = 0
|
| 204 |
self.forecast = 0
|
| 205 |
-
self.forecasters: dict[int,
|
| 206 |
self.errors: list[float] = []
|
| 207 |
|
| 208 |
-
def forecaster(self, sample: int) ->
|
| 209 |
f = self.forecasters.get(sample)
|
| 210 |
if f is None:
|
| 211 |
-
f = self.forecasters[sample] =
|
| 212 |
return f
|
| 213 |
|
| 214 |
def decide(self, step: int, total: int) -> bool:
|
|
@@ -234,20 +234,20 @@ class _Branch:
|
|
| 234 |
self.consecutive += 1
|
| 235 |
|
| 236 |
|
| 237 |
-
class
|
| 238 |
def __init__(self, cfg: SpectrumConfig, scheduler: Any):
|
| 239 |
self.cfg = cfg
|
| 240 |
self.scheduler = scheduler
|
| 241 |
self.original_forward = None
|
| 242 |
self.step_index = -1
|
| 243 |
-
self.branches: dict[Any,
|
| 244 |
self._sig_counts: dict[Any, int] = {}
|
| 245 |
self._log: list[str] = []
|
| 246 |
|
| 247 |
-
def branch(self, key: Any) ->
|
| 248 |
b = self.branches.get(key)
|
| 249 |
if b is None:
|
| 250 |
-
b = self.branches[key] =
|
| 251 |
return b
|
| 252 |
|
| 253 |
def reset_run(self) -> None:
|
|
@@ -266,20 +266,13 @@ class _State:
|
|
| 266 |
f"{f}/{a + f} ({speed:.2f}x) mean_forecast_rel_err={mean_err:.4f}"
|
| 267 |
)
|
| 268 |
|
| 269 |
-
def
|
| 270 |
layers = () if layers is None else tuple(layers)
|
| 271 |
if any(type(i) is not int or not 0 <= i < depth for i in layers):
|
| 272 |
raise ValueError(f"{name} must contain integer block indices in [0, {depth}).")
|
| 273 |
return layers
|
| 274 |
|
| 275 |
-
|
| 276 |
-
def _coord(step: int, total: int) -> float:
|
| 277 |
-
if total <= 1:
|
| 278 |
-
return 0.0
|
| 279 |
-
return max(-1.0, min(1.0, 2.0 * step / (total - 1) - 1.0))
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
def _resolve_step(state: _State, timestep: torch.Tensor) -> tuple[int, int]:
|
| 283 |
sched = state.scheduler
|
| 284 |
timesteps = getattr(sched, "timesteps", None) if sched is not None else None
|
| 285 |
if timesteps is None or len(timesteps) == 0:
|
|
@@ -289,7 +282,7 @@ def _resolve_step(state: _State, timestep: torch.Tensor) -> tuple[int, int]:
|
|
| 289 |
idx = int((ts.float() - t).abs().argmin().item())
|
| 290 |
return idx, len(ts)
|
| 291 |
|
| 292 |
-
def
|
| 293 |
self,
|
| 294 |
hidden_states: torch.Tensor,
|
| 295 |
timestep,
|
|
@@ -302,7 +295,7 @@ def _spectrum_forward(
|
|
| 302 |
License: Apache-2.0
|
| 303 |
https://huggingface.co/nebulette/moss-spectrum-diffusers
|
| 304 |
"""
|
| 305 |
-
state: Optional[
|
| 306 |
if state is None or state.scheduler is None:
|
| 307 |
return state.original_forward(
|
| 308 |
hidden_states, timestep, encoder_hidden_states,
|
|
@@ -311,7 +304,7 @@ def _spectrum_forward(
|
|
| 311 |
)
|
| 312 |
|
| 313 |
cfg = state.cfg
|
| 314 |
-
skip =
|
| 315 |
|
| 316 |
if hidden_states.ndim != 4 or hidden_states.shape[1] != self.config.latent_channels:
|
| 317 |
raise ValueError("hidden_states must be [B, latent_channels, H, W].")
|
|
@@ -326,7 +319,7 @@ def _spectrum_forward(
|
|
| 326 |
raise ValueError("encoder_attention_mask must be a binary [B, S] mask.")
|
| 327 |
|
| 328 |
# --- step bookkeeping ------------------------------------------------- #
|
| 329 |
-
step, total =
|
| 330 |
if step < 0: # no schedule available -> stay exact
|
| 331 |
return state.original_forward(
|
| 332 |
hidden_states, timestep, encoder_hidden_states,
|
|
@@ -345,7 +338,7 @@ def _spectrum_forward(
|
|
| 345 |
branch = state.branch((sig, occurrence))
|
| 346 |
|
| 347 |
actual = branch.decide(step, total)
|
| 348 |
-
u =
|
| 349 |
|
| 350 |
# shared timestep conditioning (identical to the original)
|
| 351 |
times = torch.as_tensor(timestep, device=hidden_states.device, dtype=torch.float32).reshape(-1).expand(batch)
|
|
@@ -374,7 +367,7 @@ def _spectrum_forward(
|
|
| 374 |
# skip embeddings, text blocks and all layers
|
| 375 |
try:
|
| 376 |
feat = forecaster.predict(u)
|
| 377 |
-
except Exception:
|
| 378 |
# numerical trouble -> fall back to a real step
|
| 379 |
actual = True
|
| 380 |
branch.note(True, step)
|
|
@@ -428,11 +421,11 @@ def _spectrum_forward(
|
|
| 428 |
return (sample,)
|
| 429 |
return Transformer2DModelOutput(sample=sample)
|
| 430 |
|
| 431 |
-
|
| 432 |
def apply_spectrum(pipe, config: Optional[SpectrumConfig] = None):
|
| 433 |
"""
|
| 434 |
Patch ``pipe`` in place so the MOSS DiT runs under Spectrum scheduling.
|
| 435 |
-
|
| 436 |
License: Apache-2.0
|
| 437 |
https://huggingface.co/nebulette/moss-spectrum-diffusers
|
| 438 |
"""
|
|
@@ -446,11 +439,11 @@ def apply_spectrum(pipe, config: Optional[SpectrumConfig] = None):
|
|
| 446 |
if getattr(transformer, "_spectrum_state", None) is not None:
|
| 447 |
remove_spectrum(pipe)
|
| 448 |
|
| 449 |
-
state =
|
| 450 |
state.original_forward = transformer.forward
|
| 451 |
|
| 452 |
transformer._spectrum_state = state
|
| 453 |
-
transformer.forward = types.MethodType(
|
| 454 |
return pipe
|
| 455 |
|
| 456 |
|
|
|
|
| 78 |
def window_cap(self) -> float:
|
| 79 |
return max(1.0, self.window_size, float(self.history_points))
|
| 80 |
|
| 81 |
+
def cheb_basis(u, degree: int) -> torch.Tensor:
|
| 82 |
u = torch.as_tensor(u, dtype=torch.float64).reshape(-1)
|
| 83 |
cols = [torch.ones_like(u)]
|
| 84 |
if degree >= 1:
|
|
|
|
| 87 |
cols.append(2.0 * u * cols[-1] - cols[-2])
|
| 88 |
return torch.stack(cols[: degree + 1], dim=-1) # [n, P]
|
| 89 |
|
| 90 |
+
class Forecaster:
|
| 91 |
"""Chebyshev ridge forecaster (prediction = weighted sum of anchors)"""
|
| 92 |
def __init__(self, cfg: SpectrumConfig):
|
| 93 |
self.cfg = cfg
|
|
|
|
| 116 |
self._chol = None
|
| 117 |
|
| 118 |
def _design(self) -> torch.Tensor:
|
| 119 |
+
return cheb_basis(self.us, self.cfg.chebyshev_degree) # [K, P]
|
| 120 |
|
| 121 |
def _factor(self) -> torch.Tensor:
|
| 122 |
if self._chol is not None:
|
|
|
|
| 160 |
return w
|
| 161 |
|
| 162 |
def weights(self, u: float) -> torch.Tensor:
|
| 163 |
+
phi = cheb_basis([u], self.cfg.chebyshev_degree) # [1, P]
|
| 164 |
solved = torch.cholesky_solve(self._design().T, self._factor()) # [P, K]
|
| 165 |
spectral = (phi @ solved).reshape(-1)
|
| 166 |
bw = self.cfg.blend_weight
|
|
|
|
| 194 |
den = actual.float().norm().clamp_min(1e-6)
|
| 195 |
return float((num / den).item())
|
| 196 |
|
| 197 |
+
class Branch:
|
| 198 |
"""Per-branch scheduler state"""
|
| 199 |
def __init__(self, cfg: SpectrumConfig):
|
| 200 |
self.cfg = cfg
|
|
|
|
| 202 |
self.consecutive = 0
|
| 203 |
self.actual = 0
|
| 204 |
self.forecast = 0
|
| 205 |
+
self.forecasters: dict[int, Forecaster] = {}
|
| 206 |
self.errors: list[float] = []
|
| 207 |
|
| 208 |
+
def forecaster(self, sample: int) -> Forecaster:
|
| 209 |
f = self.forecasters.get(sample)
|
| 210 |
if f is None:
|
| 211 |
+
f = self.forecasters[sample] = Forecaster(self.cfg)
|
| 212 |
return f
|
| 213 |
|
| 214 |
def decide(self, step: int, total: int) -> bool:
|
|
|
|
| 234 |
self.consecutive += 1
|
| 235 |
|
| 236 |
|
| 237 |
+
class State:
|
| 238 |
def __init__(self, cfg: SpectrumConfig, scheduler: Any):
|
| 239 |
self.cfg = cfg
|
| 240 |
self.scheduler = scheduler
|
| 241 |
self.original_forward = None
|
| 242 |
self.step_index = -1
|
| 243 |
+
self.branches: dict[Any, Branch] = {}
|
| 244 |
self._sig_counts: dict[Any, int] = {}
|
| 245 |
self._log: list[str] = []
|
| 246 |
|
| 247 |
+
def branch(self, key: Any) -> Branch:
|
| 248 |
b = self.branches.get(key)
|
| 249 |
if b is None:
|
| 250 |
+
b = self.branches[key] = Branch(self.cfg)
|
| 251 |
return b
|
| 252 |
|
| 253 |
def reset_run(self) -> None:
|
|
|
|
| 266 |
f"{f}/{a + f} ({speed:.2f}x) mean_forecast_rel_err={mean_err:.4f}"
|
| 267 |
)
|
| 268 |
|
| 269 |
+
def validate_skip_layers(layers, depth: int, name: str = "skip_layers") -> tuple:
|
| 270 |
layers = () if layers is None else tuple(layers)
|
| 271 |
if any(type(i) is not int or not 0 <= i < depth for i in layers):
|
| 272 |
raise ValueError(f"{name} must contain integer block indices in [0, {depth}).")
|
| 273 |
return layers
|
| 274 |
|
| 275 |
+
def resolve_step(state: State, timestep: torch.Tensor) -> tuple[int, int]:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 276 |
sched = state.scheduler
|
| 277 |
timesteps = getattr(sched, "timesteps", None) if sched is not None else None
|
| 278 |
if timesteps is None or len(timesteps) == 0:
|
|
|
|
| 282 |
idx = int((ts.float() - t).abs().argmin().item())
|
| 283 |
return idx, len(ts)
|
| 284 |
|
| 285 |
+
def spectrum_forward(
|
| 286 |
self,
|
| 287 |
hidden_states: torch.Tensor,
|
| 288 |
timestep,
|
|
|
|
| 295 |
License: Apache-2.0
|
| 296 |
https://huggingface.co/nebulette/moss-spectrum-diffusers
|
| 297 |
"""
|
| 298 |
+
state: Optional[State] = getattr(self, "_spectrum_state", None)
|
| 299 |
if state is None or state.scheduler is None:
|
| 300 |
return state.original_forward(
|
| 301 |
hidden_states, timestep, encoder_hidden_states,
|
|
|
|
| 304 |
)
|
| 305 |
|
| 306 |
cfg = state.cfg
|
| 307 |
+
skip = validate_skip_layers(skip_layers, len(self.layers))
|
| 308 |
|
| 309 |
if hidden_states.ndim != 4 or hidden_states.shape[1] != self.config.latent_channels:
|
| 310 |
raise ValueError("hidden_states must be [B, latent_channels, H, W].")
|
|
|
|
| 319 |
raise ValueError("encoder_attention_mask must be a binary [B, S] mask.")
|
| 320 |
|
| 321 |
# --- step bookkeeping ------------------------------------------------- #
|
| 322 |
+
step, total = resolve_step(state, timestep)
|
| 323 |
if step < 0: # no schedule available -> stay exact
|
| 324 |
return state.original_forward(
|
| 325 |
hidden_states, timestep, encoder_hidden_states,
|
|
|
|
| 338 |
branch = state.branch((sig, occurrence))
|
| 339 |
|
| 340 |
actual = branch.decide(step, total)
|
| 341 |
+
u = 0.0 if total <= 1 else max(-1.0, min(1.0, 2.0 * step / (total - 1) - 1.0))
|
| 342 |
|
| 343 |
# shared timestep conditioning (identical to the original)
|
| 344 |
times = torch.as_tensor(timestep, device=hidden_states.device, dtype=torch.float32).reshape(-1).expand(batch)
|
|
|
|
| 367 |
# skip embeddings, text blocks and all layers
|
| 368 |
try:
|
| 369 |
feat = forecaster.predict(u)
|
| 370 |
+
except Exception:
|
| 371 |
# numerical trouble -> fall back to a real step
|
| 372 |
actual = True
|
| 373 |
branch.note(True, step)
|
|
|
|
| 421 |
return (sample,)
|
| 422 |
return Transformer2DModelOutput(sample=sample)
|
| 423 |
|
| 424 |
+
|
| 425 |
def apply_spectrum(pipe, config: Optional[SpectrumConfig] = None):
|
| 426 |
"""
|
| 427 |
Patch ``pipe`` in place so the MOSS DiT runs under Spectrum scheduling.
|
| 428 |
+
|
| 429 |
License: Apache-2.0
|
| 430 |
https://huggingface.co/nebulette/moss-spectrum-diffusers
|
| 431 |
"""
|
|
|
|
| 439 |
if getattr(transformer, "_spectrum_state", None) is not None:
|
| 440 |
remove_spectrum(pipe)
|
| 441 |
|
| 442 |
+
state = State(cfg, getattr(pipe, "scheduler", None))
|
| 443 |
state.original_forward = transformer.forward
|
| 444 |
|
| 445 |
transformer._spectrum_state = state
|
| 446 |
+
transformer.forward = types.MethodType(spectrum_forward, transformer)
|
| 447 |
return pipe
|
| 448 |
|
| 449 |
|