아까 보캡의 크기는 ∣V∣=12라고 가정했다. 그러면 각 토큰은 원-핫 벡터가 되기 위해 길이가 12인 벡터로 표현된다.
예를 들어 “리오넬”의 인덱스가 3이라면, 원핫 벡터는 3번 위치만 1이고 나머지는 모두 0인 벡터다.
o리오넬=[0,0,0,1,0,0,0,0,0,0,0,0]
“메시”의 인덱스가 6이라면
o메시=[0,0,0,0,0,0,1,0,0,0,0,0]
이다.
원핫 벡터의 핵심은 “그 토큰이 보캡에서 몇 번째 토큰인지”만 표시한다는 것이다. 원핫 벡터 자체에는 의미 정보가 거의 없다. “리오넬”과 “메시”가 축구 선수 이름으로 관련 있다는 정보는 원핫 벡터에 들어 있지 않다.
3.2 문장 전체의 원핫 행렬
문장 길이가 6이고 보캡 크기가 12라면, 문장 전체는 다음 크기의 원핫 행렬로 표현된다.
O∈R6×12
각 행은 하나의 토큰을 나타낸다.
O=⎣⎢⎢⎢⎢⎢⎢⎢⎡o∗리오넬o∗메시o∗가o∗득점o∗했o∗다⎦⎥⎥⎥⎥⎥⎥⎥⎤
즉
Oij={1,0,if j=token id of tiotherwise
이다.
그림에서 가운데의 0과 1로 된 큰 행렬이 바로 이 원핫 행렬이다.
4. 원핫 벡터에서 임베딩 벡터로
4.1 임베딩 테이블
보캡 크기가 50,000이면 원핫 벡터의 길이도 50,000이 된다. 그런데 모든 벡터는 그중 단 하나의 값만 1이고 나머지는 전부 0으로 너무 희소하여 컴퓨터가 이해하기 어렵다. 그래서 원핫 벡터를 더 풍부한 정보를 담을 수 있는 벡터에 매핑하는 과정이 필요하며, 이를 임베딩 벡터라고 한다.
그림과 같은 임베딩 테이블을
E∈R∣V∣×d
라고 하자.
여기서
∣V∣=12
이고 그림에서는 임베딩 차원을
d=512
로 두었다.
그러면
E∈R12×512
이다.
이 임베딩 테이블의 각 행은 하나의 토큰에 대응하는 512차원 벡터다.
예를 들어
E3
은 “리오넬”의 임베딩 벡터이고,
E6
은 “메시”의 임베딩 벡터다.
4.2 원핫 벡터와 임베딩 테이블의 곱
원핫 벡터를 임베딩 테이블에 곱하면 해당 토큰의 임베딩 벡터가 선택된다.
“리오넬”의 원핫 벡터를
o리오넬
이라고 하면
x리오넬=o리오넬E
이다.
원핫 벡터는 3번 위치만 1이므로
o리오넬E=0E0+0E1+0E2+1E3+0E4+⋯+0E11
이다. 따라서
o리오넬E=E3
이다.
즉 원핫 벡터와 임베딩 테이블의 곱은 사실상 “임베딩 테이블에서 해당 행을 꺼내는 연산”이다.
그림에서는 간단히 X라고 표시했지만, 실제 트랜스포머에서는 이 X가 토큰 임베딩과 위치 임베딩이 합쳐진 입력이라고 생각하면 된다.
6. 셀프 어텐션의 핵심 아이디어
6.1 셀프 어텐션이 하는 일
셀프 어텐션은 문장 안의 각 토큰이 다른 토큰들을 얼마나 참고할지 계산하는 연산이다.
예시 문장에서
[리오넬,메시,가,득점,했,다]
가 있을 때,
“리오넬”과 “메시”는 함께 하나의 이름을 이룬다. 따라서 “리오넬”과 “메시”는 의미적 연관성이 크고, “메시”와 “리오넬”도 의미적 연관성이 크다.
반대로 “가”, “득점”, “했”, “다”는 이 이름 구성 관계에서는 큰 관련이 없다. 물론 실제 언어 모델 전체에서는 “가”는 주격 조사이고 “득점했다”는 술어이므로 의미상 관련이 있다. 하지만 여기서는 특정 어텐션 헤드가 마치 '개체명인식(NER)'처럼 사람 이름 등의 “고유명사 결합”만 담당한다고 가정한다.
즉 이 헤드의 관심사는 다음과 같다.
리오넬↔메시
이 관계를 강하게 잡고, 나머지 토큰과의 관계는 약하게 둔다.
6.2 Query, Key, Value의 직관
셀프 어텐션에서는 각 토큰 벡터에서 세 종류의 벡터를 만든다.
Q=XWQ
K=XWK
V=XWV
여기서 Q, K, V는 각각 Query, Key, Value다.
직관적으로 말하면 다음과 같다.
Query는 “비교할 토큰”를 나타낸다.
Key는 “비교 될 토큰”를 나타낸다.
Value는 “Query와 Key의 유사도를 기준으로 각 토큰들의 정보가 융합된 결과”를 나타낸다.
이렇게 각 토큰 쌍 사이의 관련도를 계산하는 것이 셀프 어텐션의 시작이다.
7. QKV 행렬 만들기
7.1 입력 행렬의 크기
입력 행렬을
X∈Rn×d
라고 하자.
이 예시에서는
n=6
d=512
이므로
X∈R6×512
이다.
각 행은 하나의 토큰 벡터다.
X=⎣⎢⎢⎢⎢⎢⎢⎢⎡x1x2x3x4x5x6⎦⎥⎥⎥⎥⎥⎥⎥⎤
여기서
x∗1=x∗리오넬
x∗2=x∗메시
이다.
7.2 학습 가능한 선형 변환
트랜스포머는 입력 벡터 X를 그대로 비교하지 않는다. 대신 세 개의 학습 가능한 행렬을 사용한다.
WQ∈Rd×dk
WK∈Rd×dk
WV∈Rd×dv
멀티헤드 어텐션에서는 보통 헤드마다 원래 X의 차원 d보다 더 작은 차원을 쓴다. 예를 들어 d=512, 헤드 수가 8이면 한 헤드의 차원은 보통
dk=dv=64
가 된다.
단일 헤드 기준으로는 다음과 같이 계산한다.
Q=XWQ
K=XWK
V=XWV
크기를 확인하면
X∈R6×512
WQ∈R512×dk
이므로
Q∈R6×dk
이다.
마찬가지로
K∈R6×dk
V∈R6×dv
이다.
8. 어텐션 스코어 계산
8.1 토큰 하나와 토큰 하나의 관련도
이제 각 토큰이 다른 토큰을 얼마나 참고할지 계산한다.
토큰 i의 Query를
qi
라고 하고, 토큰 j의 Key를
kj
라고 하자.
그러면 토큰 i가 토큰 j를 얼마나 참고할지는 내적값으로 계산한다.
qi⋅kj
내적은 두 벡터가 비슷한 방향을 향할수록 커진다.
따라서
q∗리오넬⋅k∗메시
가 크다면, “리오넬”은 “메시”를 중요하게 참고한다.
반대로
q∗리오넬⋅k∗가
가 작다면, “리오넬”은 “가”를 별로 참고하지 않는다.
8.2 전체 토큰 쌍에 대한 행렬 계산
이러한 토큰과 토큰간의 코사인 유사도 계산을 한 번에 할 수 있는 것이 바로 행렬 곱이다. 모든 토큰 쌍에 대해 이 값을 계산하면 행렬이 된다.
QKT
여기서
Q∈R6×dk
K∈R6×dk
이므로
KT∈Rdk×6
이다.
따라서
QKT∈R6×6
이다.
이 6×6 행렬의 (ij)번째 원소는
(QKT)ij=qi⋅kj
이다.
행 i는 “i번째 토큰이 다른 토큰들을 각각 얼마씩 참조하는가”를 나타낸다.
열 j는 “j번째 토큰이 다른 토큰들에게 각각 얼마씩 참고되는가”를 나타낸다.
그림의 빨간색 히트맵 행렬이 바로 이 관계를 나타낸다.
9. 왜 dk로 나누는가
9.1 스케일링 없는 내적의 문제
셀프 어텐션 공식은 단순히
QKT
가 아니라
dkQKT
를 사용한다.
왜 이렇게 나눌까?
qi와 kj의 각 성분이 평균 0, 분산 1인 값이라고 단순화해서 생각하자.
q∗i=[q∗i1qi2,…qidk]
k∗j=[k∗j1kj2,…kjdk]
그러면 내적은
qi⋅kj=ℓ=1∑dkqiℓkjℓ
이다.
각 항 qiℓkjℓ의 분산이 대략 1이라고 하면, dk개를 더한 값의 분산은 대략
dk
가 된다.
즉 내적값의 표준편차는
dk
정도로 커진다.
차원 dk가 커질수록 내적값도 너무 커질 수 있다.
9.2 softmax 포화 문제
어텐션에서는 이 내적값에 softmax를 적용한다.
softmax는 입력값 중 큰 값을 더 크게 강조한다.
예를 들어
[1,2,3]
에 softmax를 적용하면 적당히 분산된 확률이 나오지만,
[10,20,30]
에 softmax를 적용하면 가장 큰 값에 거의 모든 확률이 몰린다.
그러면 학습 초기에 어텐션이 너무 극단적으로 변하고, gradient가 불안정해진다.
그래서 내적값을
dk
로 나누어 스케일을 안정화한다.
따라서 스코어 행렬은
S=dkQKT
가 된다.
10. softmax로 어텐션 가중치 만들기
10.1 스코어 행렬에서 확률 행렬로 바꾸기
앞에서 QKT/dk를 통해 스코어 행렬을 만들었다.
S=dkQKT
여기서
S∈R6×6
이다.
행과 열의 순서는 모두 다음과 같다고 하자.
[리오넬,메시,가,득점,했,다]
스코어 행렬 S의 원소 Sij는 “i번째 토큰이 j번째 토큰을 얼마나 참고하고 싶은가”를 나타낸다.
하지만 Sij 자체는 아직 확률이 아니다. 값이 음수일 수도 있고, 행의 합이 1도 아니다. 왜냐하면 코사인 유사도의 값은 [−1,1] 사이의 값을 가지기 때문이다. 따라서 각 행마다 softmax를 적용해서 확률분포로 바꿀 필요가 있다.
A=softmax(S)
더 정확히는 각 행 i에 대해
Aij=∑ℓ=16exp(Siℓ)exp(Sij)
이다.
여기서 Aij는 “i번째 토큰이 자신의 새 벡터를 만들 때 j번째 토큰의 정보를 어느 정도 비율로 가져오는가”를 의미한다.
각 행은 확률분포이므로 반드시 다음을 만족한다.
j=1∑6Aij=1
즉 하나의 토큰이 나누어 가지는 관심의 총합은 항상 1이다.
10.2 어텐션 시나리오
그림 속 어텐션 모듈은 문장을 입력받아 사람 이름, 지명, 고유명사 등의 존재만 추출하는 '개체명 인식' 태스크로 학습되었다고 가정하자. 그렇다면 “리오넬”은 자기 자신을 가장 많이 참조하고, 그다음으로 “메시”를 많이 참조할 것이다.
즉 “리오넬” 입장에서 중요한 순서는 다음과 같다.
리오넬>메시≫가,득점,했,다
이것은 다음과 같은 언어적 상황을 반영한다.
“리오넬”은 그 자체로 하나의 고유명사 일부다. 그런데 바로 뒤에 “메시”가 오기 때문에, 모델은 “리오넬”이 단독 이름이 아니라 “리오넬 메시”라는 하나의 인명 표현의 일부라는 사실을 알아야 한다. 따라서 “리오넬”은 자기 자신의 정보도 강하게 유지하지만, 동시에 “메시”도 꽤 강하게 참고한다.
이때 “리오넬” 행의 softmax 이전 스코어가 다음과 같다고 하자.
S리오넬,:=[2.30,1.79,0,0,0,0]
그러면 softmax는 다음과 같이 계산된다.
먼저 각 원소에 지수함수를 적용한다.
exp(2.30)≈9.97
exp(1.79)≈5.99
exp(0)=1
따라서 분모는
9.97+5.99+1+1+1+1=19.96
이다.
이제 각 값을 분모로 나누면 된다.
A리오넬,리오넬=19.969.97≈0.50
A리오넬,메시=19.965.99≈0.30
A리오넬,가=19.961≈0.05
A리오넬,득점=19.961≈0.05
A리오넬,했=19.961≈0.05
A리오넬,다=19.961≈0.05
따라서
A리오넬,:≈[0.50,0.30,0.05,0.05,0.05,0.05]
가 된다.
이 예시의 핵심은 softmax가 단순히 큰 값을 고르는 연산이 아니라, 상대적 크기를 확률분포로 바꾸는 연산이라는 점이다. “리오넬”에 대한 스코어가 가장 크기 때문에 0.50이 되고, “메시”에 대한 스코어가 그다음으로 크기 때문에 0.30이 된다. 나머지 토큰들은 스코어가 낮기 때문에 각각 0.05 정도만 받는다.
즉 “리오넬”과 “메시”는 서로를 비교적 강하게 본다. 다만 자기 자신을 가장 많이 본다. 즉, 히트맵을 보면 대각 성분이 가장 강하고, “리오넬”과 “메시” 사이의 비대각 성분도 어느 정도 강한 형태다.
11.2 “리오넬” 행의 해석
첫 번째 행을 따로 쓰면 다음과 같다.
A리오넬,:=[0.50,0.30,0.05,0.05,0.05,0.05]
이것은 “리오넬”의 벡터를 업데이트할 때, 다른 토큰들의 정보를 어느정도 비율로 섞을지 나타낸다.
50
30
5
5
5
5
따라서 “리오넬”은 여전히 자기 자신의 정체성을 절반 가까이 유지하며 강하게 유지한다. 하지만 동시에 “메시” 정보를 꽤 많이 받아온다.
이때 “메시” 정보가 들어오는 이유는 “리오넬”과 “메시”가 서로 결합하여 하나의 이름을 이루기 때문이다.
리오넬+메시→리오넬메시
따라서 “리오넬”의 출력 벡터는 단순한 “리오넬”이 아니라, “뒤에 메시가 붙어서 리오넬 메시라는 인명을 이루는 리오넬”에 가까워진다.
11.3 “메시” 행의 해석
두 번째 행은 다음과 같다.
A메시,:=[0.30,0.50,0.05,0.05,0.05,0.05]
이것은 “메시”의 벡터를 업데이트할 때 다음 비율로 토큰들 간의 정보를 섞는다는 뜻이다.
30
50
5
5
5
5
즉 “메시”도 자기 자신의 의미를 가장 크게 유지하지만, “리오넬”을 강하게 참고한다.
이렇게 되면 “메시”의 출력 벡터는 단순한 “메시”가 아니라, “앞에 리오넬이 붙어서 리오넬 메시라는 인명을 이루는 메시”에 가까워진다.
11.4 “가”, “득점”, “했”, “다”와의 관련성이 작은 이유
우리가 상정한 시나리오에서 이 모델은 고유명사들을 뽑아내는 태스크를 하므로, 문장의 모든 문법 관계를 보는 것이 아니라, “리오넬”과 “메시”가 하나의 이름이라는 관계를 주로 본다. 따라서 이 헤드에서 “리오넬”은 “가”, “득점”, “했”, “다”를 강하게 볼 필요가 없다.
A리오넬,가=0.05
A리오넬,득점=0.05
A리오넬,했=0.05
A리오넬,다=0.05
마찬가지로 “메시”도 이 헤드에서는 “가”, “득점”, “했”, “다”를 약하게 본다.
A메시,가=0.05
A메시,득점=0.05
A메시,했=0.05
A메시,다=0.05
물론 실제 언어적으로는 “메시가”에서 “가”는 주격 조사이고, “득점했다”는 술어이므로 중요하지만, 이런 요소들을 모두 반영하면 어텐션 매커니즘을 설명하기 어려워져 간단한 시나리오를 가정한다.
12. 어텐션 가중치로 Value 벡터 섞기
12.1 최종 어텐션 출력
softmax를 통해 어텐션 행렬 A를 얻으면, 이제 이 A를 Value 행렬 V에 곱한다.
Z=AV
여기서
A∈R6×6
이고
V∈R6×dv
이므로
Z∈R6×dv
이다.
즉 입력 토큰이 6개였으므로 출력 벡터도 6개다. 다만 각 출력 벡터는 자기 자신만의 정보가 아니라, 다른 토큰들의 정보를 가중합한 결과다.
siuuu