개요
16편까지 오면서 모델은 학습을 마쳤다. 이제 답을 만들어낼 차례다.
그런데 여기서 생각보다 큰 자유도가 하나 남아 있다.
학습이 끝난 모델은 다음 토큰의 확률 분포만 알려준다. 그중에 뭘 고를지는 아직 정해지지 않았다.
같은 모델, 같은 질문인데 답이 매번 다르게 나오는 이유가 여기에 있다. 이번 글은 그 고르는 방법에 대한 이야기다.
교육 자료는 대외비라 슬라이드 이미지나 예제 데이터는 싣지 않는다. 개념 흐름만 내가 이해한 방식으로 재구성했고, 그림은 전부 생성했다.
1. 자동회귀 생성 — 한 토큰씩 만든다
거대 언어 모델이 답을 만드는 방식은 순차적이다.
자동회귀 생성(Auto-regressive Generation) = 토큰을 하나 만들고, 그걸 다시 입력에 붙여서 다음 토큰을 만드는 방식
입력: [아까, 밥, 먹고]
↓ 모델
다음 토큰의 확률 분포:
왔군 0.06
왔어 0.5
왔는데 0.2
왔거든 0.1
...
↓ 하나 고른다
입력: [아까, 밥, 먹고, 왔어]
↓ 다시 모델
...
정리하면 이렇다.
- 입력 $x = [x_1, \ldots, x_L]$ 이 주어진다
- 모델은 다음 토큰에 대한 확률 분포 $\hat{p}(x)$ 를 내놓는다
- 디코딩 알고리즘이 그 분포에서 $x_{L+1}$ 을 고른다
모델은 점수표만 주는 심판이다. 그 점수표를 보고 실제로 하나를 뽑는 사람이 디코딩 알고리즘이다. 둘은 완전히 다른 역할이다.
언제 멈추나
계속 만들다 보면 언제 끝내야 할지가 문제다. 두 가지 조건이 있다.
| 종료 조건 | 설명 |
|---|---|
| EOS 토큰 생성 | 문장 끝을 뜻하는 특수 토큰이 나오면 종료 |
| 최대 토큰 수 도달 | 미리 정해둔 개수만큼 만들면 강제 종료 |
EOS(End Of Sentence) 는 토크나이저가 붙이는 특수 토큰이다. 9편에서 본 [SEP] 같은 것이 그 역할을 한다.
text = "Tokenizing text is a core task of NLP."
↓ 토크나이저
['[CLS]', 'token', '##izing', 'text', 'is', 'a',
'core', 'task', 'of', 'nl', '##p', '.', '[SEP]']
^^^^^^^
문장 종료 표시
두 번째 조건이 실무에서 자주 걸린다. 답이 중간에 뚝 끊기는 현상은 대부분 최대 토큰 수에 먼저 도달한 것이다.
2. 디코딩 알고리즘 — 여섯 갈래
라이브러리에서 제공하는 방식만 봐도 여러 가지다. 이번 글에서는 여섯 가지를 본다.
| # | 이름 | 한 줄 요약 |
|---|---|---|
| ① | Greedy Decoding | 1등만 집는다 |
| ② | Beam Search | 후보 k개를 들고 간다 |
| ③ | Sampling | 확률대로 뽑는다 |
| ④ | Sampling with Temperature | 분포를 조작한 뒤 뽑는다 |
| ⑤ | Top-K Sampling | 상위 K개 안에서만 뽑는다 |
| ⑥ | Top-P Sampling | 누적 확률 P까지만 남기고 뽑는다 |
①과 ②는 11편에서 이미 다뤘으니 짧게 짚고 넘어간다.
3. ① Greedy Decoding
핵심 — 매 순간 가장 확률이 높은 토큰을 고른다.
| 장점 | 사용하기 쉽다. 항상 같은 답이 나온다 |
| 단점 | 직후만 고려하기 때문에 최종 결과가 최선이 아닐 수 있다 |
이 단점이 핵심이다. 지금 1등을 집었는데, 그 뒤에 이어질 수 있는 단어들이 다 별로일 수 있다.
4. ② Beam Search
핵심 — 확률이 높은 k개(beam size)의 후보를 동시에 들고 간다.
고르는 기준이 다르다. 한 시점의 확률이 아니라, 지금까지 만든 문장 전체가 나올 확률의 곱(누적 확률) 이다.
교재 예시가 직관적이다.
"The dog has" = 0.4 × 0.9 = 0.36
"The nice woman" = 0.5 × 0.4 = 0.20
Greedy는 첫 단계에서 0.5인 “nice”를 집는다. 그런데 그 뒤가 0.4밖에 안 된다. Beam Search는 둘 다 들고 가다가 끝에서 누적 확률이 높은 “The dog has” 를 고른다.
| 장점 | 최종적으로 좋은 응답을 생성할 확률이 높다 |
| 단점 | 계산 비용이 많이 늘어난다 (후보마다 추론을 수행) |
5. ③ Sampling — 확률대로 뽑는다
여기서부터가 새로 다루는 내용이다.
핵심 — 모델이 제공한 확률을 기준으로 무작위로 고른다.
"What's your favorite color?"
↓
green 50%
red 30%
the 0.2%
a 0.1%
...
Greedy라면 항상 green이다. Sampling은 주사위를 던진다. 50% 확률로 green, 30% 확률로 red가 나온다.
| 장점 | 다양한 응답을 생성할 수 있다 |
| 단점 | 생성된 응답의 품질이 불안정해질 수 있다 |
단점의 이유가 중요하다. 모델은 사전에 있는 모든 단어에 대해 확률을 매겨놓는다. 0.001% 짜리 이상한 단어도 확률이 0은 아니다. 계속 뽑다 보면 언젠가 걸린다.
100면 주사위에 대부분 정상적인 답이 적혀 있고, 한두 칸에 엉뚱한 답이 적혀 있다고 하자. 한 번은 괜찮다. 그런데 문장 하나 만드는 데 주사위를 200번 던진다면 엉뚱한 칸이 안 걸릴 수가 없다.
6. ④ Sampling with Temperature — 분포를 주무른다
핵심 — 하이퍼파라미터 $T$ 로 확률 분포 자체를 임의로 조작한 뒤 뽑는다.
방향은 두 가지다.
| 설정 | 분포가 | 결과 |
|---|---|---|
| $T > 1$ | 평평해진다 (Smooth) | 더 다양한 응답 |
| $T < 1$ | 뾰족해진다 (Sharp) | 확률 높은 응답에 집중 |
$T < 1$ 일 때
분포가 뾰족해진다. 특정 후보 하나가 압도적으로 높은 확률을 갖고, 나머지는 아주 낮아진다.
모델이 항상 비슷한 답만 내놓게 된다. 안정적이지만 다양성이 떨어진다.
$T > 1$ 일 때
분포가 평평해진다. 모든 단어가 거의 비슷한 확률로 선택될 수 있게 된다.
다양성이 극대화되지만 품질이 불안정해진다. 창의적이나 헛소리가 섞일 수 있다.
극단적으로 $T$ 를 21까지 올리면 그래프가 거의 완전히 평평해진다. 10개 후보가 전부 0.1씩이다. 이 상태면 모델이 학습한 지식이 사실상 무의미해진다.
온도를 낮추면 모범생이 된다. 안전한 답만 반복한다. 온도를 올리면 자유로운 예술가가 된다. 참신하지만 가끔 이해할 수 없는 소리를 한다.
실무에서는 작업 성격에 맞춰 조절한다. 사실 확인이 중요한 작업은 낮게, 아이디어 발산이 필요한 작업은 높게 잡는다.
7. ⑤ Top-K Sampling — 후보를 줄인다
Sampling의 단점은 꼬리에 있는 이상한 단어까지 뽑힐 수 있다는 것이었다. 그럼 잘라내면 된다.
핵심 — 확률이 높은 K개의 토큰들 중에서만 확률에 따라 샘플링한다.
P(w | "The") 의 상위 후보들
nice, dog, car, woman, guy, man | people, big, house, cat
└──────── 남긴다 (K=6) ────────┘ └─── 버린다 ───┘
| 장점 | 품질이 낮은 응답을 생성할 가능성을 줄일 수 있다 |
| 단점 | 확률 분포의 모양과 상관없이 고정된 K개의 후보군을 고려한다 |
단점을 구체적으로 보면 이렇다. 같은 K=6인데 문맥에 따라 상황이 완전히 다르다.
| 문맥 | 상위 6개의 확률 합 |
|---|---|
"The" 다음 |
0.68 |
"The car" 다음 |
0.99 |
-
"The"다음에는 올 수 있는 말이 많다. 6개로 자르면 괜찮은 후보를 버리게 된다 -
"The car"다음에는 사실상drives,is,turns정도다. 6개나 남기면 이상한 후보를 억지로 포함시킨다
문맥에 따라 선택지의 폭이 다른데 K를 고정해두면 어느 쪽에서든 어긋난다.
8. ⑥ Top-P Sampling (Nucleus Sampling)
핵심 — K를 고정하는 대신, 누적 확률(P) 을 기준으로 K를 자동으로 조절한다.
동작은 단순하다.
P = 0.9 로 설정한 경우
1. 확률이 높은 순서대로 더해나간다
2. 합이 처음으로 0.9를 넘는 지점에서 멈춘다
3. 거기까지의 후보만 남기고 그 안에서 샘플링한다
앞의 예시에 적용하면 이렇게 된다.
| 문맥 | Top-K (K 고정) | Top-P (P=0.9) |
|---|---|---|
"The" 다음 |
6개, 합 0.68 | 9개, 합 0.94 |
"The car" 다음 |
6개, 합 0.99 | 3개, 합 0.97 |
선택지가 많은 문맥에서는 넓게, 적은 문맥에서는 좁게 알아서 조절한다.
성능 비교에서도 좋은 결과를 냈다.
| 방법 | 반복률(Repetition %) | 비고 |
|---|---|---|
| Human (사람이 쓴 글) | 0.28 | 기준선 |
| Greedy | 73.66 | 같은 말을 계속 반복 |
| Beam (b=16) | 28.94 | 여전히 높음 |
| Pure Sampling | 0.22 | 반복은 없으나 품질 불안정 |
| Nucleus (p=0.95) | 0.36 | 사람과 가장 비슷 |
Greedy의 반복률 73.66%가 눈에 띈다. 매번 1등만 집으면 같은 표현을 계속 되풀이하게 된다.
9. 한눈에 비교
| 알고리즘 | 장점 | 단점 |
|---|---|---|
| Greedy Decoding | 쉬운 사용법 | 최적해 보장 X |
| Beam Search | 좋은 응답 생성 확률 ↑ | 큰 계산 비용 |
| Sampling | 다양한 응답 생성 가능 | 품질 불안정 |
| Sampling with Temperature | 창의성/안정성 조절 가능 | T↑ 품질 저하 / T↓ 다양성 부족 |
| Top-K Sampling | 잡음 단어 배제, 품질 향상 | K값 고정 → 문맥 따라 불균형 |
| Top-P Sampling (Nucleus) | 확률 누적 기준, 품질·다양성 균형 | P값 설정 필요 (경우에 따라 랜덤성 여전) |
10. 우리가 이미 만지고 있던 값들
이 값들은 이론 속에만 있는 게 아니다. OpenAI Playground 같은 곳의 모델 설정창에 그대로 노출된다.
Temperature 1.00
Max tokens 2048
Top P 1.00
같은 질문(“SSAFY에 대해 알려줘”)을 던져도 이 값을 바꾸면 답의 구성과 길이가 눈에 띄게 달라진다.
챗봇의 답이 마음에 안 들 때 질문만 바꿔볼 게 아니라, 이 손잡이들을 만질 수 있다는 것을 아는 것이 이번 글의 실질적인 소득이다.
실제 코드에서 이 값들을 어떻게 넘기는지는 Python 시리즈 10편에서 다룬다. 개념은 여기, 실행은 그쪽이다.
정리
- 자동회귀 생성 — 토큰을 하나 만들어 다시 입력에 붙이며 순차적으로 생성한다
- 모델은 확률 분포만 준다. 고르는 일은 디코딩 알고리즘의 몫
- 종료 조건은 EOS 토큰 또는 최대 토큰 수. 답이 뚝 끊기면 대개 후자
- Greedy — 1등만 집는다. 쉽지만 최선이 아닐 수 있고 반복률이 매우 높다
- Beam Search — 후보 k개를 들고 누적 확률로 고른다. 계산 비용이 크다
- Sampling — 확률대로 뽑는다. 다양하지만 꼬리의 이상한 단어가 걸린다
-
Temperature — 분포를 평평하게(T>1) / 뾰족하게(T<1) 조작한다
- 낮으면 모범생, 높으면 예술가. 작업 성격에 맞춰 조절
- Top-K — 상위 K개만 남긴다. 단 문맥에 따라 선택지 폭이 다른데 K가 고정이다
- Top-P (Nucleus) — 누적 확률로 자르니 K가 자동으로 조절된다. 균형이 가장 좋다
- 이 값들은 Playground 설정창에 그대로 나와 있다. 만질 수 있다는 걸 아는 것이 중요하다
다음 글에서
디코딩은 모델이 준 확률을 어떻게 쓸 것인가의 문제였다. 그럼 애초에 모델에게 무엇을 넣을 것인가는?
다음 글에서는 프롬프트 엔지니어링 — 시스템 프롬프트, 예시 선택, Chain-of-Thought를 다룬다.
참고 자료
한줄 평
- 재밌는 하이퍼 파라미터 조정여행