---
title: "Transformer 안에서는 무엇이 흐르는가 — 내부 작동 Primer"
slug: "a-primer-on-the-inner-workings-of-transformer-based-language-models-deep-dive"
category: "AI / LLM"
topic: "ai-llm"
subtopic: "ml-foundations"
tags: ["Transformer","Mechanistic Interpretability","Residual Stream","Activation Patching","Probing","Sparse Autoencoder","LLM","Paper Review"]
status: "published"
created: "2026-07-24"
updated: "2026-07-24"
summary: "Ferrando 외의 2024 Transformer 내부 작동 primer를 기준으로 decoder-only LLM의 residual stream·attention QK/OV 회로·FFN·unembedding과, input attribution·direct logit attribution·activation patching·probe·sparse autoencoder의 증거 범위를 12살 독자가 구분하도록 설명한다. Python 3.9.6 순수 표준 라이브러리로 작은 1-layer causal Transformer의 attention write·FFN write·residual·logit contribution·activation patching을 직접 실행해 관찰한다."
kind: "Deep Dive"
evidence: "Ferrando·Sarti·Bisazza·Costa-jussà arXiv v3 원문 Section 2–6·equations 직접 확인, Transformer 원 논문과 primer가 인용한 해석 방법의 원전 링크 확인, Python 3.9.6 표준 라이브러리로 causal attention·residual addition·FFN·unembedding·DLA·activation patching toy forward pass 직접 실행"
series: "LLM 시스템 지도 — 4단계 내부 구조와 해석"
---

> **4단계 첫 번째 논문.** 이 글은 Javier Ferrando, Gabriele Sarti, Arianna Bisazza, Marta R. Costa-jussà의 [A Primer on the Inner Workings of Transformer-based Language Models 원문](https://arxiv.org/abs/2405.00208)을 직접 읽고 썼다. 이 글이 확인한 판본은 arXiv v3, 2024-10-13이며 PDF SHA-256은 `830f8531119eb3e47869a6104969fa9a4087b6bffe57196f1a0e1bf02666044f`다. Primer는 decoder-only Transformer(디코더 전용 트랜스포머)의 **내부 벡터와 component를 관찰하고, 특정 예측에 실제로 얼마나 영향을 주는지 실험으로 묻는 해석 연구의 지도**다.

## 이 글에서 얻을 답과 범위

“LLM이 왜 이 답을 냈나”에는 서로 다른 질문이 섞여 있다.

1. 어느 input token이 결과와 함께 변했는가.
2. 어느 layer·head·FFN(Feed-Forward Network, 피드포워드 네트워크)이 output logit을 밀었는가.
3. 그 component를 다른 activation으로 바꾸면 결과가 실제로 바뀌는가.
4. model 내부 vector에 어떤 정보가 **있기만** 한가, 아니면 prediction에 **쓰이는가**.
5. 여러 component가 함께 푸는 작은 algorithm을 circuit(회로)라고 부를 근거가 있는가.

이 글은 이 다섯 질문을 섞지 않게 한다. 범위는 GPT-like auto-regressive(자기회귀) decoder-only language model(언어 모델)과 primer의 Section 2–6이다. 이 글은 특정 상용 LLM의 비공개 weight를 해석하지 않으며, 작은 실행 예제도 학습된 model의 의미 있는 circuit을 발견했다는 증거가 아니다.

### 한 문장 답

> **Transformer는 token vector를 residual stream(잔차 흐름)에 계속 더해 다음 token score를 만들고, interpretability(해석 가능성)는 그 덧셈을 관찰·대조·개입해 “무엇이 영향을 주었는가”를 검증하는 일이다. attention weight만 보는 것은 답이 아니다.**

## 왜 필요한가 — 출력 문장만으로는 원인을 구분할 수 없다

LLM이 `Paris is in` 뒤에 `France`를 높게 점수 매겼다고 하자. `France`가 training data에 많아서인지, `Paris` 위치를 attention head가 읽어서인지, FFN이 사실 지식을 꺼내서인지, 여러 component가 합친 결과인지 output만 보고는 모른다. 그럴듯한 자연어 설명은 model의 계산 증거가 아니다.

안전·편향·hallucination(환각) debugging(디버깅)에서도 이 구별이 필요하다. “이 token에 attention이 컸다”는 **관찰**이고, 그 head output을 바꾸었을 때 answer가 변했다는 것은 제한된 실험 안에서의 **인과 개입 증거**다. Primer는 해석 방법을 behavior localization(행동 위치 찾기)과 information decoding(정보 해독)으로 나눈다.[Primer 1절](https://arxiv.org/pdf/2405.00208)

| 질문 | 대표 방법 | 말할 수 있는 것 | 말하면 안 되는 것 |
| --- | --- | --- | --- |
| 어떤 입력이 민감한가 | gradient, perturbation | 작은 변화에 score가 얼마나 변하는가 | 그 token만이 원인이다 |
| 어떤 component가 logit에 더했나 | DLA(Direct Logit Attribution, 직접 logit 기여) | linear projection 전 직접 기여 | downstream 비선형 효과까지 전부다 |
| 바꾸면 output이 바뀌나 | activation patching | 선택한 intervention의 counterfactual 효과 | 자연 언어 세계의 원인 |
| 정보가 vector에 있는가 | probe | label을 decode할 상관 정보 | model이 그 정보를 사용한다 |

## 무엇인가 — decoder-only Transformer를 residual stream으로 보기

### token 확률의 출발점

token sequence를 `(t_1, …, t_n)`이라 쓰면 자기회귀 LM은 다음 token 조건부 확률을 곱해 문장 확률을 만든다.

\[
P(t_1,\dots,t_n)=P(t_1)\prod_{i=1}^{n-1}P(t_{i+1}\mid t_1,\dots,t_i)
\tag{1}
\]

각 token id는 embedding matrix(임베딩 행렬) `W_E∈R^{|V|×d}`의 한 행을 골라 길이 `d` vector가 된다. `|V|`는 vocabulary size, `d`는 hidden dimension이다. Decoder-only의 causal mask(인과 마스크)는 위치 `i`가 미래 `i+1` 이후를 읽지 못하게 한다.

Residual stream은 각 위치의 길이 `d` vector가 흐르는 누적 장부다. layer마다 attention block과 FFN block이 만든 update를 **교체하지 않고 더한다.** 마지막 vector에 unembedding matrix(언임베딩 행렬) `W_U∈R^{d×|V|}`를 곱하면 vocabulary의 raw score인 logit이 된다. softmax(소프트맥스)가 logit을 확률 분포로 바꾼다.

```text
token id → embedding + position 정보
  → residual stream
  → attention이 읽어 온 write를 더함
  → FFN write를 더함
  → 다음 layer 반복
  → W_U로 vocabulary logit
  → softmax와 sampling
```

이 관점의 핵심은 “각 component가 같은 vector 장부에 무엇을 더했는가”다. 원 Transformer 구조 자체는 [Vaswani 외 원 논문](https://arxiv.org/abs/1706.03762), residual stream 방식의 notation과 해석 지도는 [Primer 2절](https://arxiv.org/pdf/2405.00208)에서 확인했다.

## 선행 개념 — QK는 어디를 읽을지, OV는 무엇을 쓸지 정한다

### attention head 한 개

layer `l`, head `h`, 현재 위치 `i`에서 query, key, value는 residual vector에 matrix를 곱해 만든다.

\[
a_i^{l,h}=\operatorname{softmax}\left(
\frac{x_i^{l-1}W_Q^{l,h}(X_{\le i}^{l-1}W_K^{l,h})^T}{\sqrt{d_h}}\right)
\tag{2}
\]

`a_i`는 과거 각 위치에 대한 읽기 비율이다. `W_QW_K^T`를 QK circuit(질의-키 회로)이라 부른다. 그러나 attention weight가 0.9라고 해서 영향도 0.9는 아니다. 실제 write는 value와 output projection까지 거친다.

\[
\operatorname{Attn}^{l,h}(X_{\le i})=
\sum_{j\le i}a_{i,j}^{l,h}x_j^{l-1}W_V^{l,h}W_O^{l,h}
\tag{3}
\]

`W_VW_O`를 OV circuit(값-출력 회로)이라 한다. QK는 **어디를 읽을지**, OV는 **읽은 vector를 현재 residual에 무엇으로 쓸지**를 정한다. 모든 head write를 더한 뒤 residual에 더한다.

\[
x_i^{mid,l}=x_i^{l-1}+\sum_h\operatorname{Attn}^{l,h}(X_{\le i})
\tag{4}
\]

### FFN은 위치마다 작동하는 비선형 writer다

FFN은 각 position에서 같은 두 matrix와 activation function을 쓴다.

\[
\operatorname{FFN}^l(x_i^{mid,l})=g(x_i^{mid,l}W_{in}^l)W_{out}^l
\tag{5}
\]

그리고 다시 더한다.

\[
x_i^l=x_i^{mid,l}+\operatorname{FFN}^l(x_i^{mid,l})
\tag{6}
\]

Primer는 FFN의 input columns를 pattern detector처럼, output rows를 activation에 따라 residual에 쓰는 value처럼 보는 key-value memory(키-값 메모리) 관점을 소개한다. 이는 유용한 해석이지만 모든 FFN neuron이 한 개의 사람 언어 개념이라는 보장은 아니다.[Primer 2.1.3절](https://arxiv.org/pdf/2405.00208)

### LayerNorm은 생략해도 되는 장식이 아니다

LayerNorm(Layer Normalization, 층 정규화)은 vector의 평균과 크기를 조절해 deep network 학습을 안정화한다. modern pre-norm Transformer는 block **앞**에서 정규화하는 경우가 많으며, Llama 계열은 mean subtraction을 뺀 RMSNorm(Root Mean Square Normalization, 제곱평균제곱근 정규화)을 쓴다. 이 글은 이미 LayerNorm deep dive에서 다룬 수식을 반복하지 않는다. 해석할 때는 LayerNorm이 component output과 logit 사이의 선형성을 깨거나 재배치한다는 점을 포함해야 한다.

## 밑바닥 원리 — logit을 component의 덧셈으로 분해하기

마지막 residual `x_n^L`의 token `w` score는 `x_n^LW_U^{(w)}`다. 여기서 `W_U^{(w)}`는 unembedding matrix의 w번째 열이다. residual이 input, attention writes, FFN writes의 합이므로, LayerNorm을 고정 또는 fold한 해석 범위에서는 score도 각 write의 projection 합으로 분해된다.

\[
\operatorname{logit}_w=
\left(x_n^0+\sum_{l,h}\operatorname{Attn}^{l,h}+\sum_l\operatorname{FFN}^l\right)W_U^{(w)}
\tag{7}
\]

여기서 component `c`의 DLA는 다음이다.

\[
\operatorname{DLA}_{w\leftarrow c}=f^c(x)W_U^{(w)}
\tag{8}
\]

양수면 `c`가 token `w`의 raw score를 올렸고 음수면 내렸다. 하지만 softmax는 모든 logit의 상대 차이를 쓰고, 다음 block은 비선형 FFN으로 이전 write를 바꿀 수 있다. 따라서 DLA는 **그 지점의 직접 projection**이지 전체 causal effect가 아니다. Primer도 logit의 절대 scale과 softmax shift invariance를 주의한다.[Primer 3.2.1절](https://arxiv.org/pdf/2405.00208)

## 내부 구조와 실제 실행 흐름 — 관찰에서 인과 실험으로

### activation patching

target prompt `x`와 정보 하나만 다른 source prompt `x̃`를 준비한다. target forward pass 중 component activation `f^c(x)`를 source의 `f^c(x̃)`로 교체하고 output 차이를 잰다.

\[
A_{\mathrm{Patch}}=\operatorname{diff}\left(f(x),f\left(x\mid do(f^c(x)=\tilde h)\right)\right)
\tag{9}
\]

`diff`는 logit difference, probability difference, KL divergence(Kullback–Leibler 발산) 등이 될 수 있다. 이 방법은 “head가 attention weight를 크게 주었다”보다 강한 증거다. 하지만 zero vector나 noise를 넣으면 model이 학습 중 본 적 없는 activation distribution으로 나갈 수 있고, downstream component가 고장 난 write를 보정하는 self-repair(자기 복구)를 보일 수 있다. template, source/target pair, patch metric을 같이 공개해야 한다.[Primer 3.2.2–3.2.3절](https://arxiv.org/pdf/2405.00208)

### probe와 SAE가 말하는 범위

Probe(프로브)는 frozen activation에서 label을 맞히는 작은 supervised classifier다. 높은 probe accuracy는 “이 vector에 label과 상관된 정보를 decode할 수 있다”는 증거일 뿐, original model이 그 정보를 사용했다는 증거는 아니다. Probe가 너무 복잡하면 model 대신 probe가 task를 배운다.

SAE(Sparse Autoencoder, 희소 오토인코더)는 dense activation을 더 넓지만 대부분 0인 feature activation으로 encode한 뒤 원 activation을 복원한다. 목표는 one neuron equals one concept이라는 약한 가정 대신, feature direction을 더 분리해 보는 것이다. reconstruction error, sparsity, downstream causal intervention을 함께 봐야 한다. “해석 가능한 label 하나를 붙였다”만으로 monosemanticity(단의미성)를 증명할 수 없다.

### circuit은 edge까지 확인해야 한다

회로는 task에 필요한 node와 edge의 작은 subgraph다. Head A가 중요하고 Head B도 중요하다고 해서 A→B route가 증명되지는 않는다. Edge patching과 path patching은 sender write가 receiver input으로 가는 특정 경로만 바꿔 direct·indirect effect를 나누려 한다. 큰 model에서는 모든 edge에 forward pass를 반복하기 어려워, gradient 근사 방법은 빠르지만 faithfulness(충실도·근거성) 검증이 필요하다.

## 직접 검증과 재현 — 학습되지 않은 작은 Transformer에서 흐름 보기

**직접 실행 확인**이다. 2026-07-24, Python 3.9.6 표준 라이브러리만 사용해 `d=2`, 한 attention head, 한 FFN, vocabulary 3개의 causal decoder를 만들었다. weight는 사람이 정한 숫자이며 학습된 언어 model이 아니다. 목적은 Primer 식 (3)–(9)의 vector 흐름을 숫자로 확인하는 것이다.

```python
# 전체 실행 파일 경로
# /tmp/transformer-primer-research/verify_toy_transformer.py

target = [[1.0, 0.0], [0.0, 1.0], [1.0, 1.0]]
t = forward(target)

print(t["weights"])     # causal attention이 A, B, C를 읽는 비율
print(t["attention"])   # attention write
print(t["middle"])      # input residual + attention write
print(t["ffn"])         # FFN write
print(t["logits"])      # final residual × W_U
```

실제 전체 실행은 다음을 출력했다.

```text
attention weights for C reading A,B,C: ['0.248255', '0.248255', '0.503490']
attention write: ['0.751745', '0.751745']
residual after attention: ['1.751745', '1.751745']
FFN neuron activations: ['1.751745', '0.000000']
FFN write: ['0.875872', '-0.875872']
final residual: ['2.627617', '0.875872']
logits A,B,C: ['2.627617', '0.875872', '-3.503490']
DLA for token C from input residual: -2.000000
DLA for token C from attention write: -1.503490
DLA for token C from FFN write: 0.000000
```

마지막 위치 C는 causal mask 때문에 A·B·C만 읽었고 attention weights 합은 1이다. `W_U[:,C]=[-1,-1]`이므로 attention write의 DLA는 `-(0.751745+0.751745)=-1.503490`이다. 실행은 이 값과 일치한다. FFN은 final residual을 크게 바꾸지만 이 toy `W_U`에서는 C 방향과 dot product가 0이다. **FFN이 0의 DLA를 가졌다는 것은 FFN이 쓸모없다는 말이 아니라, 이 output token에 대한 직접 projection이 0이라는 뜻**이다.

source prompt의 attention write `[0.197776, 0.802224]`를 target의 attention write 자리에 patch하자 C logit은 `-3.503490`에서 `-3.000000`으로 변했다. 이것은 식 (9)의 개입을 계산한 작은 예다. 실제 model에서는 FFN을 다시 계산하는 clean·corrupted run, patch site, metric, batch aggregation을 명시해야 한다.

## 성능과 트레이드오프 — 더 많은 내부 관측은 무료가 아니다

| 방법 | 계산 비용의 감각 | 강점 | 대표 함정 |
| --- | --- | --- |
| attention weight 시각화 | forward pass 하나 | 빠른 가설 생성 | value·OV와 output 영향을 무시 |
| DLA | activation 저장과 projection | component별 token score 분해 | nonlinear downstream effect 누락 |
| gradient attribution | forward와 backward | 많은 component를 한 번에 ranking | saturation, 근사, 상관 해석 |
| activation patching | site·example마다 추가 forward | counterfactual output 변화 | OOD activation, self-repair, template 의존 |
| probe | label data와 classifier 학습 | representation에 정보 존재 확인 | model 사용 여부를 보장 못 함 |
| SAE | 대량 activation 수집과 별도 학습 | feature-level 가설 | reconstruction·sparsity·인과 검증이 모두 필요 |

큰 model에는 activation tensor가 크다. `batch×layer×position×d`를 저장하면 GPU memory가 빠르게 찬다. 운영 분석에서는 task와 token position을 좁히고, activation cache dtype·device·샘플 수·seed·metric을 기록해야 한다. 성능과 해석이 모두 좋아 보이는 한 개 prompt screenshot은 benchmark가 아니다.

## 실패와 운영 기준 — 예쁜 heatmap을 증거로 착각하지 않기

1. **attention weight를 explanation으로 선언하지 않는다.** weight는 value와 OV transformation 뒤의 write 크기를 포함하지 않는다.
2. **probe accuracy를 causal use라고 부르지 않는다.** 필요한 경우 representation patch 또는 feature ablation으로 후속 검증한다.
3. **patch baseline을 고정한다.** zero, mean, resample은 서로 다른 intervention이며 결과가 달라질 수 있다.
4. **model revision을 고정한다.** tokenizer, checkpoint hash, framework version, layer/head indexing convention이 바뀌면 activation 비교가 무의미하다.
5. **평가 대상을 contrastive하게 적는다.** `France`가 높다는 것보다 `France`가 `Italy`보다 왜 높은지 logit difference를 보면 문법·빈도·의미 요인을 덜 섞는다.

해석 결과는 RAG나 agent의 production guardrail을 대체하지 않는다. 출처 검증, tool permission, retrieval evaluation, output schema validation은 model 내부에서 “안전 feature”를 찾았다는 주장과 독립적으로 필요하다.

## 대안과 선택 기준 — 질문에 맞는 관측기를 고른다

| 목표 | 첫 선택 | 다음 검증 |
| --- | --- | --- |
| 특정 답에 영향 준 input 찾기 | contrastive gradient 또는 perturbation | 자연스러운 counterfactual과 faithfulness |
| 특정 head·FFN의 score 기여 | DLA | activation patching |
| 사실 지식 위치 가설 | clean/corrupted activation patching | 여러 paraphrase·layer·seed에서 재검증 |
| 표현에 feature 존재 여부 | simple probe와 control task | subspace intervention |
| feature를 더 작은 단위로 보기 | SAE | reconstruction, sparsity, causal effect |
| 전체 model debugging | output evaluation과 tracing | 내부 해석은 보조 증거로 사용 |

Primer는 완성된 만능 설명법을 제시하지 않는다. methods가 무엇을 측정하고 어떤 가정을 넣는지 지도를 준다. “이 method가 더 멋져 보인다”가 아니라 “내 질문이 상관, 직접 logit 기여, counterfactual effect 중 무엇을 요구하는가”로 선택해야 한다.

## 흔한 오해와 최초 질문에 대한 답

### LLM은 layer마다 앞 결과를 덮어쓰나

아니다. residual stream 관점에서는 attention과 FFN update가 기본 vector에 계속 더해진다. 그래서 앞 layer의 정보가 다음 layer와 output에 직선 경로를 가질 수 있고, component별 logit decomposition이 가능해진다.

### attention map이 진한 곳이 모델의 이유인가

아니다. attention map은 read 비율이다. 어떤 value를 읽고 OV가 무엇을 썼으며 그 write가 output logit과 alignment되는지까지 봐야 한다. causal question이면 patch해야 한다.

### activation patching은 절대적 인과 증명인가

아니다. 특정 input pair·patch source·metric·model 내부 graph에서의 counterfactual test다. distribution 밖 activation과 downstream self-repair 때문에 과도한 일반화가 위험하다.

### 이 논문을 BPE·Transformer 다음에 읽는 이유는 무엇인가

BPE는 text를 id로 만들고, Transformer는 id vector가 다음 token probability가 되는 계산을 만든다. 이 Primer는 그 계산 중 어느 component가 어떤 정보를 읽고 쓰는지 검증하는 문법을 준다. 이후 induction head, IOI circuit, sparse autoencoder 논문을 읽을 때 필요한 공통 지도다.

## 출처 및 검증 경로

### 1차 자료

- Ferrando, Sarti, Bisazza, Costa-jussà. [A Primer on the Inner Workings of Transformer-based Language Models — arXiv v3](https://arxiv.org/abs/2405.00208) — Section 2–6과 Equations 1–21을 직접 확인했다.
- Vaswani 외. [Attention Is All You Need](https://arxiv.org/abs/1706.03762) — causal self-attention의 원 architecture 근거다.
- Elhage 외. [A Mathematical Framework for Transformer Circuits](https://transformer-circuits.pub/2021/framework/index.html) — residual stream, QK·OV circuit 관점의 원전이다.

### 직접 실행 기록

- 환경 — macOS, Python 3.9.6, 외부 numerical library 없음.
- 파일 — `/tmp/transformer-primer-research/verify_toy_transformer.py`.
- 검증 — causal attention weight 합 1, `input + attention + FFN`과 final residual의 일치, `final residual×W_U`와 logit의 일치, source attention write patch 뒤 C logit 변화.
- 한계 — 사람이 지정한 작은 weight의 산술 검증이다. 실제 language feature, head circuit, safety claim을 검증한 실험이 아니다.
