"""Item 31: synthetic memory tokens — per-layer KV prefix (Nils's design). "The one read mechanism a frozen transformer natively possesses is attention over the KV cache." A KVMemoryAdapter maps carried L30 states to (k, v) entries appended to every band layer's attention — frozen heads consume the state through their existing machinery. Keys live in post-RoPE space (prefix-tuning convention: learned keys place themselves where frozen queries already point). Activation is global-flag-scoped like lora_band.LoopLoRA: a custom attention interface "kvmem" wraps the stock eager path; when _MEM is armed and the module is a band layer, memory kv columns are appended (mask columns visible to every query). """ import torch import torch.nn as nn from transformers.modeling_utils import ALL_ATTENTION_FUNCTIONS from transformers.models.gemma4.modeling_gemma4 import ( eager_attention_forward) _MEM = {"on": False, "kv": None, "band": (14, 30), "base": None} def arm_memory(kv): """kv: dict layer_idx -> (k, v), each (B, kv_heads, M, head_dim).""" _MEM["kv"] = kv _MEM["on"] = kv is not None def kvmem_attention(module, query, key, value, attention_mask, **kwargs): if (_MEM["on"] and _MEM["kv"] is not None and getattr(module, "layer_idx", -1) in _MEM["kv"]): mk, mv, gate = _MEM["kv"][module.layer_idx] m = mk.shape[2] key = torch.cat([key, mk.to(dtype=key.dtype, device=key.device)], 2) value = torch.cat([value, mv.to(dtype=value.dtype, device=value.device)], 2) if attention_mask is not None: pad = torch.zeros(*attention_mask.shape[:-1], m, dtype=attention_mask.dtype, device=attention_mask.device) + gate.to( attention_mask.dtype) attention_mask = torch.cat([attention_mask, pad], -1) base = _MEM["base"] or eager_attention_forward return base(module, query, key, value, attention_mask, **kwargs) def install(model): """Wrap the registered implementation IN PLACE — the config name is untouched, so mask construction and every other branch stays bit-identical; only the (q,k,v,mask) seam gains the memory append.""" if _MEM.get("installed"): return impl = model.config._attn_implementation _MEM["base"] = ALL_ATTENTION_FUNCTIONS.get_interface( impl, eager_attention_forward) try: ALL_ATTENTION_FUNCTIONS[impl] = kvmem_attention except TypeError: ALL_ATTENTION_FUNCTIONS.register(impl, kvmem_attention) _MEM["installed"] = True class KVMemoryAdapter(nn.Module): """Carried states (B, M, d) -> per-band-layer post-RoPE (k, v). Per-layer geometry (head_dim, kv heads) read off the live modules — gemma-4 mixes sliding (256) and global (512) head dims in the band.""" def __init__(self, model, band=(14, 30), code=512): super().__init__() self.band = band tm = model.model.language_model d = model.config.get_text_config().hidden_size self.trunk = nn.Sequential(nn.LayerNorm(d), nn.Linear(d, code), nn.GELU()) self.geom = {} self.k_heads = nn.ModuleDict() self.v_heads = nn.ModuleDict() tc = model.config.get_text_config() for l in range(band[0], band[1] + 1): att = tm.layers[l].self_attn hd = att.head_dim kvh = (tc.num_global_key_value_heads if getattr(att, "use_alternative_attention", False) else tc.num_key_value_heads) self.geom[l] = (kvh, hd) self.k_heads[str(l)] = nn.Linear(code, kvh * hd) self.v_heads[str(l)] = nn.Linear(code, kvh * hd) nn.init.zeros_(self.v_heads[str(l)].weight) nn.init.zeros_(self.v_heads[str(l)].bias) # learnable per-layer attention gate on the memory columns: # init -10 -> memory is invisible until training opens it self.gate = nn.ParameterDict( {str(l): nn.Parameter(torch.tensor(-10.0)) for l in range(band[0], band[1] + 1)}) def forward(self, states): B, M, _ = states.shape c = self.trunk(states.float()) kv = {} for l in range(self.band[0], self.band[1] + 1): kvh, hd = self.geom[l] k = self.k_heads[str(l)](c).view(B, M, kvh, hd).transpose(1, 2) v = self.v_heads[str(l)](c).view(B, M, kvh, hd).transpose(1, 2) kv[l] = (k, v, self.gate[str(l)]) return kv