토큰화 (자연어 처리)
더 많은 작업
- Tokenization; 토큰화
- 텍스트를 모델이 다루는 최소 단위(토큰)로 나누고, 각 토큰을 정해진 어휘 사전의 번호로 바꾸는 과정
토큰화(tokenization)는 문자열을 언어 모델이 처리할 수 있는 단위인 토큰(token)의 열로 바꾸는 과정이다. 토큰화를 수행하는 프로그램이나 그 규칙을 토크나이저(tokenizer)라 한다. 예를 들어 "unbelievable"은 "un", "believ", "able" 세 토큰으로 나뉘고, 각 토큰은 어휘 사전의 번호(정수)로 바뀌어 모델에 들어간다. 모델은 글자를 직접 보지 않고 이 번호열만 본다.
토큰화는 대형 언어 모델의 성능, 비용, 다국어 공정성에 직접 영향을 준다. 상용 LLM API는 토큰 수로 요금을 매기고, 모델이 한 번에 읽을 수 있는 길이(컨텍스트 윈도우)도 토큰 수로 정해진다. 같은 내용이라도 언어와 토크나이저에 따라 토큰 수가 몇 배씩 차이 나므로, 토큰화는 단순한 전처리가 아니라 모델 설계의 일부다.
컴파일러의 어휘 분석이나 보안 분야의 토큰화(민감 정보를 대체 값으로 바꾸기)와는 다른 개념이다. 컴파일러 쪽은 어휘 분석 문서 참고.
| 방식 | 예("tokenization is fun") | 어휘 크기 | 장점 | 단점 |
|---|---|---|---|---|
| 단어 단위 | tokenization / is / fun | 수십만 이상 | 의미 단위가 분명하다 | 사전에 없는 단어(OOV)를 처리하지 못한다. 활용·합성어가 많은 언어에서 어휘가 폭발한다 |
| 문자 단위 | t / o / k / e / n / ... | 수십~수천 | OOV가 없다 | 토큰열이 길어져 계산이 비싸고, 의미 단위를 모델이 처음부터 배워야 한다 |
| 바이트 단위 | UTF-8 바이트 256종 | 256 | 어떤 문자열도 표현한다 | 토큰열이 가장 길다. 한글 한 글자가 3바이트다 |
| 서브워드 단위 | token / ization / is / fun | 3만~25만 정도 | 자주 쓰는 단어는 한 토큰, 드문 단어는 조각으로 표현해 OOV가 없다 | 분할이 언어학적 단위와 어긋날 수 있다 |
2010년대 중반 이후 신경망 기계 번역과 언어 모델은 대부분 서브워드 토큰화를 쓴다. 단어 단위의 의미 효율과 문자 단위의 개방 어휘(open vocabulary)를 절충한 방식이다.
바이트 쌍 인코딩(Byte Pair Encoding, BPE)은 원래 1994년 필립 게이지(Philip Gage)가 발표한 데이터 압축 알고리즘이다. 가장 자주 나오는 바이트 쌍을 쓰이지 않는 바이트로 바꾸는 일을 반복한다. 2015년 리코 젠리히(Rico Sennrich) 등은 이를 신경망 기계 번역의 어휘 구성에 응용해, 드문 단어와 처음 보는 단어를 서브워드 단위로 번역하는 방법을 제시했다(ACL 2016 발표).[1]
학습 절차는 다음과 같다.
- 말뭉치의 단어를 문자 단위로 쪼개고, 문자 집합을 초기 어휘로 둔다.
- 인접한 두 토큰 쌍의 출현 빈도를 센다.
- 가장 빈도가 높은 쌍을 하나의 새 토큰으로 합치고, 이 병합 규칙을 기록한다.
- 어휘가 정한 크기에 이를 때까지 2~3을 반복한다.
새 텍스트를 토큰화할 때는 기록한 병합 규칙을 학습된 순서대로 적용한다. 다음은 단순화한 학습 코드다.
from collections import Counter
def learn_bpe(words, num_merges):
# words: {"l o w </w>": 5, "l o w e r </w>": 2, ...}
merges = []
for _ in range(num_merges):
pairs = Counter()
for word, freq in words.items():
symbols = word.split()
for a, b in zip(symbols, symbols[1:]):
pairs[(a, b)] += freq
if not pairs:
break
best = max(pairs, key=pairs.get)
merges.append(best)
a, b = best
words = {w.replace(f"{a} {b}", a + b): f for w, f in words.items()}
return merges
말뭉치에 "low"가 5번, "lower"가 2번, "newest"가 6번, "widest"가 3번 나온다면, "e"+"s"와 "s"+"t"가 각각 9번(newest 6번, widest 3번)으로 가장 많으므로 이 가운데 하나가 먼저 합쳐지고, 이어서 "est"가 하나의 토큰이 된다. 이렇게 "est" 같은 접미사가 자연스럽게 토큰이 된다.
구도 다쿠(Kudo Taku)가 2018년 제안한 방식이다.[4] BPE와 반대로 큰 후보 어휘에서 출발해, 각 토큰이 독립적으로 나온다고 보는 유니그램 언어 모델의 우도를 가장 적게 떨어뜨리는 토큰부터 지워 나간다. 한 문장을 여러 방식으로 나눌 수 있을 때 각 분할의 확률을 계산할 수 있으므로, 학습 중 분할을 무작위로 바꿔 모델을 강건하게 만드는 서브워드 정규화(subword regularization)가 가능하다.
SentencePiece는 구도 다쿠와 존 리처드슨이 2018년 공개한 토큰화 도구다.[5] 알고리즘이라기보다는 BPE와 유니그램을 구현한 프레임워크다. 기존 도구는 입력이 미리 공백으로 단어가 나뉘어 있다고 가정했지만, SentencePiece는 원문 문장에서 바로 학습한다. 공백도 "▁" 기호로 바꿔 일반 문자처럼 다루므로, 띄어쓰기가 없는 일본어·중국어에도 그대로 쓸 수 있고 토큰열에서 원문을 손실 없이 복원할 수 있다. T5, 라마 1·2, 젬마 등 여러 모델이 SentencePiece 토크나이저를 썼다.
| 알고리즘 | 어휘 구성 방향 | 병합·삭제 기준 | 분할 결과 | 대표 사용처 |
|---|---|---|---|---|
| BPE | 작은 어휘에서 병합 | 쌍 빈도 | 결정적 | GPT 계열(바이트 수준), 라마 3 |
| WordPiece | 작은 어휘에서 병합 | 우도 증가량 | 결정적(최장 일치) | BERT, DistilBERT |
| 유니그램 | 큰 어휘에서 삭제 | 우도 감소량 | 확률적 분할 가능 | SentencePiece의 기본 설정 |
OpenAI는 자사 모델용 BPE 토크나이저 라이브러리 tiktoken을 공개했다. README는 BPE의 성질로 원문 복원이 가능하고, 학습 데이터에 없던 텍스트도 처리하며, 실제로 토큰 하나가 평균 4바이트 정도에 해당한다고 설명한다.[6]
| 인코딩 이름 | 어휘 크기 | 쓰인 모델 |
|---|---|---|
| gpt2, r50k_base | 50,257 | GPT-2, GPT-3 초기 모델 |
| p50k_base | 50,281 | 코드 모델(Codex 등) |
| cl100k_base | 약 10만 | GPT-3.5, GPT-4 |
| o200k_base | 약 20만 | GPT-4o 이후 |
토크나이저는 BPE를 적용하기 전에 정규 표현식으로 텍스트를 미리 자른다(사전 토큰화). 예컨대 cl100k_base의 규칙은 숫자를 최대 세 자리씩 끊는다.[6] 그래서 "1234567"은 "123", "456", "7"처럼 나뉜다. 숫자를 어떻게 자르느냐는 산수 능력에 영향을 주며, LLaMA처럼 모든 숫자를 한 자리씩 자르는 모델도 있다.[7]
텍스트 조각 외에 구조를 표시하는 특수 토큰이 있다. 문서 시작·끝(BOS, EOS, <|endoftext|> 등), 패딩, BERT의 [CLS]·[SEP]·[MASK], 대화 모델의 역할 구분 토큰(시스템·사용자·어시스턴트), 도구 호출과 사고 과정 구간을 표시하는 토큰이 대표적이다. 대화 모델은 이런 토큰을 조합한 채팅 템플릿으로 대화를 하나의 토큰열로 펼쳐 입력받는다. 사용자가 입력한 문자열이 특수 토큰으로 해석되지 않도록 막는 것은 프롬프트 인젝션 방어와도 관련이 있다.
한국어는 조사와 어미가 어간에 붙는 교착어여서, "학교에", "학교에서", "학교에서도"가 모두 다른 어절이 된다. 띄어쓰기 단위(어절)로 어휘를 만들면 어휘가 폭발하고, 띄어쓰기 오류에도 약하다.
| 방식 | 설명 | 특징 |
|---|---|---|
| 형태소 분석 | 형태소 분석기(MeCab-ko, Okt, Kkma 등)로 "학교/에서/도"처럼 나눈다 | 언어학적으로 자연스럽지만 분석기 오류와 속도가 문제다 |
| 서브워드(BPE, 유니그램) | 말뭉치 통계로 자주 나오는 문자열을 토큰으로 만든다 | 언어 지식이 필요 없고 OOV가 없다 |
| 형태소 분석 후 서브워드 | 형태소로 먼저 자르고 그 안에서 BPE를 적용한다 | 여러 한국어 과제에서 가장 좋은 성능을 보였다는 연구가 있다[10] |
| 자모 단위 | 음절을 초성·중성·종성으로 풀어 다룬다 | 어휘가 작고 철자 변형에 강하지만 토큰열이 길어진다 |
다국어 LLM에서는 토큰 효율이 문제가 된다. 한글 음절은 UTF-8로 3바이트이므로, 어휘에 한국어 토큰이 적은 바이트 수준 BPE는 한 글자를 여러 토큰으로 쪼갤 수 있다. 같은 내용을 여러 언어로 번역해 토큰 수를 비교한 2023년 연구는 언어 간 차이가 최대 15배에 이르며, 다국어 지원을 의도한 토크나이저에서도 격차가 남는다고 보고했다.[11] 토큰이 많으면 같은 내용에 대해 API 요금이 더 들고, 컨텍스트 윈도우에 담을 수 있는 실제 분량이 줄고, 생성도 느려진다. 국내 기업이 자체 모델을 만들 때 한국어 토큰을 넉넉히 넣은 토크나이저를 따로 설계하는 이유다.
- 요금: 상용 LLM API는 입력 토큰과 출력 토큰에 따로 단가를 매긴다(예: 100만 토큰당 몇 달러). 출력 토큰이 보통 더 비싸며, 추론 모델의 사고 과정 토큰도 출력으로 과금된다.
- 길이 제한: 컨텍스트 윈도우와 최대 출력 길이는 토큰 수로 정해진다. 영어에서는 대략 토큰 하나가 4바이트(약 0.75단어) 정도지만, 언어와 토크나이저에 따라 크게 다르다.
- 비텍스트 입력: 이미지, 음성, 영상도 조각(패치, 프레임)을 토큰으로 바꿔 같은 문맥에 넣는다. 구글은 제미나이 1.5를 소개하며 토큰이 단어의 일부일 수도, 이미지·영상·음성·코드의 일부일 수도 있다고 설명했다.[12]
- 글자 수준 작업에 약함: 모델은 토큰 단위로 보므로 단어 안 글자 수 세기, 철자 뒤집기, 각운 맞추기 같은 작업에서 실수하기 쉽다.
- 산수: 숫자가 토크나이저에 따라 제멋대로 묶이면 자릿수 정렬이 어려워진다.
- 표기 변이에 민감: 띄어쓰기, 대소문자, 오타 하나로 토큰 분할이 크게 달라질 수 있다.
- 학습 데이터 불균형: 토크나이저 학습 말뭉치에서 드물게 나온 문자열이 토큰으로 들어가면, 언어 모델 학습 중 거의 나오지 않아 임베딩이 제대로 학습되지 않은 토큰이 생길 수 있다.
이런 이유로 토크나이저 없이 바이트나 문자를 직접 처리하는 모델, 바이트를 동적으로 묶는 모델도 연구되고 있다.[13]
- ↑ R. Sennrich, B. Haddow, A. Birch, 〈Neural Machine Translation of Rare Words with Subword Units〉, ACL, 2016. arXiv:1508.07909
- ↑ M. Schuster, K. Nakajima, 〈Japanese and Korean Voice Search〉, ICASSP, 2012.
- ↑ Y. Wu 외, 〈Google's Neural Machine Translation System: Bridging the Gap between Human and Machine Translation〉, 2016. arXiv:1609.08144
- ↑ T. Kudo, 〈Subword Regularization: Improving Neural Network Translation Models with Multiple Subword Candidates〉, ACL, 2018. arXiv:1804.10959
- ↑ T. Kudo, J. Richardson, 〈SentencePiece: A simple and language independent subword tokenizer and detokenizer for Neural Text Processing〉, EMNLP, 2018. arXiv:1808.06226
- ↑ 6.0 6.1 6.2 OpenAI, tiktoken 저장소(README, tiktoken_ext/openai_public.py), 2026-10-15 확인.
- ↑ H. Touvron 외, 〈LLaMA: Open and Efficient Foundation Language Models〉, 2023. arXiv:2302.13971
- ↑ A. Grattafiori 외, 〈The Llama 3 Herd of Models〉, 2024. arXiv:2407.21783
- ↑ S. Takase, R. Ri, S. Kiyono, T. Kato, 〈Large Vocabulary Size Improves Large Language Models〉, 2024. arXiv:2406.16508
- ↑ K. Park, J. Lee, S. Jang, D. Jung, 〈An Empirical Study of Tokenization Strategies for Various Korean NLP Tasks〉, AACL-IJCNLP, 2020. arXiv:2010.02534
- ↑ A. Petrov, E. La Malfa, P. H. S. Torr, A. Bibi, 〈Language Model Tokenizers Introduce Unfairness Between Languages〉, NeurIPS, 2023. arXiv:2305.15425
- ↑ Google, Our next-generation model: Gemini 1.5, 2024-02-15.
- ↑ S. J. Mielke 외, 〈Between words and characters: A Brief History of Open-Vocabulary Modeling and Tokenization in NLP〉, 2021. arXiv:2112.10508
- P. Gage, 〈A New Algorithm for Data Compression〉, The C Users Journal 12(2), 1994.
- Hugging Face, Summary of the tokenizers