개요

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등을 집었는데, 그 뒤에 이어질 수 있는 단어들이 다 별로일 수 있다.


핵심 — 확률이 높은 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$ 로 확률 분포 자체를 임의로 조작한 뒤 뽑는다.

Temperature의 효과

방향은 두 가지다.

설정 분포가 결과
$T > 1$ 평평해진다 (Smooth) 더 다양한 응답
$T < 1$ 뾰족해진다 (Sharp) 확률 높은 응답에 집중

$T < 1$ 일 때

분포가 뾰족해진다. 특정 후보 하나가 압도적으로 높은 확률을 갖고, 나머지는 아주 낮아진다.

모델이 항상 비슷한 답만 내놓게 된다. 안정적이지만 다양성이 떨어진다.

$T > 1$ 일 때

분포가 평평해진다. 모든 단어가 거의 비슷한 확률로 선택될 수 있게 된다.

다양성이 극대화되지만 품질이 불안정해진다. 창의적이나 헛소리가 섞일 수 있다.

극단적으로 $T$ 를 21까지 올리면 그래프가 거의 완전히 평평해진다. 10개 후보가 전부 0.1씩이다. 이 상태면 모델이 학습한 지식이 사실상 무의미해진다.

온도를 낮추면 모범생이 된다. 안전한 답만 반복한다. 온도를 올리면 자유로운 예술가가 된다. 참신하지만 가끔 이해할 수 없는 소리를 한다.

실무에서는 작업 성격에 맞춰 조절한다. 사실 확인이 중요한 작업은 낮게, 아이디어 발산이 필요한 작업은 높게 잡는다.


7. ⑤ Top-K Sampling — 후보를 줄인다

Sampling의 단점은 꼬리에 있는 이상한 단어까지 뽑힐 수 있다는 것이었다. 그럼 잘라내면 된다.

핵심 — 확률이 높은 K개의 토큰들 중에서만 확률에 따라 샘플링한다.

Top-K와 Top-P

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를 다룬다.

참고 자료

한줄 평

  • 재밌는 하이퍼 파라미터 조정여행