Deep DiveFerrando·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 직접 실행

Transformer 안에서는 무엇이 흐르는가 — 내부 작동 Primer

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을 직접 실행해 관찰한다.

4단계 첫 번째 논문. 이 글은 Javier Ferrando, Gabriele Sarti, Arianna Bisazza, Marta R. Costa-jussà의 A Primer on the Inner Workings of Transformer-based Language Models 원문을 직접 읽고 썼다. 이 글이 확인한 판본은 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절

질문대표 방법말할 수 있는 것말하면 안 되는 것
어떤 입력이 민감한가gradient, perturbation작은 변화에 score가 얼마나 변하는가그 token만이 원인이다
어떤 component가 logit에 더했나DLA(Direct Logit Attribution, 직접 logit 기여)linear projection 전 직접 기여downstream 비선형 효과까지 전부다
바꾸면 output이 바뀌나activation patching선택한 intervention의 counterfactual 효과자연 언어 세계의 원인
정보가 vector에 있는가probelabel을 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을 확률 분포로 바꾼다.

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

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

선행 개념 — 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절

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절

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

activation patching

target prompt x와 정보 하나만 다른 source prompt 를 준비한다. 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절

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 흐름을 숫자로 확인하는 것이다.

# 전체 실행 파일 경로
# /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

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

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가 높다는 것보다 FranceItaly보다 왜 높은지 logit difference를 보면 문법·빈도·의미 요인을 덜 섞는다.

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

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

목표첫 선택다음 검증
특정 답에 영향 준 input 찾기contrastive gradient 또는 perturbation자연스러운 counterfactual과 faithfulness
특정 head·FFN의 score 기여DLAactivation patching
사실 지식 위치 가설clean/corrupted activation patching여러 paraphrase·layer·seed에서 재검증
표현에 feature 존재 여부simple probe와 control tasksubspace intervention
feature를 더 작은 단위로 보기SAEreconstruction, sparsity, causal effect
전체 model debuggingoutput 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차 자료

직접 실행 기록

  • 환경 — 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을 검증한 실험이 아니다.
대화

댓글

0
댓글을 불러오는 중입니다.