3장. Attention 과 Transformer, GPT 직접 구현
GPT 논문 읽기
요리책의 레시피를 처음 볼 때는 재료 목록과 순서만 먼저 훑고, 세세한 불 조절은 나중에 봅니다. 논문도 같습니다. 2018년 OpenAI 가 낸 첫 GPT 논문 "Improving Language Understanding by Generative Pre-Training" 을 이렇게 읽어 봅니다.
1번 사전학습은 정답 표시 없는 책 글로 "다음 낱말 맞히기"를 배우는 단계이고, 2번 미세조정은 정답이 붙은 적은 데이터로 과제에 맞춰 다듬는 단계입니다. 그렇게 다듬은 모델로 3번의 분류, 추론, 질문 답하기 같은 과제를 풉니다. 여기서 레시피의 재료가 데이터와 모델 크기, 순서가 두 단계의 학습입니다.
논문을 읽는 순서
| 순서 | 읽을 곳 | 무엇을 찾나 |
|---|---|---|
| 1 | 초록(Abstract) | 무엇을 했고 결과가 어땠나, 세 문장으로 |
| 2 | 그림 1 과 표 | 모델의 짜임과 성적 |
| 3 | 결론(Conclusion) | 저자가 말하는 의미와 한계 |
| 4 | 방법(Framework) | 사전학습과 미세조정의 식 |
| 5 | 실험(Experiments) | 데이터, 설정, 견준 상대 |
처음부터 끝까지 차례로 읽기보다, 1~3을 먼저 훑어 큰 그림을 잡고 4~5를 나중에 봅니다.
GPT-1 의 핵심 숫자
| 항목 | 논문의 값 | 이 장의 미니 GPT |
|---|---|---|
| 짜임 | 디코더만 쓰는 Transformer | 같다 |
| 블록 수 | 12 | 2 |
| 임베딩 좌표 수 | 768 | 64 |
| 헤드 수 | 12 | 4 |
| 한 번에 보는 길이 | 토큰 512개 | 글자 64개 |
| 사전학습 데이터 | BooksCorpus(책 약 7,000권) | 고객센터 대화 1,500개 |
| 토큰 | 서브워드(BPE) | 글자 |
| 파라미터 | 약 1억 1,700만 | 약 12만 |
논문의 핵심 주장은 "라벨 없는 글로 사전학습해 두면, 적은 정답 데이터로도 여러 과제를 잘한다"입니다. 이 생각이 GPT-2, GPT-3 를 거쳐 지금의 LLM 으로 이어졌습니다. 4장에서 사전학습과 미세조정을 직접 해 봅니다.
# 미니 GPT 의 설정을 논문의 설정과 견주어 크기를 어림해 본다
mini = {"블록": 2, "좌표": 64}
paper = {"블록": 12, "좌표": 768}
# 블록 하나의 파라미터는 대략 12 × 좌표² 이다(어텐션 4 × 좌표² + FFN 8 × 좌표²)
for name, cfg in [("미니 GPT", mini), ("GPT-1", paper)]:
approx = cfg["블록"] * 12 * cfg["좌표"] ** 2
print(f"{name}: 블록 부분 약 {approx:,}개")미니 GPT 의 블록 부분은 약 98,304개, GPT-1 은 약 84,934,656개로 어림됩니다. 임베딩 표까지 더하면 GPT-1 은 논문의 1억 1,700만 개에 가까워집니다. 좌표 수가 12배면 파라미터는 그 제곱인 144배쯤 늘어난다는 것을 이 어림으로 알 수 있습니다.
코드에 나오는 함수
| 코드 | 쉬운 뜻 |
|---|---|
mini, paper | 블록 수와 좌표 수만 적은 사전이다. 크기를 어림하는 데 필요한 두 값이다 |
12 * cfg["좌표"] ** 2 | 블록 하나의 파라미터를 어림한다. 어텐션의 Q, K, V, 출력 가중치 4개가 각각 좌표×좌표이고, 피드포워드가 그 8배쯤이다 |
cfg["블록"] * ... | 블록 하나의 어림에 블록 수를 곱해 블록 부분 전체를 낸다 |
f"{approx:,}" | 세 자리마다 쉼표를 넣어 큰 수를 읽기 쉽게 적는다 |
이 어림에는 임베딩 표와 LayerNorm, 치우침(bias) 값이 빠져 있습니다. 그래서 정확한 개수가 아니라 크기의 차이를 견주는 데만 씁니다.
이 코드가 뜻하는 것
이 코드는 모델을 실제로 만들지 않고, "블록 수"와 "좌표 수" 두 숫자만으로 모델의 크기를 셈해 보는 코드입니다. 집을 짓기 전에 층수와 한 층의 넓이로 전체 넓이를 어림하는 것과 같습니다.
왜 "좌표²"일까요. 2장에서 본 것처럼 층의 가중치는 들어오는 칸과 나가는 칸을 잇는 선 하나마다 숫자 하나입니다. 좌표 64개가 들어와 64개로 나가면 선이 64 × 64 = 4,096개, 곧 가중치 4,096개입니다. 블록 하나에는 이런 묶음이 어텐션에 4개(Q, K, V, 출력), 피드포워드에 8개만큼 있어서 "12 × 좌표²"입니다.
| 셈 | 미니 GPT | GPT-1 |
|---|---|---|
| 좌표² | 64 × 64 = 4,096 | 768 × 768 = 589,824 |
| 블록 하나(× 12) | 49,152 | 7,077,888 |
| 블록 전체(× 블록 수) | × 2 = 98,304 | × 12 = 84,934,656 |
좌표 수는 12배(64 → 768)인데 블록 하나의 크기는 144배가 됩니다. 넓이가 가로와 세로를 곱한 것이듯, 좌표²는 들어오는 칸과 나가는 칸이 함께 늘어나기 때문입니다. 여기에 블록 수까지 6배(2 → 12)가 되어 전체는 약 864배 차이가 납니다.
주의할 점
- 논문의 숫자를 그대로 외우기보다 "무엇을 무엇과 견주었나"를 봅니다. 성적표의 상대가 무엇이었는지에 따라 같은 숫자의 뜻이 달라집니다.
- 이 절의 GPT-1 숫자는 논문에 실린 값입니다. 원문은 OpenAI 누리집에서 PDF 로 볼 수 있습니다.