TAI BUI
Back to curriculum
BuildPython

Differential Attention (V2)

Softmax attention puts a little probability on every non-matching token, and over 100k tokens that noise adds up and drowns the signal. The Differential Transformer (Ye et al., ICLR 2025) computes attention as the difference of two softmaxes, which subtracts the shared noise floor. DIFF V2 (Microsoft, January 2026) is the rewrite for production stacks: decode latency matches a baseline Transformer, no custom kernels, FlashAttention-compatible. This lesson goes from V1 to V2 and builds the difference operation in stdlib Python.

TIME: ~60 minutesPREREQUISITES: Phase 7 · 02 (self-attention), Phase 7 · 15 (attention variants), Phase 10 · 14 (architecture walkthrough)

Learning Objectives

  • State precisely why softmax attention has a noise floor and why it grows with context length.
  • Derive the differential attention formula and explain why the subtraction cancels the shared noise component while preserving signal.
  • Walk the V1-to-V2 diff: what got faster, what got simpler, what got more stable, and why each change was necessary for production pre-training.
  • Implement differential attention from scratch in pure Python and empirically verify the noise-cancellation property on a synthetic signal-plus-noise query.

The Problem

Softmax attention has a property that is harmless at 4k tokens and a headache at 128k. For a query q, the attention weights are softmax(qK^T / sqrt(d)), and softmax does not produce exact zeros. Each non-matching token gets some positive mass. That residual mass is noise, and it scales with context length. At 128k tokens, if each non-matching token gets only 0.0001% of the probability, the 127,999 of them combined contribute about 13% of the total. The model has to learn to route around a noise floor that grows with context.

In practice this shows up as attention-head interference: hallucinated citations in long-context RAG, lost-in-the-middle failures on 100k-token retrieval tasks, and accuracy that slips on needle-in-haystack benchmarks past 32k. The Differential Transformer paper (arXiv:2410.05258, ICLR 2025) measured the gap. DIFF Transformers reached lower perplexity, higher long-context accuracy, and fewer hallucinations than same-size baselines.

DIFF V1 had three problems that kept it out of frontier pre-training pipelines. Its value cache had to be loaded twice per decode step. It needed custom CUDA kernels, which broke FlashAttention compatibility. And its per-head RMSNorm destabilized long-run training at 70B-plus scale. DIFF V2 (Microsoft unilm blog, January 20, 2026) fixes those three. This lesson covers both versions, builds the difference operator, and measures noise cancellation on a toy query.

Warm-up0/3
1. In standard softmax attention over unmasked positions with finite scores, can any single attention weight be exactly zero?Warm-up
Four attention scores for one query against four keys, -8, -1, 0, and +2, with the softmax weight formula below and a blank for the weight on the score of -8. A question asks whether a weight can come out as exactly zero for the key that barely matches at all.
The four scores are illustrative, chosen to include one clear mismatch; the weight on it is the question.
2. A model has 32 query heads and 8 KV heads (GQA). Compared with full multi-head attention at 32 heads, how large is its KV cache per token?Warm-up
Eight KV-head boxes shared by 32 query heads, drawn below them, with a blank box asking how large the KV cache per token is compared with a 32-head model that does not share. A question asks the same thing.
The two head counts, 32 query heads and 8 KV heads, are the stem's own numbers; the cache size comparison is the question.
3. Why is single-token decode usually limited by memory bandwidth rather than by arithmetic?Warm-up
Five cached token boxes and a new sixth token generating, with a note that step 6 reads the stored keys and values for tokens 1 through 5 at every layer, and a blank box asking how much work is done per byte read this step. A question asks why this step is usually bandwidth-limited rather than arithmetic-limited.
The setup (cached tokens, one new token, one read of the stored K and V) is the stem's own description; why it is bandwidth-bound is the question.
Check: The Problem0/2
1. What is the "lost in the middle" failure in long-context models?Define
A term card reading Lost in the middle. Context note: Context: an empirical accuracy pattern in long-context retrieval, named in The Problem section. A question asks: What pattern does it describe?
The term as the lesson names it; its mechanism is the question.
2. At 128k tokens, each of the 127,999 non-matching tokens gets 0.0001% of the probability. About how much total mass do they hold?Apply
A field card with the stem's own numbers: 127,999 unrelated tokens, each holding 0.0001% of the attention mass, and a blank asking for the total across all of them.
Both figures are the stem's own numbers; the total is the question.

The Concept

The noise floor of softmax

For a query q and keys K = [k_1, ..., k_N], attention weights are:

w_i = exp(q . k_i / sqrt(d)) / sum_j exp(q . k_j / sqrt(d))

No w_i is zero. If k_i is unrelated to q, the score q . k_i is not 0. It fluctuates around zero with variance ||q||^2 / d. After normalization each unrelated token still contributes O(1/N) to the weighted sum, and the N-1 of them together contribute O((N-1)/N) = O(1). That is not a small quantity.

What the model wants is closer to a hard top-k: high weight on matching tokens, near-zero weight everywhere else. Softmax is too smooth to do that directly.

The differential idea

Split each head's Q and K projections into two: Q = (Q_1, Q_2) and K = (K_1, K_2). Compute two attention maps:

A_1 = softmax(Q_1 K_1^T / sqrt(d))
A_2 = softmax(Q_2 K_2^T / sqrt(d))

Output:

DiffAttn = (A_1 - lambda * A_2) V

The subtraction cancels whatever noise distribution the two maps share. If both maps put roughly uniform weight on the 127k unrelated tokens, which is what you get at random initialization, that weight cancels. The signal is a peaked weight on the few relevant tokens, and it only cancels if it shows up in both maps at the same magnitude. Once the model trains, it does not.

lambda is a learnable scalar per head, parameterized as lambda = exp(lambda_q1 dot lambda_k1) - exp(lambda_q2 dot lambda_k2) + lambda_init. It can be negative. lambda_init defaults to a small positive number like 0.8.

Why this works like noise cancellation

Think of two noisy microphones recording the same voice. Both pick up the speaker plus correlated background noise. Subtract one from the other and the shared noise drops out. The voice survives because the two signals differ in phase or amplitude enough to prevent full cancellation. The per-head lambda learns that balance.

V1 vs V2: the diff

V1 kept the parameter count equal to the baseline Transformer. To get two queries per head it halved the head dimension. That cost head expressiveness and halved the value cache per head, which hurt more: decode had to load the value cache twice per step, once per softmax branch. The result was decode slower than baseline despite matching parameter count.

V2 doubles the number of query heads and keeps the KV heads the same, borrowing parameters from the up-projection. The head dimension stays at the baseline value. After the subtraction, the extra dimension is projected back down to match the baseline Transformer's O_W projection. Three things follow:

  1. Decode speed matches baseline (the KV cache is loaded once).
  2. FlashAttention runs unchanged (no custom kernel).
  3. Arithmetic intensity at decode goes up (more compute per byte loaded from HBM).

V2 also drops the per-head RMSNorm that V1 used to stabilize the subtraction. At 70B-class pre-training scales that RMSNorm destabilized late training. V2 replaces it with a simpler initialization scheme that keeps training stable without the extra module.

When to reach for it

WorkloadBenefit
Long-context RAG (64k+)Cleaner attention maps, fewer hallucinated citations
Needle-in-haystack benchmarksSubstantial accuracy lift past 32k
Multi-document QALess cross-document interference
Code completion at 8kMarginal, not worth the architecture change
Short chat (< 4k)Essentially indistinguishable from baseline

The value grows with context length. At 4k tokens the noise floor is small enough that standard attention is fine. At 128k it is hurting you.

How it stacks with other 2026 knobs

FeatureCompatible with DIFF V2?
GQAYes (V2 increases Q heads, not KV heads)
MLA (DeepSeek)Yes in principle, no published paper combining them
MoEYes (attention is independent of MLP block)
RoPEYes (unchanged)
YaRN / long-context scalingYes (exactly where DIFF helps most)
FlashAttentionYes in V2 (was no in V1)
Speculative decodingYes (attention change is invisible to the spec-decode loop)
Check: The Concept0/18
1. What is the noise floor of softmax attention?Define
A term card reading Noise floor. Context note: Context: a property of softmax's output weights, named in The Problem and The Concept sections. A question asks: What is it?
The term as the lesson names it; its mechanism is the question.
2. What is the differential attention output formula in The Concept section?Define
Two lines from the real diff_attention function in main.py, computing row1 and row2 as two softmax maps over the split Q, K projections, followed by a comment noting that row1, row2 and V combine into one attention output, with the actual combining line replaced by three question marks. A question asks what that formula is.
The two softmax lines are quoted from main.py; the line that combines them is the question.
3. How is lambda parameterized in The Concept section?Define
A term card reading lambda. Context note: Context: a scalar that weights the second softmax map A2 inside the differential attention output. A question asks: How is it parameterized in The Concept section?
The term as the lesson names it; its mechanism is the question.
4. What is DIFF V1?Define
A term card reading DIFF V1. Context note: Context: the original Differential Transformer (Ye et al., ICLR 2025), named in V1 vs V2. A question asks: What is it?
The term as the lesson names it; its mechanism is the question.
5. What change does DIFF V2 make so the KV cache is loaded only once per decode step?Define
A term card reading DIFF V2. Context note: Context: the production-stack rewrite of differential attention (Microsoft, January 2026), named in V1 vs V2. A question asks: What change does it make so the KV cache is loaded only once per decode step?
The term as the lesson names it; its mechanism is the question.
6. What is the per-head RMSNorm in DIFF V1?Define
A term card reading Per-head RMSNorm. Context note: Context: an extra normalization module that DIFF V1 applies inside each attention head. A question asks: What is it?
The term as the lesson names it; its mechanism is the question.
7. What is arithmetic intensity at decode time?Define
A term card reading Arithmetic intensity. Context note: Context: a decode-time quantity that the V1 vs V2 comparison tracks, tied to how much is read from memory each step. A question asks: What is it, exactly?
The term as the lesson names it; its mechanism is the question.
8. What does the model want from attention that softmax cannot produce directly?Explain
A bar chart of roughly similar-height weights across several positions, labelled softmax today with no sharp zeros, next to a blank box asking what desired shape the model wants instead. A question asks what the model wants that softmax alone cannot produce.
The smooth bar pattern is softmax's known behaviour; the shape the model would prefer is the question.
9. Why does softmax noise matter more at 128k tokens than at 4k tokens?Explain
A field card comparing two context lengths, 4,000 tokens and 128,000 tokens, with a note that each unrelated token keeps about the same small weight either way. A question asks why that small weight matters more at the longer length.
The two context lengths and the same-weight note are the stem's own setup; why length changes the impact is the question.
10. Why does subtracting A_2 from A_1 cancel noise in a trained model but keep the signal?Explain
A field card naming A1 as the trained branch, peaked on the matching token, and A2 as the untrained branch, roughly uniform noise. A question asks why subtracting A2 from A1 cancels noise but keeps the signal.
Which branch is trained and which is untrained is the stem's own framing; why the subtraction behaves that way is the question.
11. What does the two-microphone analogy in The Concept say about subtracting one recording from the other?Explain
Two microphones in the same room, each recording the same voice plus shared background noise, with a blank box asking what mic 1's recording minus mic 2's recording gives. A question asks what the analogy says this subtraction does.
Both microphones picking up the same voice and shared background is the stem's own analogy; the result of subtracting one from the other is the question.
12. Why was DIFF V1 decode slower than a baseline Transformer despite an equal parameter count?Explain
A field card stating DIFF V1's parameter count equals a baseline Transformer's, while its measured decode speed is slower. A question asks why decode would be slower when the parameter count matches.
Both figures are the stem's own framing; the reason for the slowdown is the question.
13. Why can DIFF V2 run on FlashAttention unchanged when V1 could not?Explain
A field card quoting the lesson's own compatibility table: FlashAttention did not run on DIFF V1 without a custom kernel, but runs on DIFF V2 unmodified. A question asks what about V2's design makes that possible.
Both compatibility rows are the lesson's own table; what in V2 explains the second row is the question.
14. What does DIFF V2 do about the per-head RMSNorm that V1 applied after the subtraction?Explain
A field card noting that DIFF V1 applies a per-head RMSNorm after the subtraction in every head, with V2's handling of it left blank. A question asks what DIFF V2 does about this norm.
That V1 applies this norm is the stem's own setup; what V2 does instead is the question.
15. Why does the compatibility table list GQA as working with DIFF V2 without changes?Explain
Three rows quoted from the lesson's own compatibility table: RoPE marked yes and unchanged, MoE marked yes because attention is independent of the MLP block, and GQA marked yes with its reason left blank. A question asks why the table marks GQA as compatible without any change.
The RoPE and MoE rows are quoted exactly as the lesson gives them; GQA's own reason is blanked and is the question.
16. A team trains DIFF V1 and finds decode slower than baseline and FlashAttention unusable. Which V2 change addresses both problems?Analyze
A field card listing two problems a team hits with DIFF V1: decode slower than a baseline Transformer, and FlashAttention unable to run. A question asks which single V2 change addresses both.
Both problems are the stem's own description; the single V2 change that fixes them is the question.
17. A 70B-class DIFF run becomes unstable late in pre-training. Which component does the lesson blame for this in V1?Analyze
An illustrative loss curve for a 70B-class run that falls through most of training and then rises again late, representing the instability the stem describes. A question asks which V1 component the lesson blames for this.
The curve shape is illustrative, not a captured run; which V1 component is blamed is the question.
18. You plan a 70B pre-training run with a 128k-token target on a FlashAttention stack with GQA (32 Q heads, 8 KV heads). Which design fits?Design
A planning card: a 70B pre-training run, a 128k-token context target, and an existing FlashAttention stack with GQA at 32 query heads and 8 KV heads, with the differential-attention design left blank. A question asks which design fits this plan.
The scale, target and stack are the stem's own description; the design choice is the question.

Build It

code/main.py implements differential attention in pure Python, on a synthetic setup where you know where the signal is, so you can measure noise cancellation directly. One note on scope: main() runs the measurement on logits (a trained branch and an untrained branch over 1024 positions). diff_attention takes already-projected Q1, K1, Q2, K2 and implements the full operation, but main() does not call it.

Step 1: standard softmax attention

Stdlib only: lists of lists, manual matmul, and a softmax that subtracts the max for numerical stability.

python
def softmax(row):
    m = max(row)
    exps = [math.exp(x - m) for x in row]
    s = sum(exps)
    return [e / s for e in exps]

Step 2: split Q, K into two halves

V1 style halves the head dimension. V2 style keeps the head dimension and doubles the number of heads. diff_attention takes the four split inputs, so the math is the same either way and only the bookkeeping differs.

Step 3: two softmax branches + subtraction

python
A1 = [softmax([dot(q1, k) / scale for k in K1]) for q1 in Q1]
A2 = [softmax([dot(q2, k) / scale for k in K2]) for q2 in Q2]
diff_weights = [[a1 - lam * a2 for a1, a2 in zip(r1, r2)] for r1, r2 in zip(A1, A2)]
out = [[sum(w * v[j] for w, v in zip(row, V)) for j in range(d_v)] for row in diff_weights]

The output weights can be negative. That is fine, because the weighted sum over V handles signed weights.

Step 4: noise cancellation measurement

main() builds 1024 logits for the first branch (Gaussian noise with std 0.5, plus a signal logit of 4.0 at position 500) and 1024 noise logits for the second. It computes the signal-to-noise ratio, meaning the weight on the signal position divided by the mean absolute weight elsewhere, for the first branch alone and for the difference at lambda values from 0.0 to 1.0. A second sweep varies the noise std and compares standard attention against differential attention at lambda = 0.8.

The target for differential attention is a signal-to-noise gain of roughly 3x-10x, depending on how far the two branches have been trained to differ. The toy trains nothing, so its numbers are smaller. At noise std 0.5, lambda = 0.8 takes the ratio from 47.72 to 92.31, and the sweep shows the gain shrinking as the noise grows.

Step 5: V1 vs V2 parameter accounting

Given a config (hidden=4096, heads=32, d_head=128, and 8 KV heads for V2), the toy prints:

  • Baseline Transformer: Q, K, V, and O each of size hidden * hidden, so 4 * hidden * hidden in total.
  • DIFF V1: Q and K each of size hidden * hidden in total (two half-width halves), V and O unchanged, head dim halved internally. It adds per-head lambda parameters, 4 * n_heads * (d_head // 2), which comes to 8.2K.
  • DIFF V2: Q of size 2 * hidden * hidden, K and V of size hidden * kv_heads * d_head each, and O counted at the doubled width. It adds 4 * n_heads * d_head lambda parameters.

At this config the toy prints a V2 delta of 8.4M over a 67.1M baseline attention block.

Check: Build It0/10
1. In the toy measurement, what is the signal-to-noise ratio?Define
One box marked as the signal position among several unlabeled other positions, after softmax and the lambda subtraction, with a blank ratio reading signal-to-noise ratio equals the weight on the signal position divided by something left blank. A question asks what exact ratio defines it in the toy measurement.
The signal position is the stem's own setup from Build It Step 4; the exact divisor is the question.
2. How does DIFF V1 keep its parameter count equal to the baseline despite using two query and two key maps per head?Explain
A field card noting DIFF V1 uses two Q projections and two K projections per head, yet its total parameter count still equals a baseline Transformer's. A question asks how V1 keeps the count equal despite the extra maps.
Both facts are the stem's own framing; how the count stays equal is the question.
3. In the Step 5 accounting of Build It, how big is DIFF V2's Q projection for the same hidden size?Explain
A field card from Build It Step 5's accounting: baseline Q at hidden times hidden, DIFF V1's Q (through two half-width halves) also at hidden times hidden, and DIFF V2's Q left blank. A question asks how big V2's Q projection is.
The baseline and V1 figures are quoted from Build It Step 5; V2's figure is the question.
4. With the max-subtracting softmax from Step 1, what does softmax([1000.0, 1000.0]) return?Apply
The real max-subtracting softmax function from main.py's Build It Step 1, alongside a call softmax of the list 1000.0, 1000.0, with the result left blank. A question asks what that call returns.
The function body is quoted from main.py; tracing it on these two equal scores is the question.
5. In Step 3 with lambda = 0.8, one row has A1 = [0.7, 0.3] and A2 = [0.5, 0.5]. What are diff_weights for that row?Apply
A field card with Step 3's own numbers for one row: A1 at [0.7, 0.3], A2 at [0.5, 0.5], lambda at 0.8, and diff_weights for that row left blank. A question asks what diff_weights comes out to.
All three given values are the stem's own numbers; the resulting row is the question.
6. Using the V1 formula 4 * n_heads * (d_head // 2), how many lambda parameters does V1 add at 32 heads and d_head = 128?Apply
The stem's own V1 lambda-count formula, 4 times n_heads times d_head integer-divided by 2, with n_heads at 32 and d_head at 128, and the result left blank. A question asks how many lambda parameters this adds.
The formula and both numbers are the stem's own; the count is the question.
7. Using the V2 formula 4 * n_heads * d_head, how many lambda parameters does V2 add at 32 heads and d_head = 128?Apply
The stem's own V2 lambda-count formula, 4 times n_heads times d_head, with n_heads at 32 and d_head at 128, and the result left blank. A question asks how many lambda parameters this adds.
The formula and both numbers are the stem's own; the count is the question.
8. In the lambda sweep from main.py (the first block of the output, discussed in Author's Note), where does the signal-to-noise gain come from?Apply
The real lambda sweep table from main.py's output, listing the weight on the signal position and the summed absolute noise weight at lambda values 0.0, 0.3, 0.6, 0.8 and 1.0. A question asks where the signal-to-noise gain across this sweep comes from.
Every number is the lesson's own real run output, quoted in Author's Note; which column moves more is the question.
9. Per Build It (Step 4), what gain does the untrained toy show at noise std 0.5 and lambda = 0.8, compared with the 3x-10x target?Apply
A field card with the lesson's own two figures at noise std 0.5 and lambda 0.8, a standard-attention signal-to-noise ratio of 47.72 and a differential-attention ratio of 92.31, next to the target range of 3x to 10x stated in Build It Step 4, with the comparison left blank.
Both ratios are the lesson's own quoted numbers; how they compare to the target is the question.
10. In the noise sweep, standard attention matches or beats the difference once noise std reaches 1.0 and above. Which property of the toy best explains this?Analyze
The real noise-amplitude sweep table from main.py's output, listing standard-attention and differential-attention signal-to-noise ratios at noise std 0.25, 0.50, 1.00, 1.50 and 2.00. A question asks which property of the toy explains why standard attention matches or beats the difference from std 1.0 upward.
Every number is from the lesson's own real run; the property of the toy that explains the pattern is the question.

Use It

DIFF V2 is not yet shipping in every production inference server as of April 2026, but integration is underway in vLLM and SGLang. Meanwhile the pattern shows up in:

  • Microsoft internal long-context production models.
  • Research replications in several open model training runs targeting 256k-plus context.
  • Hybrid architectures that combine DIFF attention with sliding-window attention on alternate layers.

When you would reach for it in 2026:

  • Training a new model from scratch with a 64k-plus effective context target. Add differential attention from the start, because retraining later is expensive.
  • Fine-tuning a long-context model where lost-in-the-middle failures dominate your eval. A LoRA on the Q projections can approximate the DIFF structure.

When you would not:

  • You are serving a pre-trained dense model whose long-context performance is already stable. The retraining cost rarely pays back on existing weights.
  • Your context stays under 16k. The noise floor is negligible there.
Check: Use It0/3
1. A team adds DIFF V2 to a chat product with contexts under 4k tokens and sees no measurable gain. Which diagnosis fits?Analyze
A field card noting a chat product with contexts under 4,000 tokens, where DIFF V2 was added and showed no measurable gain. A question asks which diagnosis fits.
Both facts are the stem's own description; the diagnosis is the question.
2. A team serves a stable pre-trained dense model at 8k context and asks whether to adopt DIFF V2 in the next release. What does Use It suggest?Design
A field card describing a stable pre-trained dense model served at 8k context, with the team asking whether to adopt DIFF V2 in the next release. A question asks what Use It suggests.
The model's state and context length are the stem's own description; Use It's recommendation is the question.
3. You must improve a long-context model where lost-in-the-middle failures dominate the eval, and there is no budget for pre-training. What does Use It suggest?Design
A field card describing a long-context model whose eval is dominated by lost-in-the-middle failures, with no budget for pre-training. A question asks what Use It suggests for improving it.
The failure mode and the budget constraint are the stem's own description; Use It's suggestion is the question.

Ship It

This lesson produces outputs/skill-diff-attention-integrator.md. Given a model architecture, target context length, hallucination profile, and training budget, it produces an integration plan for adding differential attention to a new pre-training run or a LoRA fine-tune.

Author's Note

I'd run main.py before trusting any ratio in this lesson, including the ones I quote. The output shows differential attention losing in places. In the noise sweep, standard attention and the difference are about even at noise std 1.0 (34.62 against 35.14), and at 1.5 and 2.0 standard attention has the higher ratio. The toy trains nothing and draws the two branches' noise independently, so it is a weaker test than two real heads looking at correlated noise. Read it as a check on the arithmetic of the subtraction.

My bet is that the lambda sweep in the first block of the output is the most useful table to stare at. The weight on the signal position barely moves (0.044569 at lambda = 0.0, 0.044227 at 1.0), while the summed noise weight falls from 0.955 to 0.491 at 0.8 and climbs back to 0.531 at 1.0. That is where the ratio peaks on this grid, and the signal column shows the gain comes from removing noise and not from boosting the signal.

I'd also read the parameter printout slowly. V1's delta is 8.2K and V2's is 8.4M at 8 KV heads, so V1 spends almost nothing, while V2 nets out 8.4M: the doubled Q and doubled O add about 33.6M, and the 8-head K and V take back about 25.2M. The toy counts O at the doubled width, while the V2 description above projects the extra dimension back down before O_W. I'd check that against the blog before copying the count into a real config.

Exercises

  1. Run code/main.py. Check that the signal-to-noise ratio for differential attention beats standard softmax attention on the synthetic query at low noise. Extend the noise sweep and find the crossover point where standard attention comes out ahead.

  2. Compute the parameter-count delta from baseline to DIFF V1 and from baseline to DIFF V2 for a 7B-class model (hidden=4096, heads=32, d_head=128, 32 layers). Show which components gained parameters and which stayed the same.

  3. Read Section 3 of the DIFF V1 paper (arXiv:2410.05258) and Section 2 of the DIFF V2 Hugging Face blog. In two sentences, explain why the V1 per-head RMSNorm was necessary and why V2 could remove it without training divergence.

  4. Implement an ablation: compute differential attention with lambda = 0 (pure first softmax) and lambda = 1 (full subtraction). On the synthetic query, measure how signal-to-noise changes across the sweep. Find the lambda that maximizes signal-to-noise.

  5. Extend the toy to GQA + DIFF V2. Pick 8 KV heads and 32 Q heads. Show that the KV cache size matches a baseline GQA model with the same (8, 32) configuration.

Key Terms

TermWhat people sayWhat it actually means
Differential attention"Two softmaxes minus each other"Split Q, K into two halves, compute two softmax maps, subtract the second (scaled by lambda) from the first, then multiply by V
Noise floor"The non-zero tail of softmax"The O(1/N) weight softmax puts on every unrelated token, which sums to O(1) across long contexts
lambda"The subtraction scale"Per-head learnable scalar parameterized as exp(lq1.lk1) - exp(lq2.lk2) + lambda_init; can be negative
DIFF V1"The ICLR 2025 version"Original Differential Transformer; halves head dim to preserve parameter count, needs custom kernel, slower decode
DIFF V2"The January 2026 fix"Doubles Q heads keeping KV heads; matches baseline decode speed and works with FlashAttention
Per-head RMSNorm"The V1 stabilizer"Extra norm V1 applied after the difference; V2 removed it to prevent late-training instability
Signal-to-noise ratio"How much attention is wasted"Ratio of weight on the true signal position to average weight on unrelated positions
Lost in the middle"Long-context failure mode"Empirical phenomenon where retrieval accuracy dips for documents in the middle of a long context, and DIFF attention reduces this
Arithmetic intensity"FLOPs per byte loaded"Ratio V2 increased at decode by doubling queries per KV load; important for memory-bound decode

Further Reading

Code

Ships With