Transformer는 어떻게 동작하는가
— 블록 하나를 N번
「Attention Is All You Need」라는 제목 때문에 오해하기 쉽지만, Transformer는 어텐션만으로 된 모델이 아닙니다. 파라미터를 세어 보면 어텐션이 아니라 FFN(위치별 2층 MLP)에 더 많이 들어 있고, 학습이 되느냐 마느냐를 가르는 것은 어텐션이 아니라 잔차 연결과 LayerNorm을 어느 순서로 놓았는가입니다. 어텐션의 내부(Q·K·V, 소프트맥스, 멀티헤드)는 How Attention Works에서 이미 뜯어봤으니, 이 자료는 그 부품을 조립해 만든 블록 하나와 그것을 6번 쌓은 모델 전체를 다룹니다 — 왜 순환을 버렸는지, 입력을 왜 √dmodel로 곱하는지, 65M개의 파라미터가 어디에 있는지, 워밍업 4000스텝이 왜 필수였는지, 그리고 생성할 때 KV 캐시가 무엇을 아끼는지까지 브라우저에서 직접 계산해 봅니다.
§1 왜 순환을 버렸는가 — 경로 길이와 병렬성
2017년까지 기계 번역의 표준은 순환 신경망 + 어텐션이었습니다. 어텐션은 이미 있었습니다 — 논문의 기여는 어텐션을 발명한 것이 아니라 순환과 합성곱을 전부 걷어내고 어텐션만 남겨도 되더라는 것입니다(논문 초록). 왜 걷어내고 싶었을까요? 순환의 정의 한 줄 때문입니다.
GPU는 행렬 곱 수천 개를 동시에 돌리는 장치인데, 순환층은 그 병렬성을 쓸 수가 없습니다. 문장 안의 토큰끼리는 순차적으로 지나가야 하고(논문 3.1절의 표현으로 "sequential operations"), 배치 차원에서만 병렬화가 됩니다. 문장이 길어지면 메모리 제약 때문에 배치도 줄어듭니다.
두 번째 문제는 경로 길이(path length)입니다. 문장의 1번 토큰이 50번 토큰에 영향을 주려면 순환층에서는 신호가 49번의 곱셈을 거쳐야 합니다. 기울기는 그 길을 되돌아오며 소멸하거나 폭발합니다 (How LSTM Works에서 본 바로 그 문제). 셀프 어텐션에서는 모든 토큰이 한 번의 행렬 곱으로 서로에게 직접 연결되므로 경로 길이가 1입니다.
논문 표 1은 이 세 가지(층당 복잡도 · 순차 연산 수 · 최대 경로 길이)를 층 종류별로 비교합니다. 슬라이더로 직접 숫자를 넣어 봅시다.
| 층 종류 | 층당 복잡도 | 연산량 (실제 값) | 순차 연산 | 최대 경로 길이 |
|---|
직접 움직여 보면 논문 3.5절의 주장이 눈에 보입니다 —
셀프 어텐션이 순환보다 싼 조건은 n < d 하나뿐입니다.
n²·d 대 n·d²를 n·d로 나누면 남는 것이 n 대 d이니까요.
그리고 논문이 말하듯 기계 번역에서 쓰는 word-piece/BPE 문장은 보통 n이 수십, d는 512라
셀프 어텐션 쪽이 유리합니다. 기본값(n=70, d=512)에서 순환층은 셀프 어텐션의 7배를 씁니다.
n² 한 항입니다 —
논문도 이미 대비책으로 제한된 셀프 어텐션(반경 r 이웃만 보기, 복잡도 r·n·d)을 3.5절에 적어 뒀습니다.
대신 경로 길이가 1에서 n/r로 늘어납니다. 공짜는 없습니다.
세 번째 열 순차 연산도 같이 보세요. 셀프 어텐션·합성곱은 O(1),
순환만 O(n)입니다. 이것이 논문이 8개 P100 GPU로 base 모델을
12시간에 학습시킬 수 있었던 이유입니다. 같은 시기 최고 성능 모델들은 며칠에서 몇 주가 걸렸습니다.
§2 블록 하나의 해부 — 한 토큰이 지나가는 길
Transformer의 전체 구조는 사실 짧습니다. 블록 하나를 정의하고 N번 쌓은 것이 전부입니다. 인코더 블록은 두 개의 서브층, 디코더 블록은 세 개의 서브층으로 되어 있습니다.
인코더 블록 ×6 디코더 블록 ×6
┌──────────────────────┐ ┌──────────────────────┐
│ ① 멀티헤드 셀프 어텐션 │ │ ① 마스크된 셀프 어텐션 │
│ + 잔차 → LayerNorm │ │ + 잔차 → LayerNorm │
│ │ │ ② 교차 어텐션 (인코더→) │
│ │ │ + 잔차 → LayerNorm │
│ ② FFN (2048 → 512) │ │ ③ FFN (2048 → 512) │
│ + 잔차 → LayerNorm │ │ + 잔차 → LayerNorm │
└──────────────────────┘ └──────────────────────┘
모든 서브층은 예외 없이 같은 껍질을 쓰고 있습니다. 논문 3.1절의 식 그대로입니다.
"모든 서브층의 출력이 512"라는 제약은 그냥 디자인 취향이 아닙니다.
잔차 연결 x + 가 성립하려면 더할 수 있는 모양이어야 하고,
이 때문에 임베딩 차원부터 어텐션 출력, FFN 출력까지 전부 512로 못이 박힙니다
(FFN 내부만 2048로 부풀었다가 다시 512로 돌아옵니다, §6).
아래에서 토큰 하나가 모델을 통과하는 전 과정을 단계별로 따라가 봅시다. 각 단계의 shape와 그 단계가 쓰는 파라미터 수를 같이 표시합니다.
| 단계 | 연산 | shape | 파라미터 |
|---|
세 가지를 짚어 둡시다.
- 멀티헤드는 파라미터를 늘리지 않습니다. h=8이면 dk=dv=512/8=64입니다
(논문 3.2.2: "we use h = 8 ... dk = dv = dmodel/h = 64").
헤드 수를 바꿔도
WQ·WK·WV·WO는 각각 512×512로 그대로입니다 — 슬라이더로 h를 1에서 16까지 움직여 보세요. 총 파라미터가 한 개도 안 바뀝니다. 논문이 "총 계산 비용은 단일 헤드와 비슷하다"고 쓴 것이 이 뜻입니다. - n(토큰 수)은 파라미터에 등장하지 않습니다. 문장을 길게 만들어 보세요 — shape의 첫 축만 커지고 파라미터는 고정입니다. Transformer가 길이에 대해 가중치를 공유한다는 뜻이고, 그래서 위치 정보를 따로 넣어 줘야 합니다(§3).
- 인코더는 한 번, 디코더는 토큰마다. 학습 때는 정답 문장 전체를 한꺼번에 넣어 병렬로 돌지만, 추론 때는 디코더만 토큰 수만큼 반복합니다(§8).
§3 입력을 만드는 법 — √dmodel과 위치 인코딩
순환을 걷어낸 대가가 여기서 청구됩니다. 셀프 어텐션은 집합 연산입니다 —
입력 토큰의 순서를 섞어도 출력이 같은 순서로 섞여 나올 뿐, 값은 그대로입니다.
"개가 사람을 물었다"와 "사람이 개를 물었다"를 구분할 방법이 모델 안에 전혀 없습니다.
논문 3.5절이 이를 두고 "모델에 순환도 합성곱도 없으니 시퀀스의 순서를 쓰려면 위치 정보를 주입해야 한다"고 씁니다.
논문의 답은 사인·코사인 함수입니다. 학습되는 파라미터가 아니라 고정된 수식입니다.
이 512차원 벡터를 임베딩에 더합니다(이어 붙이는 게 아닙니다). 그런데 더하려면 두 벡터의 크기가 비슷해야 합니다 — 한쪽이 훨씬 크면 다른 쪽은 반올림 오차처럼 묻힙니다. 여기서 논문 3.4절의 마지막 한 문장이 등장합니다.
"In the embedding layers, we multiply those weights by √dmodel."
— 임베딩 층에서는 가중치에 √dmodel을 곱한다.
왜 하필 √dmodel일까요? 두 벡터의 길이를 실제로 재 보면 답이 나옵니다.
숫자가 예쁘게 떨어집니다. 위치 인코딩 벡터의 길이는 d에 따라 정확히 √(d/2)입니다 —
차원이 짝을 이뤄 sin²+cos²=1이 되고, 그런 짝이 d/2개이기 때문입니다.
d=512면 정확히 16입니다(위치와 무관하게 언제나).
한편 1/√d로 초기화한 임베딩의 길이는 약 1입니다.
곱하지 않으면 16 대 1 — 위치가 단어를 완전히 덮어씁니다.
√512 = 22.6을 곱하면 22.6 대 16, 비로소 같은 저울에 올라갑니다.
왜 사인·코사인인가 — 상대 위치가 선형 변환이 된다
학습되는 위치 임베딩을 쓸 수도 있습니다(논문도 해 봤고, 표 3의 (E)행에 결과가 있습니다 — BLEU 25.7 대 25.8로 거의 같습니다). 그래도 사인파를 고른 이유를 논문은 이렇게 적습니다: "어떤 고정된 오프셋 k에 대해서도 PEpos+k는 PEpos의 선형 함수로 표현된다" — 삼각함수 덧셈정리 때문입니다. 그래서 모델이 "몇 번째인가"가 아니라 "몇 칸 떨어졌는가"를 배우기 쉽고, 학습 때 본 적 없는 긴 문장으로도 외삽이 가능합니다.
말보다 그림이 빠릅니다. 아래 왼쪽은 위치 인코딩 행렬 자체이고, 오른쪽은 두 위치의 인코딩 벡터를 내적한 값입니다.
내적 곡선은 기준 위치에서 최댓값 d/2를 찍고 멀어질수록 줄어듭니다 — 그리고 기준을 어디로 옮겨도
모양이 그대로 평행이동합니다. 즉 이 내적은 pos가 아니라 |pos − pos′|의 함수입니다.
어텐션 점수가 q·k 내적으로 계산된다는 것을 떠올리면, 위치 인코딩이 어떤 경로로
"거리에 대한 감각"을 어텐션에 주입하는지 보입니다.
밑(base)을 10000에서 10으로 줄여 보세요. 파장이 전부 짧아져서 먼 위치끼리 구분이 안 되고 내적 곡선이 요동칩니다. 반대로 키우면 느려집니다. 10000은 그 사이에서 고른 값입니다 (오늘날의 RoPE 확장 기법들이 조절하는 것도 바로 이 밑입니다).
§4 어텐션이 쓰이는 세 군데 — 마스크가 전부를 가른다
멀티헤드 어텐션은 모델 안에 세 군데 등장합니다(논문 3.2.3). 세 곳 모두 코드가 같습니다 — 같은 함수에 다른 것을 넣을 뿐입니다. 무엇이 Q가 되고 무엇이 K·V가 되는가, 그리고 마스크를 씌우는가.
| 위치 | Q는 어디서 | K·V는 어디서 | 마스크 | t번째 행이 보는 범위 |
|---|---|---|---|---|
| ① 인코더 셀프 어텐션 | 인코더 이전 층 | 인코더 이전 층 | 없음 (패딩만) | 입력 문장 전체 |
| ② 디코더 마스크 셀프 어텐션 | 디코더 이전 층 | 디코더 이전 층 | 인과 마스크 | 출력 문장의 1..t |
| ③ 교차 어텐션 | 디코더 이전 층 | 인코더 최종 출력 | 없음 (패딩만) | 입력 문장 전체 |
②의 인과 마스크만 이해하면 나머지는 따라옵니다. 학습할 때 디코더에는 정답 문장이 통째로 들어갑니다 (teacher forcing). 그대로 두면 3번째 단어를 예측하는 자리에서 4번째 단어를 이미 볼 수 있으니, 모델은 아무것도 배우지 않고 정답을 베껴 손실을 0으로 만듭니다. 이것이 라벨 누수입니다. 그래서 소프트맥스 직전에 미래 칸의 점수를 −∞로 덮습니다.
§5 잔차와 LayerNorm — Post-LN vs Pre-LN
논문 3.1절의 식은 LayerNorm(x + Sublayer(x))입니다.
더한 다음에 정규화합니다. 이것을 오늘날 Post-LN이라고 부릅니다.
그런데 2017년 이후에 나온 거의 모든 구현(GPT-2 이후, 요즘의 LLM 전부)은
순서를 바꿔 x + Sublayer(LayerNorm(x)), 즉 Pre-LN을 씁니다.
괄호 위치 하나 옮긴 것이 왜 표준이 바뀔 만한 일이었을까요?
차이는 잔차 고속도로가 끊기는가입니다. Pre-LN에서는 x가 층을 몇 개 지나든 그대로 더해지기만 하니,
기울기가 되돌아올 때 위층에서 아래층까지 변형 없이 도착합니다
(How ResNet Works의 항등 경로와 같은 논리).
Post-LN에서는 그 길목마다 LN이 서 있어 기울기가 층마다 다시 스케일됩니다.
말로 하면 추상적이니 실제로 돌려 봅시다. 아래는 d=64짜리 잔차 스트림에 서브층 (선형 → ReLU → 선형, He 초기화)을 N개 쌓고 브라우저가 직접 순전파시킨 결과입니다. 두 가지를 잽니다 — 잔차 스트림의 크기 ‖xℓ‖와, 각 층의 서브층 출력이 그 스트림을 얼마나 덮어쓰는지를 나타내는 가지/줄기 비율 ‖F(xℓ)‖ / ‖xℓ‖입니다.
N을 키울수록 두 곡선이 뚜렷하게 갈라집니다.
- Post-LN은 스트림 크기가 매 층 √d로 리셋됩니다. LN이 맨 마지막에 있으니 당연합니다. 그런데 바로 그 때문에 가지/줄기 비율이 층을 쌓아도 줄지 않습니다 — 기본값에서 첫 층이든 48번째 층이든 0.7~1.1 근처입니다. 각 층이 잔차 스트림의 일정 비율을 계속 덮어씁니다. 깊이를 늘려도 층 하나의 상대적 영향력이 그대로라는 뜻이고, 그래서 초기 상태가 조금만 어긋나도 위로 갈수록 증폭됩니다.
- Pre-LN은 반대입니다. 스트림은 층마다 더해지며 √N에 비례해 자라는데, 가지 출력은 입력을 먼저 LN으로 눌러 놓고 계산하므로 항상 O(1) 크기입니다. 결과적으로 비율이 1/√ℓ로 떨어집니다 — N=48에서 마지막 층의 비율은 0.17까지 내려갑니다. 깊게 쌓을수록 층 하나하나가 저절로 항등에 가까워집니다. "깊은 Pre-LN은 스스로 안정된다"는 말이 이 곡선입니다.
이 차이가 학습 초기에 무엇을 하는지는 이후 연구가 정리했습니다 — Xiong 외, 「On Layer Normalization in the Transformer Architecture」(ICML 2020)는 초기화 시점의 기울기 크기가 Post-LN에서는 출력층 근처가 깊이와 무관하게 크고, Pre-LN에서는 1/√N로 줄어든다는 것을 보이고, Pre-LN으로 바꾸면 워밍업 단계를 아예 제거할 수 있다는 것을 실험으로 확인합니다.
거꾸로 말하면, 원 논문의 Post-LN은 처음 몇천 스텝이 위태로웠습니다. 논문 5.3절의 워밍업 4000스텝(§7의 데모 8)은 미적 선택이 아니라 Post-LN을 살리기 위한 필수 장치였던 셈입니다. 그래서 이후 표준이 Pre-LN으로 옮겨갔습니다.
Pre-LN에도 대가는 있습니다. 위 왼쪽 차트에서 보듯 잔차 스트림이 계속 자라기만 합니다 —
아무도 정규화해 주지 않으니까요. 그래서 Pre-LN 모델은 마지막 블록 뒤에 LN을 한 번 더 붙입니다
(final_layer_norm). 원 논문에는 없는 층입니다.
§6 FFN과 파라미터 65M — 무게는 어디에 있나
블록의 두 번째 서브층은 이름이 거창하지만(Position-wise Feed-Forward Networks) 내용은 간단합니다 — 토큰마다 독립적으로 적용되는 2층 MLP입니다. 토큰끼리 섞이지 않습니다.
"위치별(position-wise)"이 핵심입니다. 같은 W₁·W₂가 모든 토큰에 그대로 적용되니,
이것은 사실상 커널 크기 1인 합성곱 두 개입니다(논문 3.3절이 직접 그렇게 씁니다).
토큰 간 정보 교환은 어텐션이 전담하고, FFN은 각 토큰의 표현을 혼자서 가공합니다.
역할 분담이 깔끔합니다.
이제 논문 표 3에 적힌 65M이 어디에 들어 있는지 직접 세어 봅시다.
| 구성 요소 | 계산식 | 파라미터 | 비중 |
|---|
기본값에서 나오는 결론 세 가지입니다.
- 어텐션보다 FFN이 무겁습니다. 한 인코더 블록에서 어텐션은
4 × 512 × 512 ≈ 1.05M, FFN은512×2048 + 2048×512 ≈ 2.10M— 정확히 2배입니다. "Attention is all you need"라는 제목과 달리, 저장된 지식의 대부분은 FFN에 있습니다. - 디코더가 인코더보다 무겁습니다. 어텐션 서브층이 하나 더 있으니 블록당 약 1.33배입니다.
- 임베딩이 만만치 않습니다. 37,000 × 512 ≈ 18.9M — 전체의 약 30%가 사실 "단어 사전"입니다. 공유 체크를 끄면 3배로 뛰는 것을 보세요. 논문이 입력·출력·소프트맥스 행렬을 공유한 이유가 여기 있습니다.
dff 슬라이더를 움직이면 비중 막대가 통째로 기울어집니다.
오늘날의 LLM이 dff = 4×dmodel 비율을 대체로 유지하는 것도 이 균형에서 출발했습니다
(SwiGLU를 쓰는 요즘 모델은 게이트가 하나 더 붙어 8/3배로 조정하지만, 발상은 같습니다).
§7 학습 레시피 — 워밍업 4000과 레이블 스무딩
논문 5절은 하이퍼파라미터를 아주 구체적으로 적어 뒀습니다. 그중 둘은 "그냥 잘 되는 값"이 아니라 없으면 모델이 망가지거나 점수가 떨어지는 장치입니다.
① 학습률 스케줄 — 논문 식 (3)
식의 모양이 이상해 보이지만 하는 일은 단순합니다 — 4000스텝까지 직선으로 올리고, 이후 천천히 내립니다. §5에서 본 Post-LN의 초기 불안정 때문에 처음부터 큰 학습률을 쓰면 발산하기 때문입니다.
기본값(warmup=4000, d=512)에서 최고 학습률은 약 7.0 × 10⁻⁴,
정확히 4000스텝째에 찍습니다. 공식으로도 간단합니다 —
peak = (d · warmup)−0.5. 즉 warmup을 4배 늘리면 최고 학습률은 절반이 됩니다.
"워밍업을 길게 주면 더 안정적"이라는 말은 사실 최고 학습률이 낮아진다는 말이기도 합니다.
② 레이블 스무딩 — 퍼플렉시티는 나빠지고 BLEU는 좋아진다
논문 5.4절은 εls = 0.1을 씁니다. 정답 단어에 확률 1.0을 몰아주는 대신 0.9만 주고 나머지 0.1을 어휘 전체에 흩뿌립니다. 그리고 논문은 그 결과를 아주 솔직하게 적습니다.
"This hurts perplexity, as the model learns to be more unsure, but improves accuracy and BLEU score."
— 모델이 더 불확실해지도록 배우므로 퍼플렉시티는 나빠진다. 그러나 정확도와 BLEU는 좋아진다.
표 3의 (D)행이 그 증거입니다. 스무딩을 끄면(εls=0.0)
퍼플렉시티는 4.92 → 4.67로 좋아지는데 BLEU는 25.8 → 25.3으로 떨어집니다.
| 논문 표 3 (D)행 | εls | 퍼플렉시티 (낮을수록 좋음) | BLEU (높을수록 좋음) |
|---|---|---|---|
| 스무딩 없음 | 0.0 | 4.67 | 25.3 |
| 논문 base | 0.1 | 4.92 | 25.8 |
| 과하게 | 0.2 | 5.47 | 25.7 |
데모의 "손실 하한"을 먼저 보세요. 목표 분포가 더 이상 한 점에 몰려 있지 않으므로 모델이 목표를 완벽히 재현해도 교차 엔트로피가 0이 되지 않습니다 — 목표 분포 자체의 엔트로피만큼(ε=0.1, V=37,000에서 약 1.38 nats)이 바닥으로 남습니다. "퍼플렉시티가 나빠진다"의 기계적인 이유가 이것입니다. 그런데도 BLEU는 올라갑니다.
왜 그럴까요? 퍼플렉시티는 모델이 정답에 얼마나 확신하는가를 재고, BLEU는 실제로 생성한 문장이 얼마나 맞는가를 잽니다. 번역에는 정답이 여러 개인데 하나에만 확률을 몰아주게 훈련하면 모델이 과신하게 되고, 빔 서치가 대안 후보를 제대로 비교하지 못합니다. 지표가 좋아지는 것과 결과가 좋아지는 것은 다른 일이라는 것을 논문이 직접 보여 준 사례입니다.
③ 나머지 레시피
| 항목 | base | big | 하는 일 |
|---|---|---|---|
| 드롭아웃 Pdrop | 0.1 | 0.3 | 각 서브층 출력에, 그리고 임베딩+PE 합에도 적용 |
| 레이블 스무딩 εls | 0.1 | 0.1 | 위 참조 |
| 옵티마이저 | Adam (β₁=0.9, β₂=0.98, ε=1e−9) | β₂가 흔한 0.999가 아니라 0.98 | |
| 학습 스텝 | 100,000 | 300,000 | base 12시간, big 3.5일 (8× P100) |
| 체크포인트 평균 | 마지막 5개 | 마지막 20개 | 가중치를 평균내어 한 모델로 — 공짜 앙상블 |
| 배치 | 약 25,000 토큰 (문장 수가 아님) | 길이로 묶어야 패딩 낭비가 적다 | |
§8 추론 — 자기회귀 디코딩과 KV 캐시
학습은 병렬인데 생성은 그렇지 않습니다. 이것이 Transformer의 가장 흔한 오해입니다. 학습 때는 정답 문장을 통째로 넣고 인과 마스크로 한 번에 모든 위치를 계산하지만(1회 순전파), 추론 때는 다음 토큰을 알아야 그 다음을 계산할 수 있으니 토큰 수만큼 반복합니다. 순환층을 걷어낸 Transformer도 생성 단계에서는 순차적입니다.
여기서 낭비가 하나 보입니다. t번째 토큰을 만들 때 계산한 앞 토큰들의 K·V는 t+1번째에서도 똑같습니다(인과 마스크 덕에 과거는 미래를 안 보니까). 매번 다시 계산할 이유가 없습니다 — 저장해 두고 새 토큰 것만 덧붙이면 됩니다. 이것이 KV 캐시입니다.
캐시를 쓰면 토큰당 투영 비용이 t에 비례에서 상수로 바뀝니다.
n개를 생성하는 전체 비용은 O(n²)에서 O(n)으로 — n=1024면 약 500배입니다.
대신 메모리를 내줍니다. 토큰 하나당 층마다 K와 V를 들고 있어야 하니
2 × N × dmodel × 바이트이고, base·fp16이면 토큰당 12KB입니다.
마지막으로 무엇을 고를 것인가가 남습니다. 논문은 빔 크기 4, 길이 페널티 α=0.6의 빔 서치를 쓰고, 최대 출력 길이를 입력 길이 + 50으로 잡되 가능하면 일찍 끝냅니다(5.4절). 빔 서치가 무엇을 하는지는 How CTC Beam Search Works와 How seq2seq Works에서 이미 다뤘습니다.
§9 결과와 절제 실험 — 표 2·표 3
논문이 설득력을 가진 이유는 구조가 예뻐서가 아니라 더 적은 계산으로 더 높은 점수를 냈기 때문입니다. 표 2(WMT 2014 번역)의 핵심 줄만 옮기면 이렇습니다.
| 모델 | EN→DE BLEU | EN→FR BLEU | 학습 비용 (FLOPs) |
|---|---|---|---|
| GNMT + RL | 24.6 | 39.92 | 2.3 · 1019 |
| ConvS2S | 25.16 | 40.46 | 9.6 · 1018 |
| Transformer (base) | 27.3 | 38.1 | 3.3 · 1018 |
| Transformer (big) | 28.4 | 41.8 | 2.3 · 1019 |
base 줄을 보세요. EN→DE에서 ConvS2S보다 2점 이상 높으면서 학습 비용은 약 1/3입니다. big이 세운 28.4는 당시 앙상블까지 포함한 최고 기록을 넘었고, 학습에는 8개 P100으로 3.5일이 걸렸습니다. 게다가 논문은 6.3절에서 구성 구문 분석(constituency parsing)에도 거의 손대지 않고 적용해 WSJ만으로 F1 91.3, 준지도로 92.7을 냅니다 — "번역용 트릭이 아니라 범용 구조"라는 주장의 근거였습니다.
표 3의 절제 실험은 더 유익합니다. 무엇을 바꾸면 어떻게 망가지는지가 적혀 있으니까요. 행을 클릭해 보세요.
| 변경 | N | dmodel | dff | h | dk | PPL | BLEU |
|---|
읽어 낼 것들:
- 헤드는 8 근처가 최적입니다. h=1로 줄이면 BLEU가 0.9 떨어지고(24.9), h=32로 늘려도 오히려 떨어집니다(25.4). dmodel이 고정이라 헤드를 늘리면 헤드당 차원 dk가 줄어들기 때문입니다 — h=32면 dk가 16밖에 안 됩니다.
- dk를 줄이면 손해입니다((B)행). 논문은 "호환성(compatibility)을 정하는 것이 쉽지 않고, 내적보다 정교한 호환성 함수가 도움이 될 수 있다"고 조심스럽게 씁니다.
- 크게 만들면 좋아집니다((C)행). N·dmodel·dff 어느 쪽을 키워도 개선됩니다. 이 줄이 이후 몇 년의 방향을 그대로 예고했습니다.
- 드롭아웃이 없으면 과적합합니다((D)행 Pdrop=0.0 → PPL 5.77, BLEU 24.6). 꽤 큰 폭입니다.
- 학습되는 위치 임베딩은 거의 동률입니다((E)행 25.7 vs 25.8). 사인파가 성능 때문에 선택된 게 아니라는 뜻입니다 — 이유는 외삽 가능성이었습니다.
§10 정리 — 한 장 요약
| 질문 | 답 |
|---|---|
| 왜 순환을 버렸나 | 순차 연산 O(n) → O(1), 최대 경로 길이 O(n) → O(1). 단, 층당 복잡도는 n·d² → n²·d라 n < d일 때만 이득 |
| 블록 하나의 구성 | 인코더 = 셀프 어텐션 + FFN / 디코더 = 마스크 셀프 + 교차 + FFN. 전부 LayerNorm(x + Sublayer(x)) 껍질 |
| 왜 √dmodel을 곱하나 | PE 벡터 길이는 정확히 √(d/2)(d=512 → 16). 곱하지 않으면 임베딩(≈1)이 위치에 묻힌다 |
| 인코더·디코더를 가르는 것 | 층 종류가 아니라 마스크 행렬 한 장. 코드는 같다 |
| 멀티헤드는 비싼가 | 아니다. dk=dmodel/h라 h를 바꿔도 파라미터가 동일 |
| 파라미터는 어디에 | FFN > 어텐션(블록당 2:1), 임베딩이 전체의 약 30%. base 65M · big 213M |
| 워밍업 4000은 왜 | Post-LN의 초기 불안정 때문. Pre-LN으로 바꾸면 없어도 된다 (오늘날의 표준) |
| 레이블 스무딩 0.1 | 퍼플렉시티는 나빠지고(4.67 → 4.92) BLEU는 좋아진다(25.3 → 25.8) |
| 생성도 병렬인가 | 아니다. 학습만 병렬. 추론은 토큰마다 순차 → KV 캐시로 O(n²)를 O(n)으로 |
| 그래서 성과는 | EN→DE 28.4 · EN→FR 41.8 BLEU를 8× P100 3.5일에. 구문 분석에도 그대로 적용돼 F1 92.7 |
이 논문에서 오늘까지 이어진 것과 바뀐 것
| 부품 | 2017년 논문 | 오늘날 흔한 선택 |
|---|---|---|
| 정규화 위치 | Post-LN | Pre-LN (+ 마지막 LN) |
| 정규화 방식 | LayerNorm | RMSNorm |
| 위치 정보 | 사인·코사인 절대 위치 | RoPE / ALiBi (상대 위치) |
| FFN 활성함수 | ReLU | SwiGLU / GeGLU |
| K·V 헤드 | 쿼리와 같은 수 (MHA) | GQA / MQA (캐시 절감) |
| 구조 | 인코더–디코더 | 디코더 전용이 다수 |
| 바뀌지 않은 것 | 잔차 + 정규화로 감싼 블록을 N번 쌓는다 · 토큰 간 섞기는 어텐션이, 토큰 내부 가공은 FFN이 · 마스크로 인과성을 준다 — 골격은 그대로입니다 | |