Diffusion¶
diffusion
¶
Diffusion primitives: timestep embeddings, schedulers, samplers, caching.
PerHeadAttentionCache
¶
Stateful per-head attention output cache.
Returns a (num_heads,) bool decision per step. Inputs are assumed to
have the head axis at position 1 — i.e. shape (B, num_heads, ...).
previous_output
property
¶
Last cached attention output. Raises before the first cache_output call.
should_compute
¶
Per-head decide whether to recompute attention at step_index.
Side-effects: advances the stored previous input and per-head summary. Must be called once per step in order.
should_compute_from_summary
¶
Decide per head using a caller-supplied (num_heads,) summary.
summary[h] is the analogue of the per-head delta ratio. Do not
interleave with :meth:should_compute within a single denoising
run: the two methods write semantically different values into the
internal previous-summary slot. Pick one mode per run.
cache_output
¶
Store the full (B, num_heads, ...) attention output for per-head splicing on skip.
PerLayerAttentionCache
¶
Stateful per-layer attention output cache.
previous_output
property
¶
Last cached attention output. Raises before the first cache_output call.
should_compute
¶
Decide whether to recompute attention at step_index.
Side-effects: advances the stored previous input and summary. Must be called once per step in order.
should_compute_from_summary
¶
Decide using a caller-supplied scalar summary instead of a tensor.
summary is the analogue of
mean(abs(input - prev_input)) / mean(abs(prev_input)) — the caller
has already done the math.
Do not interleave with :meth:should_compute within a single
denoising run: the two methods write semantically different values
into the internal previous-summary slot. Pick one mode per run.
cache_output
¶
Store the attention output from the just-computed step for reuse on skip.
CFGSimilarityProfiler
¶
Per-(block, head) running-mean similarity accumulator.
Records the per-head similarity of cond and uncond attention outputs
during a warmup pass and produces a static (num_blocks, num_heads)
skip schedule.
CFGSkipController
¶
Wraps a static (num_blocks, num_heads) bool skip schedule.
True at (b, h) means: for block b, head h skips the
unconditional branch and reuses the conditional output. False means
the head computes uncond normally.
from_profiler
classmethod
¶
from_profiler(profiler: CFGSimilarityProfiler, threshold: float) -> 'CFGSkipController'
Build a controller from a profiler by thresholding its scores.
should_skip_uncond
¶
(num_heads,) bool mask — True heads skip uncond for this block.
apply
¶
Apply the cached schedule to splice cond/uncond outputs (wraps :func:splice_heads).
DDIMScheduler
¶
DDIMScheduler(num_train_timesteps: int = 1000, beta_start: float = 0.00085, beta_end: float = 0.012, beta_schedule: BetaSchedule = 'scaled_linear', prediction_type: PredictionType = 'v_prediction', rescale_betas_zero_snr: bool = True, timestep_spacing: TimestepSpacing = 'trailing', set_alpha_to_one: bool = True, clip_sample: bool = False, num_inference_steps: int = 50)
Deterministic DDIM scheduler (eta=0).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_train_timesteps
|
int
|
Number of diffusion steps used during
training. Defaults to |
1000
|
beta_start
|
float
|
First beta value. Defaults to |
0.00085
|
beta_end
|
float
|
Last beta value. Defaults to |
0.012
|
beta_schedule
|
BetaSchedule
|
|
'scaled_linear'
|
prediction_type
|
PredictionType
|
|
'v_prediction'
|
rescale_betas_zero_snr
|
bool
|
Whether to apply zero-terminal-SNR rescaling to the beta schedule. |
True
|
timestep_spacing
|
TimestepSpacing
|
|
'trailing'
|
set_alpha_to_one
|
bool
|
Whether the final |
True
|
clip_sample
|
bool
|
Whether to clip the predicted |
False
|
num_inference_steps
|
int
|
Default schedule length. Call
:meth: |
50
|
set_timesteps
¶
Recompute the timestep schedule for num_inference_steps steps.
step
¶
Run one deterministic DDIM step.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model_output
|
array
|
The model's prediction at |
required |
timestep
|
int | array
|
Current step's index (int or 0-d |
required |
sample
|
array
|
Current noisy sample. |
required |
Returns:
| Type | Description |
|---|---|
array
|
The denoised sample for the previous timestep. |
add_noise
¶
Forward-diffuse original to noise level timestep.
FlowMatchEulerDiscreteScheduler
¶
Stateful flow-matching Euler scheduler.
Mirrors the diffusers FlowMatchEulerDiscreteScheduler API: set_timesteps
then step through timesteps calling step with the model's velocity output.
add_noise forward-interpolates a clean sample toward pure noise.
Convention: sigmas ascend from ~0 (clean) to 1 (noise), with a terminal
1.0 appended so the final step has a valid sigma_next.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_train_timesteps
|
int
|
Number of training timesteps. |
1000
|
shift
|
float
|
Shift factor applied to the sigma schedule. |
1.0
|
set_timesteps
¶
Configure the scheduler for num_inference_steps denoising steps.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_inference_steps
|
int
|
Number of denoising steps. |
required |
sigmas
|
ndarray | list[float] | None
|
Optional custom sigmas (ascending, |
None
|
step
¶
Advance the sample by one Euler step using a velocity prediction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model_output
|
array
|
Predicted velocity (same shape as |
required |
timestep
|
array
|
Current timestep (only used to lazy-init the step index). |
required |
sample
|
array
|
Current noisy sample. |
required |
Returns:
| Type | Description |
|---|---|
array
|
Updated sample after one Euler step. |
add_noise
¶
Flow-matching interpolation: sigma * noise + (1 - sigma) * original.
TeaCacheController
¶
Stateful controller deciding when to skip a transformer forward.
Usage per denoising step::
if controller.should_compute(step_index, modulated_input):
x_in = x
x = transformer_blocks(x)
controller.cache_residual(x - x_in)
else:
x = x + controller.previous_residual
Boundary steps (step_index == 0 and step_index == num_steps - 1)
always compute and reset the accumulator.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_steps
|
int
|
Total number of denoising steps in the generation. |
required |
rel_l1_thresh
|
float
|
Skip threshold on the accumulated rescaled L1 distance. |
required |
coefficients
|
Sequence[float]
|
Polynomial coefficients in |
required |
previous_residual
property
¶
Last cached payload. Raises before the first cache_residual call.
should_compute
¶
Decide whether to run the transformer at step_index.
Side-effects: advances the stored previous_modulated_input and the
internal accumulator. Must be called once per step in order.
cache_residual
¶
Store the residual from the just-computed step for reuse on skip.
residual is whatever the caller wants to retrieve later via
previous_residual. Single-tensor models pass an mx.array;
multi-stream models (e.g. LTX-2) pass a tuple or dict. The controller
does not inspect or copy the value.
TimestepEmbedding
¶
Bases: Module
MLP that projects sinusoidal timestep embeddings into a feature space.
Weight keys: linear1.{weight,bias}, linear2.{weight,bias}.
VerifiedFeatureCache
¶
VerifiedFeatureCache(num_steps: int, tau_0: float, beta: float, *, order: int = 2, epsilon: float = 1e-08)
Lagrange-extrapolate a tracked feature and verify before accepting.
Usage per step::
cache = VerifiedFeatureCache(num_steps=50, tau_0=0.1, beta=0.5)
for step in range(num_steps):
if cache.can_predict(step):
predicted = cache.extrapolate(step)
actual = run_verifier_layer(state) # caller-supplied
if cache.accept(step, predicted, actual):
# use predicted for downstream layers / skip full forward
cache.record(step, predicted)
continue
feature = run_full_forward(state) # fallback
cache.record(step, feature)
Boundary policy: can_predict returns False at step == 0 and
step == num_steps - 1, forcing a full compute at both ends. This
matches the convention used by other step-aware controllers in
mlx_arsenal.diffusion.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_steps
|
int
|
Total number of iterative steps in the generation. |
required |
tau_0
|
float
|
Base relative-L2² threshold for accepting a draft. |
required |
beta
|
float
|
Geometric schedule base. |
required |
order
|
int
|
Lagrange polynomial order. Requires |
2
|
epsilon
|
float
|
Numerical floor in the relative-L2 denominator. |
1e-08
|
threshold
¶
Adaptive threshold at step_index (relative-L2² units).
can_predict
¶
True if a draft is available for step_index.
Returns False at boundary steps (0 and num_steps - 1) and
whenever fewer than order + 1 anchors have been recorded.
extrapolate
¶
Lagrange-extrapolate the tracked feature at step_index.
Raises RuntimeError if called when can_predict would
return False — the caller is expected to gate on it first.
accept
¶
Compare draft to ground truth on the verification layer.
Uses squared relative-L2 to match the SpeCa formulation:
e = ‖predicted − actual‖²₂ / (‖actual‖²₂ + ε).
Returns True if e <= threshold(step_index).
record
¶
Append feature as a new anchor at step_index.
Anchors are stored in a fixed-capacity FIFO of size order + 1.
step_index must be strictly greater than the last recorded
step (anchors are monotonic by construction).
WindowResidualController
¶
Step-aware controller for the WA-RS residual cache.
Construct via :meth:fixed, :meth:scheduled, or :meth:adaptive —
the bare __init__ is intentionally not part of the public API.
previous_residual
property
¶
Last cached residual. Raises before the first cache_residual call.
fixed
classmethod
¶
fixed(num_steps: int, *, refresh_every: int) -> WindowResidualController
Refresh on step 0, num_steps - 1, and every refresh_every step.
scheduled
classmethod
¶
scheduled(num_steps: int, *, refresh_steps: Sequence[int]) -> WindowResidualController
Refresh on step 0, num_steps - 1, and every step in refresh_steps.
adaptive
classmethod
¶
adaptive(num_steps: int, *, rel_l1_thresh: float) -> WindowResidualController
Refresh when relative-L1 input delta crosses rel_l1_thresh.
Mirrors :class:TeaCacheController semantics: at non-boundary
step i with previous input p, refresh iff
mean(|input - p|) / mean(|p|) >= rel_l1_thresh. A zero-norm
previous input also forces a refresh.
should_refresh
¶
Decide whether to recompute full attention at step_index.
attn_input is required in adaptive mode and ignored
otherwise. Boundary steps (0 and num_steps - 1) always
return True.
cache_residual
¶
Store the full - window residual from the just-refreshed step for reuse.
splice_heads
¶
Per-head select-between-tensors.
Where recompute_mask[h] is True, take new_output[:, h];
where False, take cached_output[:, h]. The head axis is assumed
to be axis 1.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
new_output
|
array
|
|
required |
cached_output
|
array
|
|
required |
recompute_mask
|
array
|
1D bool array of length |
required |
Returns:
| Type | Description |
|---|---|
array
|
Spliced tensor with the same shape as |
cfg_head_similarity
¶
Per-head similarity between conditional and unconditional outputs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cond
|
array
|
|
required |
uncond
|
array
|
|
required |
metric
|
Metric
|
|
'cosine'
|
Returns:
| Type | Description |
|---|---|
array
|
|
array
|
feature axes. |
cfg_skip_mask
¶
Convert similarity scores to a skip-uncond mask.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scores
|
array
|
|
required |
threshold
|
float
|
Cut-off. With |
required |
metric
|
Metric
|
Which inversion to apply. |
'cosine'
|
Returns:
| Type | Description |
|---|---|
array
|
Bool array with the same shape as |
array
|
head can skip the uncond branch". |
classifier_free_guidance
¶
Apply classifier-free guidance.
Returns uncond + scale * (cond - uncond). A scale of 1.0
yields the conditioned prediction, 0.0 the unconditioned one, and
values greater than 1.0 amplify the conditioning signal.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cond
|
array
|
Conditioned prediction. |
required |
uncond
|
array
|
Unconditioned prediction (same shape as |
required |
scale
|
float
|
Guidance scale. |
required |
Returns:
| Type | Description |
|---|---|
array
|
Guided prediction. |
euler_step
¶
Single stateless Euler step on an x0-prediction model.
Implements x_{t-1} = x + (sigma_next - sigma) * (x - x0) / sigma.
When sigma == 0 the current sample is already clean, so x0 is
returned directly.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
array
|
Current noisy sample. |
required |
x0
|
array
|
Predicted clean sample. |
required |
sigma
|
float
|
Current noise level. |
required |
sigma_next
|
float
|
Next noise level. |
required |
Returns:
| Type | Description |
|---|---|
array
|
Updated sample at |
dynamic_shift_schedule
¶
dynamic_shift_schedule(num_steps: int, num_tokens: int, base_shift: float = 0.95, max_shift: float = 2.05, base_tokens: int = 1024, max_tokens: int = 4096, stretch: bool = True, terminal: float = 0.1) -> list[float]
Sigma schedule with token-count-dependent shift (LTX-style).
Interpolates a shift factor linearly between base_shift at
base_tokens and max_shift at max_tokens, then applies it to
a descending linspace. Optional terminal stretching matches the last
non-zero sigma to 1 - terminal.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_steps
|
int
|
Number of denoising steps. |
required |
num_tokens
|
int
|
Number of latent tokens (drives the shift). |
required |
base_shift
|
float
|
Shift at |
0.95
|
max_shift
|
float
|
Shift at |
2.05
|
base_tokens
|
int
|
Anchor for |
1024
|
max_tokens
|
int
|
Anchor for |
4096
|
stretch
|
bool
|
Rescale so the last non-zero sigma equals |
True
|
terminal
|
float
|
Target terminal for stretching. |
0.1
|
Returns:
| Type | Description |
|---|---|
list[float]
|
List of |
get_sampling_sigmas
¶
Flow-matching sigma schedule: linspace(1, 0, steps+1) with optional shift.
The schedule includes the terminal 0.0 so pairs are formed via
zip(sigmas[:-1], sigmas[1:]).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_steps
|
int
|
Number of denoising steps. |
required |
shift
|
float
|
Shift factor applied as |
1.0
|
Returns:
| Type | Description |
|---|---|
list[float]
|
List of |
get_timestep_embedding
¶
get_timestep_embedding(timesteps: array, embedding_dim: int, flip_sin_to_cos: bool = True, downscale_freq_shift: float = 0.0, scale: float = 1.0, max_period: float = 10000.0) -> array
Create sinusoidal timestep embeddings.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timesteps
|
array
|
1D array of timestep values. |
required |
embedding_dim
|
int
|
Dimension of the output embeddings. |
required |
flip_sin_to_cos
|
bool
|
If True, output |
True
|
downscale_freq_shift
|
float
|
Controls delta between frequencies. |
0.0
|
scale
|
float
|
Scaling factor applied before sin/cos. |
1.0
|
max_period
|
float
|
Controls the minimum frequency. |
10000.0
|
Returns:
| Type | Description |
|---|---|
array
|
Array of shape |
geometric_threshold
¶
SpeCa-style geometric threshold schedule.
τ_t = τ₀ · β^((T - 1 - t) / max(T - 1, 1))
With beta < 1: threshold grows from τ₀·β (strict early) to
τ₀ (tolerant late). With beta > 1: the opposite. beta == 1
yields a constant threshold τ₀. The "right" regime is empirical
and depends on the schedule and model — see the research note at
docs/research/verified-feature-caching.md.
attention_cache
¶
Attention output cache (AST-style) for diffusion transformers.
Caches attention sub-layer output across denoising steps and reuses it on the next step when the input has barely changed. Two granularities:
- :class:
PerLayerAttentionCache— scalar similarity, one decision per layer per step. Simpler, mirrors :class:mlx_arsenal.diffusion.TeaCacheControllerbut at the attention sub-layer instead of a whole transformer block.
Decision rule, at step i:
- If
i == 0ori == num_steps - 1→ recompute (boundary). - If
mean(abs(prev_input))is zero → recompute (degenerate). - If
mean(abs(input - prev_input)) / mean(abs(prev_input)) >= rel_l1_thresh→ recompute.
References
DiTFastAttn — Attention Sharing across Timesteps (AST).
PerLayerAttentionCache
¶
Stateful per-layer attention output cache.
previous_output
property
¶
Last cached attention output. Raises before the first cache_output call.
should_compute
¶
Decide whether to recompute attention at step_index.
Side-effects: advances the stored previous input and summary. Must be called once per step in order.
should_compute_from_summary
¶
Decide using a caller-supplied scalar summary instead of a tensor.
summary is the analogue of
mean(abs(input - prev_input)) / mean(abs(prev_input)) — the caller
has already done the math.
Do not interleave with :meth:should_compute within a single
denoising run: the two methods write semantically different values
into the internal previous-summary slot. Pick one mode per run.
cache_output
¶
Store the attention output from the just-computed step for reuse on skip.
PerHeadAttentionCache
¶
Stateful per-head attention output cache.
Returns a (num_heads,) bool decision per step. Inputs are assumed to
have the head axis at position 1 — i.e. shape (B, num_heads, ...).
previous_output
property
¶
Last cached attention output. Raises before the first cache_output call.
should_compute
¶
Per-head decide whether to recompute attention at step_index.
Side-effects: advances the stored previous input and per-head summary. Must be called once per step in order.
should_compute_from_summary
¶
Decide per head using a caller-supplied (num_heads,) summary.
summary[h] is the analogue of the per-head delta ratio. Do not
interleave with :meth:should_compute within a single denoising
run: the two methods write semantically different values into the
internal previous-summary slot. Pick one mode per run.
cache_output
¶
Store the full (B, num_heads, ...) attention output for per-head splicing on skip.
splice_heads
¶
Per-head select-between-tensors.
Where recompute_mask[h] is True, take new_output[:, h];
where False, take cached_output[:, h]. The head axis is assumed
to be axis 1.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
new_output
|
array
|
|
required |
cached_output
|
array
|
|
required |
recompute_mask
|
array
|
1D bool array of length |
required |
Returns:
| Type | Description |
|---|---|
array
|
Spliced tensor with the same shape as |
cfg_skip
¶
CFG-skip (Attention Sharing across CFG, DiTFastAttn ASC).
Profiles per-head similarity between the conditional and unconditional CFG branches, builds a static schedule, and applies that schedule at runtime to skip the unconditional branch on heads where cond and uncond outputs are near-identical.
Two metrics:
cosine— dot/norm of flattened(B, S, D)per head, in[-1, 1]. Skip when score is at least the threshold. Default; matches the DiTFastAttn ASC literature.relative_l1—mean(|c - u|) / mean(|c|)per head, ≥ 0. Skip when score is at most the threshold. Same family as :class:~mlx_arsenal.diffusion.TeaCacheControllerand the attention output caches, so existing thresholds carry over.
The runtime apply step (:meth:CFGSkipController.apply) bundles a
:func:mlx_arsenal.diffusion.splice_heads call so callers do not have to
import the splice helper directly.
CFGSimilarityProfiler
¶
Per-(block, head) running-mean similarity accumulator.
Records the per-head similarity of cond and uncond attention outputs
during a warmup pass and produces a static (num_blocks, num_heads)
skip schedule.
CFGSkipController
¶
Wraps a static (num_blocks, num_heads) bool skip schedule.
True at (b, h) means: for block b, head h skips the
unconditional branch and reuses the conditional output. False means
the head computes uncond normally.
from_profiler
classmethod
¶
from_profiler(profiler: CFGSimilarityProfiler, threshold: float) -> 'CFGSkipController'
Build a controller from a profiler by thresholding its scores.
should_skip_uncond
¶
(num_heads,) bool mask — True heads skip uncond for this block.
apply
¶
Apply the cached schedule to splice cond/uncond outputs (wraps :func:splice_heads).
cfg_head_similarity
¶
Per-head similarity between conditional and unconditional outputs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cond
|
array
|
|
required |
uncond
|
array
|
|
required |
metric
|
Metric
|
|
'cosine'
|
Returns:
| Type | Description |
|---|---|
array
|
|
array
|
feature axes. |
cfg_skip_mask
¶
Convert similarity scores to a skip-uncond mask.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scores
|
array
|
|
required |
threshold
|
float
|
Cut-off. With |
required |
metric
|
Metric
|
Which inversion to apply. |
'cosine'
|
Returns:
| Type | Description |
|---|---|
array
|
Bool array with the same shape as |
array
|
head can skip the uncond branch". |
ddim
¶
DDIM (Denoising Diffusion Implicit Models) scheduler — MLX port.
Matches the diffusers DDIMScheduler / CogVideoXDDIMScheduler
behaviour for the deterministic case (eta=0). Supports the two
common prediction types (epsilon and v_prediction), the two
common spacing strategies (leading, trailing), and optional
zero-SNR rescaling of the beta schedule.
Use this for ports of DDPM-trained models (CogVideoX, Stable Diffusion
1.x / 2.x, ...). For flow-matching models (LTX, Hunyuan-DiT,
ERNIE-Image), see :class:FlowMatchEulerDiscreteScheduler instead.
DDIMScheduler
¶
DDIMScheduler(num_train_timesteps: int = 1000, beta_start: float = 0.00085, beta_end: float = 0.012, beta_schedule: BetaSchedule = 'scaled_linear', prediction_type: PredictionType = 'v_prediction', rescale_betas_zero_snr: bool = True, timestep_spacing: TimestepSpacing = 'trailing', set_alpha_to_one: bool = True, clip_sample: bool = False, num_inference_steps: int = 50)
Deterministic DDIM scheduler (eta=0).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_train_timesteps
|
int
|
Number of diffusion steps used during
training. Defaults to |
1000
|
beta_start
|
float
|
First beta value. Defaults to |
0.00085
|
beta_end
|
float
|
Last beta value. Defaults to |
0.012
|
beta_schedule
|
BetaSchedule
|
|
'scaled_linear'
|
prediction_type
|
PredictionType
|
|
'v_prediction'
|
rescale_betas_zero_snr
|
bool
|
Whether to apply zero-terminal-SNR rescaling to the beta schedule. |
True
|
timestep_spacing
|
TimestepSpacing
|
|
'trailing'
|
set_alpha_to_one
|
bool
|
Whether the final |
True
|
clip_sample
|
bool
|
Whether to clip the predicted |
False
|
num_inference_steps
|
int
|
Default schedule length. Call
:meth: |
50
|
set_timesteps
¶
Recompute the timestep schedule for num_inference_steps steps.
step
¶
Run one deterministic DDIM step.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model_output
|
array
|
The model's prediction at |
required |
timestep
|
int | array
|
Current step's index (int or 0-d |
required |
sample
|
array
|
Current noisy sample. |
required |
Returns:
| Type | Description |
|---|---|
array
|
The denoised sample for the previous timestep. |
add_noise
¶
Forward-diffuse original to noise level timestep.
samplers
¶
Stateless samplers and guidance primitives for diffusion denoising.
euler_step
¶
Single stateless Euler step on an x0-prediction model.
Implements x_{t-1} = x + (sigma_next - sigma) * (x - x0) / sigma.
When sigma == 0 the current sample is already clean, so x0 is
returned directly.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
array
|
Current noisy sample. |
required |
x0
|
array
|
Predicted clean sample. |
required |
sigma
|
float
|
Current noise level. |
required |
sigma_next
|
float
|
Next noise level. |
required |
Returns:
| Type | Description |
|---|---|
array
|
Updated sample at |
classifier_free_guidance
¶
Apply classifier-free guidance.
Returns uncond + scale * (cond - uncond). A scale of 1.0
yields the conditioned prediction, 0.0 the unconditioned one, and
values greater than 1.0 amplify the conditioning signal.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cond
|
array
|
Conditioned prediction. |
required |
uncond
|
array
|
Unconditioned prediction (same shape as |
required |
scale
|
float
|
Guidance scale. |
required |
Returns:
| Type | Description |
|---|---|
array
|
Guided prediction. |
schedulers
¶
Sigma schedules and noise schedulers for flow-matching diffusion.
FlowMatchEulerDiscreteScheduler
¶
Stateful flow-matching Euler scheduler.
Mirrors the diffusers FlowMatchEulerDiscreteScheduler API: set_timesteps
then step through timesteps calling step with the model's velocity output.
add_noise forward-interpolates a clean sample toward pure noise.
Convention: sigmas ascend from ~0 (clean) to 1 (noise), with a terminal
1.0 appended so the final step has a valid sigma_next.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_train_timesteps
|
int
|
Number of training timesteps. |
1000
|
shift
|
float
|
Shift factor applied to the sigma schedule. |
1.0
|
set_timesteps
¶
Configure the scheduler for num_inference_steps denoising steps.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_inference_steps
|
int
|
Number of denoising steps. |
required |
sigmas
|
ndarray | list[float] | None
|
Optional custom sigmas (ascending, |
None
|
step
¶
Advance the sample by one Euler step using a velocity prediction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model_output
|
array
|
Predicted velocity (same shape as |
required |
timestep
|
array
|
Current timestep (only used to lazy-init the step index). |
required |
sample
|
array
|
Current noisy sample. |
required |
Returns:
| Type | Description |
|---|---|
array
|
Updated sample after one Euler step. |
add_noise
¶
Flow-matching interpolation: sigma * noise + (1 - sigma) * original.
get_sampling_sigmas
¶
Flow-matching sigma schedule: linspace(1, 0, steps+1) with optional shift.
The schedule includes the terminal 0.0 so pairs are formed via
zip(sigmas[:-1], sigmas[1:]).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_steps
|
int
|
Number of denoising steps. |
required |
shift
|
float
|
Shift factor applied as |
1.0
|
Returns:
| Type | Description |
|---|---|
list[float]
|
List of |
dynamic_shift_schedule
¶
dynamic_shift_schedule(num_steps: int, num_tokens: int, base_shift: float = 0.95, max_shift: float = 2.05, base_tokens: int = 1024, max_tokens: int = 4096, stretch: bool = True, terminal: float = 0.1) -> list[float]
Sigma schedule with token-count-dependent shift (LTX-style).
Interpolates a shift factor linearly between base_shift at
base_tokens and max_shift at max_tokens, then applies it to
a descending linspace. Optional terminal stretching matches the last
non-zero sigma to 1 - terminal.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_steps
|
int
|
Number of denoising steps. |
required |
num_tokens
|
int
|
Number of latent tokens (drives the shift). |
required |
base_shift
|
float
|
Shift at |
0.95
|
max_shift
|
float
|
Shift at |
2.05
|
base_tokens
|
int
|
Anchor for |
1024
|
max_tokens
|
int
|
Anchor for |
4096
|
stretch
|
bool
|
Rescale so the last non-zero sigma equals |
True
|
terminal
|
float
|
Target terminal for stretching. |
0.1
|
Returns:
| Type | Description |
|---|---|
list[float]
|
List of |
teacache
¶
TeaCache: timestep-aware residual caching for diffusion transformers.
TeaCache (Liu et al., "Timestep Embedding Aware Cache") accelerates diffusion
inference by reusing a cached residual across timesteps when the modulated
input doesn't move much. The trade-off is governed by rel_l1_thresh:
higher = more skipping = faster but lossier.
Architecture-agnostic mechanism — coefficients are model-specific and live
with each model's port (e.g. inside the LTX-2 / Hunyuan / Flux MLX
implementation). mlx-arsenal ships only the engine.
References
https://github.com/ali-vilab/TeaCache
TeaCacheController
¶
Stateful controller deciding when to skip a transformer forward.
Usage per denoising step::
if controller.should_compute(step_index, modulated_input):
x_in = x
x = transformer_blocks(x)
controller.cache_residual(x - x_in)
else:
x = x + controller.previous_residual
Boundary steps (step_index == 0 and step_index == num_steps - 1)
always compute and reset the accumulator.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_steps
|
int
|
Total number of denoising steps in the generation. |
required |
rel_l1_thresh
|
float
|
Skip threshold on the accumulated rescaled L1 distance. |
required |
coefficients
|
Sequence[float]
|
Polynomial coefficients in |
required |
previous_residual
property
¶
Last cached payload. Raises before the first cache_residual call.
should_compute
¶
Decide whether to run the transformer at step_index.
Side-effects: advances the stored previous_modulated_input and the
internal accumulator. Must be called once per step in order.
cache_residual
¶
Store the residual from the just-computed step for reuse on skip.
residual is whatever the caller wants to retrieve later via
previous_residual. Single-tensor models pass an mx.array;
multi-stream models (e.g. LTX-2) pass a tuple or dict. The controller
does not inspect or copy the value.
timestep
¶
Timestep embeddings for diffusion models.
TimestepEmbedding
¶
Bases: Module
MLP that projects sinusoidal timestep embeddings into a feature space.
Weight keys: linear1.{weight,bias}, linear2.{weight,bias}.
get_timestep_embedding
¶
get_timestep_embedding(timesteps: array, embedding_dim: int, flip_sin_to_cos: bool = True, downscale_freq_shift: float = 0.0, scale: float = 1.0, max_period: float = 10000.0) -> array
Create sinusoidal timestep embeddings.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timesteps
|
array
|
1D array of timestep values. |
required |
embedding_dim
|
int
|
Dimension of the output embeddings. |
required |
flip_sin_to_cos
|
bool
|
If True, output |
True
|
downscale_freq_shift
|
float
|
Controls delta between frequencies. |
0.0
|
scale
|
float
|
Scaling factor applied before sin/cos. |
1.0
|
max_period
|
float
|
Controls the minimum frequency. |
10000.0
|
Returns:
| Type | Description |
|---|---|
array
|
Array of shape |
verified_cache
¶
Verified feature caching (SpeCa-style) for iterative generative models.
Forecast-then-verify cache: at each iterative step (denoising timestep, autoregressive step, etc.) the controller can extrapolate a tracked feature from previously observed anchors via Lagrange polynomial extrapolation, then accept or reject the prediction by comparing it to a freshly computed ground-truth feature (typically the output of a single inner layer — the "verification layer").
The pattern is lossy but bounded — see the SpeCa convergence analysis (Zou et al., 2025, arxiv:2509.11628). For bit-exact reproducibility, do not use.
Architecture-agnostic mechanism. The caller decides:
- Which feature to track (the verification-layer output is a common pick).
- How to map the controller's abstract
step_indexto its own iterative axis (denoising step, diffusion timestep, etc.). - The Lagrange
order(number of anchors − 1) and the threshold schedule parameterstau_0andbeta.
References
SpeCa — https://arxiv.org/abs/2509.11628 TaylorSeer — https://arxiv.org/abs/2503.06923
VerifiedFeatureCache
¶
VerifiedFeatureCache(num_steps: int, tau_0: float, beta: float, *, order: int = 2, epsilon: float = 1e-08)
Lagrange-extrapolate a tracked feature and verify before accepting.
Usage per step::
cache = VerifiedFeatureCache(num_steps=50, tau_0=0.1, beta=0.5)
for step in range(num_steps):
if cache.can_predict(step):
predicted = cache.extrapolate(step)
actual = run_verifier_layer(state) # caller-supplied
if cache.accept(step, predicted, actual):
# use predicted for downstream layers / skip full forward
cache.record(step, predicted)
continue
feature = run_full_forward(state) # fallback
cache.record(step, feature)
Boundary policy: can_predict returns False at step == 0 and
step == num_steps - 1, forcing a full compute at both ends. This
matches the convention used by other step-aware controllers in
mlx_arsenal.diffusion.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_steps
|
int
|
Total number of iterative steps in the generation. |
required |
tau_0
|
float
|
Base relative-L2² threshold for accepting a draft. |
required |
beta
|
float
|
Geometric schedule base. |
required |
order
|
int
|
Lagrange polynomial order. Requires |
2
|
epsilon
|
float
|
Numerical floor in the relative-L2 denominator. |
1e-08
|
threshold
¶
Adaptive threshold at step_index (relative-L2² units).
can_predict
¶
True if a draft is available for step_index.
Returns False at boundary steps (0 and num_steps - 1) and
whenever fewer than order + 1 anchors have been recorded.
extrapolate
¶
Lagrange-extrapolate the tracked feature at step_index.
Raises RuntimeError if called when can_predict would
return False — the caller is expected to gate on it first.
accept
¶
Compare draft to ground truth on the verification layer.
Uses squared relative-L2 to match the SpeCa formulation:
e = ‖predicted − actual‖²₂ / (‖actual‖²₂ + ε).
Returns True if e <= threshold(step_index).
record
¶
Append feature as a new anchor at step_index.
Anchors are stored in a fixed-capacity FIFO of size order + 1.
step_index must be strictly greater than the last recorded
step (anchors are monotonic by construction).
geometric_threshold
¶
SpeCa-style geometric threshold schedule.
τ_t = τ₀ · β^((T - 1 - t) / max(T - 1, 1))
With beta < 1: threshold grows from τ₀·β (strict early) to
τ₀ (tolerant late). With beta > 1: the opposite. beta == 1
yields a constant threshold τ₀. The "right" regime is empirical
and depends on the schedule and model — see the research note at
docs/research/verified-feature-caching.md.
window_residual
¶
WA-RS controller (DiTFastAttn Window Attention + Residual Sharing).
Decides when to refresh the cached full - window attention residual:
- :meth:
WindowResidualController.fixed— refresh everyKsteps. - :meth:
WindowResidualController.scheduled— refresh on an explicit list. - :meth:
WindowResidualController.adaptive— refresh when the attention input has moved more thanrel_l1_threshsince the previous step (same relative-L1 metric as :class:mlx_arsenal.diffusion.TeaCacheController).
Boundary steps (0 and num_steps - 1) always refresh regardless of
mode. The cached residual itself is opaque — the controller does not look
inside mx.array shapes.
References
DiTFastAttn — Window Attention with Residual Sharing (WA-RS).
WindowResidualController
¶
Step-aware controller for the WA-RS residual cache.
Construct via :meth:fixed, :meth:scheduled, or :meth:adaptive —
the bare __init__ is intentionally not part of the public API.
previous_residual
property
¶
Last cached residual. Raises before the first cache_residual call.
fixed
classmethod
¶
fixed(num_steps: int, *, refresh_every: int) -> WindowResidualController
Refresh on step 0, num_steps - 1, and every refresh_every step.
scheduled
classmethod
¶
scheduled(num_steps: int, *, refresh_steps: Sequence[int]) -> WindowResidualController
Refresh on step 0, num_steps - 1, and every step in refresh_steps.
adaptive
classmethod
¶
adaptive(num_steps: int, *, rel_l1_thresh: float) -> WindowResidualController
Refresh when relative-L1 input delta crosses rel_l1_thresh.
Mirrors :class:TeaCacheController semantics: at non-boundary
step i with previous input p, refresh iff
mean(|input - p|) / mean(|p|) >= rel_l1_thresh. A zero-norm
previous input also forces a refresh.
should_refresh
¶
Decide whether to recompute full attention at step_index.
attn_input is required in adaptive mode and ignored
otherwise. Boundary steps (0 and num_steps - 1) always
return True.
cache_residual
¶
Store the full - window residual from the just-refreshed step for reuse.