gta / summary_streaming_inference.py
abhisheksensharma's picture
Upload folder using huggingface_hub
ae4e95d verified
Raw History Blame Contribute Delete
45.7 kB
"""Summaryformer streaming session: one trunk, one full-res stage, one tick per body frame.
One ``SummaryKVCache`` — one K/V buffer per layer,
``| Z0 | RAW : (Y+1) slots | SUM : (W−Y) slots |`` — one ``StageSpec``, model calls only at the
timesteps on the spec.
z0 (GT, from the upload) --forward_z0 t=0, note_z0_written--> Z0 slot (never generated)
frame t (abs_t = 1, 2, ...), i frames already committed:
T = SinkChaser.rotate(kv, model.rope_table, n_committed=i) # one Z0 slot, one int (0 = none)
kv.begin_frame() # donate RAW[cursor_r]'s X summary rows into SUM
lat ~ N(0,1) fp32
for t in spec.timesteps (e.g. 999, 878, 669):
v = forward_body(lat, t) -> x0_hat = signal(t) * lat - noise(t) * v # writes record(t) into RAW[cursor_r]
lat = signal(t_next) * x0_hat + noise(t_next) * z, z FRESH (re-noise to the next timestep)
cache_mode "recache" (KR): t=0 pass rewrites that RAW slot with the clean record, then commit
cache_mode "last_step_writes" (KNR): commit the record the last pass wrote (no extra pass)
commit = cursor_r += 1 (mod Y+1); no copy
-> x0 (diag-gauss) -> un-gaussianize (rest stats) -> SAE decode_steady -> 4 RGB frames
Geometry is the model's: X summary tokens, Y raw-window frames, W summary-window frames, one
full-res grid (24x42 serve / the spec's ``hw``). One dense attention call per layer (every
query reads the prefix ``[0 : end]``); nothing on the cache path may ``torch.cat``.
Numerics: bf16 autocast on CUDA, fp32 latents / x0 arithmetic, bf16 KV (fp32 KV on CPU so
parity tests can be bit-exact). Weight dtype is the server's business.
torch.compile: the server hands in ``forward_body_compiled`` / ``decode_steady_compiled``.
``forward_body`` runs compiled from body frame 1 (frame id is a persistent 0-d int64 device
tensor filled in place; a tensor id selects ``plan_body(device_ends=True)``, whose ``end`` is
the one ``end_dev``). z0 warm is eager. SAE decode is compiled only once ``n_body >= Y`` unless
the flag says otherwise. KV storage (``k``, ``v``, the recency bias) and ``end_dev`` are pinned
(``mark_static_address``) after ``build`` and ``enable_recency``, so cudagraphs replay against
them. The wrapper marks those; this session does not mark them twice.
Long horizon: ``SinkChaser`` rotates the one Z0 slot when ``oldest_alive - sink_id`` reaches
``sink_gap_max`` (one int). Absolute ids keep growing; the session HARD-STOPS at the last RoPE
table row instead of wrapping.
Fail-fast: spec vs model at ctor; ``step()`` before ``start()``; abs_t >= RoPE rows;
a None sink gap (an unbounded stream needs the one slot chased).
Recency comes from ``StageSpec.recency`` and is enabled on the empty buffer right after build /
reset, before any body frame and before any compiled marking. The bias covers the whole buffer
and is non-zero only on the SUM region.
z0 focus region rides the z0 warm's cond ONLY, never body frames.
"""
from __future__ import annotations
import time
from collections import deque
from dataclasses import dataclass
import torch
from gta_streaming_kv_cache import SummaryKVCache
from inference_common import (
StageSampling,
cond_dict,
frame_tokens,
warm_z0_clean,
)
from sae import diag_gaussian_latent_to_training_latent, training_latent_to_diag_gaussian_latent
from summaryformer import Summaryformer
from summaryformer_utils.streaming_sink import (
SinkChaser,
sink_gaps_describe,
sink_gaps_from_config,
)
from summaryformer_wrapper import SummaryformerWrapper
# How a generated frame's keys and values get into the cache: "recache" runs one extra clean pass over
# the finished frame; "last_step_writes" keeps what the final denoising step wrote. The checkpoint's
# config names which one it expects.
CACHE_MODES = ("recache", "last_step_writes")
Z0_C = Z_REST_C = int(Summaryformer.LATENT_CHANNELS)
SAE_SPATIAL = 16
_RGB_MEAN = torch.tensor([0.485, 0.456, 0.406]).view(1, 1, 3, 1, 1)
_RGB_STD = torch.tensor([0.229, 0.224, 0.225]).view(1, 1, 3, 1, 1)
@dataclass(frozen=True)
class StageSpec:
"""ONE stage; the server builds it from the ckpt config and the session checks it against the model.
``samp``: ``resolve_sampling(ckpt_cfg)``, the timesteps a body frame is denoised at.
``stats_*``: full-res diag-gauss artifacts (C=48). ``sink_gap_max``: one int >= 2 (the one Z0 slot).
"""
hw: tuple[int, int]
stats_z0: dict
stats_rest: dict
samp: StageSampling
cache_mode: str
sink_gap_max: int
recency: dict | None
focus_region: torch.Tensor | None
def __post_init__(self):
h, w = (int(self.hw[0]), int(self.hw[1]))
if h <= 0 or w <= 0:
raise ValueError(f"StageSpec.hw must be positive (h, w); got {self.hw!r}")
if not isinstance(self.samp, StageSampling):
raise TypeError(f"StageSpec.samp must be StageSampling; got {type(self.samp)}")
if len(self.samp.timesteps) < 1:
raise ValueError(f"StageSpec.samp has no model timesteps: {self.samp.timesteps}")
if self.cache_mode not in CACHE_MODES:
raise ValueError(f"StageSpec.cache_mode={self.cache_mode!r} not in {CACHE_MODES}")
gap = sink_gaps_from_config(self.sink_gap_max)
if gap is None:
raise RuntimeError(
"StageSpec.sink_gap_max is None: an unbounded stream needs the one Z0 slot chased "
f"({sink_gaps_describe(gap)}; pass an int >= 2)"
)
object.__setattr__(self, "sink_gap_max", gap)
if self.recency is not None and not isinstance(self.recency, dict):
raise TypeError(f"StageSpec.recency must be a dict or None; got {type(self.recency)}")
for name, art in (("stats_z0", self.stats_z0), ("stats_rest", self.stats_rest)):
if not (isinstance(art, dict) and "mean" in art and "std" in art):
raise ValueError(f"StageSpec.{name} must be a diag-gauss dict with mean/std")
if int(torch.as_tensor(art["mean"]).numel()) != Z0_C:
raise ValueError(
f"StageSpec.{name} mean numel={int(torch.as_tensor(art['mean']).numel())} != C={Z0_C}"
)
region = self.focus_region
if region is None:
return
if not (
isinstance(region, torch.Tensor)
and region.dtype == torch.bool
and tuple(region.shape) == (1, h, w)
):
raise RuntimeError(
f"StageSpec.focus_region must be Bool [1,{h},{w}] or None; "
f"got {getattr(region, 'shape', type(region))} dtype={getattr(region, 'dtype', None)}"
)
if not bool(region.any()):
raise RuntimeError("StageSpec.focus_region is all-False: pass None for 'no region'")
@property
def h(self) -> int:
return int(self.hw[0])
@property
def w(self) -> int:
return int(self.hw[1])
@property
def timesteps(self) -> list[int]:
"""Timesteps the model is called at on body frames, high -> low (e.g. [999, 878, 669]). The session
only ever denoises body frames; the seed frame is written clean at t = 0."""
return list(self.samp.timesteps)
@property
def spaced_indices(self) -> list[int]:
"""Indices into the sampling grid's tables the loop visits, in order, len == nfe
(repeats when the samp carries a step_plan)."""
return list(self.samp.indices)
@property
def nfe(self) -> int:
return len(self.timesteps)
def _stats_to_device(stats: dict, device: torch.device) -> dict:
"""Diag-gauss artifact with mean/std already on `device` (fp32): no H2D per call."""
out = dict(stats)
out["mean"] = torch.as_tensor(stats["mean"]).to(device=device, dtype=torch.float32)
out["std"] = torch.as_tensor(stats["std"]).to(device=device, dtype=torch.float32)
return out
def _check_spec_against_model(model, spec: StageSpec) -> None:
"""X/Y/W live on the model."""
x, y, w = (
int(model.summary_tokens),
int(model.raw_window_frames),
int(model.summary_window_frames),
)
if x < 1 or y < 0 or w < 0:
raise RuntimeError(f"[summary-stream] model X/Y/W={(x, y, w)} is not a serveable geometry")
# ``start(focus_region=FOCUS_DEFAULT)``: use the spec's region (the ckpt's served default, a centred diamond when the
# focus operator was trained). ``None`` = no region for this game; a Bool ``[1, h, w]`` = a custom region (the client's
# painted mask) for this game only. The default is restored by the next ``start`` that does not override it.
FOCUS_DEFAULT = object()
def _coerce_focus_region(region, spec: StageSpec, device) -> torch.Tensor | None:
if region is None:
return None
if not (
isinstance(region, torch.Tensor)
and region.dtype == torch.bool
and tuple(region.shape) == (1, spec.h, spec.w)
):
raise RuntimeError(
f"[summary-stream] focus_region must be Bool [1,{spec.h},{spec.w}] or None; "
f"got {getattr(region, 'shape', type(region))} dtype={getattr(region, 'dtype', None)}"
)
if not bool(region.any()):
raise RuntimeError("[summary-stream] focus_region is all-False: pass None for 'no region'")
return region.to(device=device).contiguous()
def _normalize_fps(fps) -> float | None:
"""NaN / None = no fps conditioning; a number in [1, 120] is the game clock."""
if fps is None:
return None
if isinstance(fps, torch.Tensor):
if fps.numel() != 1:
raise RuntimeError(f"[summary-stream] fps tensor must be a scalar; got {tuple(fps.shape)}")
fps = float(fps.item())
if isinstance(fps, (int, float)):
f = float(fps)
if f != f: # NaN
return None
if not 1.0 <= f <= 120.0:
raise RuntimeError(f"[summary-stream] fps must be None/NaN or a number in [1, 120]; got {fps!r}")
return f
raise RuntimeError(f"[summary-stream] fps must be None/NaN or a number in [1, 120]; got {fps!r}")
# ----------------------------------------------------------------------------------------------
# SAE sphere projection (serve-time option)
# ----------------------------------------------------------------------------------------------
# The SAE encoder ends in `sae.SphereNorm3d`: every 48-channel token is forced to RMS=1 (L2 radius
# sqrt(48)), no mean subtraction, non-affine. The decoder expects such tokens and has no input norm of
# its own. The diffusion model works in per-channel diag-gauss space, where that sphere is an
# ellipsoid, so a generated x0_hat can drift off the sphere. These modes put it back:
# "off" nothing.
# "decode" project the RAW latent handed to the SAE decoder only (seed and every body frame). The
# diffusion loop and the KV are untouched.
# "all" "decode" plus: every x0_hat inside the renoise loop (ungauss -> project -> regauss, so
# the next re-noise, the t=0 recache write and the decode all see the on-sphere x0), and
# the seed z0 in start() (a no-op for an encoder z0, which is already on the sphere).
SPHERE_MODES = ("off", "decode", "all")
_SPHERE_EPS = 1e-6 # sae.SphereNorm3d: eps added INSIDE the sqrt
def sphere_project_raw(z_raw: torch.Tensor, *, cdim: int = 1) -> torch.Tensor:
"""RAW SAE latent -> the encoder's SphereNorm3d manifold: per-token RMS=1 over the channel axis.
Bit-for-bit the encoder's op (fp32 rms, eps inside the sqrt). Shape-agnostic; ``cdim`` is the
48-channel axis."""
rms = z_raw.float().pow(2).mean(dim=cdim, keepdim=True).add(_SPHERE_EPS).sqrt()
return z_raw / rms.to(z_raw.dtype)
def _sched_tables(samp: StageSampling, device: torch.device) -> tuple[torch.Tensor, torch.Tensor]:
"""The sampling grid's signal / noise scales, sqrt(ā) / sqrt(1-ā), on `device` (fp32), indexed by grid
index."""
a = torch.as_tensor(samp.grid.signal, device=device, dtype=torch.float32)
b = torch.as_tensor(samp.grid.noise, device=device, dtype=torch.float32)
return a, b
def _body_steps(samp: StageSampling) -> tuple[list[int], list[int]]:
"""(grid indices, timesteps) the body loop visits, in order, len == NFE. Each grid index once
high -> low, or ``samp.step_plan`` (repeats allowed: a repeated index re-noises x0_hat to the same t
and calls the model there again)."""
return list(samp.indices), list(samp.timesteps)
def renoise_body_x0(
*,
call,
cond: dict,
samp: StageSampling,
lat_shape: tuple[int, ...],
noise_fn,
sqrt_ab: torch.Tensor,
sqrt_om: torch.Tensor,
t_buffer: torch.Tensor,
project_x0=None,
) -> torch.Tensor:
"""K renoise passes on one body frame. Model at REAL timesteps; fresh z between passes.
``call(x[B,1,C,H,W], t[B,1], cond) -> v[B,1,C,H,W]``. ``noise_fn(shape) -> tensor``.
``sqrt_ab`` / ``sqrt_om`` are the device-resident signal / noise tables of the sampling grid
(``_sched_tables``). Returns x0
``[B,1,C,H,W]`` fp32. ``project_x0`` (optional, eager, fp32 gauss -> fp32 gauss) is applied to
every x0 estimate before it is re-noised or returned (sphere mode "all").
"""
indices, real_ts = _body_steps(samp)
if len(indices) != len(real_ts) or not indices:
raise RuntimeError(f"[summary-stream] spaced/real timestep mismatch: {indices} vs {real_ts}")
lat = noise_fn(lat_shape)
if not (isinstance(lat, torch.Tensor) and lat.dim() == 5 and int(lat.size(1)) == 1):
raise RuntimeError(f"[summary-stream] noise_fn must return [B,1,C,H,W]; got {getattr(lat, 'shape', type(lat))}")
x0 = None
for step_i, (t_idx, t_real) in enumerate(zip(indices, real_ts)):
t_buffer.fill_(float(t_real))
v = call(lat, t_buffer, cond).float()
a, b = sqrt_ab[int(t_idx)], sqrt_om[int(t_idx)]
x0 = (a * lat - b * v) / (a * a + b * b)
if project_x0 is not None:
x0 = project_x0(x0)
if step_i < len(indices) - 1:
z = noise_fn(tuple(x0.shape))
a_n, b_n = sqrt_ab[int(indices[step_i + 1])], sqrt_om[int(indices[step_i + 1])]
lat = a_n * x0 + b_n * z
return x0
class SummaryStreamSession:
"""One player, one device. Owns the KV buffer, RNG, SAE decode cache, gaussianization boundary."""
def __init__(
self,
*,
generator,
sae_decoder,
spec: StageSpec,
device,
rgb_hw: tuple[int, int] = (384, 672),
forward_body_compiled=None,
decode_steady_compiled=None,
use_compiled_sae_in_steady_state: bool = True,
):
gen = getattr(generator, "module", generator)
if not isinstance(gen, SummaryformerWrapper):
raise RuntimeError(f"[summary-stream] generator must be SummaryformerWrapper; got {type(generator)}")
if not isinstance(spec, StageSpec):
raise TypeError(f"[summary-stream] spec must be StageSpec; got {type(spec)}")
if not (hasattr(sae_decoder, "decode_bootstrap") and hasattr(sae_decoder, "decode_steady")):
raise RuntimeError("[summary-stream] sae_decoder must expose decode_bootstrap / decode_steady")
device = torch.device(device)
model = gen.model
_check_spec_against_model(model, spec)
rh, rw = (int(x) for x in rgb_hw)
if (rh, rw) != (spec.h * SAE_SPATIAL, spec.w * SAE_SPATIAL):
raise RuntimeError(
f"[summary-stream] rgb_hw {rh}x{rw} != {SAE_SPATIAL} * latent grid {spec.h}x{spec.w}"
)
self.generator, self.model, self.sae, self.device = gen, model, sae_decoder, device
self.spec = spec
self.focus_region_default = self.focus_region = _coerce_focus_region(spec.focus_region, spec, device)
self.rgb_hw = (rh, rw)
# Serve: bf16 autocast + bf16 KV. CPU parity: fp32 throughout so x0 can be torch.equal.
self.amp_dtype = torch.bfloat16 if device.type == "cuda" else torch.float32
try:
self.sae_dtype = next(sae_decoder.parameters()).dtype
except StopIteration:
self.sae_dtype = torch.float32
self.tf = int(frame_tokens(model, spec.h, spec.w))
self.X = int(model.summary_tokens)
self.Y = int(model.raw_window_frames)
self.W = int(model.summary_window_frames)
self.visual_kv: SummaryKVCache = gen.new_visual_kv_cache()
if not isinstance(self.visual_kv, SummaryKVCache):
raise RuntimeError("[summary-stream] new_visual_kv_cache must return SummaryKVCache")
with torch.no_grad():
self.visual_kv.build(
batch=1, frame_tokens=self.tf, dtype=self.amp_dtype, device=device,
)
# Recency on the empty buffer (bias non-zero only on SUM), before any frame and before
# static marking. mark_streaming_caches_static pins k, v, the bias, and the one end_dev.
self.visual_kv.enable_recency(spec.recency)
self.recency = self.visual_kv.recency
self._chaser = self._new_chaser()
self._body_x, self._sae_x = forward_body_compiled, decode_steady_compiled
self.use_compiled_sae_in_steady_state = bool(use_compiled_sae_in_steady_state)
self._mode_log: dict[str, str] = {}
self._any_generator_compiled = self._body_x is not None
if self._any_generator_compiled:
n_static = int(SummaryformerWrapper.mark_streaming_caches_static(self.visual_kv))
if n_static <= 0:
raise RuntimeError("[summary-stream] compiled generator given but no KV tensors were marked static")
print(f"[perf][cudagraph] marked {n_static} KV tensors static (mark_static_address) at build", flush=True)
self._rng: torch.Generator | None = None
self.noise_fn = None # optional ``(shape) -> tensor`` hook (parity tests)
self._abs_t: int | None = None
self._abs_t_dev = torch.zeros((), device=device, dtype=torch.long)
self._n_body = 0
self._sae_cache = None
self.last_x0: torch.Tensor | None = None
self.last_ms: dict[str, float] = {}
self._fps_logged: float | None | str = "unset"
self._peak_ema: float | None = None
self._stats_dev = {
"z0": _stats_to_device(spec.stats_z0, device),
"rest": _stats_to_device(spec.stats_rest, device),
}
self._sqrt_ab, self._sqrt_om = _sched_tables(spec.samp, device)
# Forward re-prefill history (see reprefill()): the last W committed body frames as
# (gauss x0 [1,C,h,w] fp32 AS WRITTEN by the recache pass, action [1,1,5], fps), plus the
# game's gauss z0. ~190 KB/frame at 24x42; 6 MB at W=32.
self._hist: deque = deque(maxlen=int(self.W))
self._z0_gauss: torch.Tensor | None = None
self._z0_fps: float | None = None
self.reprefill_every: int = 0 # 0 = off; n = rebuild the KV from history every n body frames
self._since_reprefill = 0 # body frames since start() / the last reprefill (the trigger counter)
self.n_reprefills = 0 # rebuilds this game
self.last_reprefill: dict | None = None
self._t_dev = torch.zeros((1, 1), device=device, dtype=torch.float32)
self._fps_dev = torch.zeros((1,), device=device, dtype=torch.float32)
self._action_dev = torch.zeros((1, 1, 5), device=device, dtype=torch.float32)
self._action_pin = (
torch.zeros((1, 1, 5), dtype=torch.float32).pin_memory() if device.type == "cuda" else None
)
self._rgb_mean, self._rgb_std = _RGB_MEAN.to(device), _RGB_STD.to(device)
self._ev: dict[str, tuple] = {}
if self._any_generator_compiled:
for t_ in (self._abs_t_dev, self._t_dev, self._fps_dev, self._action_dev):
torch._dynamo.mark_static_address(t_)
self._print_rings()
def _new_chaser(self) -> SinkChaser:
return SinkChaser(
raw_window=self.Y, summary_window=self.W, gaps=self.spec.sink_gap_max, first_id=1,
)
def _print_rings(self) -> None:
kv = self.visual_kv
rec = self.recency
print(
f"[summary-stream] one trunk X={self.X} Y={self.Y} W={self.W} Tf={self.tf} "
f"grid={self.spec.h}x{self.spec.w} rgb={self.rgb_hw[0]}x{self.rgb_hw[1]} "
f"cache_mode={self.spec.cache_mode} amp={self.amp_dtype} "
f"{sink_gaps_describe(self.spec.sink_gap_max)} "
f"rope_rows={int(self.model.rope_table.size(0))} (hard stop) "
f"compiled(body={self._body_x is not None}, sae={self._sae_x is not None}) "
f"body compiled from frame 1 (device frame id); sae from steady state",
flush=True,
)
print(f"[summary-stream] {kv.describe()} model t={self.spec.timesteps} nfe={self.spec.nfe}", flush=True)
print(
f"[summary-stream] {'recency OFF' if rec is None else rec.cfg.describe()}",
flush=True,
)
if rec is not None:
from summaryformer_utils.recency_bias import prepare_flex_decode
# One prefix read: queries are the whole record (Tf + X), keys are the whole buffer.
print(
f"[summary-stream] biased attend: {prepare_flex_decode(cap=int(kv.capacity), batch=1, kv_heads=int(self.model.num_heads), frame_tokens=self.tf + self.X, device=self.device)}",
flush=True,
)
print(f"[summary-stream] {self._focus_region_desc()}", flush=True)
def _focus_region_desc(self) -> str:
r = self.focus_region
if r is None:
return "z0 focus region OFF (no marker on z0)"
return (
f"z0 focus region ON: {int(r.sum().item())}/{int(r.numel())} z0 tokens marked "
f"({100.0 * float(r.float().mean()):.0f}%), z0 warm only"
)
@property
def n_body(self) -> int:
return int(self._n_body)
@property
def abs_t(self) -> int | None:
return self._abs_t
@property
def chaser(self) -> SinkChaser:
return self._chaser
def _gauss_in(self, z_raw: torch.Tensor, *, which: str) -> torch.Tensor:
return training_latent_to_diag_gaussian_latent(z_raw.float(), self._stats_dev[which])
def _gauss_out(self, z: torch.Tensor, *, which: str) -> torch.Tensor:
"""Gauss -> RAW for the SAE decoder. Sphere modes "decode" / "all" project the RAW token
onto the encoder's RMS=1 sphere here, in fp32, before the dtype cast and the compiled decode."""
z_raw = diag_gaussian_latent_to_training_latent(z.float(), self._stats_dev[which])
if self.sphere_mode != "off":
z_raw = sphere_project_raw(z_raw, cdim=1)
return z_raw.to(dtype=self.sae_dtype).unsqueeze(2).contiguous(memory_format=torch.channels_last_3d)
# Sphere projection mode (SPHERE_MODES). Plain attribute, read per call; no compiled graph depends
# on it (every projection is an eager fp32 op on the tensor BEFORE a compiled call).
sphere_mode: str = "off"
def set_sphere_mode(self, mode: str) -> None:
if mode not in SPHERE_MODES:
raise ValueError(f"[summary-stream] sphere mode {mode!r} not in {SPHERE_MODES}")
if mode != self.sphere_mode:
print(f"[summary-stream] sphere projection {self.sphere_mode} -> {mode}", flush=True)
self.sphere_mode = mode
def _project_gauss(self, z: torch.Tensor, *, which: str) -> torch.Tensor:
"""Gauss -> RAW -> sphere -> gauss, fp32. ``z`` is the [B,1,C,H,W] renoise x0 (the diag-gauss
helpers want C at dim 1, so the T=1 axis is squeezed around them)."""
stats = self._stats_dev[which]
five = z.dim() == 5
zb = z.float().squeeze(1) if five else z.float()
z_raw = sphere_project_raw(diag_gaussian_latent_to_training_latent(zb, stats), cdim=1)
out = training_latent_to_diag_gaussian_latent(z_raw, stats)
return out.unsqueeze(1) if five else out
def _coerce_bchw(self, z, *, name: str) -> torch.Tensor:
if isinstance(z, torch.Tensor) and z.dim() == 5 and 1 in (int(z.size(1)), int(z.size(2))):
z = z.squeeze(1) if int(z.size(1)) == 1 else z.squeeze(2)
if not (isinstance(z, torch.Tensor) and tuple(z.shape) == (1, Z0_C, self.spec.h, self.spec.w)):
raise RuntimeError(
f"[summary-stream] {name} must be [1,{Z0_C},{self.spec.h},{self.spec.w}]; "
f"got {getattr(z, 'shape', type(z))}"
)
return z.to(device=self.device).contiguous()
def _rgb_out(self, rgb_btchw: torch.Tensor, *, frames: int) -> torch.Tensor:
rh, rw = self.rgb_hw
if tuple(rgb_btchw.shape) != (1, frames, 3, rh, rw):
raise RuntimeError(
f"[summary-stream] SAE rgb {tuple(rgb_btchw.shape)} != (1,{frames},3,{rh},{rw})"
)
return (rgb_btchw.float() * self._rgb_std + self._rgb_mean).clamp(0.0, 1.0)
def _autocast(self, dtype: torch.dtype | None = None):
dt = self.amp_dtype if dtype is None else dtype
return torch.autocast(
device_type="cuda", dtype=dt, enabled=self.device.type == "cuda" and dt != torch.float32,
)
def _timed(self, name: str, fn):
if self.device.type == "cuda":
s, e = torch.cuda.Event(enable_timing=True), torch.cuda.Event(enable_timing=True)
s.record()
out = fn()
e.record()
self._ev[name] = (s, e)
return out
t0 = time.perf_counter()
out = fn()
self._ev[name] = (t0, time.perf_counter())
return out
def _collect_ms(self) -> dict[str, float]:
ms = {
k: float(s.elapsed_time(e)) if self.device.type == "cuda" else (e - s) * 1000.0
for k, (s, e) in self._ev.items()
}
self._ev.clear()
return ms
def _in_steady_state(self) -> bool:
return self._n_body >= int(self.Y)
def _pick(self, what: str, eager, compiled, use_compiled: bool):
mode = "compiled" if (compiled is not None and use_compiled) else "eager"
if self._mode_log.get(what) != mode:
print(f"[perf][{what}-mode] mode={mode} abs_t={self._abs_t} n_body={self._n_body}", flush=True)
self._mode_log[what] = mode
return compiled if mode == "compiled" else eager
def _forward_body(self):
return self._pick("generator-body", self.generator.forward_body, self._body_x, True)
def _decode_steady(self):
return self._pick(
"sae-decode", self.sae.decode_steady, self._sae_x,
self._in_steady_state() or not self.use_compiled_sae_in_steady_state,
)
def _cond(self, fps: float | None, action_b15: torch.Tensor | None = None, **z0_knobs) -> dict:
fps_v = None
if fps is not None:
self._fps_dev.fill_(float(fps))
fps_v = self._fps_dev
return cond_dict(
fps=fps_v,
action_context=action_b15,
**z0_knobs,
)
def _action_to_device(self, action_b15: torch.Tensor) -> torch.Tensor:
if action_b15.device == self._action_dev.device:
self._action_dev.copy_(action_b15.to(torch.float32))
elif self._action_pin is not None:
self._action_pin.copy_(action_b15.to(torch.float32))
self._action_dev.copy_(self._action_pin, non_blocking=True)
else:
self._action_dev.copy_(action_b15.to(self._action_dev.device, torch.float32))
return self._action_dev
def _noise(self, shape) -> torch.Tensor:
if self.noise_fn is not None:
z = self.noise_fn(shape)
return z.to(device=self.device, dtype=torch.float32)
if self._rng is None:
raise RuntimeError("[summary-stream] RNG missing (start() first) and no noise_fn")
return torch.randn(shape, generator=self._rng, device=self.device, dtype=torch.float32)
def _frame_id_arg(self, abs_t: int, *, compiled: bool):
"""Compiled form: persistent 0-d int64 filled in place. The model treats a tensor id as
``plan_body(device_ends=True)`` and reads the one ``end_dev``. Eager: the Python int."""
if compiled:
self._abs_t_dev.fill_(int(abs_t))
return self._abs_t_dev
return int(abs_t)
def _body_call(self, x: torch.Tensor, t_buf: torch.Tensor, cond: dict, *, abs_t: int):
fn = self._forward_body()
compiled = fn is self._body_x
with self._autocast():
v = fn(
cond, x.to(self.amp_dtype), t_buf, kv_cache=self.visual_kv,
absolute_start_frames=self._frame_id_arg(abs_t, compiled=compiled),
)
return v
def _denoise_frame(self, cond: dict, *, abs_t: int) -> torch.Tensor:
"""One body frame: the denoising passes, then the cache write the ckpt's cache_mode asks for. B=1.
``begin_frame`` once before the passes (the model's first ``forward_body`` calls it too;
the second call is a no-op until commit). Donation of the RAW slot about to be overwritten
happens here, before any write. Commit advances ``cursor_r`` and does not copy.
"""
self.visual_kv.begin_frame()
lat_shape = (1, 1, Z_REST_C, self.spec.h, self.spec.w)
x0 = renoise_body_x0(
call=lambda x, t, c, _abs=abs_t: self._body_call(x, t, c, abs_t=_abs),
cond=cond,
samp=self.spec.samp,
lat_shape=lat_shape,
noise_fn=self._noise,
sqrt_ab=self._sqrt_ab,
sqrt_om=self._sqrt_om,
t_buffer=self._t_dev,
# Sphere mode "all": every x0 estimate back onto the SAE sphere (eager fp32, before the
# re-noise, the t=0 recache below, and the decode). "decode" leaves the loop alone.
project_x0=(lambda x: self._project_gauss(x, which="rest")) if self.sphere_mode == "all" else None,
)
if self.spec.cache_mode == "recache":
self._t_dev.fill_(0.0)
self._body_call(x0, self._t_dev, cond, abs_t=abs_t)
self.visual_kv.commit_current_frame()
# What the cache now holds for this frame is the clean record of THIS x0: remember it.
self._hist.append((
x0[:, 0].detach().float().clone(),
self._action_dev.detach().clone(),
self._fps_logged if isinstance(self._fps_logged, (int, float)) else None,
))
else:
self.visual_kv.commit_current_frame()
return x0
# ------------------------------------------------------------------------------------------
# RE-PREFILL: rebuild the whole KV from the clean x0 history
# ------------------------------------------------------------------------------------------
# After thousands of frames the buffer is not what a fresh forward over the same frames would
# produce: Z0's K has been rotated in place in bf16 every (gap_max-1) frames (SinkChaser), and
# every SUM row is a memcpy of K/V that were computed against whatever the prefix was when that
# frame ran. reprefill() throws the buffer away and replays [z0 | last W clean x0]: the z0 warm,
# then every stored frame as a clean t=0 write + commit. Ids are renumbered to 0..n, so the sink
# gap is back to 1 and abs_t stays bounded (no RoPE-table hard stop). Only under "recache": in
# "last_step_writes" the committed keys are noisy-input keys and a clean rebuild would be a
# different key kind.
@torch.no_grad()
def reprefill(self) -> dict:
if self._abs_t is None or self._z0_gauss is None:
raise RuntimeError("[summary-stream] reprefill() before start()")
if self.spec.cache_mode != "recache":
raise RuntimeError(f"[summary-stream] reprefill needs cache_mode='recache'; got {self.spec.cache_mode!r}")
hist = list(self._hist)
n = len(hist)
if n > int(self.W):
raise RuntimeError(f"[summary-stream] history {n} > W={self.W}")
if self.device.type == "cuda":
torch.cuda.synchronize(self.device)
t0 = time.perf_counter()
kv = self.visual_kv
if bool(getattr(kv, "_body_open", False)):
raise RuntimeError("[summary-stream] reprefill with an open (uncommitted) frame")
old_abs_t, old_rot = int(self._abs_t), self._chaser.describe()
# 1. Empty the buffer in place (same static tensors), recency on the empty buffer, fresh chaser.
kv.reset()
kv.enable_recency(self.spec.recency)
self.recency = kv.recency
self._chaser = self._new_chaser()
# 2. Replay the history into the empty buffer.
self._reprefill_sequential(hist)
# 3. Counters follow the rebuilt buffer.
self._n_body, self._abs_t, self._since_reprefill = n, n + 1, 0
self.n_reprefills += 1
expect_r = min(n, int(self.Y) + 1)
expect_s = min(max(0, n - (int(self.Y) + 1)), max(0, int(self.W) - int(self.Y)))
if int(kv.filled_r) != expect_r or int(kv.filled_s) != expect_s or int(kv.n_committed) != n or not kv.z0_written:
raise RuntimeError(
f"[summary-stream] reprefill bookkeeping: filled_r={kv.filled_r} (want {expect_r}) "
f"filled_s={kv.filled_s} (want {expect_s}) n_committed={kv.n_committed} (want {n}) z0_written={kv.z0_written}"
)
if self.device.type == "cuda":
torch.cuda.synchronize(self.device)
ms = (time.perf_counter() - t0) * 1e3
self.last_reprefill = {"frames": n, "ms": ms, "abs_t_before": old_abs_t, "abs_t_after": n + 1}
print(
f"[reprefill] rebuilt KV from z0 + {n} clean frames in {ms:.0f} ms | abs_t {old_abs_t} -> {n + 1} | "
f"{old_rot} -> {self._chaser.describe()} | {kv.describe()}",
flush=True,
)
return self.last_reprefill
def _reprefill_sequential(self, hist: list) -> None:
"""z0 clean warm at id 0, then every stored frame as the clean t=0 write the recache pass makes (ids 1..n),
begin_frame / commit around each. n <= W so the sink never rotates inside the replay."""
kv = self.visual_kv
cond0 = self._cond(self._z0_fps, z0_focus_region=self.focus_region)
with self._autocast():
warm_z0_clean(self.generator, kv, cond0, self._z0_gauss.unsqueeze(1))
for i, (x0, action, fps) in enumerate(hist):
if self._chaser.rotation_before_frame(i):
raise RuntimeError(f"[summary-stream] reprefill: sink would rotate at replay frame {i} (n={len(hist)}, W={self.W})")
cond = self._cond(fps, self._action_to_device(action))
kv.begin_frame()
self._t_dev.fill_(0.0)
self._body_call(x0.unsqueeze(1), self._t_dev, cond, abs_t=i + 1)
kv.commit_current_frame()
def _chase_sink(self) -> None:
"""Rotate the one Z0 slot before body frame i (``n_committed`` = frames already committed).
``T = chaser.rotate(kv, freqs, i)`` with ``i`` the number of body frames committed so far.
``T == 0`` means the gap has not reached ``sink_gap_max``.
"""
T = self._chaser.rotate(self.visual_kv, self.model.rope_table, self._n_body)
if T:
print(f"[sink] T={T} ({self._chaser.describe()} n_body={self._n_body})", flush=True)
@torch.no_grad()
def start(self, z0_raw_bchw, *, fps, focus_region=FOCUS_DEFAULT) -> torch.Tensor:
"""New game. GT-warm z0 (t=0 write, never generated) under this fps clock, SAE bootstrap
-> rgb0 ``[1,1,3,H,W]`` in ``[0,1]``. Next abs_t = 1.
``focus_region``: ``FOCUS_DEFAULT`` = the ckpt's served region (spec); ``None`` = none this game; a Bool
``[1, h, w]`` = the client's custom region for this game (the z0 warm AND every reprefill of it)."""
z0_raw = self._coerce_bchw(z0_raw_bchw, name="z0_raw")
if focus_region is FOCUS_DEFAULT:
self.focus_region = self.focus_region_default
else:
self.focus_region = _coerce_focus_region(focus_region, self.spec, self.device)
if self.sphere_mode == "all":
# A first frame that is not encoder output is put on the sphere before the KV
# warm. For an encoder z0 this is the identity up to eps.
z0_raw = sphere_project_raw(z0_raw.float(), cdim=1)
fps = _normalize_fps(fps)
self.reset()
self._rng = torch.Generator(device=self.device)
self._rng.manual_seed(int(torch.randint(0, 2**31 - 1, (1,)).item()))
cond = self._cond(fps, z0_focus_region=self.focus_region)
self._fps_logged = fps
z0 = self._gauss_in(z0_raw, which="z0")
with self._autocast():
warm_z0_clean(self.generator, self.visual_kv, cond, z0.unsqueeze(1))
with self._autocast(self.sae_dtype):
rgb0, self._sae_cache = self.sae.decode_bootstrap(self._gauss_out(z0, which="z0"))
self.last_x0, self._abs_t, self._n_body = z0, 1, 0
self._z0_gauss, self._z0_fps = z0.detach().float().clone(), fps
self._hist.clear()
print(
f"[kv-boundary] z0 warmed (GT, t=0, fps={fps}) {self.visual_kv.describe()} "
f"z0 mean={float(z0.mean()):.3f} std={float(z0.std()):.3f} "
f"focus_region={'off' if self.focus_region is None else f'{int(self.focus_region.sum().item())} tokens'}",
flush=True,
)
return self._rgb_out(rgb0, frames=1)
@torch.no_grad()
def step(self, action_b15, *, fps) -> torch.Tensor:
"""One body latent frame under this fps clock (None/NaN = no clock) + action -> rgb4 ``[1,4,3,H,W]``."""
if self._abs_t is None or self._sae_cache is None:
raise RuntimeError("[summary-stream] step() before start()")
if not (isinstance(action_b15, torch.Tensor) and tuple(action_b15.shape) == (1, 1, 5)):
raise RuntimeError(f"[summary-stream] action_b15 must be [1,1,5]; got {getattr(action_b15, 'shape', None)}")
fps = _normalize_fps(fps)
every = int(self.reprefill_every or 0)
if every > 0 and self._since_reprefill >= every:
self.reprefill() # renumbers abs_t: read it after
self._since_reprefill += 1
t = int(self._abs_t)
if t >= int(self.model.rope_table.size(0)):
raise RuntimeError(
f"[summary-stream] HARD STOP: abs_t={t} >= RoPE table rows {int(self.model.rope_table.size(0))}; "
f"end the game, do not wrap"
)
self._chase_sink()
cond = self._cond(fps, self._action_to_device(action_b15))
if fps != self._fps_logged:
print(f"[fps] clock {self._fps_logged} -> {fps} from abs_t={t}", flush=True)
self._fps_logged = fps
x0 = self._timed("model", lambda: self._denoise_frame(cond, abs_t=t))
with self._autocast(self.sae_dtype):
rgb4, self._sae_cache = self._timed(
"sae", lambda: self._decode_steady()(self._gauss_out(x0[:, 0], which="rest"), self._sae_cache),
)
xf = x0[:, 0].float()
stats_dev = torch.stack([
xf.mean(), xf.std(), xf.abs().amax(),
torch.isfinite(xf).all().float(), torch.isnan(xf).sum().float(),
])
x_mean, x_std, x_absmax, x_finite, x_nan = stats_dev.tolist()
if self.device.type == "cuda":
torch.cuda.synchronize(self.device)
ms = self._collect_ms()
if x_finite < 1.0:
raise RuntimeError(f"[summary-stream] x0 at abs_t={t} is not finite (nan={int(x_nan)})")
self._n_body += 1
# Closed frame (commit already ran; the next begin_frame has not). RAW holds min(n, Y+1)
# records. SUM receives a donation only once RAW is full, at the start of the frame that
# overwrites the oldest slot, so after n commits it holds min(max(0, n-(Y+1)), W-Y).
n = int(self._n_body)
expect_r = min(n, int(self.Y) + 1)
expect_s = min(max(0, n - (int(self.Y) + 1)), max(0, int(self.W) - int(self.Y)))
if int(self.visual_kv.filled_r) != expect_r:
raise RuntimeError(
f"[summary-stream] RAW holds {self.visual_kv.filled_r} records after frame {t} "
f"(n_body={n}, expected {expect_r})"
)
if int(self.visual_kv.filled_s) != expect_s:
raise RuntimeError(
f"[summary-stream] SUM holds {self.visual_kv.filled_s} summaries after frame {t} "
f"(n_body={n}, expected {expect_s})"
)
n_rgb = int(rgb4.size(1))
tot_ms = sum(ms.values())
self._peak_ema = tot_ms if self._peak_ema is None else 0.9 * self._peak_ema + 0.1 * tot_ms
print(
f"[perf] abs_t={t} " + " ".join(f"{k}={v:.1f}ms" for k, v in ms.items())
+ f" total={tot_ms:.1f}ms"
+ f" | peak model+sae={1000.0 / tot_ms:.1f} lat/s = {n_rgb * 1000.0 / tot_ms:.1f} rgb fps"
+ f" (ema {n_rgb * 1000.0 / self._peak_ema:.1f})"
+ f" | x0 mean={x_mean:.3f} std={x_std:.3f} absmax={x_absmax:.2f} {self._chaser.describe()}",
flush=True,
)
self.last_x0, self._abs_t, self.last_ms = xf, t + 1, dict(ms, total=tot_ms)
return self._rgb_out(rgb4, frames=4)
@torch.no_grad()
def reset(self) -> None:
"""Between players (and inside start()). Zeros the one buffer in place; re-enables recency; new SinkChaser."""
kv = self.visual_kv
kv.reset()
kv.enable_recency(self.spec.recency)
self.recency = kv.recency
self._chaser = self._new_chaser()
if kv.filled_r or kv.filled_s or kv.n_committed or kv.z0_written:
raise RuntimeError("[summary-stream] reset left cache state behind")
self._rng = None
self._abs_t, self._n_body, self._sae_cache, self.last_x0 = None, 0, None, None
self._hist.clear()
self._z0_gauss = None
self._since_reprefill = 0
self.n_reprefills = 0
self.last_reprefill = None
self._fps_logged = "unset"
self._peak_ema = None
self._mode_log.clear()
print("[kv-boundary] reset visual=zeroed sae=dropped recency+chaser=rebuilt", flush=True)
@torch.no_grad()
def retarget(self, spec: StageSpec) -> None:
"""Same generator / buffer geometry; new ckpt's timesteps, stats, cache_mode, sink gap, recency, focus."""
if not isinstance(spec, StageSpec):
raise TypeError(f"[summary-stream] retarget spec must be StageSpec; got {type(spec)}")
_check_spec_against_model(self.model, spec)
if (spec.h, spec.w) != (self.spec.h, self.spec.w):
raise RuntimeError(
f"[summary-stream] retarget: hw {spec.h}x{spec.w} != session {self.spec.h}x{self.spec.w}; "
f"release() and rebuild"
)
new_on = spec.recency is not None and bool(spec.recency.get("enabled", True))
old_on = self.recency is not None
if new_on != old_on and self._any_generator_compiled:
raise RuntimeError(
"[summary-stream] retarget: recency on<->off changes the compiled graph; release() and rebuild"
)
self.spec = spec
self.focus_region_default = self.focus_region = _coerce_focus_region(spec.focus_region, spec, self.device)
self._stats_dev = {
"z0": _stats_to_device(spec.stats_z0, self.device),
"rest": _stats_to_device(spec.stats_rest, self.device),
}
self._sqrt_ab, self._sqrt_om = _sched_tables(spec.samp, self.device)
self.reset()
print(
f"[summary-stream] retargeted cache_mode={spec.cache_mode} {sink_gaps_describe(spec.sink_gap_max)} "
f"{self._focus_region_desc()}",
flush=True,
)
@torch.no_grad()
def release(self) -> None:
"""Drop every device tensor this session owns so a switch can allocate a different buffer."""
try:
self.reset()
except Exception:
pass
if getattr(self, "visual_kv", None) is not None:
self.visual_kv.release()
self.visual_kv = None
self.recency = None
self._sae_cache = None
self._stats_dev = {}
self._sqrt_ab = self._sqrt_om = None
self._abs_t_dev = self._t_dev = self._fps_dev = self._action_dev = self._action_pin = None
self._rgb_mean = self._rgb_std = None
self._ev = {}
print("[kv-boundary] released visual=dropped sae=dropped", flush=True)
def build_session_from_runtime(
generator,
sae_decoder,
spec,
device,
*,
rgb_hw,
forward_body_compiled=None,
decode_steady_compiled=None,
use_compiled_sae_in_steady_state: bool = True,
) -> SummaryStreamSession:
"""Server: one call per served checkpoint (startup + every switch), on the CUDA thread."""
return SummaryStreamSession(
generator=generator,
sae_decoder=sae_decoder,
spec=spec,
device=device,
rgb_hw=rgb_hw,
forward_body_compiled=forward_body_compiled,
decode_steady_compiled=decode_steady_compiled,
use_compiled_sae_in_steady_state=use_compiled_sae_in_steady_state,
)