01

Adaptive Neural Infrastructure
with Memory Accumulation

Beyond fixed-compute, fixed-memory transformers — models that route compute where it's needed and remember across time.

Adaptive Compute

MoE · MoD · early exit — different tokens, different compute

Memory Accumulation

KV cache · SSMs · external memory banks

Combined

An end-to-end implementation in PyTorch

02 / Motivation

What's Wrong with Vanilla Transformers? TWO BIG GAPS

A standard decoder-only transformer is uniform and amnesiac. Both turn out to matter at scale.

Problem 1 — Uniform Compute

Every token gets the same number of FLOPs, no matter how easy or hard:

  • Predicting the next token after "hello," (probably " world") takes the same compute as predicting the next token in a complex math proof.
  • For a 70B model, every token traverses 70B parameters worth of matmuls.
  • Massive waste — and a hard ceiling on inference throughput.

Problem 2 — Bounded, Amnesiac Memory

The model has no state outside its current context window:

  • Conversations don't persist. Same user tomorrow → blank slate.
  • Attention is O(N²) in context length — long contexts get expensive fast.
  • Even within a single session, KV cache memory grows linearly forever.

The Fix — Two Orthogonal Levers

Vanilla Transformer all tokens, all params no memory between sessions + Adaptive Compute router picks experts per token ~⅛ of weights per token + Accumulating Memory persistent across sessions key-value bank · grows over time

The two are orthogonal — you can have one, the other, or both. Most frontier systems combine them.

03 / Adaptive Compute

Adaptive Neural Infrastructure ROUTE THE COMPUTE

A learned router decides which sub-network fires for each token at each layer. Most parameters stay dormant for any given token.

Mixture of Experts (MoE)

Replace each FFN with N experts. Router picks top-k per token.

  • Total params: huge
  • Active params: small
  • Memory cost: full · compute cost: sparse

In the wild: Mixtral 8×7B (47B total / 13B active), GPT-4 (rumored), DeepSeek-V3, Switch Transformer

Mixture of Depths (MoD)

Per-token, per-block routing. Router decides which tokens enter each transformer block; the rest skip via the residual.

  • Easy tokens → fewer layers
  • Hard tokens → full depth
  • Variable per-token compute

In the wild: Google's "Mixture-of-Depths" (Raposo et al. 2024); related: PonderNet, Adaptive Computation Time

Early Exit / ACT

Stop early when confident. Each layer outputs an "exit signal." When confidence crosses a threshold, generation halts.

  • Fastest path for trivial tokens
  • Variable model depth at inference
  • No retraining cost (with right loss)

In the wild: CALM (Schuster et al. 2022), DeeBERT, Adaptive Computation Time (Graves 2016)

The Common Mechanism — A Learned Router

class Router(nn.Module):
    def __init__(self, d_model, n_choices):
        super().__init__()
        self.gate = nn.Linear(d_model, n_choices, bias=False)

    def forward(self, x, top_k=1):
        scores       = self.gate(x)                         # (B, T, n_choices)
        weights, idx = scores.topk(top_k, dim=-1)        # pick top-k
        weights      = F.softmax(weights, dim=-1)         # normalize
        return weights, idx                              # downstream uses these

Same routing primitive used by all three patterns above. The only difference is what the choices are: experts (MoE), entry-or-skip (MoD), continue-or-exit (ACT).

04 / Adaptive Compute — MoE

Deep Dive — Mixture of Experts SAMPLE CODE

Replace the dense FFN with N specialized FFNs. A router picks top-k of them per token, weighted by softmax of the gate scores.

The Architecture

token x router (linear) expert 0 expert 1 w=0.7 expert 2 expert 3 w=0.3 weighted sum output = 0.7·E₁(x) + 0.3·E₃(x)

With 8 experts and top-k=2, only ¼ of FFN weights are touched per token. Mixtral 8×7B has 47B total params but only ~13B fire per token.

Sample Code

import torch
import torch.nn as nn
import torch.nn.functional as F


class Expert(nn.Module):
    def __init__(self, d):
        super().__init__()
        self.fc1 = nn.Linear(d, 4*d)
        self.fc2 = nn.Linear(4*d, d)

    def forward(self, x):
        return self.fc2(F.gelu(self.fc1(x)))


class MoEFFN(nn.Module):
    def __init__(self, d, n_experts=8, top_k=2):
        super().__init__()
        self.top_k   = top_k
        self.router  = nn.Linear(d, n_experts, bias=False)
        self.experts = nn.ModuleList([
            Expert(d) for _ in range(n_experts)
        ])

    def forward(self, x):                 # x: (B, T, d)
        scores = self.router(x)            # (B, T, N)

        # Pick top-k experts per token
        weights, idx = scores.topk(self.top_k, dim=-1)
        weights = F.softmax(weights, dim=-1)

        # Sparse dispatch: send each token only
        # to its chosen experts
        out = torch.zeros_like(x)
        for e in range(len(self.experts)):
            for k in range(self.top_k):
                mask = (idx[..., k] == e)
                if mask.any():
                    out[mask] += (
                        weights[..., k:k+1][mask]
                        * self.experts[e](x[mask])
                    )
        return out


# Drop-in replacement for the FFN sublayer
# in a standard transformer block:
#   self.ffn = MoEFFN(d=128, n_experts=8, top_k=2)

Real production MoE adds load-balancing loss (so all experts get used) and capacity factor (token dropping when an expert overflows). Omitted for clarity.

05 / Memory Accumulation

Memory Accumulation STATE THAT PERSISTS

Three flavors of accumulating state — from microsecond working memory to cross-session persistent knowledge.

KV Cache

Working memory within one generation.

  • Cache K and V from each past token
  • New token only computes its own Q
  • O(N) per token instead of O(N²)
  • Lifetime: one inference call

Universal — every modern LLM serving framework uses it.

SSM Recurrent State

Compressed running summary. Replace attention with a fixed-size state vector updated each step.

  • Constant memory regardless of length
  • Linear-time inference
  • Lifetime: full sequence
  • "Infinite context" — in principle

In the wild: Mamba (Gu & Dao 2023), RWKV, RetNet, Jamba (hybrid).

External Memory Bank

Persistent across sessions. Learnable key-value store the model writes to and retrieves from.

  • Decoupled from context window
  • Survives between conversations
  • Lifetime: forever (or until pruned)
  • Read via attention, written via gate

In the wild: MemGPT, Memorizing Transformers, RAG (a degenerate form), Letta.

Three Time-Scales of Memory

KV Cache milliseconds — minutes (within one generation) SSM Recurrent State seconds — hours (across one full sequence) External Memory Bank days — months — forever (across sessions, users, time)
06 / Memory — SSM

State Space Models — Constant-Memory Recurrence MAMBA · RWKV

Replace attention with a tiny recurrent state updated each step. Inference becomes linear-time and constant-memory.

The Core Equation

h_t = A · h_{t-1} + B · x_t       # update state
y_t = C · h_t                     # emit output

A classical recurrence. The whole sequence is summarized into h_t — a fixed-size vector. Compute per step is constant.

vs Attention

AttentionSSM
Compute / tokenO(N)O(1)
Total computeO(N²)O(N)
State / tokengrows with Nfixed
Random accessperfectlossy compression
Trainable in parallelyesyes (with tricks)

Mamba's clever bit: A, B, C are made input-dependent, giving it attention-like selectivity while keeping linear complexity.

Sample Code — A Minimal SSM Layer

class MinimalSSM(nn.Module):
    """Linear recurrent layer (simplified Mamba-style)."""

    def __init__(self, d_model, d_state=16):
        super().__init__()
        self.d_state = d_state

        # Learnable state-transition matrices
        self.A_log = nn.Parameter(torch.randn(d_state))
        self.B = nn.Linear(d_model, d_state, bias=False)
        self.C = nn.Linear(d_state, d_model, bias=False)

    def forward(self, x):                 # x: (B, T, d_model)
        B, T, _ = x.shape
        A = -torch.exp(self.A_log)        # stable, negative

        h = torch.zeros(B, self.d_state, device=x.device)
        outputs = []

        for t in range(T):
            # Recurrence — same shape every step
            h = torch.exp(A) * h + self.B(x[:, t])
            y = self.C(h)
            outputs.append(y)

        return torch.stack(outputs, dim=1)


# Drop-in replacement for self-attention.
# Notice: no QK^T matrix → no O(N²) cost.
# 'h' carries all information about the past in d_state floats.

Real Mamba: parallel scan for fast training, hardware-aware kernel, selective parameters that gate input flow. This minimal version is the conceptual core.

07 / Memory — External Bank

External Memory Banks PERSISTENT KNOWLEDGE

A learnable key-value store that lives outside the context window — written to during conversation, read from across sessions.

The Read/Write Cycle

Memory Bank important? x_t (hidden state) if yes: WRITE query q current context attend to bank: READ recalled info read = softmax(q·Kᵀ/√d) · V    (attention over the bank)

Sample Code — Memory Bank with Gated Write

class MemoryBank(nn.Module):
    """Persistent KV bank — read by attention, write by gate."""

    def __init__(self, d_model, capacity=256):
        super().__init__()
        self.capacity = capacity
        self.d_model  = d_model

        # Slots stored as buffers (saved with state_dict)
        self.register_buffer("keys", torch.zeros(capacity, d_model))
        self.register_buffer("vals", torch.zeros(capacity, d_model))
        self.register_buffer("size", torch.tensor(0))

        self.write_gate = nn.Linear(d_model, 1)

    def read(self, q):                          # q: (B, T, d)
        if self.size == 0:
            return torch.zeros_like(q)
        K = self.keys[:self.size]                # (M, d)
        V = self.vals[:self.size]
        scores = q @ K.T / (self.d_model ** 0.5)   # (B, T, M)
        return F.softmax(scores, dim=-1) @ V

    def write(self, x):                         # x: (N, d) flattened
        importance = torch.sigmoid(self.write_gate(x))
        keep = (importance > 0.5).squeeze(-1)
        new = x[keep]
        n = min(new.size(0), self.capacity - self.size)
        if n == 0: return
        self.keys[self.size:self.size+n] = new[:n]
        self.vals[self.size:self.size+n] = new[:n]
        self.size += n

    def save(self, path):
        torch.save({"keys": self.keys, "vals": self.vals,
                    "size": self.size}, path)

The bank can be saved/loaded across sessions — that's what makes it persistent. Real systems add eviction policies, sharding, learned compression.

08 / Combined Architecture

Putting It Together — The AnimaBlock FULL IMPLEMENTATION

A drop-in transformer block that's adaptive (MoE FFN) AND has accumulating memory (external bank). ~80 lines of PyTorch.

The Wiring

input x memory.read(x) x + recall attention + MoE FFN + memory.write(x) output

Both adaptations are drop-in replacements. You can stack AnimaBlocks exactly like vanilla transformer blocks.

The AnimaBlock

class AnimaBlock(nn.Module):
    """
    Transformer block with:
      - adaptive compute (MoE FFN)
      - accumulating memory (external bank)
    """

    def __init__(self, d_model, n_heads=4,
                 n_experts=8, top_k=2,
                 mem_capacity=256):
        super().__init__()
        self.ln1    = nn.LayerNorm(d_model)
        self.attn   = nn.MultiheadAttention(
                          d_model, n_heads, batch_first=True)
        self.ln2    = nn.LayerNorm(d_model)
        self.ffn    = MoEFFN(d_model, n_experts, top_k)
        self.memory = MemoryBank(d_model, mem_capacity)

    def forward(self, x):
        # 1. Recall: pull relevant past memory
        recall = self.memory.read(x)
        h = self.ln1(x + recall)

        # 2. Attention sublayer
        attn_out, _ = self.attn(h, h, h, need_weights=False)
        x = x + attn_out

        # 3. Adaptive FFN sublayer
        x = x + self.ffn(self.ln2(x))

        # 4. Persist what mattered
        with torch.no_grad():
            self.memory.write(x.view(-1, x.size(-1)))

        return x


# Stack them like normal transformer blocks:
blocks = nn.ModuleList([
    AnimaBlock(d_model=128) for _ in range(6)
])

# Forward pass:
for block in blocks:
    x = block(x)

Memory writes use no_grad + detach in production — you don't want gradients flowing through saved memory across batches.

09 / In Production

Real-World Systems WHO USES WHAT

A non-exhaustive map of what's actually shipping today. Notice how often "frontier model" = "vanilla transformer + at least one of these tricks".

System Adaptive compute Memory accumulation Notable
Mixtral 8×7B (Mistral) MoE — 8 experts, top-2 Standard KV cache 47B total params, ~13B active. Open-weights.
DeepSeek-V3 MoE — 256 experts, top-8 + 1 shared Multi-head Latent Attention (compressed KV) 671B total / 37B active. Open weights.
GPT-4 / GPT-4o (rumored) MoE Long-context attention Architecture not public; widely believed to be sparse MoE.
Mamba / Mamba-2 Selective State-Space (recurrent) Linear-time inference; competitive with transformers up to 7B.
Jamba (AI21) MoE Hybrid: SSM + attention layers Best of both worlds — long context + adaptive compute.
RWKV Linear-attention recurrent state RNN-flavored transformer; very efficient inference.
MemGPT / Letta External memory bank with self-managed read/write Persistent personality / facts across sessions.
Memorizing Transformers kNN over external memory cache (last layer only) Showed external memory works at scale (Wu et al. 2022).
Mixture of Depths (Google) Per-token block routing Standard KV cache Variable depth per token. ~50% FLOPs reduction at iso-quality.

Pattern

Pure attention transformers are still dominant for sub-30B models, but as scale grows, every frontier system adds at least one of: MoE for cheap inference, SSMs for long context, or external memory for persistence. The "vanilla" GPT-2 architecture from 2019 is increasingly the exception, not the rule.

10 / Recap

The Whole Picture ONE-PAGE SUMMARY

Why Bother

  • Vanilla transformers spend equal compute on every token and forget everything between sessions.
  • Adaptive infrastructure routes compute where it's needed — sparse activation gives you a big model at a small model's cost.
  • Memory accumulation persists state across time — shorter latency, longer effective context, true cross-session memory.
  • The two are orthogonal; modern systems combine them.

Tools You Now Have

  • A working MoEFFN in ~30 lines
  • A minimal MinimalSSM as a recurrence primitive
  • A MemoryBank with gated writes & attention reads
  • An end-to-end AnimaBlock wiring it all together
  • A map of who uses what in production

What to Read Next

  • MoE: "Switch Transformer" (Fedus et al. 2021), "Mixtral of Experts" (Jiang et al. 2024)
  • MoD: "Mixture-of-Depths" (Raposo et al. 2024)
  • Mamba: "Mamba: Linear-Time Sequence Modeling" (Gu & Dao 2023)
  • RWKV: "RWKV: Reinventing RNNs for the Transformer Era" (2023)
  • External memory: "MemGPT" (Packer et al. 2023), "Memorizing Transformers" (Wu et al. 2022)
  • Hybrid: "Jamba: A Hybrid Transformer-Mamba Language Model" (AI21 2024)

Questions?