Token
개요
토큰(Token)은 LLM이 텍스트를 처리하는 가장 기본적인 단위입니다. 인간이 단어나 문장 단위로 텍스트를 이해하는 것과 달리, LLM은 토큰이라는 더 작은 단위로 텍스트를 분해하여 처리합니다. 토크나이저(Tokenizer)는 이러한 텍스트를 토큰으로 변환하는 핵심 도구입니다.
토큰이란?
1. 토큰의 정의
토큰(Token)은 LLM이 이해할 수 있는 텍스트의 최소 단위입니다.
예시:
텍스트: "안녕하세요, 반갑습니다!"
토큰: ["안녕", "하세요", ",", "반갑", "습니다", "!"]
2. 토큰의 특징
- 고정된 어휘집: 모델이 학습할 때 사용한 토큰들의 집합
- 숫자 인덱스: 각 토큰은 고유한 숫자로 매핑
- 벡터 변환: 토큰은 임베딩을 통해 벡터로 변환
3. 토큰화의 필요성
왜 토큰화가 필요한가?
- 다양한 언어 지원: 영어, 한국어, 중국어 등 모든 언어를 통일된 방식으로 처리
- 알 수 없는 단어 처리: 학습 시 보지 못한 새로운 단어도 처리 가능
- 효율적인 처리: 텍스트를 일정한 크기의 단위로 나누어 처리
토크나이저의 종류
1. 단어 기반 토크나이저 (Word-based Tokenizer)
특징:
- 공백을 기준으로 단어를 분리
- 가장 직관적이고 이해하기 쉬움
- 어휘집 크기가 매우 클 수 있음
예시:
# 영어 예시
text = "I love artificial intelligence"
tokens = ["I", "love", "artificial", "intelligence"]
# 한국어 예시 (공백 기준)
text = "나는 인공지능을 좋아합니다"
tokens = ["나는", "인공지능을", "좋아합니다"]
장단점:
- 장점: 직관적이고 이해하기 쉬움
- 단점: 어휘집이 매우 크고, 새로운 단어 처리 어려움
2. 문자 기반 토크나이저 (Character-based Tokenizer)
특징:
- 각 문자를 개별 토큰으로 처리
- 어휘집 크기가 매우 작음
- 모든 텍스트를 처리할 수 있음
예시:
text = "Hello"
tokens = ["H", "e", "l", "l", "o"]
text = "안녕하세요"
tokens = ["안", "녕", "하", "세", "요"]
장단점:
- 장점: 어휘집이 작고, 새로운 텍스트 처리 가능
- 단점: 토큰 수가 많아지고, 의미 정보 손실
3. 서브워드 토크나이저 (Subword Tokenizer)
특징:
- 단어를 더 작은 단위로 분해
- 자주 사용되는 패턴을 학습
- 알 수 없는 단어도 처리 가능
대표적인 서브워드 토크나이저:
BPE (Byte Pair Encoding)
# BPE 예시
text = "artificial intelligence"
# 학습 과정에서 자주 나타나는 패턴을 찾아 토큰화
tokens = ["art", "ificial", "intel", "ligence"]
WordPiece
# WordPiece 예시 (BERT에서 사용)
text = "artificial intelligence"
tokens = ["art", "##ificial", "intel", "##ligence"]
# ##은 서브워드임을 나타내는 표시
SentencePiece
# SentencePiece 예시 (다국어 지원)
text = "안녕하세요 Hello"
tokens = ["▁안녕", "하세요", "▁Hello"]
# ▁은 단어 시작을 나타내는 표시
주요 토크나이저 비교
1. GPT 계열 (BPE)
특징:
- 영어 중심으로 설계
- 웹 크롤링 데이터로 학습
- 대소문자 구분
예시:
# GPT 토크나이저
text = "Hello, world!"
tokens = ["Hello", ",", "Ġworld", "!"]
# Ġ는 공백 다음에 오는 토큰을 나타냄
2. BERT 계열 (WordPiece)
특징:
- 영어 중심이지만 다국어 지원
- 대소문자 구분
- 서브워드 표시로 ## 사용
예시:
# BERT 토크나이저
text = "artificial intelligence"
tokens = ["art", "##ificial", "intel", "##ligence"]
3. T5 계열 (SentencePiece)
특징:
- 다국어 지원
- 언어 구분 없이 통합 처리
- 단어 시작 표시로 ▁ 사용
예시:
# T5 토크나이저
text = "안녕하세요 Hello"
tokens = ["▁안녕", "하세요", "▁Hello"]
토크나이저의 작동 원리
1. 학습 과정
BPE 학습 예시:
# 1단계: 초기 어휘집 생성
vocab = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"}
# 2단계: 텍스트를 문자 단위로 분리
text = "artificial intelligence"
chars = ["a", "r", "t", "i", "f", "i", "c", "i", "a", "l", " ", "i", "n", "t", "e", "l", "l", "i", "g", "e", "n", "c", "e"]
# 3단계: 가장 자주 나타나는 쌍을 찾아 병합
# "ar" + "t" = "art"
# "intel" + "ligence" = "intelligence"
# 4단계: 최종 토큰
tokens = ["art", "ificial", "intelligence"]
2. 토큰화 과정
def tokenize_text(text, tokenizer):
# 1. 텍스트 전처리
text = preprocess(text)
# 2. 토큰화
tokens = tokenizer.encode(text)
# 3. 토큰 ID로 변환
token_ids = tokenizer.convert_tokens_to_ids(tokens)
return token_ids
# 예시
text = "안녕하세요"
token_ids = [101, 102, 103, 104, 105] # 실제 ID는 다를 수 있음
3. 역토큰화 과정
def detokenize_text(token_ids, tokenizer):
# 1. ID를 토큰으로 변환
tokens = tokenizer.convert_ids_to_tokens(token_ids)
# 2. 토큰을 텍스트로 결합
text = tokenizer.convert_tokens_to_string(tokens)
return text
# 예시
token_ids = [101, 102, 103, 104, 105]
text = "안녕하세요"
토큰화의 실제 영향
1. 토큰 수와 비용
토큰 수 계산:
def count_tokens(text, tokenizer):
tokens = tokenizer.encode(text)
return len(tokens)
# 예시
text = "안녕하세요, 반갑습니다!"
token_count = count_tokens(text, tokenizer) # 예: 8개 토큰
비용 계산:
def calculate_cost(token_count, price_per_1k_tokens):
cost = (token_count / 1000) * price_per_1k_tokens
return cost
# 예시
token_count = 1000
price_per_1k = 0.002 # $0.002 per 1K tokens
cost = calculate_cost(token_count, price_per_1k) # $0.002
2. 언어별 토큰 효율성
영어 vs 한국어 비교:
# 영어
english_text = "Hello, how are you?"
english_tokens = ["Hello", ",", "Ġhow", "Ġare", "Ġyou", "?"] # 6개 토큰
# 한국어
korean_text = "안녕하세요, 어떻게 지내세요?"
korean_tokens = ["안녕", "하세요", ",", "어떻게", "지내세요", "?"] # 6개 토큰
# 같은 의미지만 토큰 수가 다를 수 있음
3. 토큰 제한과 처리
컨텍스트 길이 제한:
def check_context_length(text, tokenizer, max_tokens=4096):
tokens = tokenizer.encode(text)
token_count = len(tokens)
if token_count > max_tokens:
# 토큰 수가 제한을 초과하면 잘라내기
tokens = tokens[:max_tokens]
text = tokenizer.decode(tokens)
return text, token_count
else:
return text, token_count
# 예시
long_text = "매우 긴 텍스트..."
truncated_text, count = check_context_length(long_text, tokenizer)
토큰 수 계산과 분석
1. 토큰 수 계산 방법
기본 토큰 수 계산:
def count_tokens(text, tokenizer):
"""텍스트의 토큰 수 계산"""
tokens = tokenizer.encode(text)
return len(tokens)
def count_tokens_detailed(text, tokenizer):
"""상세한 토큰 정보 반환"""
tokens = tokenizer.encode(text)
token_ids = tokenizer.convert_tokens_to_ids(tokens)
return {
"text": text,
"tokens": tokens,
"token_ids": token_ids,
"token_count": len(tokens),
"character_count": len(text),
"tokens_per_character": len(tokens) / len(text) if text else 0
}
# 예시
text = "안녕하세요, 반갑습니다!"
result = count_tokens_detailed(text, tokenizer)
print(f"토큰 수: {result['token_count']}")
print(f"문자 수: {result['character_count']}")
print(f"문자당 토큰 수: {result['tokens_per_character']:.2f}")
2. 다양한 텍스트 유형별 토큰 수 분석
def analyze_token_usage_by_type():
"""텍스트 유형별 토큰 사용량 분석"""
sample_texts = {
"영어": "Hello, how are you today?",
"한국어": "안녕하세요, 오늘 날씨가 좋네요.",
"코드": "def hello_world(): print('Hello, World!')",
"숫자": "1234567890",
"특수문자": "!@#$%^&*()",
"이모지": "안녕하세요 😊 반갑습니다 👋"
}
results = {}
for text_type, text in sample_texts.items():
tokens = tokenizer.encode(text)
results[text_type] = {
"text": text,
"token_count": len(tokens),
"character_count": len(text),
"efficiency": len(text) / len(tokens) if tokens else 0
}
return results
# 분석 결과 예시
analysis = analyze_token_usage_by_type()
for text_type, data in analysis.items():
print(f"{text_type}: {data['token_count']} 토큰 ({data['character_count']} 문자)")
3. 토큰 수 예측 모델
def predict_token_count(text, language="korean"):
"""언어별 토큰 수 예측"""
# 언어별 평균 토큰 비율
token_ratios = {
"korean": 0.8, # 한국어: 문자당 약 0.8 토큰
"english": 0.4, # 영어: 문자당 약 0.4 토큰
"chinese": 1.2, # 중국어: 문자당 약 1.2 토큰
"code": 0.6, # 코드: 문자당 약 0.6 토큰
"mixed": 0.7 # 혼합: 문자당 약 0.7 토큰
}
estimated_tokens = int(len(text) * token_ratios.get(language, 0.7))
return estimated_tokens
def estimate_cost_by_tokens(token_count, model="gpt-3.5-turbo"):
"""토큰 수에 따른 비용 추정"""
# 모델별 토큰당 비용 (USD)
costs_per_1k_tokens = {
"gpt-3.5-turbo": {"input": 0.0015, "output": 0.002},
"gpt-4": {"input": 0.03, "output": 0.06},
"gpt-4-turbo": {"input": 0.01, "output": 0.03}
}
model_costs = costs_per_1k_tokens.get(model, {"input": 0.0015, "output": 0.002})
# 입력 토큰 비용 (예상)
input_cost = (token_count * model_costs["input"]) / 1000
# 출력 토큰 비용 (예상 - 입력의 50%로 가정)
output_cost = (token_count * 0.5 * model_costs["output"]) / 1000
total_cost = input_cost + output_cost
return {
"input_tokens": token_count,
"estimated_output_tokens": int(token_count * 0.5),
"input_cost": input_cost,
"output_cost": output_cost,
"total_cost": total_cost
}
# 사용 예시
text = "인공지능에 대해 자세히 설명해주세요."
estimated_tokens = predict_token_count(text, "korean")
cost_estimate = estimate_cost_by_tokens(estimated_tokens, "gpt-3.5-turbo")
print(f"예상 토큰 수: {estimated_tokens}")
print(f"예상 비용: ${cost_estimate['total_cost']:.4f}")
4. 토큰 수 최적화 도구
class TokenOptimizer:
def __init__(self, tokenizer, target_tokens=1000):
self.tokenizer = tokenizer
self.target_tokens = target_tokens
def optimize_text(self, text):
"""텍스트를 목표 토큰 수에 맞게 최적화"""
current_tokens = len(self.tokenizer.encode(text))
if current_tokens <= self.target_tokens:
return text, current_tokens
# 1. 불필요한 공백 제거
optimized = re.sub(r'\s+', ' ', text).strip()
# 2. 반복되는 표현 제거
optimized = self._remove_redundant_expressions(optimized)
# 3. 문장 단위로 자르기
if len(self.tokenizer.encode(optimized)) > self.target_tokens:
optimized = self._truncate_by_sentences(optimized)
final_tokens = len(self.tokenizer.encode(optimized))
return optimized, final_tokens
def _remove_redundant_expressions(self, text):
"""반복되는 표현 제거"""
# 간단한 예시: 연속된 동일한 단어 제거
words = text.split()
cleaned_words = []
prev_word = None
for word in words:
if word != prev_word:
cleaned_words.append(word)
prev_word = word
return ' '.join(cleaned_words)
def _truncate_by_sentences(self, text):
"""문장 단위로 자르기"""
sentences = text.split('.')
result = ""
for sentence in sentences:
test_text = result + sentence + "."
if len(self.tokenizer.encode(test_text)) <= self.target_tokens:
result = test_text
else:
break
return result.strip()
# 사용 예시
optimizer = TokenOptimizer(tokenizer, target_tokens=100)
long_text = "매우 긴 텍스트 내용..."
optimized_text, token_count = optimizer.optimize_text(long_text)
print(f"최적화된 토큰 수: {token_count}")
5. 배치 토큰 수 계산
def calculate_batch_tokens(texts, tokenizer):
"""여러 텍스트의 토큰 수를 배치로 계산"""
results = []
total_tokens = 0
for i, text in enumerate(texts):
tokens = tokenizer.encode(text)
token_count = len(tokens)
total_tokens += token_count
results.append({
"index": i,
"text": text[:50] + "..." if len(text) > 50 else text,
"token_count": token_count,
"cumulative_tokens": total_tokens
})
return {
"individual_results": results,
"total_tokens": total_tokens,
"average_tokens": total_tokens / len(texts) if texts else 0
}
# 배치 처리 예시
texts = [
"첫 번째 텍스트입니다.",
"두 번째 텍스트입니다.",
"세 번째 텍스트입니다."
]
batch_result = calculate_batch_tokens(texts, tokenizer)
print(f"총 토큰 수: {batch_result['total_tokens']}")
print(f"평균 토큰 수: {batch_result['average_tokens']:.1f}")
실무에서의 고려사항
1. 토크나이저 선택
언어별 권장 토크나이저:
tokenizer_recommendations = {
"영어": "GPT, BERT 토크나이저",
"한국어": "KoBERT, KoGPT 토크나이저",
"다국어": "mT5, XLM-R 토크나이저",
"코드": "CodeGPT, CodeBERT 토크나이저"
}
2. 토큰 효율성 최적화
def optimize_token_usage(text, tokenizer):
# 1. 불필요한 공백 제거
text = text.strip()
# 2. 반복되는 패턴 제거
text = remove_redundant_patterns(text)
# 3. 토큰 수 확인
token_count = len(tokenizer.encode(text))
return text, token_count
# 예시
original_text = " 안녕하세요 반갑습니다 "
optimized_text, count = optimize_token_usage(original_text, tokenizer)
3. 토큰 예산 관리
class TokenBudget:
def __init__(self, max_tokens=4096):
self.max_tokens = max_tokens
self.used_tokens = 0
def add_tokens(self, token_count):
self.used_tokens += token_count
return self.used_tokens <= self.max_tokens
def get_remaining_tokens(self):
return max(0, self.max_tokens - self.used_tokens)
# 사용 예시
budget = TokenBudget(max_tokens=4096)
text = "안녕하세요"
tokens = tokenizer.encode(text)
if budget.add_tokens(len(tokens)):
print(f"토큰 추가 성공. 남은 토큰: {budget.get_remaining_tokens()}")
else:
print("토큰 제한 초과!")
결론
토큰과 토크나이저는 LLM의 핵심 구성 요소로, 텍스트를 모델이 이해할 수 있는 형태로 변환하는 역할을 합니다. 적절한 토크나이저 선택과 토큰 효율성 관리는 LLM 서비스의 성능과 비용에 직접적인 영향을 미칩니다.
핵심 포인트
- 토큰의 중요성: LLM이 텍스트를 처리하는 기본 단위
- 토크나이저의 종류: 단어, 문자, 서브워드 기반 토크나이저
- 언어별 특성: 영어, 한국어 등 언어에 따른 토크나이저 차이
- 실무 고려사항: 토큰 수 제한, 비용 관리, 효율성 최적화
이러한 이해를 바탕으로 LLM 서비스를 구축할 때 적절한 토크나이저를 선택하고 토큰 사용을 최적화할 수 있습니다.