"LLM 핵심 학습 (3/6) — 디코딩과 생성: Greedy·Beam·Top-p·Speculative"

모델이 한 번 forward해서 만든 vocab 크기 logits은 분포일 뿐이다. 그 분포에서 어떤 토큰을 뽑는가가 사용자 눈에 보이는 텍스트의 품질을 좌우한다. 이 편은 디코딩 전략을 결정론·확률론·구조 탐색·가속 네 갈래로 정리한다.


0. 학습 목표

  • logits → 확률 → 다음 토큰 한 개를 뽑는 전체 흐름을 코드로 재현한다.
  • Temperature, Top-k, Top-p (Nucleus, Holtzman 2020), Min-p의 차이를 한 줄씩 적는다.
  • GreedyBeam Search언제 좋고 길이 패널티가 필요한지 답한다.
  • Repetition Penalty, Frequency/Presence Penalty의 식과 부작용을 안다.
  • Speculative Decoding (Leviathan 2023)의 수락 조건을 손으로 검증한다.
  • AR vs Masked 생성 모델의 학습/추론 차이를 구분한다.

1. 핵심 요약

  • 디코딩 = "logits에서 토큰을 뽑는 정책". 한 번에 1토큰씩 자기회귀로 반복.
  • Greedy/Beam은 결정론적. Beam은 길이 패널티가 없으면 짧은 출력을 선호.
  • Temperature·Top-k·Top-p는 확률 분포 변형. 작은 \(T\)는 더 결정적, 큰 \(T\)는 더 다양.
  • Nucleus(Top-p)는 동적 cutoff. 분포가 평평할 때 Top-k보다 더 다양성을 잘 유지.
  • Speculative Decoding은 작은 draft 모델이 \(k\) 토큰을 미리 만들고 원본 모델이 한 번의 forward로 검증해 수학적으로 동등한 분포를 더 적은 forward로 만든다.
  • AR(GPT)은 좌→우 순차 생성. Masked(BERT)는 양방향 인코더로 분류·임베딩 용도.

2. 직관: logits에서 토큰을 뽑는 게임

길이 \(t\)까지 입력을 본 모델은 다음 토큰 분포를

$$ P(x_{t+1} \mid x_{1:t}) = \mathrm{softmax}(z),\ \ z \in \mathbb{R}^{|V|} $$

로 출력한다. 디코더는 이 분포에서 토큰 하나를 뽑고, 다시 그 토큰을 입력에 붙여서 다음 분포를 만든다. 이를 "stop 토큰" 또는 길이 한도까지 반복한다.

선택을 어떻게: (a) 가장 큰 logit, (b) 상위 \(k\)개에서 무작위 샘플, (c) 누적 확률 \(p\)까지 잘라 샘플, (d) 빔 후보 \(B\)개를 동시에 확장. 같은 모델이라도 디코더에 따라 출력 텍스트의 결정성·다양성·길이·반복 경향이 크게 달라진다.


3. 결정론 디코더 — Greedy와 Beam

3.1 Greedy

각 스텝에서 \(\arg\max_z\). 가장 단순하지만 국소 최적에 갇혀 긴 호흡의 정답을 놓치기 쉽다. 같은 입력 → 같은 출력(완전 결정론).

def greedy_decode(model, ids, max_new_tokens=64):
    for _ in range(max_new_tokens):
        with torch.no_grad():
            logits = model(ids)[:, -1, :]  # (B, |V|)
        next_id = logits.argmax(dim=-1, keepdim=True)
        ids = torch.cat([ids, next_id], dim=1)
        if next_id.item() == EOS_ID:
            break
    return ids

3.2 Beam Search

매 스텝에서 상위 \(B\)개 부분 시퀀스를 유지하면서 확장한다. 각 후보의 로그확률 합을 비교해 \(B\)개를 다시 추린다.

$$ \text{score}(x_{1:t}) = \sum_{i=1}^{t} \log P(x_i \mid x_{<i}). $$

3.2.1 길이 패널티

\(\log P\)는 음수이므로 문장이 길수록 누적 스코어가 작아진다. 길이 패널티 없이는 짧은 문장이 항상 이긴다. 표준은

$$ \text{score}_{\text{lp}}(x_{1:T}) = \frac{\sum_i \log P(x_i \mid x_{<i})}{((5 + T)/6)^\alpha},\ \ \alpha \in [0.6, 1.0] $$

(Wu et al., 2016, Google NMT). 또는 단순 평균 \((1/T) \sum \log P\)을 쓰기도 한다.

3.2.2 장점·단점

  • ✅ 결정적이고 지역 탐욕보다 일관된 텍스트.
  • ❌ Beam 크기 \(B\)배 메모리·연산.
  • 반복 루프에 빠지기 쉽다. \(B\)개 후보가 같은 토큰 시퀀스로 수렴해 출력이 단조로워진다.
  • ❌ 창의적 생성(스토리·자유 작문)에는 부적합. 대신 번역·요약에 강하다.

3.3 다이어그램

diagram-1

4. 확률 기반 디코더 — Temperature·Top-k·Top-p·Min-p

4.1 Temperature

$$ P_T(y) = \frac{\exp(z_y / T)}{\sum_{y'} \exp(z_{y'}/T)}. $$

  • \(T = 1\): 모델 분포 그대로.
  • \(T \to 0\): 분포가 \(\arg\max\)에 집중 → Greedy 동등.
  • \(T > 1\): 분포가 평평해져 다양성 증가, 일관성 저하.

코드:

def sample_with_temperature(logits, T=0.8):
    probs = torch.softmax(logits / T, dim=-1)
    return torch.multinomial(probs, num_samples=1)

4.2 Top-k

확률 상위 \(k\)개를 제외한 logits에 \(-\infty\)를 채워 분포를 잘라 낸다.

$$ P^{(k)}(y) = \begin{cases} P(y)/Z & y \in \mathrm{TopK} \\ 0 & \text{otherwise} \end{cases} $$

장점: 항상 \(k\)개 후보. 단점: 분포가 평평한 곳에서 \(k\)가 부족하고, 분포가 매우 뾰족한 곳에서는 \(k\)가 과잉.

4.3 Top-p (Nucleus, Holtzman 2020)

확률을 내림차순 정렬해 누적합이 \(p\)를 처음 넘는 위치까지 남기고 자른다.

$$ \mathrm{Nucleus}_p = \{y_1, y_2, \dots, y_K\}\quad \text{s.t.}\quad \sum_{i=1}^{K} P(y_i) \ge p,\ \ y_i \text{ 내림차순} $$

분포가 평평하면 \(K\)가 크고, 뾰족하면 \(K\)가 작다. 적응적. 보통 \(p = 0.9 \sim 0.95\)가 표준.

def top_p_filter(logits, p=0.9):
    sorted_logits, sorted_idx = torch.sort(logits, descending=True)
    probs = torch.softmax(sorted_logits, dim=-1)
    cum = torch.cumsum(probs, dim=-1)
    mask = cum > p
    mask[..., 0] = False  # 최소 한 개는 남긴다
    sorted_logits[mask] = float('-inf')
    return sorted_logits.scatter(-1, sorted_idx, sorted_logits)

4.4 Min-p

Min-p는 최대 확률 대비 비율 임계값이다. \(P_{\max} = \max_y P(y)\)일 때 \(P(y) < \text{minp} \cdot P_{\max}\)인 후보를 제거. Top-p 대비 분포가 뾰족할 때 더 자연스럽게 좁아지고, 평평할 때 적당히 넓게 유지.

4.5 결합 사용

실무에서 흔한 조합: Temperature → Top-k 또는 Top-p → 샘플. 예: T=0.7, top_p=0.9. T를 먼저 적용해 분포를 조정한 뒤 cutoff. 순서가 바뀌면 결과가 미세하게 달라진다(softmax 비선형성 때문).

4.6 한계

  • 샘플링은 비결정적. 평가·디버깅에는 보통 Greedy 또는 \(T = 0\) 사용.
  • 다양성과 일관성은 항상 트레이드오프. 도메인별 최적값이 다르다.

5. 반복 제어 — Repetition·Frequency·Presence Penalty

5.1 Repetition Penalty (Keskar 2019)

이미 등장한 토큰의 logit을 나누거나 빼서 다시 나올 확률을 낮춘다.

$$ z'_y = \begin{cases} z_y / r & z_y > 0,\ y \in \text{history} \\ z_y \cdot r & z_y < 0,\ y \in \text{history} \\ z_y & \text{otherwise} \end{cases},\ \ r > 1 $$

부작용: 정답이 반복일 때(예: 사람 이름 재호명) 부자연스럽게 회피한다.

5.2 Frequency Penalty (OpenAI API)

토큰 \(y\)가 \(n\)번 등장했다면 logit에서 \(n \cdot \alpha\)를 뺀다. 반복 누적 제어.

5.3 Presence Penalty (OpenAI API)

토큰이 한 번이라도 등장했다면 logit에서 상수 \(\beta\)를 뺀다. 새 토픽으로의 전환을 유도.

5.4 No-Repeat n-gram (Beam Search)

이미 등장한 \(n\)-gram은 다음 후보에서 강제 제외. 번역에서 흔히 쓰임. 정답 자체가 반복일 때 손해.


6. Speculative Decoding (Leviathan 2023)

6.1 문제

LLM 추론의 병목은 직렬화다. \(T\) 토큰을 만들려면 \(T\)번의 forward가 필요. GPU는 거대한 행렬곱에서 매번 같은 KV 캐시 메모리를 읽어와 한 토큰만 만든다 — 산술강도가 낮아 메모리 대역폭에 묶인다.

6.2 아이디어

작은 draft 모델 \(M_q\)가 \(k\)개 토큰을 순차로 만든다(빠름). 큰 target 모델 \(M_p\)가 한 번의 forward로 그 \(k\)개 위치의 logits을 모두 본다(병렬). 각 위치에서 다음 확률 비교를 통해 어디까지 받아들일지 결정한다.

수락 규칙 (위치 \(i\)):

$$ \text{accept with prob} = \min\!\left(1, \frac{p_i(x_i)}{q_i(x_i)}\right) $$

거절되면 그 위치에서 분포 \((p - q)_+\)를 정규화해 대신 한 토큰을 뽑는다. 이 절차가 분포적으로 정확히 \(p\)에서 뽑은 것과 같다는 것이 핵심 정리(Leviathan et al., 2023, Theorem 1).

6.3 평균 가속

draft의 수락률 \(\alpha\)에 대해 평균 한 번의 target forward가 \(1 + \alpha + \alpha^2 + \dots + \alpha^{k-1}\)개 토큰을 만든다. \(\alpha = 0.7, k = 5\)면 평균 \(\approx 2.6\)배 가속. 단, draft 비용도 더해야 하므로 실측 가속은 1.5~3배가 흔하다.

6.4 구현 핵심

  • draft 모델은 같은 어휘를 공유해야 함.
  • target에서 \(k+1\)번째 위치의 logits도 함께 얻어, 모두 거절 시 fallback 토큰으로 사용.
  • KV 캐시 동기화에 주의: 거절 후 KV 캐시를 거절된 위치까지 잘라야 함.

6.5 변형

  • Medusa: 단일 모델에 여러 예측 헤드를 붙여 \(k\) 토큰을 동시에 예측. draft 모델이 필요 없다.
  • Lookahead Decoding: 동일 모델에서 N-gram 캐시로 가속.
  • EAGLE-2: draft 모델을 더 정교하게 학습한 후속 방법.

6.6 한계

  • 수락률이 낮은 도메인(코드, 수학 등)에서는 가속이 미미.
  • 메모리 \(\sim 2\)배(draft + target). 작은 모델·임베디드에는 불리.

7. AR vs Masked

7.1 Autoregressive (GPT 계열)

$$ P(x_{1:T}) = \prod_{t=1}^{T} P(x_t \mid x_{<t}). $$

학습 시 인과 마스크로 미래를 가린 채 모든 위치에서 다음 토큰 cross-entropy를 합산. 추론은 좌→우 순차.

7.2 Masked Language Model (BERT 계열)

학습 시 입력의 일부(\(15\%\))를 [MASK]로 치환하고 그 위치의 토큰을 양방향 컨텍스트로 복원. 양방향 인코더이므로 생성에는 부적합, 분류·임베딩에 강하다.

7.3 비교

측면 AR (GPT) MLM (BERT)
학습 목표 다음 토큰 예측 마스크 토큰 복원
마스크 인과 (상삼각) 무작위 위치 mask
방향성 좌→우 양방향
생성 자기회귀 가능 직접 생성 불가 (T5 같은 인코더-디코더 별도 필요)
분류 마지막 hidden state 사용 [CLS] 또는 hidden state pooling

T5(인코더-디코더), Prefix-LM(중간형), Diffusion-LM(잡음 제거형) 같은 변형도 있지만, 디코딩 전략 이야기는 대부분 AR을 전제로 한다.


8. 정리된 결론 — 보지 않고 답해 보라

이 글이 답한 핵심 질문 5개. 먼저 답을 가린 채로 한 줄로 답해 본 뒤 정답과 비교.

Q1. Greedy와 Beam의 결정성·메모리 비교는?

정답 둘 다 결정론적 (같은 입력 → 같은 출력). 메모리: Greedy O(1), Beam O(\(b \cdot L\)) — beam 수 \(b\)와 길이 \(L\)에 비례. Greedy는 매 step argmax 한 토큰만 추적, Beam은 상위 \(b\)개 가설 동시 추적. Beam은 번역·요약처럼 명확한 정답이 있는 작업에서 우세. 창의적 생성은 stochastic 디코더가 적합. (본문 §3)

Q2. Top-p가 Top-k보다 동적이라는 의미는?

정답 Top-k는 고정 개수 \(k\) 토큰을 자름. Top-p는 누적 확률 합 \(p\) 가 되는 만큼 자름 — 분포가 뾰족하면 적게, 평탄하면 많이. "확신 있는 분포는 좁게, 모호한 분포는 넓게"라는 직관. 같은 \(p=0.9\) 가 한 step에서는 토큰 3개, 다른 step에서는 50개를 선택. Holtzman et al. 2020. (본문 §4)

Q3. Frequency vs Presence Penalty의 차이는?

정답 Frequency: 같은 토큰이 몇 번 나왔는가 에 비례한 페널티. Presence: 토큰이 한 번이라도 나왔으면 고정 페널티. Frequency는 반복 빈도 자체를 줄임, Presence는 다양성 을 유도. OpenAI API에서 두 파라미터를 별도로 제공하는 이유. (본문 §5)

Q4. Speculative Decoding의 수락 규칙을 식으로 적으면? 왜 draft·target이 같은 어휘를 써야 하나?

정답 수락 확률: \(\min\!\left(1, \frac{p_{\text{target}}(t)}{p_{\text{draft}}(t)}\right)\). 어휘 공유: draft가 만든 토큰을 target이 해석할 수 있어야 검증 가능. Leviathan 2023. draft 모델이 작고 빠른 모델로 N개 토큰을 한 번에 예측, target 모델이 병렬로 검증. 어휘가 다르면 토큰 ID가 호환되지 않아 검증 자체 불가. 2~3배 latency 감소. (본문 §6)

Q5. AR과 MLM 학습 목표의 차이를 한 줄로?

정답 AR (Autoregressive, GPT 계열): 다음 토큰 예측. MLM (Masked LM, BERT 계열): 가려진 토큰 예측 (양방향 문맥 사용). AR은 생성 최적, MLM은 표현 학습 최적. 같은 트랜스포머 아키텍처가 학습 목표 만 바뀌면 다른 모델이 된다는 본질. 디코딩 알고리즘은 AR에만 적용. (본문 §7)


5개를 한 줄로 답할 수 있었다면 디코딩의 결정론 vs 확률 → 반복 제어 → speculative → AR vs MLM 흐름이 자리잡은 것이다.


9. 실습 과제

  1. temperature ∈ {0.1, 0.7, 1.5}, top_p ∈ {0.5, 0.9, 0.99}로 같은 프롬프트에 10개씩 샘플을 만들어 다양성과 일관성을 5단계로 평가한다.
  2. Beam=4, length_penalty α ∈ {0.0, 0.6, 1.0}로 번역 짧은 문장을 디코딩하고 출력 길이 분포를 비교한다.
  3. transformers 라이브러리에서 assistant_model 인자(speculative)를 사용해 동일 입력의 토큰/초 처리량을 측정한다.
  4. Top-p 필터 코드에서 mask[..., 0] = False 한 줄을 제거하면 어떤 입력에서 무엇이 깨지는지 시뮬레이션한다.

10. 추가 학습


이 글은 LLM 핵심 학습 시리즈의 3/6 편이다. 다음 편(4/6)은 고급 — RAG·CoT·MoE·In-Context Learning으로 이어진다.

시리즈 전체 안내: 시리즈 목차

댓글

이 블로그의 인기 게시물

"LLM 핵심 학습 (1/6) — 기본: 토큰화·임베딩·어텐션·위치 인코딩"

"LLM 핵심 학습 (2/6) — 파인튜닝: LoRA·QLoRA·증류·Adapter"

"ML 기초 학습 (1/9) — 머신러닝과 sklearn: 학습의 좌표계"