10장 — 어텐션과 트랜스포머: 멀리 떨어진 칸끼리 읽기

자주 하는 실수와 요약

자주 하는 실수

실수 나온 문제 바로잡는 법
점수가 가장 큰 것 하나만 읽는다고 봄 1 소프트맥스 비중으로 모두를 섞는다. 점수 차이와 배율이 쏠림을 정한다
점수를 키우면(나누지 않으면) 확실하게 골라 좋다고 봄 2 처음부터 99.97%로 쏠리면 기울기 p(1 − p)가 0.000335로 사라진다. √d_k 로 나눠 점수의 표준편차를 1로 맞춘다
√d_k 로 나누면 학습 뒤의 쏠림도 막힌다고 봄 2 성분이 독립인 처음 상태에서 크기를 맞출 뿐이다. 학습이 만든 쏠림은 남는다
그림을 두 배로 키우면 점수 표도 두 배라고 셈 3 칸이 네 배, 점수 표는 칸 수의 제곱이라 열여섯 배다
소프트맥스를 질의 묶음으로 잘라 계산하면 답이 달라진다고 봄 3 소프트맥스는 한 질의의 줄 안에서만 나눈다. 줄 묶음마다 따로 해도 같다
회전 위치 인코딩에서 내적만 보고 절대 자리를 안다고 봄 4 내적에는 자리의 차이만 남는다. 빠르기 하나로는 한 바퀴 뒤 차이도 겹친다
셀프 어텐션을 쓰는 신경망은 늘 순서를 모른다고 봄 5, 6 어텐션 앞에 자리를 아는 층(합성곱)이 없을 때만이다
머리를 나누면 매개변수와 계산이 머리 수만큼 는다고 봄 7 행렬을 머리 수로 자를 뿐이라 둘 다 그대로다. 느는 것은 소프트맥스(비중 분포)의 수다
머리들의 비중 평균을 「머리 하나였을 때의 비중」으로 읽음 8 평균 낸 비중은 어떤 소프트맥스에서도 나온 값이 아니다
문장 하나의 비중 표로 머리의 역할을 정함 8 그 문장에서의 버릇일 뿐이다. 여러 문장으로 확인해야 한다
층 정규화가 토큰의 정보를 지우지 않는다고 봄 9 토큰 하나의 평균과 크기를 지운다. 앞 정규화는 그래서 줄기에는 정규화 전 값을 남긴다
앞 정규화의 뒤쪽 블록은 일을 안 한다고 봄 10 처음에는 몫이 작지만, 학습이 몫의 크기와 방향을 정한다
뒤 정규화 트랜스포머를 깊게 쌓고 예열 없이 큰 학습률로 시작함 11 블록 24벌 실험에서 손실이 ln 64 에서 내려오지 않았다. 예열을 두거나 앞 정규화를 쓴다
크로스 어텐션은 글 토큰이 하나여도 칸마다 다르게 읽는다고 봄 12 토큰이 하나거나 모두 같으면 모든 칸이 같은 벡터를 받는다
「어텐션 블록」의 매개변수는 대부분 어텐션이라고 봄 13 SD 1.x 에서는 MLP 가 55.7%다
글 인코더를 바꿔도 U-Net 은 그대로 쓸 수 있다고 봄 13 크로스 어텐션의 열쇠·값 행렬은 글 쪽 폭에 맞춰져 있어 크기부터 바뀐다
적어 둔 누계·캐시는 앞 기록이 바뀌어도 쓸 수 있다고 봄 14, 15 앞의 것이 다시 바뀌지 않을 때만 맞다. 트랜스포머에서는 가림이 그 보장이다
KV 캐시 크기에서 열쇠·값 두 벌을 빼먹음 16 2 × 블록 수 × 열쇠·값 머리 수 × 머리 길이 × 바이트

요약

합성곱은 자리마다 무게를 정해 두어 멀리 있는 칸을 읽기 어려웠다. 셀프 어텐션은 토큰마다 질의·열쇠·값을 만들고, 질의와 열쇠의 내적을 √d_k 로 나눠 소프트맥스를 씌운 비중으로 값을 섞어, 거리와 상관없이 내용이 맞는 토큰을 읽는다. 내용만 보므로 토큰을 뒤섞어도 출력이 따라 옮겨 갈 뿐이라, 자리는 위치 인코딩으로 따로 적는다. 자리 벡터를 더하는 사인 꼴에서 질의와 열쇠를 자리만큼 돌리는 회전 꼴로 넘어가면서, 내적에는 자리의 차이만 남게 되었고 그림은 행과 열을 따로 돌린다. 한 소프트맥스는 평균 하나만 내므로 질의·열쇠·값을 여러 머리로 나눠 따로 읽고 이어 붙인다. 계산량과 매개변수는 그대로다. 여러 머리 어텐션과 토큰마다의 MLP 를 「층 정규화 → 부품 → 잔차 더하기」로 감싼 트랜스포머 블록을 쌓되, 정규화를 부품 입력에 두면 깊이 쌓아도 예열 없이 학습된다. 질의를 그림 칸에서, 열쇠와 값을 글 토큰에서 만들면 크로스 어텐션이 되어 칸마다 필요한 낱말을 골라 읽는다. 한 토큰씩 이어 쓰는 모델은 뒤 토큰을 가려 앞 토큰의 열쇠와 값이 바뀌지 않게 하고, 그것을 KV 캐시에 적어 두어 걸음마다 새 토큰의 계산만 한다.

flowchart LR
  A["합성곱<br/>자리마다 정한 무게"] -->|"멀리 있는 짝을<br/>내용으로 못 고른다"| B["셀프 어텐션<br/>질의·열쇠로 비중, 값을 섞기"]
  B -->|"뒤섞어도<br/>같게 읽는다"| C["위치 인코딩<br/>사인 더하기 → 회전"]
  B -->|"소프트맥스 하나는<br/>평균 하나"| D["여러 머리 어텐션"]
  D --> E["트랜스포머 블록<br/>층 정규화 → 부품 → 잔차"]
  C --> E
  E -->|"글을 읽어야 한다"| F["크로스 어텐션<br/>질의는 그림, 열쇠·값은 글"]
  E -->|"한 토큰씩 이어 쓴다"| G["가림 + KV 캐시"]

막힌 곳

이제 그림의 칸들이 거리와 상관없이 서로를 읽고, 글 토큰까지 골라 읽게 할 수 있다. 그런데 셀프 어텐션의 점수 표는 칸 수의 제곱으로 자랐다. Stable Diffusion 1.x 가 512 × 512 그림을 만들 때 가장 고운 단계의 칸이 4096개였던 것은, 그림을 가로세로 8배 줄인 64 × 64칸 위에서 일했기 때문이다. 픽셀마다 칸 하나로 두면 칸이 262,144개, 점수 표 하나에 687억 개가 넘는 점수가 들어간다. 그 64 × 64칸, 칸마다 수 4개인 그림은 어디서 왔을까? 그림을 작게 줄여 놓고 그 위에서 잡음을 섞고 걷어 내도, 줄이기 전의 그림으로 되살릴 수 있을까?