Studio diffusion: eager patches + torch.compile cache speed phase

Adds the opt-in speed path for the GGUF diffusion transformer behind a
selectable speed mode (default off, so output is unchanged until a profile
is chosen):

- diffusion_eager_patches.py: shared eager fast-paths (channels_last,
  attention/backend selection, fused norms and QKV) installed at load and
  rolled back on unload or failed load.
- diffusion_compile_cache.py / diffusion_gguf_compile.py: a persistent
  torch.compile cache and the GGUF-transformer compile wiring.
- diffusion_arch_patches.py: architecture-specific patches.
- diffusion_patch_backend.py: shared install/restore plumbing.
- diffusion_speed.py: speed-profile planning.

Tests for each module plus the benchmarking and probe scripts used to
measure speed, memory, and accuracy of the path.
This commit is contained in:
Daniel Han 2026-06-30 23:09:42 +00:00
commit f24384b4e9
12 changed files with 2037 additions and 31 deletions

View file

@ -0,0 +1,469 @@
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
"""Per-architecture eager fusions for the diffusion DiT blocks.
The shared patches in ``diffusion_eager_patches.py`` cover what diffusers factors into
SHARED classes (``RMSNorm``, the ``AdaLayerNorm*`` modulation classes -- the latter only
used by flux.1). The remaining fusible ops -- the gated residual ``x = x + gate * out`` and
the inline modulation ``norm * (1 + scale) + shift`` -- are written longhand in each
family's PER-MODEL block ``forward`` (flux.2 / qwen / z-image), so they need per-arch
patches. This module supplies them, in the ``unsloth_zoo.temporary_patches`` style: one
small patch function per target, applied through the shared, fingerprint-checked,
reversible backend (``diffusion_patch_backend`` -> ``patch_function`` / ``restore_original``).
The single actionable fused op is ``torch.addcmul(a, b, c) == a + b * c`` (one FMA kernel,
1-ULP vs mul+add, MORE accurate). Two forms exist:
* out-of-place ``torch.addcmul(...)`` -- COMPILE-SAFE: lowers to plain ops, no aliasing,
neutral under ``torch.compile``. Used here for ALL non-``off`` tiers. It captures the
real eager win (fewer kernel launches); it does NOT save the output allocation.
* in-place ``x.addcmul_(...)`` -- would also save the allocation, but the allocation part
measured NEUTRAL on this stack (CUDA caching allocator already recycles; cf. the GGUF
weight-buffer result), and in-place residual mutation is compile-unsafe + aliasing-risky.
So it is deliberately NOT used; the out-of-place form is the whole, safe win.
Each patch is guarded TWICE: ``can_safely_patch`` checks the forward SIGNATURE, and a local
source-body check (``_body_has``) confirms the exact lines we rewrite are still present, so a
future diffusers that changed the block body simply leaves the block UNPATCHED (correctness
first) rather than running a stale copy. Kill-switch: ``UNSLOTH_DIFFUSION_ARCH_PATCHES=0``.
Implemented for all four families (extend by adding entries to ``_SPECS``):
* qwen-image ``QwenImageTransformerBlock._modulate`` -- modulation addcmul (all 4 sites).
* z-image ``ZImageTransformerBlock.forward`` -- the 2 gated-residual addcmuls.
* flux.1 ``FluxTransformerBlock.forward`` (inline norm2 modulation + 4 gated residuals)
+ ``FluxSingleTransformerBlock.forward`` (residual + gate*proj_out).
* flux.2-klein ``Flux2TransformerBlock.forward`` (4 inline modulations + 4 gated residuals)
+ ``Flux2SingleTransformerBlock.forward`` (inline modulation + gated residual).
"""
from __future__ import annotations
import inspect
import logging
import os
from typing import Any, Callable, Optional
import torch
from .diffusion_patch_backend import apply_patch, revert_patch
logger = logging.getLogger(__name__)
_ENV_ENABLE = "UNSLOTH_DIFFUSION_ARCH_PATCHES"
def _patches_enabled() -> bool:
return (os.environ.get(_ENV_ENABLE) or "").strip().lower() not in ("0", "off", "false", "no")
def _body_has(fn: Callable, *needles: str) -> bool:
"""True iff every ``needle`` appears in ``fn``'s source -- a body-drift guard so a patch
self-disables if diffusers changed the lines it rewrites."""
try:
src = inspect.getsource(fn)
except (OSError, TypeError):
return False
return all(n in src for n in needles)
# =====================================================================================
# qwen-image: QwenImageTransformerBlock._modulate (modulation addcmul, all 4 call sites)
# =====================================================================================
def _qwen_modulate(self, x, mod_params, index=None):
"""diffusers 0.38 ``QwenImageTransformerBlock._modulate`` with the final
``x*(1+scale)+shift`` fused to ``torch.addcmul`` (covers both the global and the
per-token ``index`` branches, since both end in that same expression)."""
shift, scale, gate = mod_params.chunk(3, dim=-1)
if index is not None:
actual_batch = shift.size(0) // 2
shift_0, shift_1 = shift[:actual_batch], shift[actual_batch:]
scale_0, scale_1 = scale[:actual_batch], scale[actual_batch:]
gate_0, gate_1 = gate[:actual_batch], gate[actual_batch:]
index_expanded = index.unsqueeze(-1)
shift_0_exp = shift_0.unsqueeze(1)
shift_1_exp = shift_1.unsqueeze(1)
scale_0_exp = scale_0.unsqueeze(1)
scale_1_exp = scale_1.unsqueeze(1)
gate_0_exp = gate_0.unsqueeze(1)
gate_1_exp = gate_1.unsqueeze(1)
shift_result = torch.where(index_expanded == 0, shift_0_exp, shift_1_exp)
scale_result = torch.where(index_expanded == 0, scale_0_exp, scale_1_exp)
gate_result = torch.where(index_expanded == 0, gate_0_exp, gate_1_exp)
else:
shift_result = shift.unsqueeze(1)
scale_result = scale.unsqueeze(1)
gate_result = gate.unsqueeze(1)
# fused: x * (1 + scale_result) + shift_result
return torch.addcmul(shift_result, x, 1 + scale_result), gate_result
def _spec_qwen_modulate():
try:
from diffusers.models.transformers.transformer_qwenimage import QwenImageTransformerBlock as cls
except Exception: # noqa: BLE001
return None
orig = getattr(cls, "_modulate", None)
if orig is None or not _body_has(orig, "x * (1 + scale_result) + shift_result"):
return None
return (cls, "_modulate", _qwen_modulate)
# =====================================================================================
# z-image: ZImageTransformerBlock.forward (the 2 gated-residual addcmuls)
# =====================================================================================
def _zimage_forward(
self,
x: torch.Tensor,
attn_mask: torch.Tensor,
freqs_cis: torch.Tensor,
adaln_input: torch.Tensor | None = None,
noise_mask: torch.Tensor | None = None,
adaln_noisy: torch.Tensor | None = None,
adaln_clean: torch.Tensor | None = None,
):
"""diffusers 0.38 ``ZImageTransformerBlock.forward`` with the two gated residuals
``x = x + gate * sublayer`` fused to ``torch.addcmul`` (out-of-place). The shift-free
``*scale`` modulation and the non-gated (``else``) residuals are left as-is."""
from diffusers.models.transformers.transformer_z_image import select_per_token
if self.modulation:
seq_len = x.shape[1]
if noise_mask is not None:
mod_noisy = self.adaLN_modulation(adaln_noisy)
mod_clean = self.adaLN_modulation(adaln_clean)
scale_msa_noisy, gate_msa_noisy, scale_mlp_noisy, gate_mlp_noisy = mod_noisy.chunk(4, dim=1)
scale_msa_clean, gate_msa_clean, scale_mlp_clean, gate_mlp_clean = mod_clean.chunk(4, dim=1)
gate_msa_noisy, gate_mlp_noisy = gate_msa_noisy.tanh(), gate_mlp_noisy.tanh()
gate_msa_clean, gate_mlp_clean = gate_msa_clean.tanh(), gate_mlp_clean.tanh()
scale_msa_noisy, scale_mlp_noisy = 1.0 + scale_msa_noisy, 1.0 + scale_mlp_noisy
scale_msa_clean, scale_mlp_clean = 1.0 + scale_msa_clean, 1.0 + scale_mlp_clean
scale_msa = select_per_token(scale_msa_noisy, scale_msa_clean, noise_mask, seq_len)
scale_mlp = select_per_token(scale_mlp_noisy, scale_mlp_clean, noise_mask, seq_len)
gate_msa = select_per_token(gate_msa_noisy, gate_msa_clean, noise_mask, seq_len)
gate_mlp = select_per_token(gate_mlp_noisy, gate_mlp_clean, noise_mask, seq_len)
else:
mod = self.adaLN_modulation(adaln_input)
scale_msa, gate_msa, scale_mlp, gate_mlp = mod.unsqueeze(1).chunk(4, dim=2)
gate_msa, gate_mlp = gate_msa.tanh(), gate_mlp.tanh()
scale_msa, scale_mlp = 1.0 + scale_msa, 1.0 + scale_mlp
# Attention block -- fused gated residual: x + gate_msa * attention_norm2(attn_out)
attn_out = self.attention(
self.attention_norm1(x) * scale_msa, attention_mask=attn_mask, freqs_cis=freqs_cis
)
x = torch.addcmul(x, gate_msa, self.attention_norm2(attn_out))
# FFN block -- fused gated residual: x + gate_mlp * ffn_norm2(feed_forward(...))
x = torch.addcmul(
x, gate_mlp, self.ffn_norm2(self.feed_forward(self.ffn_norm1(x) * scale_mlp))
)
else:
attn_out = self.attention(self.attention_norm1(x), attention_mask=attn_mask, freqs_cis=freqs_cis)
x = x + self.attention_norm2(attn_out)
x = x + self.ffn_norm2(self.feed_forward(self.ffn_norm1(x)))
return x
def _spec_zimage_forward():
try:
from diffusers.models.transformers.transformer_z_image import ZImageTransformerBlock as cls
except Exception: # noqa: BLE001
return None
orig = getattr(cls, "forward", None)
if orig is None or not _body_has(
orig,
"x = x + gate_msa * self.attention_norm2(attn_out)",
"x = x + gate_mlp * self.ffn_norm2(self.feed_forward(self.ffn_norm1(x) * scale_mlp))",
):
return None
return (cls, "forward", _zimage_forward)
# =====================================================================================
# flux.1: FluxTransformerBlock / FluxSingleTransformerBlock
# (block modulation goes through AdaLayerNormZero -- already handled by the shared patch;
# here we fuse the inline norm2 modulation + the gated residual adds.)
# =====================================================================================
def _flux_double_forward(
self, hidden_states, encoder_hidden_states, temb, image_rotary_emb=None, joint_attention_kwargs=None
):
norm_hidden_states, gate_msa, shift_mlp, scale_mlp, gate_mlp = self.norm1(hidden_states, emb=temb)
norm_encoder_hidden_states, c_gate_msa, c_shift_mlp, c_scale_mlp, c_gate_mlp = self.norm1_context(
encoder_hidden_states, emb=temb
)
joint_attention_kwargs = joint_attention_kwargs or {}
attention_outputs = self.attn(
hidden_states=norm_hidden_states,
encoder_hidden_states=norm_encoder_hidden_states,
image_rotary_emb=image_rotary_emb,
**joint_attention_kwargs,
)
if len(attention_outputs) == 2:
attn_output, context_attn_output = attention_outputs
elif len(attention_outputs) == 3:
attn_output, context_attn_output, ip_attn_output = attention_outputs
# fused: hidden_states + gate_msa * attn_output
hidden_states = torch.addcmul(hidden_states, gate_msa.unsqueeze(1), attn_output)
norm_hidden_states = self.norm2(hidden_states)
# fused: norm * (1 + scale_mlp) + shift_mlp
norm_hidden_states = torch.addcmul(shift_mlp[:, None], norm_hidden_states, 1 + scale_mlp[:, None])
ff_output = self.ff(norm_hidden_states)
hidden_states = torch.addcmul(hidden_states, gate_mlp.unsqueeze(1), ff_output)
if len(attention_outputs) == 3:
hidden_states = hidden_states + ip_attn_output
encoder_hidden_states = torch.addcmul(encoder_hidden_states, c_gate_msa.unsqueeze(1), context_attn_output)
norm_encoder_hidden_states = self.norm2_context(encoder_hidden_states)
norm_encoder_hidden_states = torch.addcmul(
c_shift_mlp[:, None], norm_encoder_hidden_states, 1 + c_scale_mlp[:, None]
)
context_ff_output = self.ff_context(norm_encoder_hidden_states)
encoder_hidden_states = torch.addcmul(encoder_hidden_states, c_gate_mlp.unsqueeze(1), context_ff_output)
if encoder_hidden_states.dtype == torch.float16:
encoder_hidden_states = encoder_hidden_states.clip(-65504, 65504)
return encoder_hidden_states, hidden_states
def _spec_flux_double():
try:
from diffusers.models.transformers.transformer_flux import FluxTransformerBlock as cls
except Exception: # noqa: BLE001
return None
orig = getattr(cls, "forward", None)
if orig is None or not _body_has(
orig,
"hidden_states = hidden_states + attn_output",
"norm_hidden_states = norm_hidden_states * (1 + scale_mlp[:, None]) + shift_mlp[:, None]",
"encoder_hidden_states = encoder_hidden_states + c_gate_mlp.unsqueeze(1) * context_ff_output",
):
return None
return (cls, "forward", _flux_double_forward)
def _flux_single_forward(
self, hidden_states, encoder_hidden_states, temb, image_rotary_emb=None, joint_attention_kwargs=None
):
text_seq_len = encoder_hidden_states.shape[1]
hidden_states = torch.cat([encoder_hidden_states, hidden_states], dim=1)
residual = hidden_states
norm_hidden_states, gate = self.norm(hidden_states, emb=temb)
mlp_hidden_states = self.act_mlp(self.proj_mlp(norm_hidden_states))
joint_attention_kwargs = joint_attention_kwargs or {}
attn_output = self.attn(
hidden_states=norm_hidden_states,
image_rotary_emb=image_rotary_emb,
**joint_attention_kwargs,
)
hidden_states = torch.cat([attn_output, mlp_hidden_states], dim=2)
gate = gate.unsqueeze(1)
# fused: residual + gate * proj_out(hidden_states)
hidden_states = torch.addcmul(residual, gate, self.proj_out(hidden_states))
if hidden_states.dtype == torch.float16:
hidden_states = hidden_states.clip(-65504, 65504)
encoder_hidden_states, hidden_states = hidden_states[:, :text_seq_len], hidden_states[:, text_seq_len:]
return encoder_hidden_states, hidden_states
def _spec_flux_single():
try:
from diffusers.models.transformers.transformer_flux import FluxSingleTransformerBlock as cls
except Exception: # noqa: BLE001
return None
orig = getattr(cls, "forward", None)
if orig is None or not _body_has(
orig,
"hidden_states = gate * self.proj_out(hidden_states)",
"hidden_states = residual + hidden_states",
):
return None
return (cls, "forward", _flux_single_forward)
# =====================================================================================
# flux.2-klein: Flux2TransformerBlock / Flux2SingleTransformerBlock
# (modulation is INLINE here -- not via AdaLayerNorm -- so we fuse both the modulation and
# the gated residuals; scale/shift/gate are [B,1,dim] so no [:, None] is needed.)
# =====================================================================================
def _flux2_double_forward(
self, hidden_states, encoder_hidden_states, temb_mod_img, temb_mod_txt,
image_rotary_emb=None, joint_attention_kwargs=None,
):
from diffusers.models.transformers.transformer_flux2 import Flux2Modulation
joint_attention_kwargs = joint_attention_kwargs or {}
(shift_msa, scale_msa, gate_msa), (shift_mlp, scale_mlp, gate_mlp) = Flux2Modulation.split(temb_mod_img, 2)
(c_shift_msa, c_scale_msa, c_gate_msa), (c_shift_mlp, c_scale_mlp, c_gate_mlp) = Flux2Modulation.split(
temb_mod_txt, 2
)
norm_hidden_states = self.norm1(hidden_states)
norm_hidden_states = torch.addcmul(shift_msa, norm_hidden_states, 1 + scale_msa)
norm_encoder_hidden_states = self.norm1_context(encoder_hidden_states)
norm_encoder_hidden_states = torch.addcmul(c_shift_msa, norm_encoder_hidden_states, 1 + c_scale_msa)
attention_outputs = self.attn(
hidden_states=norm_hidden_states,
encoder_hidden_states=norm_encoder_hidden_states,
image_rotary_emb=image_rotary_emb,
**joint_attention_kwargs,
)
attn_output, context_attn_output = attention_outputs
hidden_states = torch.addcmul(hidden_states, gate_msa, attn_output)
norm_hidden_states = self.norm2(hidden_states)
norm_hidden_states = torch.addcmul(shift_mlp, norm_hidden_states, 1 + scale_mlp)
ff_output = self.ff(norm_hidden_states)
hidden_states = torch.addcmul(hidden_states, gate_mlp, ff_output)
encoder_hidden_states = torch.addcmul(encoder_hidden_states, c_gate_msa, context_attn_output)
norm_encoder_hidden_states = self.norm2_context(encoder_hidden_states)
norm_encoder_hidden_states = torch.addcmul(c_shift_mlp, norm_encoder_hidden_states, 1 + c_scale_mlp)
context_ff_output = self.ff_context(norm_encoder_hidden_states)
encoder_hidden_states = torch.addcmul(encoder_hidden_states, c_gate_mlp, context_ff_output)
if encoder_hidden_states.dtype == torch.float16:
encoder_hidden_states = encoder_hidden_states.clip(-65504, 65504)
return encoder_hidden_states, hidden_states
def _spec_flux2_double():
try:
from diffusers.models.transformers.transformer_flux2 import Flux2TransformerBlock as cls
except Exception: # noqa: BLE001
return None
orig = getattr(cls, "forward", None)
if orig is None or not _body_has(
orig,
"norm_hidden_states = (1 + scale_msa) * norm_hidden_states + shift_msa",
"hidden_states = hidden_states + gate_mlp * ff_output",
"encoder_hidden_states = encoder_hidden_states + c_gate_mlp * context_ff_output",
):
return None
return (cls, "forward", _flux2_double_forward)
def _flux2_single_forward(
self, hidden_states, encoder_hidden_states, temb_mod, image_rotary_emb=None,
joint_attention_kwargs=None, split_hidden_states=False, text_seq_len=None,
):
from diffusers.models.transformers.transformer_flux2 import Flux2Modulation
if encoder_hidden_states is not None:
text_seq_len = encoder_hidden_states.shape[1]
hidden_states = torch.cat([encoder_hidden_states, hidden_states], dim=1)
mod_shift, mod_scale, mod_gate = Flux2Modulation.split(temb_mod, 1)[0]
norm_hidden_states = self.norm(hidden_states)
norm_hidden_states = torch.addcmul(mod_shift, norm_hidden_states, 1 + mod_scale)
joint_attention_kwargs = joint_attention_kwargs or {}
attn_output = self.attn(
hidden_states=norm_hidden_states,
image_rotary_emb=image_rotary_emb,
**joint_attention_kwargs,
)
hidden_states = torch.addcmul(hidden_states, mod_gate, attn_output)
if hidden_states.dtype == torch.float16:
hidden_states = hidden_states.clip(-65504, 65504)
if split_hidden_states:
encoder_hidden_states, hidden_states = hidden_states[:, :text_seq_len], hidden_states[:, text_seq_len:]
return encoder_hidden_states, hidden_states
else:
return hidden_states
def _spec_flux2_single():
try:
from diffusers.models.transformers.transformer_flux2 import Flux2SingleTransformerBlock as cls
except Exception: # noqa: BLE001
return None
orig = getattr(cls, "forward", None)
if orig is None or not _body_has(
orig,
"norm_hidden_states = (1 + mod_scale) * norm_hidden_states + mod_shift",
"hidden_states = hidden_states + mod_gate * attn_output",
):
return None
return (cls, "forward", _flux2_single_forward)
# =====================================================================================
# registry + lifecycle
# =====================================================================================
# Each entry is a zero-arg resolver returning (cls, attr, new_fn) or None (target absent /
# body drifted). All entries here are COMPILE-SAFE (out-of-place addcmul).
_SPECS: tuple[Callable[[], Optional[tuple]], ...] = (
_spec_qwen_modulate,
_spec_zimage_forward,
_spec_flux_double,
_spec_flux_single,
_spec_flux2_double,
_spec_flux2_single,
)
# (cls, attr) pairs we successfully patched, for an exact reverse.
_patched: list[tuple] = []
def install_arch_patches() -> int:
"""Install the per-arch compile-safe fusions (idempotent). Returns the count applied.
Safe for every non-``off`` tier: the fusions lower to plain ops and are neutral under
``torch.compile`` (so they also help the ``max`` regionally-compiled blocks)."""
if not _patches_enabled():
uninstall_arch_patches()
return 0
if _patched:
return len(_patched)
for resolve in _SPECS:
try:
spec = resolve()
except Exception as exc: # noqa: BLE001
logger.warning("arch-patch: resolver %s failed: %s", getattr(resolve, "__name__", resolve), exc)
spec = None
if spec is None:
continue
cls, attr, new_fn = spec
if apply_patch(cls, attr, new_fn, match_level="relaxed"):
_patched.append((cls, attr))
else:
logger.warning("arch-patch: skipping %s.%s (signature mismatch / unavailable)",
getattr(cls, "__name__", cls), attr)
logger.info("arch-patch: installed %d/%d per-arch fusions", len(_patched), len(_SPECS))
return len(_patched)
def uninstall_arch_patches() -> None:
"""Restore every per-arch patched method/forward (idempotent)."""
for cls, attr in list(_patched):
revert_patch(cls, attr)
_patched.clear()
def is_installed() -> bool:
return bool(_patched)

View file

@ -0,0 +1,338 @@
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
"""Pre-warmed ``torch.compile`` cache for the diffusion denoiser (Mega-cache).
The regional ``torch.compile`` of the repeated denoiser block (``diffusion_speed.py``)
pays a one-time 25-58s compile on the FIRST image after a load. This module lets that
cost be paid ONCE -- by us (the distributor) ahead of time, or by the user on a first
run -- and reused on every later load via torch's portable Mega-cache
(``torch.compiler.save_cache_artifacts`` / ``load_cache_artifacts``, torch >= 2.7).
PORTABILITY IS NOT UNIVERSAL. A compiled artifact is only valid for the SAME torch
version, Triton version, CUDA build, and GPU architecture it was produced on (and the
same model graph: family, dtype, quant scheme, attention backend, compile kwargs, shape
bucket). torch validates these on load and a mismatch simply yields no cache hit -- it
does NOT error. So this layer is built around an EXACT-MATCH fingerprint with a SILENT
FALLBACK to local compile: a miss is normal and never fatal. We therefore ship per-arch
bundles keyed by the full fingerprint, never one universal cache. See
``outputs/compile_cache/DISTRIBUTION.md``.
Lifecycle (driven by the caller, around ``_compile_repeated_blocks``):
1. ``begin(...)`` -> build the fingerprint, point ``TORCHINDUCTOR_CACHE_DIR`` at a
per-key dir, and ``load_cache_artifacts`` if a matching bundle
exists. Must run BEFORE the first compiled forward.
2. (compile + one warmup forward happen as usual; on a hit they reuse the cache.)
3. ``save(...)`` -> ``save_cache_artifacts`` to the bundle + manifest, AFTER the
warmup forward, when in distributor/save mode.
4. ``restore(...)`` -> put ``TORCHINDUCTOR_CACHE_DIR`` back on unload.
Everything is env-gated and best-effort; torch is imported lazily.
"""
from __future__ import annotations
import dataclasses
import hashlib
import json
import os
import time
from pathlib import Path
from typing import Any, Optional
# ----------------------------------------------------------------------------- env knobs
# UNSLOTH_DIFFUSION_COMPILE_CACHE: auto (default) | 0 | 1
# auto -> load a matching bundle if present (no automatic save).
# 1 -> load AND save (distributor / first-run warm).
# 0 -> disabled (plain local compile, no cache dir override).
# UNSLOTH_DIFFUSION_COMPILE_CACHE_DIR: root dir for bundles (default under the workspace).
# UNSLOTH_DIFFUSION_COMPILE_CACHE_SAVE: 1 -> force-enable save even in "auto".
_ENV_MODE = "UNSLOTH_DIFFUSION_COMPILE_CACHE"
_ENV_DIR = "UNSLOTH_DIFFUSION_COMPILE_CACHE_DIR"
_ENV_SAVE = "UNSLOTH_DIFFUSION_COMPILE_CACHE_SAVE"
_DEFAULT_ROOT = Path.home() / ".cache" / "unsloth" / "diffusion_compile_cache"
_MANIFEST_NAME = "manifest.json"
_BUNDLE_NAME = "cache.bin"
_FORMAT_VERSION = 1
def cache_mode() -> str:
"""``off`` | ``auto`` | ``on`` from the environment. ``auto`` is the default."""
raw = (os.environ.get(_ENV_MODE) or "auto").strip().lower()
if raw in ("0", "off", "false", "no"):
return "off"
if raw in ("1", "on", "true", "yes"):
return "on"
return "auto"
def _save_enabled(mode: str) -> bool:
if mode == "off":
return False
if mode == "on":
return True
# auto: save only if explicitly opted in.
return (os.environ.get(_ENV_SAVE) or "").strip().lower() in ("1", "on", "true", "yes")
def cache_root() -> Path:
root = os.environ.get(_ENV_DIR)
return Path(root) if root else _DEFAULT_ROOT
# --------------------------------------------------------------------------- fingerprint
def _triton_version() -> Optional[str]:
try:
import triton # noqa: PLC0415
return str(getattr(triton, "__version__", None))
except Exception: # noqa: BLE001 — triton optional
return None
def _diffusers_version() -> Optional[str]:
try:
import diffusers # noqa: PLC0415
return str(getattr(diffusers, "__version__", None))
except Exception: # noqa: BLE001
return None
def environment_fingerprint() -> dict[str, Any]:
"""The HARD-portability dimensions: any difference here invalidates a bundle.
These mirror what torch's inductor cache itself keys on (torch + triton + CUDA +
GPU type), plus diffusers (the graph source). We surface them explicitly so the
manifest is self-describing and a mismatch is obvious to a human, not just to torch.
"""
fp: dict[str, Any] = {
"format": _FORMAT_VERSION,
"torch": None,
"torch_cuda": None,
"triton": _triton_version(),
"diffusers": _diffusers_version(),
"gpu_name": None,
"gpu_capability": None,
}
try:
import torch # noqa: PLC0415
fp["torch"] = str(torch.__version__)
fp["torch_cuda"] = str(torch.version.cuda)
if torch.cuda.is_available():
fp["gpu_name"] = torch.cuda.get_device_name(0)
cap = torch.cuda.get_device_capability(0)
fp["gpu_capability"] = f"sm_{cap[0]}{cap[1]}"
except Exception: # noqa: BLE001 — best-effort
pass
return fp
def model_fingerprint(
*,
family: Any,
transformer: Any,
dtype: Any,
quant: Any,
attention_backend: Any,
compile_kwargs: dict[str, Any],
shape_bucket: Any = None,
) -> dict[str, Any]:
"""The MODEL-graph dimensions that change the compiled artifact.
``family`` is the Unsloth family name; ``transformer`` is the live module (we read
its class name + ``_repeated_blocks`` so the key tracks exactly what gets compiled).
"""
blocks = list(getattr(transformer, "_repeated_blocks", []) or [])
return {
"family": str(family),
"transformer_cls": type(transformer).__name__ if transformer is not None else None,
"repeated_blocks": sorted(str(b) for b in blocks),
"dtype": str(dtype),
"quant": str(quant) if quant is not None else "none",
"attention_backend": str(attention_backend) if attention_backend is not None else "default",
"compile_kwargs": {k: compile_kwargs[k] for k in sorted(compile_kwargs)},
"shape_bucket": shape_bucket,
}
def cache_key(env_fp: dict[str, Any], model_fp: dict[str, Any]) -> str:
payload = json.dumps({"env": env_fp, "model": model_fp}, sort_keys=True, default=str)
return hashlib.sha256(payload.encode("utf-8")).hexdigest()[:32]
# ----------------------------------------------------------------------------- lifecycle
@dataclasses.dataclass
class CacheContext:
"""Carries the per-load cache state between ``begin`` and ``save``/``restore``."""
key: str
dir: Path
bundle: Path
manifest_path: Path
env_fp: dict[str, Any]
model_fp: dict[str, Any]
mode: str
hit: bool = False
saved: bool = False
prev_inductor_dir: Optional[str] = None
prev_inductor_dir_set: bool = False
def begin(
*,
family: Any,
transformer: Any,
dtype: Any,
quant: Any,
attention_backend: Any,
compile_kwargs: dict[str, Any],
shape_bucket: Any = None,
logger: Any = None,
) -> Optional[CacheContext]:
"""Point inductor at a per-key dir and load a matching bundle, BEFORE compile.
Returns a ``CacheContext`` to pass to ``save``/``restore``, or ``None`` when the
cache is disabled or torch lacks the Mega-cache API. Never raises.
"""
mode = cache_mode()
if mode == "off":
return None
try:
import torch # noqa: PLC0415
if not (hasattr(torch.compiler, "save_cache_artifacts")
and hasattr(torch.compiler, "load_cache_artifacts")):
_warn(logger, "Mega-cache API unavailable (need torch >= 2.7); skipping")
return None
except Exception as exc: # noqa: BLE001
_warn(logger, f"torch import failed: {exc}")
return None
env_fp = environment_fingerprint()
model_fp = model_fingerprint(
family=family, transformer=transformer, dtype=dtype, quant=quant,
attention_backend=attention_backend, compile_kwargs=compile_kwargs,
shape_bucket=shape_bucket,
)
key = cache_key(env_fp, model_fp)
cdir = cache_root() / key
ctx = CacheContext(
key=key, dir=cdir, bundle=cdir / _BUNDLE_NAME,
manifest_path=cdir / _MANIFEST_NAME, env_fp=env_fp, model_fp=model_fp, mode=mode,
)
# Isolate inductor's on-disk cache per key so bundles never cross-contaminate.
try:
cdir.mkdir(parents=True, exist_ok=True)
ctx.prev_inductor_dir = os.environ.get("TORCHINDUCTOR_CACHE_DIR")
ctx.prev_inductor_dir_set = True
os.environ["TORCHINDUCTOR_CACHE_DIR"] = str(cdir / "inductor")
except Exception as exc: # noqa: BLE001
_warn(logger, f"could not set TORCHINDUCTOR_CACHE_DIR: {exc}")
# Try an exact-match load. A miss/mismatch is normal and non-fatal.
if ctx.bundle.exists() and ctx.manifest_path.exists():
ctx.hit = _try_load(ctx, logger)
else:
_info(logger, f"compile-cache: no bundle for key {key} (will compile locally)")
return ctx
def _try_load(ctx: CacheContext, logger: Any) -> bool:
try:
manifest = json.loads(ctx.manifest_path.read_text())
except Exception as exc: # noqa: BLE001
_warn(logger, f"compile-cache: unreadable manifest: {exc}")
return False
# Exact-match guard (defence in depth: torch also validates internally on load).
if manifest.get("env") != ctx.env_fp or manifest.get("model") != ctx.model_fp:
_warn(logger, "compile-cache: fingerprint mismatch; falling back to local compile")
return False
try:
data = ctx.bundle.read_bytes()
except Exception as exc: # noqa: BLE001
_warn(logger, f"compile-cache: cannot read bundle: {exc}")
return False
# Integrity check (corruption / truncation; not a security signature).
digest = hashlib.sha256(data).hexdigest()
if manifest.get("sha256") and manifest["sha256"] != digest:
_warn(logger, "compile-cache: bundle checksum mismatch; ignoring")
return False
try:
import torch # noqa: PLC0415
info = torch.compiler.load_cache_artifacts(data)
if info is None:
_warn(logger, "compile-cache: load_cache_artifacts returned None (no hit)")
return False
_info(logger, f"compile-cache: loaded bundle for key {ctx.key}")
return True
except Exception as exc: # noqa: BLE001
_warn(logger, f"compile-cache: load failed: {exc}")
return False
def save(ctx: Optional[CacheContext], *, logger: Any = None) -> bool:
"""Persist the compiled artifacts to the bundle + manifest, AFTER a warmup forward.
No-op unless save is enabled (mode ``on`` or ``UNSLOTH_DIFFUSION_COMPILE_CACHE_SAVE``).
Returns True if a bundle was written.
"""
if ctx is None or not _save_enabled(ctx.mode) or ctx.saved:
return False
try:
import torch # noqa: PLC0415
result = torch.compiler.save_cache_artifacts()
except Exception as exc: # noqa: BLE001
_warn(logger, f"compile-cache: save_cache_artifacts failed: {exc}")
return False
if not result or result[0] is None:
_warn(logger, "compile-cache: nothing to save (empty artifacts)")
return False
data = result[0]
try:
ctx.dir.mkdir(parents=True, exist_ok=True)
ctx.bundle.write_bytes(data)
manifest = {
"format": _FORMAT_VERSION,
"key": ctx.key,
"created": time.time(),
"bytes": len(data),
"sha256": hashlib.sha256(data).hexdigest(),
"env": ctx.env_fp,
"model": ctx.model_fp,
}
ctx.manifest_path.write_text(json.dumps(manifest, indent=2, sort_keys=True, default=str))
ctx.saved = True
_info(logger, f"compile-cache: saved bundle ({len(data)} bytes) for key {ctx.key}")
return True
except Exception as exc: # noqa: BLE001
_warn(logger, f"compile-cache: could not write bundle: {exc}")
return False
def restore(ctx: Optional[CacheContext]) -> None:
"""Restore ``TORCHINDUCTOR_CACHE_DIR`` to its pre-load value. Call on unload."""
if ctx is None or not ctx.prev_inductor_dir_set:
return
try:
if ctx.prev_inductor_dir is None:
os.environ.pop("TORCHINDUCTOR_CACHE_DIR", None)
else:
os.environ["TORCHINDUCTOR_CACHE_DIR"] = ctx.prev_inductor_dir
except Exception: # noqa: BLE001
pass
def _warn(logger: Any, msg: str) -> None:
if logger is not None:
logger.warning("diffusion.compile_cache: %s", msg)
def _info(logger: Any, msg: str) -> None:
if logger is not None:
logger.info("diffusion.compile_cache: %s", msg)

View file

@ -0,0 +1,203 @@
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
"""Reversible, failure-safe monkey-patches that speed up the diffusion denoiser.
These patch a couple of SHARED diffusers building-block classes (so a tiny patch surface
covers all four Studio families) to make inference faster WITHOUT reducing accuracy and
WITHOUT regressing ``torch.compile``. Both patches are *compile-safe*: they lower to plain
torch ops, are bit-identical or FMA-1-ULP (i.e. equal-or-MORE accurate) vs stock diffusers,
and ``torch.compile`` fuses either form to the same kernel -- so they help the EAGER path
and are neutral under compile.
What it patches (measured on a B200, bf16, DiT shapes):
* ``normalization.RMSNorm.forward`` -> fused ``F.rms_norm`` on the common path (non-NPU,
no bias, weight None/fp16/bf16; else the exact original, incl. its fp32 quirk). This is
the standout win (~6-12x per call) because QK-norm runs every attention block on
Qwen-Image + Z-Image. Bit-identical in bf16.
* ``AdaLayerNormContinuous`` / ``AdaLayerNormZero`` / ``AdaLayerNormZeroSingle`` ->
the ``norm(x)*(1+scale)+shift`` modulation fused via ``torch.addcmul`` (~1.2x). fp32
exact; bf16 within 1 ULP (FMA, a single rounding -> more accurate than mul+add). Covers
flux.1 / flux.2-klein / qwen-image.
Deliberately NOT patched (evidence-based):
* ``FeedForward`` (skipping its eval no-op Dropout) -- measured a small REGRESSION because
the per-module ``isinstance`` check costs more than the skipped identity dispatch.
* GEGLU / SwiGLU / GELU -- already mul-bound; a real win needs a custom Triton/CUDA kernel
(out of scope, correctness risk).
* Per-family custom MLP/norm classes and attention -- not shared (no leverage), and
attention already routes through ``F.scaled_dot_product_attention`` via the existing
``set_attention_backend`` dispatcher.
Lifecycle: ``install_compile_safe_patches()`` is idempotent and patches at the class level.
Install it for any active speed tier; the bit-identical ``off`` reference path must run with
the patches UNINSTALLED, so the caller uninstalls on an ``off`` load and on unload. The
Studio CHAT<->DIFFUSION arbiter guarantees a single active diffusion pipe, so class-level
state is safe.
"""
from __future__ import annotations
import logging
import os
from typing import Callable, Optional
import torch
import torch.nn.functional as F
from .diffusion_patch_backend import apply_patch, revert_patch
logger = logging.getLogger(__name__)
# Kill-switch: set UNSLOTH_DIFFUSION_EAGER_PATCHES=0 to disable the patches entirely (for
# A/B benchmarking or to rule them out while debugging). Enabled by default.
_ENV_ENABLE = "UNSLOTH_DIFFUSION_EAGER_PATCHES"
def _patches_enabled() -> bool:
return (os.environ.get(_ENV_ENABLE) or "").strip().lower() not in ("0", "off", "false", "no")
# --------------------------------------------------------------------------- #
# Resolve the diffusers classes we patch. Any import failure -> that patch is
# simply unavailable (None) and is skipped at install time.
# --------------------------------------------------------------------------- #
try:
from diffusers.models.normalization import (
AdaLayerNormContinuous as _AdaLayerNormContinuous,
AdaLayerNormZero as _AdaLayerNormZero,
AdaLayerNormZeroSingle as _AdaLayerNormZeroSingle,
RMSNorm as _RMSNorm,
)
except Exception: # noqa: BLE001
_AdaLayerNormContinuous = _AdaLayerNormZero = _AdaLayerNormZeroSingle = _RMSNorm = None
try:
from diffusers.utils.import_utils import is_torch_npu_available as _is_npu
_NPU = bool(_is_npu())
except Exception: # noqa: BLE001
_NPU = False
# --------------------------------------------------------------------------- #
# Patched forwards. Each mirrors diffusers 0.38 semantics, with the documented
# fused fast path. ``addcmul(input, t1, t2) == input + t1 * t2`` in one fused kernel.
# --------------------------------------------------------------------------- #
def _adaln_continuous_forward(self, x, conditioning_embedding):
emb = self.linear(self.silu(conditioning_embedding).to(x.dtype))
scale, shift = torch.chunk(emb, 2, dim=1)
# original: self.norm(x) * (1 + scale)[:, None, :] + shift[:, None, :]
return torch.addcmul(shift[:, None, :], self.norm(x), 1 + scale[:, None, :])
def _adaln_zero_forward(self, x, timestep=None, class_labels=None, hidden_dtype=None, emb=None):
if self.emb is not None:
emb = self.emb(timestep, class_labels, hidden_dtype=hidden_dtype)
emb = self.linear(self.silu(emb))
shift_msa, scale_msa, gate_msa, shift_mlp, scale_mlp, gate_mlp = emb.chunk(6, dim=1)
# original: self.norm(x) * (1 + scale_msa[:, None]) + shift_msa[:, None]
x = torch.addcmul(shift_msa[:, None], self.norm(x), 1 + scale_msa[:, None])
return x, gate_msa, shift_mlp, scale_mlp, gate_mlp
def _adaln_zero_single_forward(self, x, emb=None):
emb = self.linear(self.silu(emb))
shift_msa, scale_msa, gate_msa = emb.chunk(3, dim=1)
x = torch.addcmul(shift_msa[:, None], self.norm(x), 1 + scale_msa[:, None])
return x, gate_msa
# Filled in at install time with the ORIGINAL RMSNorm.forward so the guarded fast path
# can fall back for the uncommon (NPU / bias / fp32-weight) cases.
_orig_rmsnorm_forward: Optional[Callable] = None
def _rmsnorm_forward(self, hidden_states):
# Fall back to the exact original for cases where F.rms_norm is NOT equivalent to
# diffusers' implementation:
# * NPU / bias / fp32-weight -> the original has special handling / an fp32 quirk;
# * tuple `dim` -> diffusers always reduces the LAST dim (`mean(-1)`) while
# F.rms_norm reduces every dim in `self.dim` (differs for a multi-dim shape);
# * dtype mismatch (e.g. fp32 activations into an fp16/bf16-weight norm) -> diffusers
# computes the variance in fp32 from the ORIGINAL tensor and only casts before the
# weight multiply, so casting first would change the variance.
if (
_NPU
or self.bias is not None
or _orig_rmsnorm_forward is None
or len(tuple(self.dim)) != 1
):
return _orig_rmsnorm_forward(self, hidden_states) # type: ignore[misc]
weight = self.weight
if weight is None:
return F.rms_norm(hidden_states, self.dim, None, self.eps)
if weight.dtype in (torch.float16, torch.bfloat16) and hidden_states.dtype == weight.dtype:
# Common DiT path (bf16 activations + bf16 weight): F.rms_norm matches diffusers
# bit-for-bit (both reduce the variance in fp32 internally), just fused.
return F.rms_norm(hidden_states, self.dim, weight, self.eps)
# Mixed dtype / fp32 weight -> keep the exact original behaviour.
return _orig_rmsnorm_forward(self, hidden_states) # type: ignore[misc]
# --------------------------------------------------------------------------- #
# Install / uninstall. All swaps go through the shared patch backend
# (unsloth_zoo patch_function / restore_original): the live original is fingerprinted
# (can_safely_patch, relaxed) so a diffusers that renamed/reordered a forward's params is
# left UNPATCHED instead of miscompiled, and the original is stashed for an exact restore.
# --------------------------------------------------------------------------- #
def _specs():
# (class, patched_fn)
return [
(_AdaLayerNormContinuous, _adaln_continuous_forward),
(_AdaLayerNormZero, _adaln_zero_forward),
(_AdaLayerNormZeroSingle, _adaln_zero_single_forward),
(_RMSNorm, _rmsnorm_forward),
]
# Classes whose `forward` we successfully patched, so uninstall reverts exactly those.
_patched: list[type] = []
def install_compile_safe_patches() -> int:
"""Install the shared compile-safe speedup patches (idempotent).
Returns the number of patches applied. A second call while installed is a no-op.
"""
global _orig_rmsnorm_forward
if not _patches_enabled():
uninstall_patches() # ensure OFF even if a prior call installed them
return 0
if _patched:
return len(_patched)
for cls, new_fn in _specs():
if cls is None:
continue
# Capture the live original BEFORE patching so the RMSNorm fast path can fall back
# to it for the uncommon (NPU / bias / fp32-weight / tuple-dim) cases.
if cls is _RMSNorm:
_orig_rmsnorm_forward = cls.forward
if apply_patch(cls, "forward", new_fn, match_level="relaxed"):
_patched.append(cls)
else:
logger.warning("eager-patch: skipping %s (signature mismatch / unavailable)",
getattr(cls, "__name__", cls))
if cls is _RMSNorm:
_orig_rmsnorm_forward = None
logger.info("eager-patch: installed %d/%d shared diffusion patches", len(_patched), len(_specs()))
return len(_patched)
def uninstall_patches() -> None:
"""Restore every patched class to its exact original ``forward`` (idempotent)."""
global _orig_rmsnorm_forward
for cls in list(_patched):
revert_patch(cls, "forward")
_patched.clear()
_orig_rmsnorm_forward = None
def is_installed() -> bool:
"""True if any compile-safe patch is currently installed."""
return bool(_patched)

View file

@ -0,0 +1,132 @@
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
"""GGUF dequant accelerator for the light-compile (``default``) diffusion path.
Profiling (outputs/profile_eager/) showed that ~70-80% of EAGER GGUF denoise CUDA
time is the per-forward weight dequant: every ``GGUFLinear.forward`` calls
``diffusers.quantizers.gguf.utils.dequantize_gguf_tensor`` -> ``dequantize_blocks_Q4_K``,
a ~20-op pure-PyTorch chain (nibble shifts + masks + block-scale mul + zero-point sub +
assembly), once per linear per step.
COMPILED DEQUANT (``install_compiled_dequant``): swap ``dequantize_gguf_tensor`` for
``torch.compile(orig, dynamic=True)``. Inductor fuses the op chain into a few kernels.
Measured 1.24-1.64x warm with a small one-time compile (~7.5-10.4s) and ZERO extra VRAM --
the weights stay quantized. ``dynamic=True`` is key: the dequant inputs are the WEIGHT
tensors (fixed shapes, independent of image resolution / batch), so it compiles once and
never recompiles on a resolution change. ``GGUFLinear.forward_native`` resolves the
function as a module global, so replacing the module attribute reroutes every linear.
It is the ``default`` tier's lever (the transformer block stays eager). It is deliberately
NOT used under ``max`` (full regional block compile): there the block is compiled as one
graph which fuses the dequant inline, and a separately-compiled dequant would be traced
into that graph and break it -- so ``max`` runs the stock dequant and lets the block
compile fuse it.
The swap goes through the shared, fingerprint-checked, reversible patch backend
(``diffusion_patch_backend``); ``uninstall_*`` restores the exact original so a later
bit-identical ``off`` load runs the stock dequant. Kill-switch:
``UNSLOTH_DIFFUSION_GGUF_COMPILE_DEQUANT=0``. torch / diffusers are imported lazily.
(A global weight-buffer accelerator lived here too but was removed: it measured neutral
end-to-end -- the CUDA caching allocator already serves the per-forward cast allocation
from its pool with zero ``cudaMalloc`` churn, so reusing one buffer saved nothing on a
DiT's compute-bound forward. See outputs/arch_patch/SUMMARY.md.)
"""
from __future__ import annotations
import os
from typing import Any
from .diffusion_patch_backend import apply_patch, revert_patch
# --- kill-switch -------------------------------------------------------------------
_ENV_COMPILE_DEQUANT = "UNSLOTH_DIFFUSION_GGUF_COMPILE_DEQUANT"
_DISABLED = {"0", "off", "false", "no"}
def _enabled(env_name: str) -> bool:
"""Enabled unless explicitly disabled (default ON)."""
return str(os.environ.get(env_name, "1")).strip().lower() not in _DISABLED
def _gguf_utils():
"""The diffusers GGUF utils module, or None if this diffusers build lacks it."""
try:
from diffusers.quantizers.gguf import utils as gguf_utils # noqa: PLC0415
return gguf_utils
except Exception: # noqa: BLE001 — old/!GGUF diffusers -> accelerator is a no-op
return None
# --- compiled dequant --------------------------------------------------------------
# True while our compiled wrapper is installed (the shared patch backend stashes the
# original on the module for an exact restore).
_compiled_dequant_installed = False
_DEQUANT_ATTR = "dequantize_gguf_tensor"
def is_compiled_dequant_installed() -> bool:
return _compiled_dequant_installed
def install_compiled_dequant(logger: Any = None) -> bool:
"""Replace ``dequantize_gguf_tensor`` with ``torch.compile(orig, dynamic=True)`` via the
shared patch backend (original stashed for restore).
Idempotent (a second call is a no-op while installed). Returns True if the compiled
dequant is in place afterwards, False if disabled / unavailable / it failed."""
global _compiled_dequant_installed
if not _enabled(_ENV_COMPILE_DEQUANT):
return False
if _compiled_dequant_installed:
return True
gguf_utils = _gguf_utils()
if gguf_utils is None or not hasattr(gguf_utils, _DEQUANT_ATTR):
return False
try:
import torch # noqa: PLC0415
compiled = torch.compile(gguf_utils.dequantize_gguf_tensor, dynamic=True)
# force=True: the new callable is the SAME function compiled, so its fingerprint
# differs from the original and can_safely_patch would (correctly) reject it.
if apply_patch(gguf_utils, _DEQUANT_ATTR, compiled, force=True):
_compiled_dequant_installed = True
return True
return False
except Exception as exc: # noqa: BLE001 — optimisation only
_warn(logger, "install_compiled_dequant", exc)
_compiled_dequant_installed = False
return False
def uninstall_compiled_dequant() -> None:
"""Restore the original ``dequantize_gguf_tensor``. Idempotent."""
global _compiled_dequant_installed
if not _compiled_dequant_installed:
return
gguf_utils = _gguf_utils()
if gguf_utils is not None:
revert_patch(gguf_utils, _DEQUANT_ATTR)
_compiled_dequant_installed = False
# --- convenience -------------------------------------------------------------------
def uninstall_all() -> None:
"""Uninstall the GGUF accelerator. Idempotent; safe to call on every unload."""
uninstall_compiled_dequant()
def is_installed() -> bool:
return is_compiled_dequant_installed()
def _warn(logger: Any, what: str, exc: Exception) -> None:
if logger is not None:
logger.warning("diffusion.gguf_compile: %s failed: %s", what, exc)

View file

@ -0,0 +1,70 @@
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
"""One vetted path for every diffusion monkey-patch.
Thin wrappers over ``unsloth_zoo.temporary_patches.utils`` ``patch_function`` /
``restore_original`` so all of the backend's runtime patching (eager fusions, GGUF
accelerators, per-arch block rewrites) goes through the SAME fingerprint-checked,
reversible mechanism:
* ``patch_function`` stores the live original under a unique attribute and, unless
``force=True``, runs ``can_safely_patch`` (a parameter-name/kind/required fingerprint;
``match_level="relaxed"`` ignores type-annotation drift but still rejects a real
signature change) -- so a future diffusers/transformers that renamed or reordered a
forward's parameters is simply left unpatched instead of silently miscompiled.
* ``restore_original`` puts the stored original back -- exact, idempotent uninstall.
``unsloth_zoo`` is imported LAZILY inside each call, never at module import: it runs GPU
detection at import time and raises without an accelerator (set ``UNSLOTH_ALLOW_CPU=1`` to
bypass, as the test conftest does), and the diffusion backend must stay importable on a
CPU-only host. This mirrors the backend's existing deferred unsloth_zoo imports (see
``core/training/trainer.py``, ``core/export/export.py``). If the import fails (unsloth_zoo
absent, or a no-GPU host without the bypass), patching is a best-effort no-op: the stock
forward runs, correctness is preserved, only the optimisation is skipped.
"""
from __future__ import annotations
from typing import Any
def apply_patch(
target: Any,
attr: str,
new_fn: Any,
*,
match_level: str = "relaxed",
force: bool = False,
) -> bool:
"""Patch ``target.attr -> new_fn`` via ``unsloth_zoo`` ``patch_function`` (the original is
stashed for ``revert_patch``). Returns True iff the swap was applied. Returns False
(never raises) if unsloth_zoo is unavailable or ``can_safely_patch`` rejects the swap.
``force=True`` skips the safety check -- use it only when the new callable is the SAME
function transformed (e.g. its ``torch.compile`` wrapper), where a fingerprint mismatch
is expected and benign."""
try:
from unsloth_zoo.temporary_patches.utils import patch_function
except Exception: # noqa: BLE001 — no unsloth_zoo / no-GPU host -> optimisation skipped
return False
try:
return bool(
patch_function(target, attr, new_fn, match_level=match_level, force=force)
)
except Exception: # noqa: BLE001 — best-effort; leave the original in place
return False
def revert_patch(target: Any, attr: str) -> bool:
"""Restore ``target.attr`` from the original stashed by ``apply_patch``. Idempotent and
best-effort: returns False (never raises) if there is nothing stored or unsloth_zoo is
unavailable."""
try:
from unsloth_zoo.temporary_patches.utils import restore_original
except Exception: # noqa: BLE001
return False
try:
return bool(restore_original(target, attr))
except Exception: # noqa: BLE001
return False

View file

@ -6,22 +6,34 @@
Off by default, so the default render path stays bit-identical to a plain run (the
property the regression harness checks). When the operator opts in, this applies the
near-lossless speedups in the order the diffusers guides recommend
(channels_last + cudnn.benchmark -> regional compile, with TF32 / fused-QKV under
"max"):
(channels_last + cudnn.benchmark -> compile, with TF32 / fused-QKV under "max"):
off - nothing (default; bit-identical reference).
default - near-lossless: channels_last VAE memory format + cudnn.benchmark conv
autotune + regional torch.compile of the denoiser's repeated block WHERE
eligible (bf16, CUDA, a compile-friendly family). Compile is the big win
(~2.3x denoise on the GGUF Z-Image transformer, PSNR ~36 dB vs eager,
well above the Q4 quantisation noise floor, so it does not meaningfully
move output quality).
max - default plus near-lossless TF32 matmul and fused QKV projections.
eager - everything lossless EXCEPT torch.compile: channels_last VAE +
cudnn.benchmark + the attention backend + the shared eager monkey-patches
(fused RMSNorm / AdaLayerNorm + per-arch addcmul fusions, see
diffusion_eager_patches.py / diffusion_arch_patches.py). The fast first-image
/ casual-use path -- no compile tax to amortise.
default - LIGHT compile. For a GGUF model: channels_last + cudnn.benchmark +
torch.compile of ONLY the dequant op chain
(``torch.compile(dequantize_gguf_tensor, dynamic=True)``) -- the dequant is
~70-80% of eager GGUF time, so fusing it gives ~1.24-1.64x for a small
one-time compile (~7.5-10.4s) and ZERO extra VRAM, resolution-invariant
(the dequant inputs are fixed-shape weights). For a dense (non-GGUF) model
there is no dequant, so ``default`` falls back to regional torch.compile of
the denoiser's repeated block (the only compile lever a dense model has).
max - the FULL torch.compile: regional max-autotune compile of the denoiser's
repeated block (which fuses the GGUF dequant AND the matmul/norm/elementwise
in one graph -- ~3.2x on the GGUF Z-Image transformer, PSNR ~36 dB vs eager,
well above the Q4 noise floor) plus TF32 matmul and fused QKV projections.
Regional compile used to be gated off for the GGUF transformer, but it compiles and
runs faster on the current diffusers/torch (measured; the GGUF dequant ops stay
eager and the rest of the repeated block compiles), so the GGUF gate is removed; the
per-family ``supports_torch_compile`` flag and the bf16/CUDA checks still apply.
Tier rationale: ``default`` is the cheap, always-amortising compile (compile just the
hot GGUF dequant; the block stays eager) so the first image is fast and VRAM is
untouched; ``max`` pays the larger regional-compile tax for the bigger warm speedup.
The compiled dequant is deliberately skipped under ``max`` -- the regional block compile
subsumes the dequant fusion (a separately-compiled dequant would be traced into that
graph and break it), so ``max`` runs the stock dequant and lets the block compile it. The
per-family ``supports_torch_compile`` flag and the bf16/CUDA checks gate regional compile.
The backend flags this layer flips (TF32, cudnn.benchmark) are PROCESS-WIDE, so
``snapshot_backend_flags`` / ``restore_backend_flags`` let the caller capture the
@ -34,10 +46,13 @@ from __future__ import annotations
from typing import Any, Optional
from . import diffusion_gguf_compile as gguf_compile
SPEED_OFF = "off"
SPEED_EAGER = "eager"
SPEED_DEFAULT = "default"
SPEED_MAX = "max"
SPEED_MODES = (SPEED_OFF, SPEED_DEFAULT, SPEED_MAX)
SPEED_MODES = (SPEED_OFF, SPEED_EAGER, SPEED_DEFAULT, SPEED_MAX)
def snapshot_backend_flags() -> Optional[dict]:
@ -85,12 +100,13 @@ def normalize_speed_mode(value: Optional[str]) -> str:
def resolve_speed_mode(value: Optional[str], *, is_gguf: bool) -> str:
"""The effective speed mode when the caller leaves it UNSET (``None``).
A GGUF model defaults to ``default``: regional compile is ~2.2x faster and its
numeric perturbation sits well below the quantisation noise floor (measured
PSNR ~37 dB compile-vs-eager versus ~21 dB Q4-vs-bf16), so it does not reduce
output quality relative to the dense reference. A dense (non-GGUF) model stays
``off`` / bit-identical, since there compile would be the only source of drift.
An explicit value -- including ``"off"`` -- is always honored verbatim."""
A GGUF model defaults to ``default``: it compiles only the hot dequant op chain
(~70-80% of eager GGUF time) for ~1.24-1.64x at a small one-time compile and zero
extra VRAM -- a cheap, always-amortising win whose numeric perturbation sits well
below the quantisation noise floor (the dequant graph is unchanged, just
Inductor-fused). A dense (non-GGUF) model stays ``off`` / bit-identical, since there
compile would be the only source of drift. An explicit value -- including ``"off"``
-- is always honored verbatim."""
if value is None:
return SPEED_DEFAULT if is_gguf else SPEED_OFF
return normalize_speed_mode(value)
@ -139,30 +155,47 @@ def apply_speed_optims(
"tf32": False,
"fused_qkv": False,
"compiled": False,
"compiled_dequant": False,
}
mode = normalize_speed_mode(speed_mode)
if mode == SPEED_OFF:
return applied
on_cuda = getattr(target, "device", None) == "cuda"
family_allows_compile = bool(getattr(family, "supports_torch_compile", True))
# Lossless: a channels-last VAE speeds up its convolutions with no numeric change.
applied["channels_last"] = _vae_channels_last(pipe, logger)
# Near-lossless: let cuDNN autotune the fixed-shape VAE convs (CUDA only). It may
# pick a different conv algorithm, so it is a "default"-tier (not bit-identical) win.
if getattr(target, "device", None) == "cuda":
if on_cuda:
applied["cudnn_benchmark"] = _enable_cudnn_benchmark(logger)
# Near-lossless and the largest win: regional compile of the repeated denoiser
# block, where eligible (now incl. the GGUF transformer). `max` opts into
# max-autotune (longer compile, autotuned kernels).
if compile_eligible(target, is_gguf = is_gguf, family = family):
# --- the compile lever, remapped per tier ----------------------------------------
# default = LIGHT compile: for a GGUF model, compile ONLY the dequant op chain
# (~70-80% of eager GGUF time) -- cheap, VRAM-free, resolution-invariant; the
# transformer block stays eager. A dense model has no dequant, so default falls
# back to the regional block compile (its only compile lever).
# max = FULL compile: regional max-autotune compile of the repeated denoiser block
# (fuses dequant + matmul + norm + elementwise in one graph). It subsumes the
# dequant fusion, so we do NOT also install the standalone compiled dequant here.
# eager = no compile at all.
if mode == SPEED_DEFAULT:
if is_gguf and on_cuda and family_allows_compile:
applied["compiled_dequant"] = gguf_compile.install_compiled_dequant(logger)
elif compile_eligible(target, is_gguf = is_gguf, family = family):
applied["compiled"] = _compile_repeated_blocks(
pipe, logger, max_autotune = False, cache_active = cache_active
)
elif mode == SPEED_MAX and compile_eligible(target, is_gguf = is_gguf, family = family):
applied["compiled"] = _compile_repeated_blocks(
pipe, logger, max_autotune = mode == SPEED_MAX, cache_active = cache_active
pipe, logger, max_autotune = True, cache_active = cache_active
)
if mode == SPEED_MAX:
# Near-lossless: TF32 matmul (CUDA only) trades a few mantissa bits for speed.
if getattr(target, "device", None) == "cuda":
if on_cuda:
applied["tf32"] = _enable_tf32(logger)
applied["fused_qkv"] = _fuse_qkv(pipe, logger)

View file

@ -22,6 +22,12 @@ _backend_root = Path(__file__).resolve().parent.parent
if str(_backend_root) not in sys.path:
sys.path.insert(0, str(_backend_root))
# Let the diffusion patch backend lazily import unsloth_zoo on a CPU-only / no-GPU test
# host: unsloth_zoo runs accelerator detection at import and raises without a GPU unless
# this is set (device_type.get_device_type checks torch.cuda first, so it is a no-op on a
# real GPU run). setdefault so an explicit override wins.
os.environ.setdefault("UNSLOTH_ALLOW_CPU", "1")
# Pytest CLI options

View file

@ -0,0 +1,252 @@
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
"""Numerical + lifecycle tests for the per-arch eager fusions (``diffusion_arch_patches``).
Each per-arch patch only fuses ``a + b*c`` -> ``torch.addcmul`` (1-ULP, more accurate), so
the patched method/forward must match the stock diffusers one within fp tolerance. We also
check install/uninstall reversibility + idempotency, the kill-switch, and the body-drift
guard (a diffusers whose block body changed is left unpatched). Runs on CPU.
"""
from __future__ import annotations
import types
import pytest
torch = pytest.importorskip("torch")
pytest.importorskip("diffusers")
from core.inference import diffusion_arch_patches as ap # noqa: E402
@pytest.fixture(autouse=True)
def _clean():
ap.uninstall_arch_patches()
yield
ap.uninstall_arch_patches()
# ── qwen-image _modulate (modulation addcmul) ───────────────────────────────────
def test_qwen_modulate_matches_stock_global_and_indexed():
from diffusers.models.transformers.transformer_qwenimage import QwenImageTransformerBlock as Q
B, L, D = 2, 16, 64
x = torch.randn(B, L, D)
mod = torch.randn(B, 3 * D)
# _modulate uses no real `self` state, so call it unbound with self=None.
ref_x, ref_g = Q._modulate(None, x, mod)
got_x, got_g = ap._qwen_modulate(None, x, mod)
torch.testing.assert_close(got_x, ref_x, atol=1e-5, rtol=1e-4)
assert torch.equal(got_g, ref_g)
# per-token `index` branch (mod batch is 2*B).
idx = torch.randint(0, 2, (B, L))
mod2 = torch.randn(2 * B, 3 * D)
ref2_x, ref2_g = Q._modulate(None, x, mod2, idx)
got2_x, got2_g = ap._qwen_modulate(None, x, mod2, idx)
torch.testing.assert_close(got2_x, ref2_x, atol=1e-5, rtol=1e-4)
assert torch.equal(got2_g, ref2_g)
# ── z-image block forward (gated-residual addcmul) ──────────────────────────────
class _AttnStub(torch.nn.Module):
"""Deterministic stand-in for ZImageAttention so the block forward runs without RoPE /
freqs_cis (the patch only changes the residual adds, which is what we validate)."""
def __init__(self, dim):
super().__init__()
self.proj = torch.nn.Linear(dim, dim, bias=False)
def forward(self, h, **kwargs):
return self.proj(h)
def _zimage_block(dim=64, heads=4):
from diffusers.models.transformers.transformer_z_image import ZImageTransformerBlock
blk = ZImageTransformerBlock(
layer_id=0, dim=dim, n_heads=heads, n_kv_heads=heads,
norm_eps=1e-5, qk_norm=True, modulation=True,
).eval()
blk.attention = _AttnStub(dim).eval()
return blk
def _adaln_dim(dim):
from diffusers.models.transformers.transformer_z_image import ADALN_EMBED_DIM
return min(dim, ADALN_EMBED_DIM)
def test_zimage_forward_matches_stock_global_modulation():
from diffusers.models.transformers.transformer_z_image import ZImageTransformerBlock
torch.manual_seed(0)
blk = _zimage_block()
B, L, D = 2, 16, 64
x = torch.randn(B, L, D)
adaln = torch.randn(B, _adaln_dim(D))
with torch.inference_mode():
ref = ZImageTransformerBlock.forward(blk, x, None, None, adaln_input=adaln).clone()
got = ap._zimage_forward(blk, x, None, None, adaln_input=adaln)
torch.testing.assert_close(got, ref, atol=1e-5, rtol=1e-4)
def test_zimage_forward_matches_stock_per_token_modulation():
from diffusers.models.transformers.transformer_z_image import ZImageTransformerBlock
torch.manual_seed(1)
blk = _zimage_block()
B, L, D = 2, 16, 64
x = torch.randn(B, L, D)
ad = _adaln_dim(D)
adaln_noisy = torch.randn(B, ad)
adaln_clean = torch.randn(B, ad)
noise_mask = torch.randint(0, 2, (B, L))
with torch.inference_mode():
ref = ZImageTransformerBlock.forward(
blk, x, None, None, noise_mask=noise_mask,
adaln_noisy=adaln_noisy, adaln_clean=adaln_clean,
).clone()
got = ap._zimage_forward(
blk, x, None, None, noise_mask=noise_mask,
adaln_noisy=adaln_noisy, adaln_clean=adaln_clean,
)
torch.testing.assert_close(got, ref, atol=1e-5, rtol=1e-4)
# ── flux.1 / flux.2 block forwards (modulation + gated-residual addcmul) ─────────
class _Tuple2AttnStub(torch.nn.Module):
"""Double-stream attention stub -> (img_out, ctx_out)."""
def __init__(self, dim):
super().__init__()
self.pi = torch.nn.Linear(dim, dim, bias=False)
self.pc = torch.nn.Linear(dim, dim, bias=False)
def forward(self, hidden_states, encoder_hidden_states=None, **kwargs):
return self.pi(hidden_states), self.pc(encoder_hidden_states)
class _SingleAttnStub(torch.nn.Module):
"""Single-stream attention stub -> tensor."""
def __init__(self, dim):
super().__init__()
self.p = torch.nn.Linear(dim, dim, bias=False)
def forward(self, hidden_states, **kwargs):
return self.p(hidden_states)
def _close_any(got, ref):
if isinstance(ref, tuple):
assert len(got) == len(ref)
for g, r in zip(got, ref):
torch.testing.assert_close(g, r, atol=1e-5, rtol=1e-4)
else:
torch.testing.assert_close(got, ref, atol=1e-5, rtol=1e-4)
D, H = 64, 4
B, L, LC = 2, 16, 8
def test_flux_double_forward_matches_stock():
from diffusers.models.transformers.transformer_flux import FluxTransformerBlock
torch.manual_seed(0)
blk = FluxTransformerBlock(dim=D, num_attention_heads=H, attention_head_dim=D // H).eval()
blk.attn = _Tuple2AttnStub(D).eval()
hs, ehs, temb = torch.randn(B, L, D), torch.randn(B, LC, D), torch.randn(B, D)
with torch.inference_mode():
ref = FluxTransformerBlock.forward(blk, hs, ehs, temb)
got = ap._flux_double_forward(blk, hs, ehs, temb)
_close_any(got, ref)
def test_flux_single_forward_matches_stock():
from diffusers.models.transformers.transformer_flux import FluxSingleTransformerBlock
torch.manual_seed(1)
blk = FluxSingleTransformerBlock(dim=D, num_attention_heads=H, attention_head_dim=D // H).eval()
blk.attn = _SingleAttnStub(D).eval()
hs, ehs, temb = torch.randn(B, L, D), torch.randn(B, LC, D), torch.randn(B, D)
with torch.inference_mode():
ref = FluxSingleTransformerBlock.forward(blk, hs, ehs, temb)
got = ap._flux_single_forward(blk, hs, ehs, temb)
_close_any(got, ref)
def test_flux2_double_forward_matches_stock():
from diffusers.models.transformers.transformer_flux2 import Flux2TransformerBlock
torch.manual_seed(2)
blk = Flux2TransformerBlock(dim=D, num_attention_heads=H, attention_head_dim=D // H).eval()
blk.attn = _Tuple2AttnStub(D).eval()
hs, ehs = torch.randn(B, L, D), torch.randn(B, LC, D)
tmi, tmt = torch.randn(B, 6 * D), torch.randn(B, 6 * D)
with torch.inference_mode():
ref = Flux2TransformerBlock.forward(blk, hs, ehs, tmi, tmt)
got = ap._flux2_double_forward(blk, hs, ehs, tmi, tmt)
_close_any(got, ref)
def test_flux2_single_forward_matches_stock():
from diffusers.models.transformers.transformer_flux2 import Flux2SingleTransformerBlock
torch.manual_seed(3)
blk = Flux2SingleTransformerBlock(dim=D, num_attention_heads=H, attention_head_dim=D // H).eval()
blk.attn = _SingleAttnStub(D).eval()
hs, ehs, tm = torch.randn(B, L, D), torch.randn(B, LC, D), torch.randn(B, 3 * D)
with torch.inference_mode():
ref = Flux2SingleTransformerBlock.forward(blk, hs, ehs, tm)
got = ap._flux2_single_forward(blk, hs, ehs, tm)
_close_any(got, ref)
# ── lifecycle ───────────────────────────────────────────────────────────────────
def test_install_idempotent_and_reversible():
from diffusers.models.transformers.transformer_qwenimage import QwenImageTransformerBlock as Q
from diffusers.models.transformers.transformer_z_image import ZImageTransformerBlock as Z
q_orig, z_orig = Q._modulate, Z.forward
n1 = ap.install_arch_patches()
n2 = ap.install_arch_patches() # idempotent
assert n1 == 6 and n2 == n1 # qwen + z-image + flux.1 x2 + flux.2 x2
assert Q._modulate is not q_orig and Z.forward is not z_orig
assert ap.is_installed()
ap.uninstall_arch_patches()
assert not ap.is_installed()
assert Q._modulate is q_orig and Z.forward is z_orig # exact restore
ap.uninstall_arch_patches() # idempotent
def test_kill_switch(monkeypatch):
from diffusers.models.transformers.transformer_qwenimage import QwenImageTransformerBlock as Q
monkeypatch.setenv("UNSLOTH_DIFFUSION_ARCH_PATCHES", "0")
orig = Q._modulate
assert ap.install_arch_patches() == 0
assert not ap.is_installed()
assert Q._modulate is orig
def test_body_drift_guard_skips_changed_block(monkeypatch):
# If a resolver's body-check fails (diffusers changed the lines we rewrite), that patch
# is skipped. Force the qwen resolver to see a drifted body.
monkeypatch.setattr(ap, "_body_has", lambda fn, *needles: False)
assert ap.install_arch_patches() == 0
assert not ap.is_installed()

View file

@ -0,0 +1,189 @@
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
"""Unit tests for the pre-warmed torch.compile cache (``diffusion_compile_cache.py``).
The Mega-cache API (``torch.compiler.save_cache_artifacts`` / ``load_cache_artifacts``)
is monkeypatched with deterministic in-memory fakes so the fingerprint / exact-match /
integrity / fallback / lifecycle logic is exercised without a real compile. The
fingerprint helpers run against the real torch on this box.
"""
from __future__ import annotations
import json
import types
import pytest
from core.inference import diffusion_compile_cache as cc
def _transformer(blocks=("FluxTransformerBlock", "FluxSingleTransformerBlock")):
return types.SimpleNamespace(_repeated_blocks=list(blocks))
_BEGIN_KW = dict(
family="flux.1",
dtype="torch.bfloat16",
quant=None,
attention_backend="_native_cudnn",
compile_kwargs={"fullgraph": True, "dynamic": True},
shape_bucket="1024x1024",
)
# --------------------------------------------------------------------------- fingerprint
def test_environment_fingerprint_has_hard_dimensions():
fp = cc.environment_fingerprint()
for k in ("torch", "torch_cuda", "triton", "diffusers", "gpu_name", "gpu_capability"):
assert k in fp
def test_cache_key_stable_across_kwarg_order():
efp = cc.environment_fingerprint()
t = _transformer()
a = cc.model_fingerprint(family="flux.1", transformer=t, dtype="bf16", quant=None,
attention_backend="x", compile_kwargs={"fullgraph": True, "dynamic": True})
b = cc.model_fingerprint(family="flux.1", transformer=t, dtype="bf16", quant=None,
attention_backend="x", compile_kwargs={"dynamic": True, "fullgraph": True})
assert cc.cache_key(efp, a) == cc.cache_key(efp, b)
@pytest.mark.parametrize("field,value", [
("family", "qwen-image"),
("dtype", "torch.float16"),
("quant", "int8"),
("attention_backend", "native"),
("shape_bucket", "512x512"),
])
def test_cache_key_sensitive_to_model_dims(field, value):
efp = cc.environment_fingerprint()
t = _transformer()
base = dict(family="flux.1", transformer=t, dtype="bf16", quant=None,
attention_backend="x", compile_kwargs={"fullgraph": True}, shape_bucket="1024x1024")
k0 = cc.cache_key(efp, cc.model_fingerprint(**base))
base[field] = value
assert cc.cache_key(efp, cc.model_fingerprint(**base)) != k0
def test_repeated_blocks_change_key():
efp = cc.environment_fingerprint()
k1 = cc.cache_key(efp, cc.model_fingerprint(family="f", transformer=_transformer(("A",)),
dtype="bf16", quant=None, attention_backend="x", compile_kwargs={}))
k2 = cc.cache_key(efp, cc.model_fingerprint(family="f", transformer=_transformer(("B",)),
dtype="bf16", quant=None, attention_backend="x", compile_kwargs={}))
assert k1 != k2
# ----------------------------------------------------------------------------- env knobs
@pytest.mark.parametrize("raw,expected", [
("0", "off"), ("off", "off"), ("1", "on"), ("on", "on"),
("auto", "auto"), ("", "auto"), ("garbage", "auto"),
])
def test_cache_mode(monkeypatch, raw, expected):
monkeypatch.setenv(cc._ENV_MODE, raw)
assert cc.cache_mode() == expected
def test_cache_mode_default_auto(monkeypatch):
monkeypatch.delenv(cc._ENV_MODE, raising=False)
assert cc.cache_mode() == "auto"
# ------------------------------------------------------------------------------ disabled
def test_begin_returns_none_when_disabled(monkeypatch):
monkeypatch.setenv(cc._ENV_MODE, "0")
assert cc.begin(transformer=_transformer(), **_BEGIN_KW) is None
def test_begin_returns_none_without_megacache_api(monkeypatch):
monkeypatch.setenv(cc._ENV_MODE, "auto")
fake_torch = types.ModuleType("torch")
fake_torch.compiler = types.SimpleNamespace() # no save/load attrs
monkeypatch.setitem(__import__("sys").modules, "torch", fake_torch)
assert cc.begin(transformer=_transformer(), **_BEGIN_KW) is None
# ----------------------------------------------------------------- megacache fake + flow
@pytest.fixture
def fake_megacache(monkeypatch):
"""Patch torch.compiler save/load with deterministic in-memory behaviour."""
import torch
state = {"saved": None, "loaded_with": None}
def fake_save():
return (b"ARTIFACT-BYTES", None)
def fake_load(data: bytes):
state["loaded_with"] = data
return object() if data == b"ARTIFACT-BYTES" else None
monkeypatch.setattr(torch.compiler, "save_cache_artifacts", fake_save, raising=False)
monkeypatch.setattr(torch.compiler, "load_cache_artifacts", fake_load, raising=False)
return state
def test_save_then_load_roundtrip(monkeypatch, tmp_path, fake_megacache):
monkeypatch.setenv(cc._ENV_MODE, "on") # load + save
monkeypatch.setenv(cc._ENV_DIR, str(tmp_path))
# First load: cold (no bundle yet).
ctx = cc.begin(transformer=_transformer(), **_BEGIN_KW)
assert ctx is not None and ctx.hit is False
assert cc.save(ctx) is True
assert ctx.bundle.exists() and ctx.manifest_path.exists()
# Second load with the SAME fingerprint: warm hit.
ctx2 = cc.begin(transformer=_transformer(), **_BEGIN_KW)
assert ctx2 is not None and ctx2.hit is True
assert fake_megacache["loaded_with"] == b"ARTIFACT-BYTES"
assert ctx2.key == ctx.key
def test_no_save_in_auto_mode(monkeypatch, tmp_path, fake_megacache):
monkeypatch.setenv(cc._ENV_MODE, "auto")
monkeypatch.delenv(cc._ENV_SAVE, raising=False)
monkeypatch.setenv(cc._ENV_DIR, str(tmp_path))
ctx = cc.begin(transformer=_transformer(), **_BEGIN_KW)
assert cc.save(ctx) is False # auto without SAVE opt-in does not write
assert not ctx.bundle.exists()
def test_fingerprint_mismatch_falls_back(monkeypatch, tmp_path, fake_megacache):
monkeypatch.setenv(cc._ENV_MODE, "on")
monkeypatch.setenv(cc._ENV_DIR, str(tmp_path))
ctx = cc.begin(transformer=_transformer(), **_BEGIN_KW)
cc.save(ctx)
# Tamper the manifest's env fingerprint -> exact-match guard must reject the bundle.
manifest = json.loads(ctx.manifest_path.read_text())
manifest["env"]["torch"] = "0.0.0-other"
ctx.manifest_path.write_text(json.dumps(manifest))
ctx2 = cc.begin(transformer=_transformer(), **_BEGIN_KW)
assert ctx2.hit is False # mismatch -> local compile, non-fatal
def test_corrupt_bundle_rejected(monkeypatch, tmp_path, fake_megacache):
monkeypatch.setenv(cc._ENV_MODE, "on")
monkeypatch.setenv(cc._ENV_DIR, str(tmp_path))
ctx = cc.begin(transformer=_transformer(), **_BEGIN_KW)
cc.save(ctx)
ctx.bundle.write_bytes(b"CORRUPTED") # manifest sha256 no longer matches
ctx2 = cc.begin(transformer=_transformer(), **_BEGIN_KW)
assert ctx2.hit is False
# ------------------------------------------------------------------------------- restore
def test_restore_inductor_dir(monkeypatch, tmp_path, fake_megacache):
import os
monkeypatch.setenv(cc._ENV_MODE, "auto")
monkeypatch.setenv(cc._ENV_DIR, str(tmp_path))
monkeypatch.setenv("TORCHINDUCTOR_CACHE_DIR", "/tmp/prior-inductor")
ctx = cc.begin(transformer=_transformer(), **_BEGIN_KW)
assert os.environ["TORCHINDUCTOR_CACHE_DIR"] != "/tmp/prior-inductor" # redirected
cc.restore(ctx)
assert os.environ["TORCHINDUCTOR_CACHE_DIR"] == "/tmp/prior-inductor" # restored

View file

@ -0,0 +1,183 @@
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
"""Numerical + lifecycle tests for the shared eager speedup patches.
Builds the REAL diffusers 0.38 modules, captures the stock output, installs the patches,
and asserts the patched output matches within tolerance (fp32 on CPU always; bf16 on CUDA
when available). Also checks install/uninstall reversibility + idempotency, the
signature-guard no-op, and that a patched block compiles ``fullgraph=True`` (no graph break).
"""
from __future__ import annotations
import pytest
torch = pytest.importorskip("torch")
pytest.importorskip("diffusers")
import torch.nn as nn # noqa: E402
from core.inference import diffusion_eager_patches as ep # noqa: E402
from diffusers.models.normalization import ( # noqa: E402
AdaLayerNormContinuous,
AdaLayerNormZero,
AdaLayerNormZeroSingle,
RMSNorm,
)
B, S, D, COND = 2, 16, 64, 32
@pytest.fixture(autouse=True)
def _clean_patches():
ep.uninstall_patches()
yield
ep.uninstall_patches()
def _devices_dtypes():
cases = [("cpu", torch.float32)]
if torch.cuda.is_available():
cases.append(("cuda", torch.bfloat16))
return cases
def _build(cls, device, dtype):
torch.manual_seed(0)
if cls is RMSNorm:
m = RMSNorm(D, eps=1e-6, elementwise_affine=True)
elif cls is AdaLayerNormContinuous:
m = AdaLayerNormContinuous(D, COND, elementwise_affine=False, eps=1e-6, norm_type="layer_norm")
elif cls is AdaLayerNormZero:
m = AdaLayerNormZero(D, num_embeddings=None, norm_type="layer_norm")
elif cls is AdaLayerNormZeroSingle:
m = AdaLayerNormZeroSingle(D, norm_type="layer_norm")
return m.to(device=device, dtype=dtype).eval()
def _inputs(cls, device, dtype):
torch.manual_seed(1)
x = torch.randn(B, S, D, device=device, dtype=dtype)
if cls is RMSNorm:
return (x,)
if cls is AdaLayerNormContinuous:
return (x, torch.randn(B, COND, device=device, dtype=dtype))
# AdaLayerNormZero / Single take the conditioning emb of width D
return (x, torch.randn(B, D, device=device, dtype=dtype))
def _call(cls, m, args):
if cls is AdaLayerNormZero:
return m(args[0], emb=args[1])
return m(*args)
def _first(out):
return out[0] if isinstance(out, tuple) else out
@pytest.mark.parametrize("cls", [RMSNorm, AdaLayerNormContinuous, AdaLayerNormZero, AdaLayerNormZeroSingle])
@pytest.mark.parametrize("device,dtype", _devices_dtypes())
def test_patched_matches_original(cls, device, dtype):
m = _build(cls, device, dtype)
args = _inputs(cls, device, dtype)
with torch.inference_mode():
ref = _first(_call(cls, m, args)).clone()
assert ep.install_compile_safe_patches() >= 1
with torch.inference_mode():
got = _first(_call(cls, m, args))
# The fused ops are FMA-based (addcmul) / fused (F.rms_norm): within ~1 ULP of the
# stock mul+add (and more accurate, single rounding), NOT bit-identical in fp32.
atol, rtol = (1e-5, 1e-4) if dtype == torch.float32 else (8e-3, 8e-3)
torch.testing.assert_close(got, ref, atol=atol, rtol=rtol)
def test_rmsnorm_mixed_dtype_falls_back():
"""fp32 activations into a bf16-weight RMSNorm: diffusers reduces variance in fp32 from
the original tensor, so the fused path must FALL BACK (identical output, not divergent)."""
m = RMSNorm(D, eps=1e-6, elementwise_affine=True).to(torch.bfloat16).eval()
x = torch.randn(B, S, D, dtype=torch.float32)
with torch.inference_mode():
ref = m(x).clone()
ep.install_compile_safe_patches()
with torch.inference_mode():
got = m(x)
torch.testing.assert_close(got, ref, atol=0.0, rtol=0.0) # exact fallback
def test_rmsnorm_tuple_dim_falls_back():
"""diffusers RMSNorm always reduces the LAST dim even for a tuple `dim`; F.rms_norm
would reduce all of them, so a multi-dim `dim` must FALL BACK to the original."""
m = RMSNorm((2, D), eps=1e-6, elementwise_affine=True).eval()
x = torch.randn(B, 2, D)
with torch.inference_mode():
ref = m(x).clone()
ep.install_compile_safe_patches()
with torch.inference_mode():
got = m(x)
torch.testing.assert_close(got, ref, atol=0.0, rtol=0.0) # exact fallback
def test_install_idempotent_and_reversible():
rms = RMSNorm(D, eps=1e-6)
orig = RMSNorm.forward
n1 = ep.install_compile_safe_patches()
n2 = ep.install_compile_safe_patches() # second call is a no-op
assert n1 >= 1 and n2 == n1
assert RMSNorm.forward is not orig
assert ep.is_installed()
ep.uninstall_patches()
assert RMSNorm.forward is orig # exact restore
assert not ep.is_installed()
ep.uninstall_patches() # idempotent uninstall
del rms
def test_kill_switch_disables_patches(monkeypatch):
monkeypatch.setenv("UNSLOTH_DIFFUSION_EAGER_PATCHES", "0")
orig = RMSNorm.forward
assert ep.install_compile_safe_patches() == 0 # no-op
assert not ep.is_installed()
assert RMSNorm.forward is orig # untouched
def test_signature_guard_skips_changed_class(monkeypatch):
"""A diffusers class whose forward signature differs must be left untouched."""
class WeirdRMS(nn.Module):
def forward(self, x, extra): # not (self, hidden_states)
return x
orig = WeirdRMS.forward
monkeypatch.setattr(ep, "_RMSNorm", WeirdRMS)
monkeypatch.setattr(ep, "_AdaLayerNormContinuous", None)
monkeypatch.setattr(ep, "_AdaLayerNormZero", None)
monkeypatch.setattr(ep, "_AdaLayerNormZeroSingle", None)
applied = ep.install_compile_safe_patches()
assert applied == 0 # nothing matched -> nothing patched
assert WeirdRMS.forward is orig # left untouched
@pytest.mark.skipif(not torch.cuda.is_available(), reason="compile graph-break check needs CUDA")
def test_no_graph_break_under_fullgraph():
ep.install_compile_safe_patches()
class Block(nn.Module):
def __init__(self):
super().__init__()
self.rms = RMSNorm(D, eps=1e-6)
self.ada = AdaLayerNormContinuous(D, COND, elementwise_affine=False, norm_type="layer_norm")
def forward(self, x, cond):
return self.ada(self.rms(x), cond)
m = Block().to("cuda", torch.bfloat16).eval()
x = torch.randn(B, S, D, device="cuda", dtype=torch.bfloat16)
cond = torch.randn(B, COND, device="cuda", dtype=torch.bfloat16)
compiled = torch.compile(m, fullgraph=True) # raises if a graph break occurs
with torch.inference_mode():
out = compiled(x, cond)
assert out.shape == (B, S, D)

View file

@ -0,0 +1,73 @@
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
"""Unit tests for the compiled GGUF dequant accelerator (``diffusion_gguf_compile.py``).
Covers install/uninstall idempotency + exact reversibility, the kill-switch, and the
on-by-default behaviour. Runs on CPU -- patching the module attribute is lazy
(torch.compile only traces on the first real call).
"""
from __future__ import annotations
import pytest
torch = pytest.importorskip("torch")
gguf_utils = pytest.importorskip("diffusers.quantizers.gguf.utils")
from core.inference import diffusion_gguf_compile as gc # noqa: E402
@pytest.fixture(autouse=True)
def _clean():
# Always start and end from a clean, unpatched state so tests do not leak the
# process-wide patch into each other.
gc.uninstall_all()
yield
gc.uninstall_all()
def test_compiled_dequant_install_uninstall_reversible():
orig = gguf_utils.dequantize_gguf_tensor
assert gc.is_compiled_dequant_installed() is False
assert gc.install_compiled_dequant() is True
assert gc.is_compiled_dequant_installed() is True
# The module attribute is now a different (compiled) callable...
assert gguf_utils.dequantize_gguf_tensor is not orig
# ...idempotent: a second install is a no-op, attribute unchanged.
patched = gguf_utils.dequantize_gguf_tensor
assert gc.install_compiled_dequant() is True
assert gguf_utils.dequantize_gguf_tensor is patched
gc.uninstall_compiled_dequant()
assert gc.is_compiled_dequant_installed() is False
# Exact original restored.
assert gguf_utils.dequantize_gguf_tensor is orig
# Uninstall is idempotent.
gc.uninstall_compiled_dequant()
assert gguf_utils.dequantize_gguf_tensor is orig
def test_compiled_dequant_kill_switch(monkeypatch):
monkeypatch.setenv("UNSLOTH_DIFFUSION_GGUF_COMPILE_DEQUANT", "0")
orig = gguf_utils.dequantize_gguf_tensor
assert gc.install_compiled_dequant() is False
assert gc.is_compiled_dequant_installed() is False
assert gguf_utils.dequantize_gguf_tensor is orig
def test_compiled_dequant_on_by_default(monkeypatch):
# The compiled dequant is the real win, so it is ON without any env opt-in.
monkeypatch.delenv("UNSLOTH_DIFFUSION_GGUF_COMPILE_DEQUANT", raising=False)
assert gc.install_compiled_dequant() is True
assert gc.is_compiled_dequant_installed() is True
def test_uninstall_all(monkeypatch):
orig = gguf_utils.dequantize_gguf_tensor
gc.install_compiled_dequant()
assert gc.is_installed() is True
gc.uninstall_all()
assert gc.is_installed() is False
assert gguf_utils.dequantize_gguf_tensor is orig

View file

@ -14,8 +14,10 @@ import types
import pytest
from core.inference import diffusion_speed as ds_mod
from core.inference.diffusion_speed import (
SPEED_DEFAULT,
SPEED_EAGER,
SPEED_MAX,
SPEED_OFF,
apply_speed_optims,
@ -27,6 +29,20 @@ from core.inference.diffusion_speed import (
)
def _stub_gguf_accel(monkeypatch):
"""Replace the real compiled-dequant installer (which touches torch.compile /
diffusers) with a recorder, so the tier-gating logic in apply_speed_optims is tested
in isolation. Returns a dict of how many times it was called."""
called = {"compiled_dequant": 0}
def _install(logger = None):
called["compiled_dequant"] += 1
return True
monkeypatch.setattr(ds_mod.gguf_compile, "install_compiled_dequant", _install)
return called
def _target(
*,
device = "cuda",
@ -158,14 +174,18 @@ def test_speed_off_applies_nothing(monkeypatch):
"tf32": False,
"fused_qkv": False,
"compiled": False,
"compiled_dequant": False,
}
assert pipe.vae.mem_format is None and pipe.compiled is False
# off must not touch any process-wide flag (bit-identical reference path).
assert torch.backends.cudnn.benchmark is False
def test_speed_default_channels_last_compile_and_cudnn_benchmark(monkeypatch):
def test_speed_default_dense_falls_back_to_regional_compile(monkeypatch):
# A DENSE model has no GGUF dequant to compile, so `default` falls back to the
# regional block compile (its only compile lever) -- and no GGUF accelerators.
torch = _stub_torch(monkeypatch)
called = _stub_gguf_accel(monkeypatch)
pipe = _Pipe(with_compile = True)
applied = apply_speed_optims(
pipe, _target(), is_gguf = False, family = _family(), speed_mode = SPEED_DEFAULT
@ -178,17 +198,55 @@ def test_speed_default_channels_last_compile_and_cudnn_benchmark(monkeypatch):
# default also autotunes the VAE convs but does NOT flip TF32 or fuse QKV.
assert applied["cudnn_benchmark"] is True and torch.backends.cudnn.benchmark is True
assert applied["tf32"] is False and applied["fused_qkv"] is False
# No GGUF dequant on a dense model.
assert applied["compiled_dequant"] is False
assert called == {"compiled_dequant": 0}
def test_speed_default_compiles_gguf(monkeypatch):
def test_speed_default_gguf_compiles_only_dequant(monkeypatch):
# GGUF `default` is the LIGHT path: compile ONLY the dequant op chain, NOT the
# regional block compile.
_stub_torch(monkeypatch)
called = _stub_gguf_accel(monkeypatch)
pipe = _Pipe(with_compile = True)
applied = apply_speed_optims(
pipe, _target(), is_gguf = True, family = _family(), speed_mode = SPEED_DEFAULT
)
assert applied["channels_last"] is True
# GGUF now compiles (the big near-lossless win).
assert applied["compiled_dequant"] is True
# The transformer block is NOT regionally compiled under GGUF default.
assert applied["compiled"] is False and pipe.compiled is False
assert called == {"compiled_dequant": 1}
def test_speed_eager_gguf_installs_no_accelerator(monkeypatch):
# eager = lossless-but-no-compile: neither the compiled dequant nor the regional
# block compile run; only the process-wide lossless levers (channels_last, cudnn)
# and the shared/per-arch eager monkey-patches (installed elsewhere) engage.
_stub_torch(monkeypatch)
called = _stub_gguf_accel(monkeypatch)
pipe = _Pipe(with_compile = True)
applied = apply_speed_optims(
pipe, _target(), is_gguf = True, family = _family(), speed_mode = SPEED_EAGER
)
assert applied["compiled_dequant"] is False and applied["compiled"] is False
assert pipe.compiled is False
assert called == {"compiled_dequant": 0}
def test_speed_max_gguf_regional_compile_not_dequant(monkeypatch):
# GGUF `max` = the FULL regional block compile (which fuses the dequant inline), so
# the standalone compiled dequant is deliberately OFF.
_stub_torch(monkeypatch)
called = _stub_gguf_accel(monkeypatch)
pipe = _Pipe(with_compile = True, with_fuse = True)
applied = apply_speed_optims(
pipe, _target(), is_gguf = True, family = _family(), speed_mode = SPEED_MAX
)
assert applied["compiled"] is True and pipe.compiled is True
assert pipe.compile_kwargs["mode"] == "max-autotune-no-cudagraphs"
assert applied["compiled_dequant"] is False
assert called == {"compiled_dequant": 0}
def test_speed_default_cudnn_benchmark_only_on_cuda(monkeypatch):