N-gram 인터랙티브 노트
How AI Works · Language Models · 1948 →

N-gram — 세는 것만으로
언어를 예측하다

GPT가 하는 일의 본질은 1948년 섀넌(Shannon)이 종이와 연필로 하던 것과 같다 — 지금까지의 글을 보고 다음에 올 것의 확률을 구하는 것. n-gram은 그 가장 단순한 구현이다. 그냥 센다. 이 페이지의 모든 데모는 외부 라이브러리 없이 브라우저에서 직접 실행된다. 코퍼스를 직접 고쳐 가며 만져보자.

1948Shannon, 통신의 수학적 이론
— n-gram으로 영어 흉내 내기
1980sIBM 음성인식,
통계적 언어 모델 실용화
1995Kneser–Ney 스무딩
2003Bengio, 신경망 언어 모델
(NPLM)
2006Google Web 1T
— 웹에서 센 5-gram 공개
2017→Transformer·GPT
— 목표는 그대로, 방법만 교체

1언어 모델 = 다음 단어의 확률

"나는 커피를 ___" 다음에 올 단어는? "마셨다"일 확률이 높고 "던졌다"일 확률은 낮으며 "파랗다"일 확률은 거의 0이다. 사람은 이걸 직관으로 안다. 언어 모델(language model)은 이 직관을 확률 분포로 만든 것이다: 지금까지의 단어열이 주어졌을 때 다음 단어의 확률 P(wt | w1, …, wt−1).

문장 전체의 확률은 연쇄 법칙(chain rule)으로 다음 단어 확률들의 곱이 된다. 문제는 조건부의 "지금까지의 모든 단어"가 너무 길다는 것 — 똑같은 20단어 문맥을 두 번 보는 일은 거의 없으므로 확률을 추정할 수 없다. n-gram의 답은 과감한 근사다: 직전 n−1개 단어만 보자 (마르코프 가정).

P(w1, …, wT) = ∏t P(wt | w1, …, wt−1)  ≈  ∏t P(wt | wt−n+1, …, wt−1)
n=1: 유니그램(문맥 없음) · n=2: 바이그램(직전 1단어) · n=3: 트라이그램(직전 2단어)

이때 연속된 n개의 토큰 묶음을 n-gram이라 부른다. 모델을 만들기 전에, 문장이 n-gram으로 어떻게 쪼개지는지부터 눈으로 보자.

DEMO 1

n-gram 분해기

문장을 넣고 n을 바꿔 보자. 창(window)이 한 칸씩 미끄러지며 n-gram을 뽑아낸다. 아래 n-gram을 클릭하면 해당 창이 강조된다.

2세어서 확률 만들기 — MLE

확률은 어디서 오는가? 코퍼스(corpus), 즉 훈련 텍스트에서 그냥 센다. 바이그램이라면 "나는" 뒤에 어떤 단어가 몇 번 왔는지 세고, "나는"이 나온 총 횟수로 나눈다. 이것이 최대 우도 추정(MLE, maximum likelihood estimate)이다.

P(wi | wi−1) = C(wi−1 wi)C(wi−1)
C(·) = 코퍼스에서의 등장 횟수. 문장 시작/끝은 <s>, </s> 토큰으로 처리한다.

아래 코퍼스는 직접 수정할 수 있다. 한 줄이 한 문장이다. 문장을 추가하거나 지우면 이 페이지의 모든 데모(생성기, 희소성, 스무딩, 퍼플렉시티)가 즉시 다시 계산된다.

DEMO 2

바이그램 카운트 행렬

행 = 앞 단어(문맥), 열 = 다음 단어. 셀 색이 진할수록 자주 등장한 조합이다. 행 머리글을 클릭하면 그 문맥의 조건부 확률 분포가 아래에 그려진다.

프리셋:
등장 빈도 상위 단어만 표시한다. 셀에 마우스를 올리면 계산식이 보인다.
이게 전부다. n-gram 언어 모델의 "학습"은 거대한 카운트 표를 채우는 것이고, "추론"은 표에서 행 하나를 읽는 것이다. 경사 하강법도, 가중치도 없다.

3텍스트 생성 — 섀넌의 게임

확률 분포가 있으면 샘플링으로 텍스트를 만들 수 있다. <s>에서 시작해 분포에서 다음 단어를 하나 뽑고, 그 단어를 문맥에 넣어 또 뽑고… </s>가 나올 때까지 반복한다. 섀넌은 1948년 논문에서 이걸 손으로 했다 — 책을 아무 데나 펴서 마지막 단어를 찾고, 그 다음 단어를 받아 적는 식으로. 그렇게 만든 문장이 n이 커질수록 점점 영어처럼 보인다는 것이 논문의 유명한 시연이다.

DEMO 3

n-gram 텍스트 생성기

위(§2)의 코퍼스로 학습된 모델이다. n을 바꿔 가며 생성해 보자. 각 스텝에서 모델이 실제로 본 확률 분포가 오른쪽에 표시된다 — ■ 이 선택된 단어다.

생성된 문장
마지막 스텝의 분포
n=2로 몇 문장 생성해 보자. 문법은 그럴듯한데 내용이 뒤섞인 문장이 나온다 — 바이그램은 딱 한 단어 앞만 기억하기 때문이다. n=4로 올리면? 코퍼스 문장이 거의 그대로 나온다(배지 확인). n이 작으면 엉터리, n이 크면 통째 암기 — 이 긴장이 다음 절의 주제다.

4희소성 — n을 키우면 무너진다

문맥을 길게 볼수록(n↑) 예측은 정확해져야 한다. 그런데 현실에서는 어느 지점부터 오히려 망가진다. 어휘가 V개면 가능한 n-gram 조합은 Vn개 — n이 하나 늘 때마다 경우의 수가 V배씩 지수적으로 폭발하는데, 코퍼스 크기는 그대로이기 때문이다. 대부분의 조합은 코퍼스에 한 번도 등장하지 않고, 카운트가 0이면 MLE 확률도 0이다.

확률 0은 치명적이다. 문장 확률은 곱이므로 0이 하나라도 끼면 문장 전체가 확률 0이 되고, 퍼플렉시티는 무한대가 된다. 멀쩡한 문장인데 훈련 때 그 조합을 못 봤다는 이유만으로.

DEMO 4

처음 보는 n-gram의 비율

§2 코퍼스의 문장을 절반은 훈련용, 절반은 테스트용으로 나눴다. 테스트 문장 속 n-gram 중 훈련 쪽에서 한 번도 못 본 비율이다. 코퍼스를 수정하면 다시 계산된다.

진짜 규모로 상상해 보자. 어휘 5만 단어면 가능한 트라이그램은 50000³ = 1.25×1014개. 구글이 2006년 공개한 Web 1T 코퍼스는 1조 단어를 세고도 이 조합 공간의 티끌만 채웠다. n-gram은 본 것만 알고, 본 적 없는 것은 확률 0으로 단언한다 — 일반화가 없다.

5스무딩 — 0을 없애는 기술

해결책은 확률을 조금씩 걷어서 못 본 조합에 나눠주는 것, 스무딩(smoothing)이다. 가장 단순한 방법은 모든 카운트에 k를 더해 주는 애드-k(라플라스) 스무딩:

Padd-k(wi | wi−1) = C(wi−1 wi) + kC(wi−1) + k·V
V = 어휘 크기. k=1이면 라플라스 스무딩. 분모에 k·V를 더해 전체 합이 1로 유지된다.
DEMO 5

애드-k 스무딩 전후 비교

문맥 하나를 골라 k를 움직여 보자. 관측된 단어(카운트>0)의 확률이 깎이고, 그만큼이 관측 안 된 단어들에 배분된다.

MLE (k=0) 애드-k 스무딩

애드-k는 이해하기 쉽지만 실전에서는 확률을 너무 뭉개서 성능이 나쁘다. 실제 시스템들은 더 영리한 방법을 썼다:

  • 백오프(backoff) — 트라이그램이 없으면 바이그램으로, 그것도 없으면 유니그램으로 후퇴한다.
  • 보간(interpolation) — 트라이그램·바이그램·유니그램 확률을 항상 가중 평균한다.
  • Kneser–Ney — 단어가 "얼마나 다양한 문맥에 등장했는가"로 백오프 확률을 정한다. 30년 가까이 n-gram 스무딩의 최종 병기였다 (Chen & Goodman 1998의 비교 실험이 유명하다).

6퍼플렉시티 — 언어 모델의 성적표

어느 모델이 더 좋은가를 어떻게 잴까? 테스트 문장에 높은 확률을 주는 모델이 좋은 모델이다. 이를 문장 길이에 무관하게 정규화한 것이 퍼플렉시티(perplexity, PPL)다.

PPL = P(w1, …, wN)−1/N = exp( −1N ∑ ln P(wi | 문맥) )
직관: "매 스텝 평균 몇 개의 후보 중에서 균등하게 고르는 셈인가". 낮을수록 좋다. 균등 랜덤 모델의 PPL은 어휘 크기 V와 같다.
DEMO 6

퍼플렉시티 계산기

§2 코퍼스로 학습한 유니그램/바이그램/트라이그램 모델(애드-k 스무딩)이 아래 테스트 문장을 평가한다. 코퍼스에 있는 문장, 새로 조합한 문장, 엉터리 문장을 넣어 비교해 보자.

바이그램 모델의 스텝별 계산 보기
보통은 n이 클수록 PPL이 낮다(좋다) — 문맥 정보가 많으니까. 하지만 테스트 문장이 코퍼스에 없는 조합이면 트라이그램이 오히려 나빠지기도 한다. 카운트 표가 희소해서 스무딩된 바닥 확률에 의존하기 때문이다. §4의 희소성 문제가 숫자로 드러나는 순간이다.

7n-gram에서 신경망으로

n-gram의 한계는 셋으로 요약된다. 첫째, 희소성 — n을 키울수록 카운트 표가 빈다(§4). 둘째, 일반화 불가 — "고양이는 물을 마신다"를 아무리 봐도 "강아지는 물을 마신다"의 확률은 1도 오르지 않는다. n-gram에게 단어는 서로 무관한 기호일 뿐, "고양이와 강아지는 비슷하다"는 개념이 없다. 셋째, 짧은 기억 — n−1 단어 밖의 문맥은 원리적으로 볼 수 없다.

2003년 Bengio의 신경망 언어 모델(NPLM)이 두 번째 문제를 정면으로 돌파했다. 단어를 기호가 아니라 연속 벡터(임베딩)로 표현하면, 비슷한 단어는 비슷한 벡터를 갖게 되어 본 적 없는 조합에도 확률이 번져 나간다. RNN(→ RNN 노트)은 세 번째 문제를, Transformer는 그 확장성을 해결했다.

그러나 목표 함수는 한 번도 바뀐 적이 없다. GPT의 사전학습도 정확히 "다음 토큰의 확률을 맞혀라"이고, 성적표도 여전히 퍼플렉시티 계열이다. n-gram을 이해하면 LLM이 무엇을 하도록 훈련되는지를 이해한 것이다.

n-gram신경망 언어 모델 (NPLM → GPT)
목표다음 토큰의 확률 분포 P(wt | 문맥) — 동일
확률을 구하는 방법카운트 표에서 조회파라미터화된 함수(신경망)가 계산
단어의 표현서로 무관한 원자 기호임베딩 벡터 — 유사성이 거리로 표현됨
못 본 조합확률 0 (스무딩으로 땜질)비슷한 조합에서 일반화
문맥 길이n−1 단어, 고정RNN: 이론상 무제한 · Transformer: 수십만 토큰
학습세기 (한 번 훑으면 끝)경사 하강법

✓이해도 점검

핵심을 7문제로 확인하자. 답을 고르면 즉시 해설이 보인다. — 0 / 7