"""Functional hybrid prefixes with native multimodal embeddings and 3-axis RoPE. Prefix and the layer-wise training schedule are adapted from jaredpalmer/kev@f1535963cea021439370c23127bc970b6788e730/kev/shared_prefix.py (Apache-2.0; see third_party/kev/). Branches never mutate a saved prefix. """ import os from collections import OrderedDict import torch from torch.nn import functional as F from torch.utils.checkpoint import checkpoint class Prefix: record_past = True def __init__(self): self.keys = self.values = self.conv = None self.recurrent_states = {} @property def layers(self): return self def __getitem__(self, layer_idx): return self def has_previous_state(self, layer_idx=None, state_idx=0): return self.conv is not None def update_conv_state(self, conv_input, layer_idx, conv_kernel_size, **kwargs): if self.conv is not None: return torch.cat([self.conv, conv_input], -1) self.conv = F.pad(conv_input, (max(0, conv_kernel_size - conv_input.shape[-1]), 0))[ ..., -conv_kernel_size: ] return conv_input def update_recurrent_state(self, recurrent_state, layer_idx, **kwargs): self.recurrent_states.setdefault(0, recurrent_state) return recurrent_state def update(self, keys, values, layer_idx, *args, **kwargs): if self.keys is None: self.keys, self.values = keys, values return keys, values return torch.cat([self.keys, keys], -2), torch.cat([self.values, values], -2) def branch(self, owner): other = Prefix() pick = lambda t: None if t is None else t.index_select(0, owner) other.keys, other.values, other.conv = pick(self.keys), pick(self.values), pick(self.conv) other.recurrent_states = {k: pick(v) for k, v in self.recurrent_states.items()} return other def nbytes(self): tensors = [self.keys, self.values, self.conv, *self.recurrent_states.values()] return sum(t.numel() * t.element_size() for t in tensors if t is not None) def compact(self): # Cached slices must own their storage so byte accounting does not hide a # complete prefill tensor behind a small convolution window or KV view. self.keys = None if self.keys is None else self.keys.clone().contiguous() self.values = None if self.values is None else self.values.clone().contiguous() self.conv = None if self.conv is None else self.conv.clone().contiguous() self.recurrent_states = { k: v.clone().contiguous() for k, v in self.recurrent_states.items() } return self def attention_mask(allow, hidden, implementation): allow = allow[:, None] if implementation == "sdpa": return allow return hidden.new_zeros(allow.shape).masked_fill(~allow, torch.finfo(hidden.dtype).min) def split_rows(hidden, positions, packed): prefixes = packed["prefix_lengths"].tolist() lengths = packed["lengths"].tolist() unique, first, owners = {}, [], [] for i, key in enumerate(packed["state_keys"]): if key not in unique: unique[key] = len(first) first.append(i) reference = first[unique[key]] n = prefixes[i] if n != prefixes[reference] or not torch.equal( packed["inputs"]["input_ids"][i, :n], packed["inputs"]["input_ids"][reference, :n] ): raise ValueError("Same state identity compiled to different prefix tokens") if not torch.equal(positions[:, i, :n], positions[:, reference, :n]): raise ValueError("Same state identity compiled to different multimodal positions") owners.append(unique[key]) ns, nb = max(prefixes), max(n - p for n, p in zip(lengths, prefixes)) s = hidden.new_zeros((len(first), ns, hidden.shape[-1])) b = hidden.new_zeros((len(lengths), nb, hidden.shape[-1])) sp = positions.new_zeros((3, len(first), ns)) bp = positions.new_zeros((3, len(lengths), nb)) sm = torch.zeros(s.shape[:2], dtype=torch.bool, device=hidden.device) bm = torch.zeros(b.shape[:2], dtype=torch.bool, device=hidden.device) for j, i in enumerate(first): n = prefixes[i] s[j, -n:], sp[:, j, -n:], sm[j, -n:] = hidden[i, :n], positions[:, i, :n], True for i, (p, n) in enumerate(zip(prefixes, lengths)): b[i, : n - p], bp[:, i, : n - p], bm[i, : n - p] = ( hidden[i, p:n], positions[:, i, p:n], True, ) return s, b, sp, bp, sm, bm, torch.tensor(owners, device=hidden.device) def masks(lm, s, b, sm, bm, owner): ns, nb, device = s.shape[1], b.shape[1], s.device causal = lambda n: torch.ones(n, n, dtype=torch.bool, device=device).tril() eye = lambda n: torch.eye(n, dtype=torch.bool, device=device) impl = lm.config._attn_implementation s_allow = (causal(ns)[None] & sm[:, None, :]) | eye(ns)[None] b_allow = torch.cat( [ sm[owner][:, None, :].expand(-1, nb, -1), (causal(nb)[None] & bm[:, None, :]) | eye(nb)[None], ], -1, ) ms = { "full_attention": None if impl == "sdpa" and bool(sm.all()) else attention_mask(s_allow, s, impl), "linear_attention": sm.to(s.dtype), } mb = {"full_attention": attention_mask(b_allow, b, impl), "linear_attention": bm.to(b.dtype)} return ms, mb def shared_hidden(lm, hidden, positions, packed): s, b, sp, bp, sm, bm, owner = split_rows(hidden, positions, packed) ms, mb = masks(lm, s, b, sm, bm, owner) rs, rb = lm.rotary_emb(s, sp), lm.rotary_emb(b, bp) for layer in lm.layers: # Capture the current layer, never a late-bound loop variable in recomputation. def step(s, b, layer=layer): prefix = Prefix() s = layer.forward( s, position_embeddings=rs, attention_mask=ms[layer.block_type], past_key_values=prefix, ) b = layer.forward( b, position_embeddings=rb, attention_mask=mb[layer.block_type], past_key_values=prefix.branch(owner), ) return s * sm[..., None], b if lm.gradient_checkpointing and lm.training and torch.is_grad_enabled(): s, b = checkpoint(step, s, b, use_reentrant=False) else: s, b = step(s, b) return lm.norm(b) class ByteLRU: def __init__(self, max_bytes): self.max_bytes, self.bytes = max_bytes, 0 self.entries = OrderedDict() self.hits = self.misses = 0 def get(self, key): if key not in self.entries: self.misses += 1 return None self.hits += 1 self.entries.move_to_end(key) return self.entries[key][0] def put(self, key, value, size): if size > self.max_bytes: return if key in self.entries: self.bytes -= self.entries.pop(key)[1] while self.entries and self.bytes + size > self.max_bytes: self.bytes -= self.entries.popitem(last=False)[1][1] self.entries[key] = (value, size) self.bytes += size def clear(self): self.entries.clear() self.bytes = 0 class KevRuntime: """An immutable-model session with byte-bounded image and hybrid prefix caches. Every round recomputes only the private question history from the original state. All branches of one state are batched; attention/conv/recurrent prefixes are read-only. """ def __init__(self, model, config, prefix_bytes=8 * 1024**3, image_bytes=2 * 1024**3, enable_native_qk=False): from .roi_replay import REPLAY_VARIANTS if config.get('point_variant') in REPLAY_VARIANTS: raise ValueError('ROI replay uses uncached full rows, not the persistent hybrid-prefix runtime') if config.get("point_variant") == "visual_tokens": raise ValueError("Visual-token pointing requires prefix keys; cached branch-only readout is unsupported") if not enable_native_qk and config.get("readout_kind") in ( "native_last_qk_mean", "native_merged_qk256", "native_last_qk_concat", ): raise ValueError("Native QK currently uses the uncached causal-row forward") if enable_native_qk and (config.get("readout_kind") != "native_last_qk_mean" or config.get("readout_layer_indices") is not None or config.get("gradient_checkpointing", False)): raise ValueError("Experimental native cache requires single-layer mean and no checkpointing") import hashlib import json self.model = model self.signature = hashlib.sha256(json.dumps(config, sort_keys=True).encode()).hexdigest() self.versions = tuple((p._version, p.dtype, p.device) for p in model.parameters()) self.prefix_cache, self.image_cache = ByteLRU(prefix_bytes), ByteLRU(image_bytes) def clear(self): self.prefix_cache.clear() self.image_cache.clear() @torch.inference_mode() def __call__(self, packed): if packed.get("visual_pointing", False): raise ValueError("Visual-token pointing requires the uncached causal-row forward") if self.model.training or self.versions != tuple( (p._version, p.dtype, p.device) for p in self.model.parameters() ): raise ValueError("Create a fresh runtime after changing model weights or training mode") model, inputs = self.model, packed["inputs"] device_type = inputs["input_ids"].device.type precision = ( torch.is_autocast_enabled(device_type), str(torch.get_autocast_dtype(device_type)), torch.get_float32_matmul_precision(), os.environ.get("TRITON_F32_DEFAULT", "tf32"), ) scope = (self.signature, precision) features = [self.image_cache.get((scope, k)) for k in packed["image_keys"]] missing = [i for i, f in enumerate(features) if f is None] if missing: chunks = inputs["pixel_values"].split(inputs["unique_grid_thw"].prod(-1).tolist()) fs = model.native.get_image_features( torch.cat([chunks[i] for i in missing]), inputs["unique_grid_thw"][missing], return_dict=True, ).pooler_output for i, f in zip(missing, fs): f = f.clone().contiguous() features[i] = f self.image_cache.put( (scope, packed["image_keys"][i]), f, f.numel() * f.element_size() ) hidden, positions = model.embeddings(inputs, features=features) with model.language_context(hidden.device.type): return self.language_forward(packed, hidden, positions, scope) def language_forward(self, packed, hidden, positions, scope): model, inputs = self.model, packed["inputs"] s, b, sp, bp, sm, bm, owner = split_rows(hidden, positions, packed) lm = model.native.language_model result = torch.zeros_like(b) for state in range(len(s)): rows = (owner == state).nonzero().flatten() first = int(rows[0]) ns = int(packed["prefix_lengths"][first]) key = ( scope, packed["state_keys"][first], str(hidden.dtype), tuple(inputs["input_ids"][first, :ns].tolist()), tuple(positions[:, first, :ns].flatten().tolist()), ) entry = self.prefix_cache.get(key) if entry is None: hs = s[state : state + 1, -ns:] rs = lm.rotary_emb(hs, sp[:, state : state + 1, -ns:]) entry = [] for layer in lm.layers: prefix = Prefix() hs = layer.forward(hs, position_embeddings=rs, past_key_values=prefix) entry.append(prefix.compact()) self.prefix_cache.put(key, entry, sum(p.nbytes() for p in entry)) # Different states need not inherit the longest unrelated question's # padding. Their final readouts only index these real branch lengths. branch_length = int(bm[rows].sum(-1).max()) hb, mask = b[rows, :branch_length], bm[rows, :branch_length] rb = lm.rotary_emb(hb, bp[:, rows, :branch_length]) owners = torch.zeros(len(rows), dtype=torch.long, device=hb.device) _, mb = masks( lm, s[state : state + 1, -ns:], hb, sm[state : state + 1, -ns:], mask, owners ) for layer, prefix in zip(lm.layers, entry): hb = layer.forward( hb, position_embeddings=rb, attention_mask=mb[layer.block_type], past_key_values=prefix.branch(owners), ) result[rows, :branch_length] = lm.norm(hb) if model.pointer is None: # The cached image prefix is unchanged. Candidates and decisions are # private text suffix tokens; retain their ORIGINAL M-RoPE coordinates # while translating tensor indices into the returned suffix buffer. selected = dict(packed) for key in ("positions", "option_positions"): indices = packed[key].clone() indices[:, 1] -= packed["prefix_lengths"][indices[:, 0]] if (indices[:, 1] < 0).any(): raise ValueError("Native suffix cache cannot read keys inside the prefix") selected[key] = indices return lm.native_qk(result, selected, lm.rotary_emb(result, bp)) return model.readout(result, packed, branch_only=True)