"""First-block cache for MiniMax-H3: skip the trunk on steps whose block-0 residual barely moved. Block 0 and the final AdaLN head run at the true timestep on **every** step; only blocks 1..49 are skipped, and only while the residual they would have been handed looks like the one from the last step that actually ran. The decision signal is the relative L1 between this step's block-0 residual (`block0_out - block0_in`) and the residual of the last *computed* step, over the whole packed sequence. On a skip the trunk's contribution is replayed as a cached residual, `(final_trunk_out - block0_out)` of that computed step. Ported from `duckyshell/ComfyUI-MiniMaxH3-FirstBlockCache` (`nodes.py` @ 725973c) — same signal, same protected window (10%-95% of the schedule, converted through the video shift of 12.0) and the same cap of two consecutive skips, which is their "H3 Safe" preset at threshold 0.08. **The audio exemption is not theirs.** duckyshell has no audio term anywhere: the decision is ~98% video by row count and every audio row rides the stale trunk residual, which is what costs the soundtrack its energy. Audio runs its own schedule (shift 3 against video's 12, diverging by up to 11x in rate across 20 steps), so on a skip the audio rows of the trunk output are instead a 2-point **linear** extrapolation of the last two actually-computed audio features, in the audio sigma coordinate — `xmarre/ComfyUI-Spectrum-MiniMax-H3`'s `audio_blend_weight=0.0` path, applied where Spectrum applies it (the post-trunk hidden feature, ahead of the head that still runs at the true timestep) and fixed to the right coordinate. Following ComfyUI PR #15390, no carried audio tensor is ever mutated: every write is a fresh tensor out of `index_copy`. It earns its place. Running this Space's own request at threshold 0.08 with `H3_FBC_AUDIO_EXEMPT=0` — the duckyshell mechanism verbatim, same 13 skipped forwards, same video to within 0.2 dB — costs the soundtrack **16.7% of its RMS** (0.0483 against an uncached 0.0580), while the exemption holds it at 1.04x. That is the same direction the offline study measured on a near-silent clip, three times the size on one with real audio energy. **A threshold does not travel across step counts.** The signature shrinks as the schedule is subdivided, so the same number gates far more loosely at more steps. Measured on this Space — 960x544, 124 frames, one image reference, seed 42, AoTI blocks, at its **default 28 steps** (27 forwards) — against the same request with `H3_FBC=0`: | threshold | skipped | denoise loop | end to end | audio RMS vs uncached | |---|---|---|---|---| | 0.03 | 0 / 27 | 1.02x | 1.06x | 1.000 (bitwise-identical audio) | | 0.05 | 9 / 27 | 1.46x | 1.36x | 0.956 | | 0.08 | 13 / 27 | 2.19x | 1.82x | 1.040 | The offline study calibrated 0.08 over a 20-step schedule, where it skipped 7 of 19 forwards. At 28 steps that same 0.08 skips 13 of 27 — nearly half — and the sampled video visibly re-rolls its background detail. **0.05 is the default** because it reproduces the skip fraction that study validated (33% here against 37% there); 0.08 is the aggressive setting. Below the signature floor — 0.03 skipped nothing at all here — a threshold buys nothing and still pays for the signature, so lower is not safer, it is just slower. A cached request is not the uncached one: the trajectory moves, so the video is a different sample of the same prompt (same shot, same subject, same quality — different signage and background detail). `H3_FBC=0` restores today's output exactly, and is worth reaching for when a request has to reproduce a specific earlier result. This composes with `h3_aoti`: that module patches each of the 50 blocks' own `forward` and they stay a real `ModuleList`, so skipping the trunk simply does not call blocks 1..49 that step. `LazyAOTIModel` rebinds its constants whenever the weights dict it is handed changes identity, and the first forward of a request never skips, so every block has bound its own weights before any step is cached. """ from __future__ import annotations import contextlib import os import types ENABLED = os.environ.get("H3_FBC", "1") == "1" # Relative-L1 gate on the block-0 residual, calibrated at this Space's default 28 steps — see the table above. THRESHOLD = float(os.environ.get("H3_FBC_THRESHOLD", "0.05")) # duckyshell's cap. Without it the gate compares against an ever-older computed step and drifts away unbounded. MAX_CONSECUTIVE_HITS = int(os.environ.get("H3_FBC_MAX_CONSECUTIVE", "2")) # The protected head and tail of the schedule, as fractions, converted to sigma through the video shift below. START_PERCENT = float(os.environ.get("H3_FBC_START_PERCENT", "0.10")) END_PERCENT = float(os.environ.get("H3_FBC_END_PERCENT", "0.95")) # `MiniMaxH3SetTimestepsStep` builds the video schedule at shift 12.0 and the audio one at 3.0. VIDEO_SHIFT = float(os.environ.get("H3_FBC_VIDEO_SHIFT", "12.0")) AUDIO_EXEMPT = os.environ.get("H3_FBC_AUDIO_EXEMPT", "1") == "1" # Every keyword `MiniMaxH3LoopDenoiser` passes. It filters the packed-sequence layout through # `inspect.signature(transformer.forward).parameters`, so a replacement forward that drops a name silently stops # receiving it; `install` refuses rather than let that happen quietly. FORWARD_PARAMETERS = ( "hidden_states", "audio_hidden_states", "encoder_hidden_states", "timestep", "timestep_indices", "token_tags", "position_ids", "video_indices", "audio_indices", "text_indices", "attention_kwargs", "return_dict", ) def status() -> str: return ( f"first-block cache **on** · threshold `{THRESHOLD}` · audio exemption " f"{'on' if AUDIO_EXEMPT else 'off'}" if ENABLED else "first-block cache **off** (`H3_FBC=1` to skip the trunk on steady steps)" ) def _shifted_sigma(u: float, shift: float) -> float: return shift * u / (1.0 + (shift - 1.0) * u) def _rel_l1(current, previous) -> float: numerator = (current.float() - previous.float()).abs().mean() denominator = previous.float().abs().mean().clamp(min=1e-8) return float((numerator / denominator).item()) class _State: def __init__(self, threshold: float, steps: int, audio_exempt: bool): self.threshold = threshold self.steps = steps self.audio_exempt = audio_exempt # duckyshell reads the window as sigma bounds: a flow model's sigma at `u = 1 - percent`, shifted. self.start_sigma = _shifted_sigma(1.0 - START_PERCENT, VIDEO_SHIFT) self.end_sigma = _shifted_sigma(1.0 - END_PERCENT, VIDEO_SHIFT) self.original = None self.failed = False self.consecutive_hits = 0 self.prev_first_residual = None self.tail_residual = None self.audio_history = [] # [(sigma_audio, audio rows of the trunk output)], newest last, at most two self.computed = 0 self.skipped = 0 def _cached_forward( self, state, hidden_states, audio_hidden_states, encoder_hidden_states, timestep, timestep_indices, token_tags, position_ids, video_indices, audio_indices, text_indices, return_dict, ): """`MiniMaxH3Transformer3DModel.forward` with the block loop split at block 0. Everything outside the loop is that method verbatim, at the `diffusers` commit `requirements.txt` pins; keep the two in step when the pin moves. """ import torch from diffusers.models.transformers.transformer_minimax_h3 import ( MINIMAX_H3_MODALITY_NUM, MiniMaxH3TransformerOutput, ) sequence_length = position_ids.shape[0] rotary_emb = self.rope(position_ids) video_embeds = self.proj_in(hidden_states.to(self.proj_in.weight.dtype)) audio_embeds = self.audio_proj_in(audio_hidden_states.to(self.audio_proj_in.weight.dtype)) text_embeds = self.context_embedder(encoder_hidden_states.to(self.context_embedder.weight.dtype)) text_embeds = self.token_refiner(text_embeds) packed = text_embeds.new_zeros((text_embeds.shape[0], sequence_length, text_embeds.shape[-1])) packed = packed.index_copy(1, text_indices, text_embeds) packed = packed.index_copy(1, video_indices, video_embeds.to(text_embeds.dtype)) packed = packed.index_copy(1, audio_indices, audio_embeds.to(text_embeds.dtype)) temb = self.time_proj(timestep) temb = self.time_embedder(temb.to(self.time_embedder.linear_1.weight.dtype)) adaln_indices = timestep_indices * MINIMAX_H3_MODALITY_NUM + token_tags.clamp(min=0) attention_mask = None is_pad = token_tags < 0 if bool(is_pad.any()): attention_mask = is_pad[None, :] == is_pad[:, None] blocks = self.transformer_blocks block0_out = blocks[0](packed, temb, adaln_indices, rotary_emb, attention_mask) first_residual = block0_out - packed # The generated rows trail their modality's index list, so the last row of each carries that stream's live noise # level. The scheduler exposes `timesteps = 1 - sigmas[:-1]`. sigma_video = 1.0 - float(timestep[timestep_indices[video_indices[-1]]].item()) sigma_audio = 1.0 - float(timestep[timestep_indices[audio_indices[-1]]].item()) use_cache = False if ( state.prev_first_residual is not None and state.tail_residual is not None and state.prev_first_residual.shape == first_residual.shape and state.consecutive_hits < MAX_CONSECUTIVE_HITS and state.end_sigma <= sigma_video <= state.start_sigma ): use_cache = _rel_l1(first_residual, state.prev_first_residual) <= state.threshold if use_cache: state.consecutive_hits += 1 state.skipped += 1 trunk_out = block0_out + state.tail_residual if state.audio_exempt and state.audio_history: sigma_prev, feature_prev = state.audio_history[-1] if len(state.audio_history) == 2 and abs(sigma_prev - state.audio_history[-2][0]) > 1e-8: sigma_prev2, feature_prev2 = state.audio_history[-2] ratio = (sigma_audio - sigma_prev) / (sigma_prev - sigma_prev2) audio_feature = feature_prev + (feature_prev - feature_prev2) * ratio else: audio_feature = feature_prev trunk_out = trunk_out.index_copy(1, audio_indices, audio_feature.to(trunk_out.dtype)) else: state.consecutive_hits = 0 state.computed += 1 trunk_out = block0_out for block in blocks[1:]: trunk_out = block(trunk_out, temb, adaln_indices, rotary_emb, attention_mask) state.tail_residual = (trunk_out - block0_out).detach() state.prev_first_residual = first_residual.detach() if state.audio_exempt: state.audio_history.append((sigma_audio, trunk_out.index_select(1, audio_indices).detach().float())) state.audio_history = state.audio_history[-2:] out = self.norm_out(trunk_out, temb, timestep_indices).to(self.proj_out.weight.dtype) video_output = self.proj_out(out).index_select(1, video_indices) audio_output = self.audio_proj_out(out).index_select(1, audio_indices) if not return_dict: return (video_output, audio_output) return MiniMaxH3TransformerOutput(sample=video_output, audio_sample=audio_output) def _forward( self, hidden_states, audio_hidden_states, encoder_hidden_states, timestep, timestep_indices, token_tags, position_ids, video_indices, audio_indices, text_indices, attention_kwargs=None, return_dict: bool = True, ): """The installed forward. Anything it cannot serve — a LoRA scale, an unexpected layout, a bug — is handed to the original forward instead, for this call and every later one, so a cached request can degrade to an uncached one but never to a failed one.""" state = self._h3_fbc original = dict( hidden_states=hidden_states, audio_hidden_states=audio_hidden_states, encoder_hidden_states=encoder_hidden_states, timestep=timestep, timestep_indices=timestep_indices, token_tags=token_tags, position_ids=position_ids, video_indices=video_indices, audio_indices=audio_indices, text_indices=text_indices, attention_kwargs=attention_kwargs, return_dict=return_dict, ) # `apply_lora_scale` decorates the real forward and this one is not it, so a request that actually scales a LoRA # goes down the original path rather than silently losing its scale. if state.failed or (attention_kwargs or {}).get("scale") is not None: return state.original(**original) try: return _cached_forward( self, state, hidden_states, audio_hidden_states, encoder_hidden_states, timestep, timestep_indices, token_tags, position_ids, video_indices, audio_indices, text_indices, return_dict, ) except Exception as error: state.failed = True print(f"[h3-fbc] disabled for this request ({type(error).__name__}: {error}); running uncached", flush=True) return state.original(**original) def install(transformer, steps: int = 0, threshold: float = THRESHOLD, audio_exempt: bool = AUDIO_EXEMPT) -> bool: """Bind the caching forward onto `transformer`. Returns whether it went on. `accelerate`'s `add_hook_to_module` — what `ComponentsManager.enable_auto_cpu_offload` installs — moves the real forward to `_old_forward` and puts its own onload wrapper in `forward`. Replacing `forward` there would step over the wrapper and run the block stack against weights still on the host, so the replacement goes into `_old_forward` whenever the hook is present. """ import inspect if getattr(transformer, "_h3_fbc", None) is not None: return True hooked = hasattr(transformer, "_hf_hook") and hasattr(transformer, "_old_forward") current = transformer._old_forward if hooked else transformer.forward missing = [name for name in FORWARD_PARAMETERS if name not in inspect.signature(current).parameters] if missing: print(f"[h3-fbc] this transformer's forward has no {missing}; running uncached", flush=True) return False if not hasattr(transformer, "transformer_blocks") or len(transformer.transformer_blocks) < 2: print("[h3-fbc] no block stack to skip; running uncached", flush=True) return False state = _State(threshold, steps, audio_exempt) state.original = current transformer._h3_fbc = state bound = types.MethodType(_forward, transformer) if hooked: transformer._old_forward = bound else: transformer.forward = bound return True def uninstall(transformer) -> None: state = getattr(transformer, "_h3_fbc", None) if state is None: return if hasattr(transformer, "_hf_hook") and hasattr(transformer, "_old_forward"): transformer._old_forward = state.original else: transformer.__dict__.pop("forward", None) del transformer._h3_fbc total = state.computed + state.skipped if total: print( f"[h3-fbc] {state.skipped}/{total} forwards served from cache " f"(threshold {state.threshold}, audio exemption {'on' if state.audio_exempt else 'off'})", flush=True, ) @contextlib.contextmanager def enabled(transformer, steps: int = 0): """Cache the trunk for the duration of one request. The state is per-request by construction — a residual only ever means something within the schedule it was measured on — and nothing in here can raise into the request.""" installed = False if ENABLED: try: installed = install(transformer, steps=steps) except Exception as error: print(f"[h3-fbc] install failed ({type(error).__name__}: {error}); running uncached", flush=True) try: yield installed finally: if installed: try: uninstall(transformer) except Exception as error: print(f"[h3-fbc] uninstall failed ({type(error).__name__}: {error})", flush=True)