Where Does a Fact LiveKnowledge Localization
interpretabilitylocalization
One-line analogy
Picture a 70B-parameter model as a giant distributed KV store. The fact "the Eiffel Tower is in Paris" isn't smeared across the whole cluster — it lives on a few specific nodes. The catch: no schema, no index, no docs. How do you find that node? The answer is chaos-engineering style (fault injection): deliberately corrupt a layer's activations, watch whether the model now gets it wrong, and reverse-engineer where the data is stored.
Problem it solves + how it works
The old intuition says a neural net is a "black box where knowledge is globally entangled." But in 2021 Geva et al. gave a key insight: a Transformer's FFN (feed-forward layer) is essentially a key-value memory. The FFN has two matrices — each row of the first (W_in) is a key (matching an input pattern, e.g. "the subject is a landmark"), and the matching column of the second (W_out) is a value (pouring tokens like "Paris" into the output vocabulary). This turns "where is knowledge stored" from a philosophy question into a locatable engineering problem.
How to localize? Two main paths:
- Knowledge Neurons (Dai et al. 2022) — use gradient attribution (integrated gradients) to compute which neuron's activation contributes most to "producing the correct answer." Zero it out, and the model's confidence in that fact drops.
- Causal Tracing (the ROME paper) — a cleverer "corrupt-then-restore" experiment: ① add noise to the whole sentence's representation so the model gets it wrong; ② layer by layer, token by token, restore one position's clean activation; ③ see which restoration brings back the right answer — that position is the causal mediator storing the fact.
Causal tracing: corrupt → restore layer by layer → see who rescues the answer
clean input Eiffel Tower is in ___ → "Paris" ✓
corrupted ▓▓Tower▓ is in ___ → "Tokyo" ✗ (amnesia)
restore clean activations layer by layer, find which rescues:
early layer no effect
mid MLP (last subject token) rescued → causal mediator!
late layer weak
↑ conclusion: facts mostly live in the mid-layer FFN at the "last subject token"
The ROME paper's core empirical finding: the mid-layer MLP, active while processing the last token of the subject name, is decisive for fact recall. Not a guess — a statistical result from causal experiments over thousands of facts. Once you know "where it's stored," the natural next step is "can you edit it precisely."
Code
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
# Use a hook to grab FFN activations — observe the KV-memory structure
model = AutoModelForCausalLM.from_pretrained("gpt2-xl")
tok = AutoTokenizer.from_pretrained("gpt2-xl")
acts = {}
def grab(name):
def hook(mod, inp, out): acts[name] = out.detach()
return hook
# Hook after the mid-layer MLP activation (where keys fire)
layer = 17 # the "decisive mid layer" range ROME found
model.transformer.h[layer].mlp.act.register_forward_hook(grab("mlp_key"))
ids = tok("The Eiffel Tower is located in the city of", return_tensors="pt")
model(**ids)
# Which neurons fire hardest at the last subject token = candidate "knowledge neurons"
key = acts["mlp_key"][0, -1]
print("top-5 most-active neurons:", key.topk(5).indices.tolist())
Common misconception + practical scenario
"Found the knowledge neuron = found where to edit" — wrong, and seriously debunked. Hase et al. 2023 found that the layer causal tracing localizes and "which layer is best to edit" are nearly uncorrelated. In other words, knowing where the data is stored ≠ knowing where it's best to write it in — familiar to distributed folks: read paths and write paths can hit entirely different replicas.
📌 Super-individual scenario: to understand "why does this model keep getting my domain knowledge wrong," reuse the causal-tracing mindset as probing experiments — systematically rewrite different parts of the prompt and watch which change breaks the answer, locating the model's knowledge boundary instead of blindly trying prompts.
Takeaway + question
💡 Knowledge in a large model isn't mystically entangled — it has a locatable physical address, and the mid-layer FFN is that distributed KV store.
🤔 If facts really live in specific parameter layers, where's the line between "the model understands a concept" and "the model stored a KV entry"? Does table lookup count as understanding?
Edit One Fact PreciselyROME · Rank-One Model Editing
model editinglinear algebra
One-line analogy
The model learned "the current US president is X" wrong. Three options: re-pretrain (rebuild the whole database — astronomically expensive), fine-tune (a full-table update that easily hits other rows and causes forgetting), or ROME — like a surgical UPDATE ... WHERE id=?: change one MLP weight matrix by adding a single "rank-one" correction, so "this subject's" key maps to the "new object's" value, ideally touching no other record.
Problem it solves + how it works
Facts go stale (elections, renames, data errors). Fine-tuning one fact is costly: build data, risk overfitting, and cause catastrophic forgetting of other knowledge. ROME pushes the previous card's insight to its conclusion — if the FFN is a linear associative memory, then editing it is a linear-algebra problem.
Treat the FFN's output matrix W as an associative memory mapping key vectors k to value vectors v (i.e. W k ≈ v). We want a specific subject key k* ("Eiffel Tower") to output a new value v* (pointing to "Rome"), while disturbing as little as possible what W does for all other keys. This becomes a constrained least-squares:
# Goal: find a new matrix W' satisfying two things
W' k* = v* ← new fact: this subject must output the new answer
min ‖W' − W‖ ← minimal disturbance: leave other memories alone
# Closed-form solution = a rank-one update
W' = W + Λ (C⁻¹ k*)ᵀ
Λ = a column vector, sets "which direction to push the value"
C = KKᵀ, a precomputed "covariance of existing keys" — the guardrail for old memories
(C⁻¹k*)ᵀ = a row vector; column × row = a rank-one matrix
Intuition: a rank-one matrix = a column vector times a row vector — the lowest-information kind of edit — it changes W's behavior in one direction only. The C⁻¹ term is the key guardrail: it uses "the statistics of all historical keys" to project the update into a direction that doesn't disturb common keys — like adding a WHERE clause to the UPDATE so other rows aren't hit. After editing, the model not only says "Rome" on the original sentence but also generalizes to paraphrases like "which country is the tower in" — because it edited the internal representation, not memorized a string.
Code
# EasyEdit: a unified implementation of ROME/MEMIT and other editors
# pip install easyeditor
from easyeditor import BaseEditor, ROMEHyperParams
hparams = ROMEHyperParams.from_hparams("./hparams/ROME/gpt2-xl")
editor = BaseEditor.from_hparams(hparams)
# Edit one fact at a time: change the Eiffel Tower's location to Rome
metrics, edited_model, _ = editor.edit(
prompts=["The Eiffel Tower is located in the city of"],
ground_truth=["Paris"], # old fact
target_new=["Rome"], # new fact (to write into weights)
subject=["Eiffel Tower"], # key: locate the subject token
)
# metrics includes efficacy (edit success) / generalization (paraphrase)
# / specificity (did unrelated knowledge get hit) — the 3 core metrics
print(metrics)
Common misconception + practical scenario
"ROME is cheaper than fine-tuning per fact, so I'll loop it to edit a thousand" — wrong. ROME is designed for single edits; repeated edits accumulate interference: each rank-one update slightly perturbs W, and after dozens the model starts to "bleed" and lose general ability. This is exactly what MEMIT (next card) solves.
📌 Super-individual scenario: model editing is not a mature way for individuals to "teach the model my private facts" — RAG / memory is steadier for that (see Day 8). But understanding ROME lets you decode a class of news: when a company claims it "fixed a model's wrong belief in minutes without retraining," it's usually this kind of pinpoint edit.
Takeaway + question
💡 ROME reduces "edit one fact" from "retrain" to "one rank-one matrix update" — a beautiful case of turning interpretability insight into an actionable lever.
🤔 What's the essential difference between a fact you can precisely rewrite with a rank-one update and a capability that won't budge and must be retrained? Which "knowledge" is really "table lookup," which is "computation"?
Batch-Edit ThousandsMEMIT · Mass-Editing Memory
model editingscaling
One-line analogy
If ROME is a single UPDATE, MEMIT is batch UPDATE + load balancing. Looping edits a thousand times locks the table and accumulates error; MEMIT solves for the thousand corrections at once and spreads them across several mid-layer MLPs — like distributing write pressure across shards instead of dumping it all on one node.
Problem it solves + how it works
Real needs are often batched: a knowledge base updated thousands of facts, sync them into the model at once. Editing one by one with ROME makes them fight. MEMIT (Meng et al. 2022) made two key improvements:
- ① Joint solve, not sequential stacking — put all edited facts into one least-squares objective solved together, so the updates "know about each other" and a later one won't wipe out an earlier one.
- ② Spread across multiple layers — instead of editing one layer, distribute the total correction across a contiguous range of mid-layer MLPs (e.g. layers 13–17). Each layer carries only part of the change, so per-layer disturbance is small and total capacity is large. This is the key to editing thousands at once, orders of magnitude beyond ROME.
ROME vs MEMIT: single-point write vs spread across shards
ROME (one fact · one layer):
1 fact → Layer 17 overload it → accumulated interference
MEMIT (thousands · multi-layer joint):
1000 facts → joint solve → spread over a range:
L13L14L15L16L17
↑ each layer carries part of the correction → small per-layer disturbance, big total capacity
MEMIT's empirical result: on GPT-J (6B) and GPT-NeoX (20B), it can inject thousands of associations at once, far beyond prior methods. It remains the mainstream baseline for "batch knowledge injection" research.
Code
from easyeditor import BaseEditor, MEMITHyperParams
hparams = MEMITHyperParams.from_hparams("./hparams/MEMIT/gpt-j-6b")
editor = BaseEditor.from_hparams(hparams)
# Key difference: prompts is a batch, injected in one shot
metrics, edited_model, _ = editor.edit(
prompts=[
"The president of the USA is",
"The capital of Australia is",
"The CEO of Twitter is",
# ... can be thousands
],
target_new=["Jane Doe", "Sydney", "John Roe"],
subject=["USA", "Australia", "Twitter"],
)
# MEMIT jointly solves this batch and spreads it across several mid MLPs
print(metrics)
Common misconception + practical scenario
"MEMIT batch-edits, so it can replace RAG / fine-tuning for knowledge updates" — not so fast. The more you batch-edit, the more "specificity (not hitting unrelated knowledge)" and overall fluency degrade; and it edits isolated fact points, not automatically updating logically related facts (the core pain of the next card). It's a precise scalpel, not a knowledge-base sync pipeline.
📌 Super-individual scenario: treat ROME/MEMIT as a lens for understanding "model plasticity" — it reveals that a model's knowledge is more locally rewritable than you'd think. That has direct implications for judging "how easily a model can be poisoned / backdoored" (whoever can change the weights can pinpoint-tamper with facts).
Takeaway + question
💡 MEMIT's core engineering wisdom is identical to distributed systems: jointly solve big batches of writes + spread across shards to scale without collapsing.
🤔 If thousands of facts can be "spread" into weights without noticeably hurting the model, how much "redundant capacity" in the parameters is waiting to be written? What does that mean for model security?
Edit One, a Whole Region CollapsesRipple Effects & Knowledge Conflict
side effectsconsistency
One-line analogy
You changed one master record in a database but didn't run the cascade update — every materialized view depending on it still holds the old value. Model editing has exactly this disease: you change "the club Messi plays for" to a new team, but the model still answers old facts for "who are Messi's teammates" and "which league is he in" — the logically entailed facts. You changed the primary key, the derived views didn't refresh, the data is now inconsistent.
Problem it solves + how it works
ROME/MEMIT look beautiful, but Cohen et al. 2023 posed a stinging question: a fact is never isolated. Changing "A's capital is B" should ripple through a chain of inferences: "A's seat of government," "B is the capital of which country," "which way to travel from A to reach the capital"... They built the RippleEdits benchmark (~5000 edits, specifically testing these chain reactions) and found:
- Mainstream editing methods fail broadly on the "ripple" — they change the target fact correctly, but the logically entailed related facts don't follow, leaving the model self-contradictory.
- Counterintuitive result: a simple in-context edit (just put the new fact in the prompt, touch no weights at all) scored best on this benchmark — because a fact placed in context can be used consistently through reasoning, which an isolated fact welded into weights cannot.
Edit one → the cascade that should fire doesn't
edit: Messi plays for → Inter Miami ✓ (target changed)
but the logically derived facts don't refresh:
Who are Messi's teammates? → still old teammates ✗
Which league is Messi in? → still old league ✗
Which city does Messi live in? → not updated ✗
↑ like editing the master table without triggering FK cascades — derived views full of stale data
Another layer of "knowledge conflict" is parametric memory vs context: when a fact retrieved by RAG clashes with the old memory in the model's parameters, which does the model trust? Research shows models often stubbornly trust their own parametric memory even when context clearly gives an update — the hardest part of hallucination mitigation, and proof that "writing knowledge into parameters" and "getting the model to use knowledge correctly" are two different things.
Code
# After editing you MUST test the "ripple," not just the target fact
# edit: the club Messi plays for → Inter Miami
target = "Where does Lionel Messi currently play? "
print(query(edited_model, target)) # ✓ likely correct — the target fact
# The real test: logically entailed "ripple facts"
ripples = [
"Which league does Lionel Messi play in? ", # league
"Who are Lionel Messi's teammates? ", # teammates
"In which country does Lionel Messi work? ", # country
]
for q in ripples:
# editing methods often crack here: target right, ripple all wrong
print(q, "→", query(edited_model, q))
Common misconception + practical scenario
"Efficacy 90% = the edit succeeded" — a dangerous single-metric trap. The target being correct doesn't mean knowledge was updated consistently. Watch three things: efficacy (target changed), generalization (still right under paraphrase), and specificity + ripple (did it hit others, did it cascade what should cascade). Watching only the first is like testing "the master table changed" without testing "is the whole database still consistent."
📌 Super-individual scenario: this changes how you trust AI output — when a model "updates" some belief, don't assume its entailed inferences are now self-consistent too. When you hand it fresh facts via RAG, watch for clashes with the model's old memory. Especially in cross-disciplinary thinking: change a premise and you naturally re-derive downstream, but the model may not — you have to check consistency for it.
Takeaway + question
💡 Welding a fact into weights is easy; updating knowledge consistently is brutally hard — model editing's biggest enemy isn't "can't change it" but "changed it without cascading." Sometimes the steadiest "edit" is putting the new fact in context (RAG).
🤔 If even large models can't "change one premise and auto-cascade all inferences," how does the human brain do it (or does it also fail)? Is belief-update consistency itself a core hard problem of intelligence?