Field Log · Entry
언어모델 입문: 다음 토큰 예측이 문장 생성이 되는 이유 (5/10)
오늘의 결론
- language model은 앞의 token들이 주어졌을 때 다음 token의 확률 분포를 계산합니다.
- 긴 문장의 확률은 각 위치의 조건부확률을 곱하는 chain rule로 분해할 수 있습니다.
- 학습 때는 정답 이전 token을, 생성 때는 모델이 방금 고른 token을 다음 입력으로 사용합니다.
- “그럴듯한 다음 token”이라는 목표는 사실 검증과 다릅니다. RAG는 이 간극에 외부 근거를 넣습니다.
LLM이 번역하고, 요약하고, 코드를 쓰고, 질문에 답하는 모습을 보면 “다음 단어 맞히기”라는 설명이 너무 단순해 보입니다. 하지만 핵심 학습 목표는 정말 다음 token 예측입니다.
차이는 규모와 context 처리 능력에 있습니다. 수많은 문장에서 다음 token을 잘 맞히려면 문법, 문체, 개념 관계, 코드 패턴과 세계에 대한 통계적 규칙을 압축해야 합니다. Transformer는 긴 context에서 이 예측을 수행하고, 같은 과정을 반복해 문장을 만듭니다.
그림 1. 학습은 여러 위치의 다음 token을 병렬로 채점하고, 생성은 방금 선택한 token을 붙여 한 칸씩 반복한다.
Language model이 계산하는 것
문장 token을 x₁, x₂, …, xₙ이라고 하겠습니다. 문장 전체의 확률은 chain rule로 분해할 수 있습니다.
P(x₁, x₂, …, xₙ)
= P(x₁)
× P(x₂ | x₁)
× P(x₃ | x₁, x₂)
× …
× P(xₙ | x₁, …, xₙ₋₁)
즉 매 위치에서 “앞의 token들이 주어졌을 때 다음 token이 무엇일까?”를 풀면 문장 전체를 모델링할 수 있습니다.
입력 context: [서울은] [대한민국의]
다음 token 분포:
[수도] 0.66
[도시] 0.24
[강] 0.10
모델은 하나의 정답 문자열을 바로 내놓지 않습니다. vocabulary의 모든 token에 대한 logit을 만들고, 이를 확률 분포로 바꿉니다. 어떤 token을 고를지는 greedy, sampling 같은 decoding 전략이 결정합니다.
n-gram이 먼저 풀었던 문제
Transformer 전에도 language model은 있었습니다. n-gram은 최근 n-1개 단어만 보고 다음 단어 확률을 셉니다.
bigram: P(수도 | 대한민국의)
trigram: P(수도 | 서울은, 대한민국의)
말뭉치에서 “대한민국의 수도”가 자주 나왔다면 높은 확률을 줄 수 있습니다. 하지만 본 적 없는 조합에는 count가 없고, context를 길게 늘리면 가능한 조합 수가 폭발합니다. smoothing으로 완화할 수 있지만 의미가 비슷한 표현 사이의 일반화는 제한적입니다.
Bengio et al.의 2003년 neural probabilistic language model은 단어를 distributed representation으로 바꾸고 neural network로 확률을 계산해, 비슷한 단어와 문맥 사이에 학습 신호를 공유하는 방향을 제시했습니다.
학습 데이터는 한 칸 밀어서 만든다
causal language model의 label은 별도 사람이 작성하지 않아도 됩니다. 원문 sequence를 한 칸 이동하면 됩니다.
원문: [나는] [RAG를] [만든다] [EOS]
위치 1 입력 [나는] → 정답 [RAG를]
위치 2 입력 [나는, RAG를] → 정답 [만든다]
위치 3 입력 [나는, RAG를, 만든다] → 정답 [EOS]
구현에서는 전체 sequence를 한 번에 넣고 각 위치의 logits를 다음 위치 token과 비교합니다.
inputs = tokens[:, :-1]
targets = tokens[:, 1:]
logits = model(inputs) # [batch, sequence, vocabulary]
loss = cross_entropy(
logits.reshape(-1, vocabulary_size),
targets.reshape(-1),
)
이때 padding이나 학습에서 제외할 위치는 label을 mask합니다. 각 유효 위치의 cross entropy를 평균해 batch loss를 만듭니다.
Teacher forcing이란
학습 중 각 위치에는 모델의 이전 예측이 아니라 데이터의 정답 이전 token이 주어집니다. 이를 teacher forcing이라고 합니다.
학습:
정답 "나는 RAG를 만든다"를 한 번에 제공
→ 각 위치에서 다음 정답을 채점
생성:
"나는" 제공
→ 모델이 "RAG를" 선택
→ "나는 RAG를" 다시 입력
→ 모델이 "만든다" 선택
학습은 정답 sequence가 이미 있으므로 여러 위치의 loss를 GPU에서 병렬 계산할 수 있습니다. 생성은 다음 입력이 직전 출력에 의존하므로 기본적으로 token을 순차적으로 만듭니다. 이 차이가 training과 inference 성능 특성의 차이를 만듭니다.
미래를 보지 못하게 하는 Causal mask
학습 때 전체 정답 sequence를 한 번에 넣으면 모델이 오른쪽의 정답 token을 미리 훔쳐볼 수 있습니다. causal mask는 각 위치가 자기보다 오른쪽 미래 위치를 attention하지 못하게 막습니다.
볼 수 있음 = ○, 볼 수 없음 = ×
나는 RAG를 만든다
나는 ○ × ×
RAG를 ○ ○ ×
만든다 ○ ○ ○
이 삼각형 mask 덕분에 병렬 학습을 하면서도 각 위치는 실제 생성 시점과 같은 왼쪽 context만 사용합니다.
생성은 같은 forward를 반복한다
prompt가 들어오면 모델은 다음 과정을 반복합니다.
- 현재 context로 다음-token logits 계산
- temperature, top-p 등의 규칙 적용
- token 하나 선택
- context 뒤에 선택한 token 추가
- EOS 또는 중단 조건까지 반복
tokens = tokenizer.encode(prompt)
for _ in range(max_new_tokens):
logits = model(tokens)[-1]
next_token = sample(logits)
tokens.append(next_token)
if next_token == eos_token_id:
break
실제 구현은 매번 전체 attention 계산을 되풀이하지 않도록 KV cache를 사용합니다. 그 원리는 9편에서 자세히 다룹니다.
모델은 문장을 저장해 꺼내는 DB가 아니다
language model의 parameter에는 학습 데이터의 패턴이 분산되어 있습니다. “서울은 대한민국의” 뒤에 “수도”가 올 가능성을 높일 수 있지만, 특정 사실을 key로 정확히 조회하는 데이터베이스 인터페이스가 아닙니다.
세 가지를 구분해야 합니다.
- 확률적 완성: 현재 context에서 그럴듯한 다음 token
- 기억된 패턴: 학습 데이터에서 얻어 parameter에 압축된 관계
- 검증 가능한 사실: 현재 시점의 신뢰할 수 있는 출처가 지지하는 주장
첫 번째가 강하다고 세 번째가 자동 보장되지는 않습니다. 모델은 모르는 상황에서도 확률 분포를 만들고 token을 선택해야 합니다. 문법적으로 자연스럽지만 출처가 없는 답이 나올 수 있습니다.
Hallucination을 학습 목표에서 바라보기
“모델이 거짓말한다”는 표현만으로는 설계하기 어렵습니다. 다음-token objective 관점에서는 이렇게 볼 수 있습니다.
- 모델은 true/false 판정기가 아니라 다음 token 분포를 학습했습니다.
- prompt가 답변 형식을 요구하면 답변처럼 이어지는 token을 선택합니다.
- parameter 지식이 부족하거나 충돌해도 생성 루프는 계속됩니다.
- 자연스러움과 사실성은 상관이 있을 수 있지만 같은 목표는 아닙니다.
그래서 hallucination 대응은 “더 단호하게 답하라” 같은 prompt만으로 끝나지 않습니다.
- 최신·도메인 지식을 retrieval로 제공
- 각 주장에 출처를 연결
- 근거가 부족하면 abstain
- 생성 뒤 claim-evidence 검증
- 정답 집합으로 faithfulness 평가
RAG가 language model에 더하는 것
RAG는 next-token model을 없애지 않습니다. 조건부확률의 조건에 검색 문서를 추가합니다.
기본 LM:
P(answer token | user question, previous answer tokens)
RAG:
P(answer token | user question, retrieved evidence, previous answer tokens)
검색이 올바른 근거를 context에 넣으면, 모델은 parameter의 희미한 기억만으로 답하지 않고 제공된 문서를 따라갈 수 있습니다. 하지만 검색이 틀리면 잘못된 조건에서 자연스러운 답을 만들 수 있습니다. 그래서 retrieval 평가와 generation 평가를 나눠야 합니다.
Perplexity는 무엇인가
language model의 기본 평가는 held-out text의 평균 negative log-likelihood입니다. 이를 지수화한 값이 perplexity입니다.
perplexity = exp(평균 cross-entropy)
직관적으로는 매 위치에서 모델이 몇 개 후보 사이에서 헷갈리는지 나타내는 값으로 읽을 수 있습니다. 낮을수록 해당 데이터 분포의 다음 token을 잘 예측합니다.
하지만 perplexity가 낮다고 RAG 답변의 정확성, 인용 충실도, 도구 사용 능력이 자동으로 좋은 것은 아닙니다. 제품 task에 맞는 별도 평가가 필요합니다.
10분 실습: 생성 루프의 누적 오류 관찰하기
실제 모델이 없어도 확률 선택의 차이를 생각해 볼 수 있습니다.
import random
transitions = {
"나는": [("RAG를", 0.7), ("사과를", 0.3)],
"RAG를": [("만든다", 0.8), ("먹는다", 0.2)],
"사과를": [("먹는다", 0.9), ("만든다", 0.1)],
}
def choose(options):
words, weights = zip(*options)
return random.choices(words, weights=weights, k=1)[0]
tokens = ["나는"]
for _ in range(2):
tokens.append(choose(transitions[tokens[-1]]))
print(" ".join(tokens))
첫 선택에서 “사과를”이 나오면 다음 분포도 달라집니다. autoregressive generation에서는 초기의 작은 선택이 이후 context가 되어 경로 전체를 바꿉니다. temperature와 sampling이 출력 다양성과 안정성에 영향을 주는 이유입니다.
자주 하는 오해
“다음 token만 보니 긴 문맥은 이해하지 못한다.”
예측 대상은 다음 token 하나지만, 그 분포를 계산할 때 긴 이전 context를 사용할 수 있습니다. 무엇을 얼마나 잘 반영하는지는 architecture, 학습, context 길이와 데이터에 달렸습니다.
“greedy decoding이면 사실을 말한다.”
가장 확률이 큰 token을 고르는 것과 사실 검증은 다릅니다. 잘못된 전제에서 가장 그럴듯한 답을 일관되게 만들 수도 있습니다.
“RAG를 쓰면 hallucination이 사라진다.”
RAG는 근거를 제공하지만 잘못된 검색, context 무시, 근거 왜곡이 남습니다. retrieval과 faithfulness를 측정해야 합니다.
스스로 확인하기
- 문장 전체 확률을 다음-token 조건부확률의 곱으로 어떻게 분해하는가?
- teacher forcing과 실제 generation의 입력이 다른 점은 무엇인가?
- causal mask가 없으면 학습 때 어떤 부정행위가 가능한가?
- next-token probability와 사실성은 왜 같은 개념이 아닌가?
다음 글에서는 긴 context에서 각 token이 어떤 다른 token을 참고할지 정하는 self-attention의 Q·K·V를 계산합니다.