上一篇我們整理了 Mechanistic Interpretability 裡幾種不同的 evidence,現在我們終於可以開始介紹更多工具了!首先,我們回到一個很直覺的問題:假設我們輸入:”The capital of Taiwan is ...”,模型最後預測:”Taipei”。我們知道最後一層已經「決定」要輸出 Taipei。但這個答案到底是什麼時候形成的?是在最後一層突然出現?還是早在模型運算到某一步時,它就已經開始傾向 Taipei,只是後面的 layers 再慢慢把答案修得更確定?
如果能直接問模型每一層:「如果現在就要你回答,你會選哪個 token?」我們似乎就能偷看答案形成的過程,而這就是 Logit Lens 的核心想法。[1]
還記得 Day 2 的 Residual Stream 嗎?模型一路計算,最後會拿最後一層的 Residual Stream,經過 LayerNorm 和 unembedding matrix,轉換成 vocabulary 中每個 token 的 logits:

接著 softmax 才把 logits 轉成下一個 token 的機率。Logit Lens 做的事情非常直接:既然最後一層可以這樣解碼,那如果把「中間層」也直接丟進同一個 unembedding 呢?簡單來說,就像他的名字說的一樣,本來我們只會在模型完成運算時去「觀測」取得模型的回應。現在,我們拿這個「Lens」去到處看看能找到什麼。

於是,本來是一串難以理解的高維 activation,突然被翻譯成我們熟悉的 token。
假設我們看到:
Layer 2 → "the"
Layer 4 → "Taiwan"
Layer 6 → "Taipei"
Layer 8 → "Taipei"
那麼一個很自然的觀察就是:「Taipei」這個答案,在模型真正輸出以前,就已經可以從中間的 representation 中讀出來。Logit Lens 最早由 nostalgebraist 在分析 GPT-2 時系統性展示:直接把不同 layer 的 hidden states 投影回 vocabulary,可以看到模型的 prediction 隨著層數逐漸演化。[1]
這次同樣會有一份完整的 companion notebook,但文章裡只需要看最核心的幾行。首先讓 TransformerLens(由 Neel Nanda 開發的 interpretability 常用開源工具)幫我們保存模型每一層的 activation:
logits, cache = model.run_with_cache(
"The capital of Taiwan is"
)
接著取出每一層最後一個 token position 的 Residual Stream:
residual_stack, labels = cache.accumulated_resid(
layer=-1,
pos_slice=-1,
return_labels=True
)
最後,把每一層的 residual state 經過模型原本的 final LayerNorm 和 unembedding:
layer_logits = model.unembed(
model.ln_final(residual_stack)
)
top_tokens = layer_logits.argmax(dim=-1)
概念上就這麼簡單。我們沒有訓練新的 probe,也沒有修改模型,只是把模型原本用來產生最終輸出的 decoder,提前套到每一層。
只看每一層 top-1 token 有時候其實有點粗糙,也不夠 informative。另一個常見做法,是直接追蹤我們在意的 token 的 logit。例如對:”The capital of Taiwan is”,我們可以一路追蹤 Taipei:

如果是有兩個候選答案的任務,還可以看 logit difference

正值代表模型比較支持 Taipei,負值代表比較支持 Taichung。
這種方式比只看 top token 更容易追蹤:「某個答案的 evidence 是在什麼時候開始累積的?」而且因為 Residual Stream 是不同元件輸出的總和,我們之後甚至可以繼續往下拆:「到底是哪一層?哪個 Attention Head?哪個 MLP?在直接推高某個 token 的 logit?」這類分析通常被稱作 Direct Logit Attribution (DLA),之後談 circuit 時還會再遇到。[3]
直覺上,我們先把最後的 Residual Stream 拆成不同 component 的貢獻,再把每一項 contribution 投影到我們關心的 output direction 上。例如,我們不只看 Taipei 本身,而是比較「Taipei vs. Taichung」哪一些 internal components 正在把模型往 Taipei 推?用 TransformerLens,大概可以寫成:
logits, cache = model.run_with_cache(
"The capital of Taiwan is"
)
resid_stack, labels = cache.decompose_resid(
layer=-1,
pos_slice=-1,
apply_ln=True,
return_labels=True,
)
taipei = model.to_single_token(" Taipei")
taichung = model.to_single_token(" Taichung")
logit_diff_direction = (
model.W_U[:, taipei]
- model.W_U[:, taichung]
)
dla = resid_stack[:, 0] @ logit_diff_direction
(因為實務上 Taichung 不會被 tokenize 成單一 token,因此搭配的 notebook 會先使用它的第一個 token 作為簡化示範。若要完整處理 multi-token 答案,通常會使用 teacher forcing,依序計算每個 token 在前文與先前答案 token 條件下的 log-probability,再將它們加總成完整答案的 log-likelihood;比較不同長度的答案時,也常進一步做 length normalization。[4])
dla 裡的每一個值,就可以理解成某個 residual component 對 logit(Taipei) - logit(Taichung) 的直接貢獻。如果某個 component 的值很大而且是正的,它會直接把 output 往 Taipei 推;如果是負的,則比較偏向 Taichung。不過這裡的「直接」非常重要。DLA 只是在問:
這個 component 最後寫進 Residual Stream 的內容,經過 Unembedding 後,直接支持哪些 tokens?
它不會告訴我們這個 component 是怎麼算出這項資訊的,也不會包含它透過後續元件間接造成的影響。所以 DLA 很適合幫我們找:「誰正在直接推動答案?」但如果想繼續問:「這項資訊從哪裡來?前面的元件又是怎麼一起完成這段 computation?」我們就必須開始進入 Circuit 的世界。後面的章節會再回來處理這個問題。[3]
這裡要回到上一篇的 evidence map。Logit Lens 很直覺,但我們要非常小心一句常見的說法:
「模型第 6 層就已經想好了答案。」
這可能是一個方便的描述,但嚴格來說有點太強。原因是,中間 layer 的 representation 本來就不是被訓練成可以直接經過 final unembedding 產生答案的。雖然每一層的 Residual Stream 都存在於相同維度的向量空間中,但它們形成的 representational space / geometry 可能並不相同,而 layer 與 layer 之間也還會經過許多 nonlinear transformations。
我們等於跳過了後面所有 layers。因此,如果中間 representation 和最後一層的 representation 分布(space)不完全相同,直接使用同一個 unembedding 就可能產生偏差。換句話說,Logit Lens 告訴我們的不一定「模型此刻真的準備輸出哪些 token」,比較像是用某種簡化的、直覺的視角試圖逼近「目前最像哪些 token」。這正是一個很好的 readout / localization tool,但不是對模型 cognition 的直接讀心術。
既然我們說這個 Lens 是某種試圖逼近「目前最像哪些 token」的工具,那麼很自然的改進方向就會是「怎麼做能讓我們讀出的更接近模型此刻真的準備輸出的 token?」這個問題後來催生了 Tuned Lens。[2]
Tuned Lens 不直接把所有 layer 都塞進同一個 unembedding,而是替每一層學習一個簡單的 affine transformation,再將 representation 轉換到比較適合 final decoder 的空間。可以把它想成:
Belrose 等人的實驗顯示,Tuned Lens 在多種 autoregressive language models 上,比原始 Logit Lens 更可靠地預測 intermediate states 所隱含的 token distribution。[2]
不過它也有一個 trade-off:Logit Lens 幾乎不用訓練任何東西,直覺又透明;Tuned Lens 則多學了一組參數,因此 interpretation 也多了一層 learned transformation。所以兩者回答的是稍微不同的需求:
而到了後面的章節,我們還會看到另一種很不一樣的 approach:與其另外學一個翻譯器,能不能直接利用模型後續的 computation,推回某個中間 representation 最後可能被「說成什麼」?這會帶我們走到之後介紹的 J-Lens。
如果 Logit Lens 顯示從 Layer 7 開始,「Taipei」就一直是最被支持的答案,根據上一篇建立的 evidence map,我們目前得到的主要還是 observation / localization,也就是 Taipei-related information 可以從這裡被讀出來。我們還不能說 Layer 7 的這段 information 「造成」了最後的 Taipei,因為可能有某項資訊可以被讀出,模型後面的 computation 卻完全沒有依賴它。
所以接下來的問題非常自然:如果我們真的把這段 activation 換掉,答案會跟著變嗎?這就從「看」模型跨到了「動」模型。
下一篇,我們會開始做第一次真正的 causal intervention:Activation Patching。
[1] nostalgebraist, “interpreting GPT: the logit lens”, 2020. https://www.lesswrong.com/posts/AcKRB8wDpdaN6v6ru/interpreting-gpt-
[2] Belrose, N., Furman, Z., Smith, L., et al., “Eliciting Latent Predictions from Transformers with the Tuned Lens”, 2023. https://arxiv.org/abs/2303.08112
[3] TransformerLens, “Exploratory Analysis Demo — Logit Lens and Direct Logit Attribution”. https://transformerlensorg.github.io/TransformerLens/generated/demos/Exploratory_Analysis_Demo.html
[4] Kauf, C., & Ivanova, A. A., “A Better Way to Do Masked Language Model Scoring”, ACL, 2023. https://aclanthology.org/2023.acl-short.80/