pipenetwork's picture
Add files using upload-large-folder tool
cbf14fd verified
Raw
History Blame Contribute Delete
2.07 kB
"""Incremental caches for Inkling generation.
Two kinds of per-layer state must persist across decode steps:
* ``KVCache`` — the appended key/value tensors for attention.
* ``ConvCache`` — the last ``kernel-1`` inputs of each depthwise short-convolution
(there are 4 per layer: k, v, post-attn, post-mlp).
A ``LayerCache`` bundles one KVCache + the 4 ConvCaches; ``make_cache`` builds one
per decoder layer. Absolute key positions are always ``arange(kv_len)`` because the
cache holds every key from position 0 (KVCache keeps the full history — correct for
both global and sliding layers, since the sliding-window constraint is enforced by
the attention mask).
"""
from __future__ import annotations
import mlx.core as mx
class ConvCache:
"""Holds the last ``kernel-1`` inputs of a short convolution."""
__slots__ = ("state",)
def __init__(self):
self.state = None # [B, kernel-1, C] or None
class KVCache:
"""Appends keys/values along the sequence axis (full history)."""
__slots__ = ("keys", "values")
def __init__(self):
self.keys = None # [B, heads, T, d]
self.values = None
@property
def offset(self) -> int:
return 0 if self.keys is None else self.keys.shape[2]
def update(self, k: mx.array, v: mx.array):
if self.keys is None:
self.keys, self.values = k, v
else:
self.keys = mx.concatenate([self.keys, k], axis=2)
self.values = mx.concatenate([self.values, v], axis=2)
return self.keys, self.values
class LayerCache:
__slots__ = ("kv", "k_conv", "v_conv", "attn_conv", "mlp_conv")
def __init__(self):
self.kv = KVCache()
self.k_conv = ConvCache()
self.v_conv = ConvCache()
self.attn_conv = ConvCache()
self.mlp_conv = ConvCache()
def make_cache(model) -> list[LayerCache]:
"""One LayerCache per text decoder layer."""
n = len(model.model.llm.layers) if hasattr(model, "model") else len(model.layers)
return [LayerCache() for _ in range(n)]