신경망은 이미 깨끗하다: 엉킨 줄 알았던 뉴런 다시 읽기

딥러닝 모델 속을 뜯어보는 기계적 해석가능성(mechanistic interpretability) 분야에는 오래된 전제가 하나 있다. "신경망은 엉켜 있다"는 것이다. 뉴런 하나가 서로 상관없는 여러 개념에 동시에 반응한다. 그러니 뉴런을 그대로 들여다봐야 소용없고, 희소 오토인코더(SAE) 같은 별도 모델로 먼저 풀어내야 한다는 생각이다. 지난 몇 년 동안 이 분야의 큰 흐름이 이 전제 위에 쌓였다.
그런데 이 전제를 세운 쪽에 서 있던 사람이 직접 고쳐 쓴 글을 냈다. Goodfire의 Nick Cammarata가 쓴 「Neural Networks Are Already Clean」이다. 필자는 OpenAI 해석가능성 팀에서 Zoom In, Multimodal Neurons 연구에 참여한 사람이다. 글의 첫 문장은 이렇다. "I think I have good news about the nature of neural networks." 해석가능성 쪽에서 '좋은 소식'이라는 말을 들을 일은 별로 없다. 그래서 끝까지 읽었고, 개발자 입장에서도 정리해 둘 만하다고 봤다.
중첩 가설은 무엇이었나
중첩(superposition) 가설의 내용은 이렇다. 표현해야 할 개념은 많은데 뉴런이 모자라면, 신경망은 관련 있는 것끼리 묶는 일을 그만둔다. 대신 서로 간섭할 일이 없는 무관한 것들을 한 뉴런에 접어 넣는다. 옷장이 좁으니 양말이랑 겨울 코트를 한 서랍에 넣는 식이다. 둘을 같이 꺼낼 일이 없으니 섞여 있어도 크게 문제가 안 된다. 수식으로 쓰면 $d$차원 공간에 $n > d$개의 특징 방향 $f_i$를 거의 직교하게 넣는 것이다.
$$ |\langle f_i, f_j \rangle| \approx 0 \quad (i \neq j), \qquad n \gg d $$
정말 이렇게 접혀 있다면, 어떤 뉴런이 무엇과 무엇을 함께 묶었는지 봐도 배울 게 거의 없다. 서랍 하나에 양말과 코트가 같이 있다고 해서 둘 사이에 무슨 관계가 있는 건 아니니까. 그래서 지금까지는 SAE로 활성화 $x$를 더 넓은 희소 공간에 다시 펼친 다음, 펼쳐진 쪽을 연구하는 게 표준이었다.
$$ z = \mathrm{ReLU}(W_{enc}\,x + b_{enc}), \quad \hat{x} = W_{dec}\,z + b_{dec}, \quad \mathcal{L} = \|x - \hat{x}\|^2 + \lambda \|z\|_1 $$
필자는 이 분해를 먼저 할 필요가 없다고 주장한다. 신경망이 스스로 만든 뉴런과 회로가 이미 읽을 수 있는 부품이라는 것이다.
핵심 근거 세 가지
1. InceptionV1의 마지막 층은 중첩이 아니라 학습 실패였다. 초기 연구에서 InceptionV1 마지막 층에는 해석 가능한 뉴런이 거의 없었다. 필자는 그 원인을 두 가지로 본다. 아키텍처 문제로 뒤쪽 층이 넘쳤고, 약한 도구가 그 문제를 더 키웠다. 그래서 모델 크기와 학습 데이터는 그대로 두고, 깊은 층 학습을 돕는 평범한 개선만 넣어 봤다. 그랬더니 그 층 뉴런의 99~100%가 쉽게 해석됐다고 한다. 크기를 약 300배 범위로 바꿔 가며 학습해도 결과는 같았다. 작은 모델도 무관한 것을 접지 않았다. 대신 뉴런 하나가 '여러 종류의 차'처럼 더 거친 개념을 맡았고, 모델이 커지면 그 뉴런이 구체적인 차 종류별로 갈라졌다.
2. 대표 사례도 다시 읽혔다. 2019년 Zoom In에서 중첩의 예로 소개된 회로가 있다. 차 특징이 무관한 개 뉴런들로 퍼져 나가는 것처럼 보였던 회로다. 그런데 그 조합을 다시 읽어 내는 하류 뉴런이 없었다. 필자는 이것이 평범한 일반화와 합성이었다고 정정했다. 필자가 아는 한, 같은 모양의 회로가 두 번째로 발표된 적도 없다. 교과서에 실린 대표 예제가 사실 한 번밖에 관측되지 않았던 셈이다.
3. 최신 언어 모델에서 나온 숫자가 다르다. 2023년에 Anthropic의 Towards Monosemanticity는 1층짜리 모델에서 중앙값 뉴런에 14점 만점에 0점을 줬다. OpenAI의 자동 해석 프로젝트는 가장 너그러운 기준을 적용해도 약 1.7%만 해석 가능하다고 봤다. 이번에 Qwen3-32B를 예비 감사한 결과는 이렇다.
구분비율(뉴런 극 기준)주된 일 하나(작은 관련 가지 포함)약 90%서로 관련된 일 둘약 7%아직 이해 못 함약 2~4%
덴스 모델과 MoE 모델이 비슷했고, 수조 파라미터 규모의 Kimi K3에서도 비슷했다고 한다. 다만 필자는 이 숫자에 스스로 단서를 달았다. 약한 활성화를 어디까지 셀지, 무엇을 '한 가지'로 볼지에 따라 비율이 달라진다는 것이다.
재귀적 일반화: 접은 게 아니라 가지를 뻗었다
그렇다면 아직 남아 있는 '다의적으로 보이는' 뉴런은 뭘까. 필자는 이것을 재귀적 일반화(recursive generalization)라고 부른다. 예시가 직관적이다. "iy"를 감지하던 뉴런이 학습하면서 "diy"로 넓어지고, 다시 "do it yourself"로 넓어진다. 철자 공부하던 뉴런이 정신 차려 보니 공구함을 들고 있는 꼴이다. 마지막 표현에는 "iy"라는 글자가 한 자도 없다. 결과만 보면 철자 패턴과 DIY라는 개념, 서로 무관한 두 가지에 반응하는 것처럼 보인다. 하지만 자라 온 과정을 따라가면 나뭇가지처럼 이어진 하나의 일이다.
두 설명은 정반대 방향을 가리킨다. 중첩은 무관한 것을 묶고, 일반화는 비슷한 것을 묶는다. 필자는 학습 원리가 결국 하나, 곧 '프랙탈한 일반화'라고 본다. 그렇다면 설명도 프랙탈하게 할 수 있다. 큰 줄기부터 설명하고, 더 궁금하면 가지로 들어가면 된다. 문서를 쓸 때 요약을 먼저 쓰고 세부는 접어 두는 것과 비슷하다.
직접 해 보기: 뉴런 하나의 top-k 문맥 뽑기
"이 뉴런이 정말 한 가지 일만 하는가"는 직접 확인해 볼 수 있다. 아래는 작은 Qwen 모델의 MLP 뉴런 하나에서 활성화가 가장 높은 토큰 문맥을 모으는 예시 코드다. 내가 직접 돌려 보지는 않았으니, 모듈 경로는 모델 구조에 맞는지 확인하고 써야 한다.
# 예시 코드 (직접 실행해 보지 않음)
import torch, heapq
from transformers import AutoTokenizer, AutoModelForCausalLM
name = "Qwen/Qwen3-0.6B"
tok = AutoTokenizer.from_pretrained(name)
model = AutoModelForCausalLM.from_pretrained(name, torch_dtype=torch.float32).eval()
LAYER, NEURON, K = 10, 1234, 20
acts = {}
# SwiGLU MLP에서 down_proj에 들어가는 입력 = act(gate) * up → 이것을 '뉴런 활성화'로 본다
def pre_hook(mod, args):
acts["h"] = args[0][0, :, NEURON].detach()
h = model.model.layers[LAYER].mlp.down_proj.register_forward_pre_hook(pre_hook)
texts = ["Here is a DIY guide to fixing a bike.", "I'd rather do it yourself than pay someone."] # 실제로는 큰 말뭉치
top = [] # (활성화, 문맥) 최소 힙
with torch.no_grad():
for t in texts:
ids = tok(t, return_tensors="pt").input_ids
model(ids)
for i, a in enumerate(acts["h"].tolist()):
ctx = tok.decode(ids[0, max(0, i - 12): i + 1])
item = (a, ctx)
if len(top) < K: heapq.heappush(top, item)
else: heapq.heappushpop(top, item)
h.remove()
for a, ctx in sorted(top, reverse=True):
print(f"{a:+.3f} | {ctx!r}")
SwiGLU 뉴런은 음수 쪽으로도 크게 활성화된다. 그래서 양의 방향과 음의 방향은 따로 보는 게 좋다. 필자가 '뉴런 극(pole)' 단위로 센 것도 이 때문이라고 나는 이해했다. 또 top-k만 보면 강한 활성화만 눈에 들어온다. 하위 분위까지 내려가 보면 '관련 가지'가 더 많이 보일 것이다. 필자도 그 임계값에 따라 비율이 달라진다고 직접 밝혔다.
내 생각: 실무에 주는 의미
솔직히 말하면, 나는 "LLM 내부는 원래 읽을 수 없다"는 말을 꽤 당연하게 받아들이고 있었다. 이 글에서 제일 와닿은 건 필자가 짚은 격차의 원인이다. 2023년의 설명 모델은 추측하고 검증하는 루프를 돌리지 못했다. 지표는 맞는 설명보다 활성화를 그럴듯하게 흉내 내는 설명에 점수를 줬다. 연구자들은 어떤 모티프를 기대해야 하는지 몰랐고, 작거나 단순화한 모델을 썼다. 정리하면 신경망이 원래 엉켜 있었다기보다 도구와 평가 지표가 약했다는 얘기다. 코드가 스파게티인 줄 알고 몇 년을 한탄했는데, 알고 보니 문법 하이라이팅이 꺼져 있었던 셈이다. 개발 실무에서도 낯익은 교훈이다. 벤치마크가 잘못되면 시스템은 실제보다 나빠 보이기도 하고 좋아 보이기도 한다.
실무로 옮겨 보면, 뉴런을 직접 읽을 수 있다면 SAE를 따로 학습하는 비용 없이 모델 디버깅이나 안전 점검을 바로 시작할 수 있다. 에이전트가 가설을 세우고 실험하는 루프를 대규모로 돌리는 방식과도 궁합이 좋다. 필자도 글을 이렇게 맺는다. "Maybe there's a bitter lesson for interpretability too: scaling ordinary investigation beats engineering a clever new decomposition."
그렇다고 그대로 받아들이기엔 이르다. Qwen3-32B 결과는 '예비 감사'이고, 자세한 내용을 담을 동반 논문은 아직 나오지 않았다. daily.dev 토론에서도 반응이 갈렸다. 집계로는 긍정 25%, 혼합 45%, 회의 30%였다. 중첩이 확정적으로 반증된 건 아니라는 지적, 'clean'의 정의가 모호하다는 지적이 나왔다. 나도 두 지적에 동의한다. 필자의 주장은 "중첩은 없다"라기보다 "중첩으로 설명하던 대표 증거가 다른 것으로 더 잘 설명된다" 쪽으로 읽는 게 맞다고 본다.
정리
필자는 다의성과 중첩의 대표 증거가 잘못 읽혔다고 주장한다. 그 대부분은 뉴런이 가지를 뻗는 재귀적 일반화라는 것이다.
깊은 층 학습을 돕는 평범한 개선만으로 InceptionV1 마지막 층 뉴런의 99~100%가 해석 가능해졌다.
Qwen3-32B 예비 감사에서 뉴런 극의 약 90%가 주된 일 하나를 가졌다. 단, 임계값에 따라 수치가 달라진다.
SAE로 먼저 분해하지 말고 뉴런과 회로를 직접 보자는 방향 전환을 제안한다. 동반 논문과 반론을 함께 지켜볼 만하다.