어텐션 심화에서 어텐션 한 조각을 열어봤다면, 이제 Transformer 전체의 수학적 골격을 세웁니다. softmax의 성질부터 Multi-Head의 차원 산술, Positional Encoding, 그리고 6층 Transformer의 파라미터 수를 마지막 한 자리까지 직접 계산합니다. 필요한 선수지식은 행렬 곱셈뿐이에요.
유사도 행렬 · softmax와 온도 · Multi-Head 차원 산술 · sin/cos 위치 부호화 · 파라미터 종합 계산 · 25분
3분 요약
QK⊤ 는 모든 토큰 쌍의 관련도를 한 번에 잰 유사도 행렬이고, dk 나누기는 내적의 분산을 1로 되돌리는 안전장치다.
softmax는 점수를 합이 1인 비중으로 바꾸며, 나누는 수(온도)가 클수록 완만해진다 — dk 나누기는 온도 T=dk 를 건 셈. 계산 전에 최댓값을 빼도 결과는 같다(오버플로 방지 트릭).
Multi-Head는 dmodel 을 h 개 헤드가 dk=dmodel/h 씩 나눠 갖는다 — 그래서 헤드가 몇 개든 어텐션 블록의 파라미터는 4dmodel2 로 같다.
Positional Encoding은 sin/cos 파동으로 위치를 새긴다 — 파장이 2π 부터 10000⋅2π 까지 기하급수로 퍼져, 상대 위치를 회전(선형 변환)으로 표현할 수 있다.
dmodel=512,h=8,dff=2048 인 인코더 층 1개는 3,150,336개, 6층이면 18,902,016개의 파라미터 — 이 글에서 전부 손으로 합산한다.
선수 단원 — 이 글은 Self-Attention 심화의 바로 다음 단원입니다. Q·K·V가 무엇인지, 어텐션의 4단계(점수 → 스케일 → softmax → 섞기)가 낯설다면 먼저 보고 오세요. 여기서는 그 지식을 발판으로 Transformer 전체의 수학을 세웁니다.
STEP 1Scaled Dot-Product — QK⊤ 는 유사도 행렬이다
Attention(Q,K,V)=softmax(dkQK⊤)V
어텐션 심화에서는 토큰 하나의 관점에서 이 공식을 따라갔죠. 이번에는 행렬 전체로 봅니다. 토큰이 n 개면 Q,K 는 각각 n×dk 행렬이고, 곱 QK⊤ 는 n×n 행렬이 됩니다. 이 행렬의 (i,j) 성분은 qi⋅kj — 즉 "i번째 토큰의 질문이 j번째 토큰의 색인과 얼마나 잘 맞는가"예요. 행렬 곱 한 번으로 모든 토큰 쌍의 관련도를 동시에 계산하니, 이것이 유사도 행렬(관련도 점수표)이고 Transformer가 병렬 처리에 강한 이유입니다.
토큰 1은 자기 자신(점수 2)에, 토큰 2는 상대적으로 토큰 2 쪽(0 대 1)에 비중을 실었죠. 어텐션의 출력 각 행은 Value들의 가중 평균이라는 것 — 그리고 그 가중치가 유사도 행렬에서 나온다는 것이 전부입니다.
그런데 왜 하필 dk 로 나눌까요? 원논문(Vaswani et al. 2017, §3.2.1 각주 4)의 논증은 확률 이야기예요. Query와 Key의 각 성분이 서로 독립이고 평균 0, 분산 1이라면, 내적 q⋅k=∑i=1dkqiki 는 분산이 1인 항 dk 개의 합이므로 분산이 dk 가 됩니다(독립 확률변수 합의 분산 = 분산의 합). 표준편차 dk 로 나누면,
Var(dkq⋅k)=dkdk=1
점수의 분산이 차원과 무관하게 1 근처로 유지됩니다. 나누지 않으면 dk=512 같은 큰 차원에서 점수가 ±512≈±23 규모로 널을 뛰고, 다음 단계의 softmax가 포화되어 학습이 멈춥니다. 그 이유는 STEP 2에서 softmax를 뜯어보면 바로 보여요.
STEP 2softmax의 수학 — 온도, 그리고 max 빼기 트릭
softmax의 정의부터 정확히 적어봅시다.
softmax(z)i=∑j=1nezjezi⇒모두양수, 합이1
지수함수 ez 는 z 가 조금만 커져도 폭발적으로 커지므로, softmax는 큰 점수를 더 크게 벌리는 성질이 있어요. 점수를 상수 T (온도, temperature)로 나눈 뒤 softmax를 걸면 이 벌어짐의 정도를 조절할 수 있습니다. 점수 z=[2,0,1] 로 직접 계산해보면,
온도 T
softmax(z / T)
성격
0.5
[0.867, 0.016, 0.117]
뾰족 — 1등에 몰아줌
1
[0.665, 0.090, 0.245]
기본
2
[0.506, 0.186, 0.307]
완만 — 고르게 나눔
스케일링 = 온도 — STEP 1의 ÷dk 는 정확히 온도 T=dk 를 건 softmax와 같습니다 (dk=4 였으니 T=2 — 위 표의 셋째 줄). 점수의 분산이 커질수록 softmax가 "T = 0.5" 줄처럼 한쪽에 1을 몰아주는 포화 상태가 되는데, 이때 입력을 조금 바꿔도 출력이 거의 안 변하니 기울기가 0에 가까워져 학습이 멈춥니다. dk 나누기는 온도를 올려 이 포화를 막는 장치예요. (LLM 생성 옵션의 temperature도 같은 수식입니다 — 출력 확률을 뾰족하게/완만하게 조절하죠.)
실전에서는 한 가지 문제가 더 있습니다. 점수가 크면 ez 자체가 컴퓨터로 계산 불가능해져요. e1000 은 오버플로(무한대 처리)됩니다. 해법은 모든 점수에서 최댓값을 빼고 시작하는 것: 임의의 상수 c 에 대해,
분자·분모에 같은 수 e−c 가 곱해지니 결과는 그대로예요. c=max(z) 로 잡으면 지수가 전부 0 이하가 되어 절대 오버플로되지 않습니다. 예를 들어 z=[1000,1001,1002] 는 그대로는 계산 불가지만, 최댓값 1002를 빼면 [−2,−1,0] 이 되고,
e−2=0.1353, e−1=0.3679, e0=1.0000 (합 = 1.5032)
→ softmax = [0.0900, 0.2447, 0.6652] — 원래 [1000, 1001, 1002]의 softmax와 정확히 같은 값
이 "max 빼기 트릭"은 numpy·PyTorch 등 모든 라이브러리의 softmax 구현에 들어 있는 표준 기법입니다. 아래 실습의 코드에도 넣어뒀으니 확인해보세요.
실습 1 — 손계산을 numpy로 검증
STEP 1의 2×2 손계산을 코드로 재현합니다. 실행 버튼을 누르면 브라우저 안에서 파이썬이 돌아가고, 가중치 [0.6225,0.3775] 와 출력 [2.49,1.51] 이 그대로 나와야 합니다.
첫 실행 시 파이썬 런타임을 내려받습니다 (수 초 소요)
직접 해보기 — V를 바꾸면 출력이 어떻게 변하나요? d_k를 64로 늘리고 Q·K에 큰 값을 넣으면(예: 전부 3) 스케일링 전후의 softmax가 얼마나 달라지는지 scaled 대신 scores로 softmax를 걸어 비교해보세요.
STEP 3Multi-Head의 차원 산술 — 512를 8명이 나눠 갖기
언어에는 문법·의미·시제 같은 여러 관계가 동시에 작동합니다. 그래서 Transformer는 어텐션을 h 개 병렬로 돌리는데, 이때 차원을 늘리는 게 아니라 나눕니다. 원논문의 기본 설정은 dmodel=512,h=8 이고, 각 헤드는
dk=dv=hdmodel=8512=64
차원씩 나눠 갖습니다. 헤드 i 는 자기만의 투영 행렬 WiQ,WiK,WiV (각 512×64)로 입력을 64차원 세계로 내려보내 어텐션을 계산하고, 8개 헤드의 출력(각 64차원)을 이어 붙인 512차원을 WO (512×512)로 한 번 더 섞습니다(Vaswani et al. 2017, §3.2.2).
깔끔한 결론 — 8개 헤드의 Q·K·V 투영을 다 합치면 8×(512×64)=512×512 이므로, 어텐션 블록 전체는 정확히 4dmodel2=4×5122=1,048,576 개. 헤드 수를 1개로 하든 8개로 하든 총 파라미터는 같습니다.dk=dmodel/h 로 나눠 갖기 때문이죠. 원논문도 "차원을 줄인 덕에 총 계산 비용이 (전체 차원의) 단일 헤드 어텐션과 비슷하다"고 밝힙니다. 여러 헤드의 이득은 파라미터가 아니라 서로 다른 표현 부분공간을 동시에 보는 능력에서 옵니다.
STEP 4Positional Encoding — 위치를 파동으로 새기다
어텐션은 모든 토큰을 동시에 바라보기 때문에, 그 자체로는 순서를 모릅니다. "개가 사람을 물었다"와 "사람이 개를 물었다"의 유사도 행렬이 (조사를 무시하면) 같아질 수 있어요. 그래서 입력 임베딩에 위치 신호를 더해주는데, 원논문(§3.5)의 정의는 이렇습니다. 위치 pos 의 2i, 2i+1 번째 성분에 대해,
dmodel=4 로 줄여 직접 계산해봅시다. 분모는 성분 쌍마다 100000/4=1 과 100002/4=100 — 즉 첫 쌍은 각도가 pos 라디안씩, 둘째 쌍은 pos/100 라디안씩 도는 두 개의 시계입니다.
pos
sin(pos)
cos(pos)
sin(pos/100)
cos(pos/100)
0
0.0000
1.0000
0.0000
1.0000
1
0.8415
0.5403
0.0100
1.0000
2
0.9093
−0.4161
0.0200
0.9998
3
0.1411
−0.9900
0.0300
0.9996
※ 소수 4자리 반올림 (pos=1의 cos(0.01)은 정확히는 0.99995).
왜 이런 모양일까요? 두 가지 성질이 핵심이에요. 첫째, 파장의 스펙트럼. 성분 쌍마다 파장(한 바퀴 도는 데 걸리는 위치 수)이 2π 에서 10000⋅2π 까지 기하급수로 길어집니다. 빨리 도는 시계(첫 쌍)는 이웃 위치를 촘촘히 구분하고, 느리게 도는 시계(뒤쪽 쌍)는 멀리 떨어진 위치를 구분해요 — 초침·분침·시침이 함께 시각을 표현하는 것과 같은 원리입니다. 그리고 sin/cos 값은 늘 [−1,1] 안이라 위치가 아무리 커져도 신호가 폭주하지 않죠.
둘째, 상대 위치의 선형 표현(소개 수준). 삼각함수 덧셈정리에 따라 고정 간격 k 에 대해,
— 즉 "k 칸 뒤의 위치 신호"는 현재 위치 신호에 k 에만 의존하는 회전 행렬(선형 변환)을 곱한 것입니다. 원논문은 이 성질 덕분에 모델이 "3칸 앞의 단어" 같은 상대 위치 참조를 쉽게 배울 것이라는 가설로 이 형태를 골랐다고 밝힙니다.
실습 2 — Positional Encoding 값을 직접 계산
위 표의 값을 코드로 재현하고, 각 (sin, cos) 쌍이 항상 반지름 1인 원 위의 점이라는 것(sin2+cos2=1)도 확인합니다.
첫 실행 시 파이썬 런타임을 내려받습니다 (수 초 소요)
직접 해보기 — d_model을 8로, n_pos를 16으로 늘려 뒤쪽 성분일수록 값이 천천히 변하는(파장이 길어지는) 모습을 관찰해보세요. pos=100, 1000처럼 큰 위치를 넣어도 값이 [-1, 1]을 벗어나지 않는 것도 확인해보세요.
STEP 5잔차 연결 + LayerNorm, 그리고 FFN
어텐션과 함께 Transformer 블록을 이루는 나머지 부품을 수식으로 정리합니다(개요 수준). 각 부속층(어텐션이든 FFN이든)은 다음 형태로 감싸입니다(Vaswani et al. 2017, §3.1).
output=LayerNorm(x+Sublayer(x))
x+Sublayer(x) 가 잔차 연결(residual connection)입니다. 부속층은 x 를 통째로 새로 만드는 게 아니라 "고칠 부분(잔차)"만 계산해 원본에 더합니다. 입력이 그대로 통과하는 지름길이 있으니 기울기도 이 길로 잘 흘러, 층을 수십 개 쌓아도 학습이 됩니다(He et al. 2016의 아이디어). LayerNorm은 각 토큰 벡터의 성분들을 평균 0·분산 1로 맞춘 뒤 배율과 이동을 학습하는 정규화입니다(Ba et al. 2016).
이제 부품별 계산을 모읍니다. 원논문 기본 설정(dmodel=512, h=8, dff=2048)의 인코더 층 1개는,
부품
계산
파라미터 수
비중
Multi-Head Attention
4 × 512²
1,048,576
33.3%
FFN
512·2048 + 2048 + 2048·512 + 512
2,099,712
66.7%
LayerNorm × 2
2 × (2 × 512)
2,048
0.1%
층 1개 합계
3,150,336
100%
× 6층
3,150,336 × 6
18,902,016
읽는 법 — 층 파라미터의 약 2/3가 FFN에 있습니다. "어텐션은 정보를 어디서 가져올지 정하는 라우팅, 지식은 주로 FFN에 저장된다"는 통찰이 숫자로도 보이죠. 그리고 18,902,016개는 인코더 스택의 가중치만 센 것입니다. 실제 원논문의 base 모델은 여기에 디코더 스택(어텐션이 층마다 2개라 더 큼)과 토큰 임베딩·출력층까지 더해 약 6,500만(65 × 10⁶)개로 보고됩니다(Vaswani et al. 2017, Table 3).
같은 셈법을 함수로 만들어두면 어떤 모델이든 즉시 셀 수 있습니다. 아래 실습에서 직접 확인해보세요.
실습 3 — Transformer 파라미터 계산기
첫 실행 시 파이썬 런타임을 내려받습니다 (수 초 소요)
직접 해보기 — GPT-2 small 급 설정(d_model=768, h=12, d_ff=3072, 12층)을 넣으면 몇 개가 나오나요? h를 8에서 16으로 바꿔도 총합이 변하지 않는 것(STEP 3의 결론)도 확인해보세요.
스스로 점검 — 5문항
보기를 누르면 즉시 정답과 해설이 나옵니다. 헷갈리면 해당 STEP으로 돌아가 보세요.
Q1. Attention 공식의 QKᵀ 가 만드는 행렬의 (i, j) 성분이 뜻하는 것은?
Q5. Positional Encoding에 sin/cos 함수를 쓴 이유로 원논문이 제시한 가설은?
sin/cos이 계산이 가장 빠른 함수라서
고정 간격 k에 대해 PE(pos+k)를 PE(pos)의 선형 함수(회전)로 표현할 수 있어, 모델이 상대 위치에 주목하는 법을 쉽게 배울 것이라 기대했기 때문
값이 항상 양수가 되기 때문
위치가 커질수록 값이 계속 커져 순서를 구분할 수 있기 때문
참고 자료 — 1차 출처
Vaswani et al. (2017) — "Attention Is All You Need" (NeurIPS). Scaled Dot-Product와 √d_k 분산 논거(§3.2.1, 각주 4), Multi-Head 구성과 차원 분할(§3.2.2), 잔차 연결·LayerNorm 배치(§3.1), FFN 구조와 d_ff=2048(§3.3), sin/cos Positional Encoding과 상대 위치 가설·파장 스펙트럼(§3.5), base 모델 65×10⁶ 파라미터(Table 3)의 원전.