Ch.3 텍스트를 숫자로 — 토큰화의 세계

BPE 토크나이저 직접 만들기

BPE(Byte Pair Encoding) 알고리즘의 원리를 이해한다가장 빈번한 쌍을 병합하는 과정을 추적한다어휘 크기와 병합 횟수의 관계를 파악한다

GPT는 '단어' 단위가 아니라 '서브워드' 단위로 읽습니다

영어 'unhappiness'를 통째로 외우면 비효율적입니다. 'un' + 'happi' + 'ness'로 쪼개면 다른 단어에도 재활용할 수 있죠. BPE가 바로 이 분해를 자동으로 수행합니다.

어디서 쪼개야 최적일까? BPE는 어떤 기준으로 결정할까?

BPE 알고리즘 — 가장 자주 붙어 다니는 쌍을 반복적으로 합치는 방법입니다.

lightbulb

핵심 개념

BPE

빈번한 문자 쌍을 반복 병합하여 서브워드를 만드는 알고리즘

토큰

텍스트를 모델이 처리할 수 있는 최소 단위로 쪼갠 조각


article

핵심 내용

BPE는 글자부터 시작해서 자주 나오는 쌍을 반복 병합합니다

BPE (Byte Pair Encoding) 알고리즘 ① 모든 단어를 글자 단위로 분리 ② 가장 빈번한 연속 쌍(pair)을 찾는다 ③ 그 쌍을 하나의 새 토큰으로 병합 ④ 원하는 어휘 크기가 될 때까지 ②~③ 반복

GPT-4는 약 10만 개의 BPE 토큰을 사용합니다. 처음엔 256개 바이트로 시작해서 수만 번 병합한 결과입니다.

글자들이 하나씩 합쳐져서 서브워드가 되는 과정입니다

예시: "low lower lowest" 초기: [l, o, w, e, r, s, t] 병합1: (l, o) → lo ← 가장 빈번한 쌍 병합2: (lo, w) → low 병합3: (e, r) → er 병합4: (e, s) → es 결과: [low, er, es, t] — 4개 서브워드로 3단어를 표현!

BPE의 핵심인 쌍 빈도 계산과 병합 과정을 추적합니다

BPE 알고리즘을 직접 구현해봅시다!

from collections import Counter

def get_pairs(tokens):
    pairs = Counter()
    for i in range(len(tokens) - 1):
        pairs[(tokens[i], tokens[i+1])] += 1
    return pairs

def merge(tokens, pair):
    merged = pair[0] + pair[1]
    new_tokens = []
    i = 0
    while i < len(tokens):
        if i < len(tokens)-1 and tokens[i] == pair[0] and tokens[i+1] == pair[1]:
            new_tokens.append(merged)
            i += 2
        else:
            new_tokens.append(tokens[i])
            i += 1
    return new_tokens

text = "low low lower lowest"
tokens = list(text.replace(" ", " _ "))
print(f"초기 토큰 ({len(set(tokens))}종): {tokens}
")

for step in range(5):
    pairs = get_pairs(tokens)
    if not pairs: break
    best = pairs.most_common(1)[0][0]
    tokens = merge(tokens, best)
    print(f"병합 {step+1}: {best[0]}+{best[1]} → {best[0]+best[1]}")
    print(f"  토큰: {tokens}")
    print(f"  고유: {len(set(tokens))}
")

병합을 많이 할수록 어휘 사전 크기는 커지고 토큰 수는 줄어듭니다

GPT-2: 50,257개 토큰 (약 50,000번 병합) GPT-4: ~100,000개 토큰 어휘가 크면: 한 토큰이 더 많은 의미를 담아 효율적 어휘가 작으면: 메모리 절약, 하지만 문장이 길어짐

BPE 병합 과정을 한 단계씩 추적하며 어휘가 어떻게 만들어지는지 관찰합니다

# 간단한 BPE 병합 시뮬레이션
from collections import Counter

# 초기 토큰 시퀀스 (문자 단위)
tokens = list("abababcab")
print(f"초기 토큰: {tokens}")
print(f"초기 어휘: {sorted(set(tokens))}\n")

# BPE 병합 3라운드 실행
for round_num in range(1, 4):
    # 연속 쌍 빈도 계산
    pairs = Counter()
    for i in range(len(tokens) - 1):
        pair = (tokens[i], tokens[i + 1])
        pairs[pair] += 1

    if not pairs:
        break

    best_pair, count = pairs.most_common(1)[0]
    merged = best_pair[0] + best_pair[1]
    print(f"[라운드 {round_num}] 최빈 쌍: {best_pair} ({count}회)")

    # 병합 실행
    new_tokens = []
    i = 0
    while i < len(tokens):
        if i < len(tokens) - 1 and (tokens[i], tokens[i+1]) == best_pair:
            new_tokens.append(merged)
            i += 2
        else:
            new_tokens.append(tokens[i])
            i += 1
    tokens = new_tokens
    print(f"  결과: {tokens}")
    print(f"  어휘: {sorted(set(tokens))}\n")

토큰: [a, b, a, b, c, a, b] 가장 먼저 병합될 쌍은?

BPE에서 병합 횟수를 늘리면 하나의 토큰이 표현하는 의미가 커진다

BPE는 왜 단어 단위가 아닌 서브워드 단위로 토큰화하나요?

BPE에서 어휘 사전(vocabulary) 크기가 커지면 어떤 트레이드오프가 있나요?

GPT-4의 토크나이저는 약 10만 개의 어휘 사전을 사용한다.

텍스트 → 토큰 → 숫자 LLM 파이프라인의 2단계 완료!

[[전처리]]: split, join, replace로 텍스트 정제 [[어휘 사전]]: 딕셔너리로 단어 → 정수 매핑 BPE: 서브워드 단위 토큰화 — GPT의 핵심 다음 챕터: 숫자가 된 토큰을 벡터(임베딩)로 변환합니다!

토큰화의 세계

key

핵심 용어

🔤

BPE

빈번한 문자 쌍을 반복 병합하여 서브워드를 만드는 알고리즘

🧩

토큰

텍스트를 모델이 처리할 수 있는 최소 단위로 쪼갠 조각

edit_note

정리 노트

BPE 알고리즘 핵심 정리

BPE 알고리즘 단계

1단계
모든 단어를 글자 단위로 분리 (초기 어휘 = 개별 문자)
2단계
가장 빈번한 연속 쌍을 찾는다 (예: l+o → lo)
3단계
해당 쌍을 하나의 새 토큰으로 병합
4단계
원하는 어휘 크기까지 2~3단계 반복

어휘 크기와 트레이드오프

어휘가 크면
한 토큰이 더 많은 의미를 담아 효율적 (GPT-4: ~10만 개)
어휘가 작으면
메모리 절약, 하지만 문장이 더 많은 토큰으로 쪼개짐
서브워드의 장점
처음 보는 단어도 부분적으로 표현 가능 (OOV 해결)

GPT-2는 약 5만 번, GPT-4는 약 10만 번 병합하여 어휘 사전을 구축합니다!

image

시각 자료

다이어그램: py-scene-bpe
다이어그램: bpe-merge
check_circle

핵심 정리

  • 1split/join/replace — 텍스트 전처리의 3대 도구
  • 2딕셔너리 + Counter — 어휘 사전 구축
  • 3BPE — 서브워드 토큰화, GPT의 핵심 알고리즘

퀴즈와 인터랙션으로 더 깊이 학습하세요

play_circle인터랙티브 레슨 시작