Как работают различные токенизаторы текста?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Как работают различные токенизаторы текста
Токенизация — это первый шаг в обработке естественного языка (NLP). Это процесс разбиения текста на меньшие единицы (токены). Существует несколько подходов, от простых к сложным.
1. Character-level токенизация (Посимвольная)
Как работает: Каждый символ становится отдельным токеном.
text = "Hello World!"
# Character-level
tokens = list(text)
print(tokens)
# Output: ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!']
vocab_size = len(set(tokens)) # 11 символов
Преимущества:
- Очень малый размер словаря (vocab size ~100-256)
- Может обработать любое слово, даже опечатки
- Простая реализация
Недостатки:
- Очень длинные последовательности (текст из 1000 слов = 5000+ токенов)
- Модель должна учиться комбинировать символы в слова
- Неэффективно для трансформеров (квадратичная сложность внимания)
Когда использовать:
- Очень маленькие модели
- Языки с иероглифами
- Когда нужна максимальная гибкость
2. Word-level токенизация (Словная)
Как работает: Разбиение по пробелам и пунктуации на слова.
import string
text = "Hello, World! How are you?"
# Простая word-level
tokens = text.lower().split()
# Output: ['hello,', 'world!', 'how', 'are', 'you?']
# С удалением пунктуации
translator = str.maketrans('', '', string.punctuation)
tokens = [w.translate(translator) for w in text.lower().split()]
# Output: ['hello', 'world', 'how', 'are', 'you']
vocab_size = len(set(tokens)) # 5 слов
Преимущества:
- Разумная длина последовательности
- Простая интерпретация (каждый токен — слово)
- Хорошо для небольших корпусов
Недостатки:
- Большой размер словаря (десятки тысяч слов)
- Проблема с OOV (Out-Of-Vocabulary) словами
- Не обрабатывает морфологию (running, runs, ran — разные токены)
Проблема OOV:
# Если в обучении не видели слово "unbelievable"
# как его обработать при инфиренсе?
# Вариант 1: <UNK> токен
# Вариант 2: Разбить на подслова
3. Subword токенизация (Подсловная)
Это современный стандарт. Разбивает редкие слова на подслова.
3.1 Byte Pair Encoding (BPE)
Как работает:
- Начинаем с символов
- Итеративно объединяем самые частые пары символов
# Пример BPE
text = "low low low low low low low low low low"
# Шаг 0: посимвольная представление
vocab = {
'l o</w>': 10, # </w> обозначает конец слова
'l o w</w>': 10
}
# Шаг 1: найти самую частую пару
# 'l' 'o' встречается в каждом слове
pair = ('l', 'o')
new_token = 'lo'
# Шаг 2: объединить
vocab_after = {
'lo w</w>': 10
}
# Шаг 3: повтори
# 'lo' 'w' объединяется
vocab_after2 = {
'low</w>': 10
}
# Результат: один токен 'low</w>'
Реальный пример с GPT-2:
import tiktoken
encoder = tiktoken.get_encoding("cl100k_base") # GPT-3.5/4
text = "The quick brown fox"
tokens = encoder.encode(text)
print(tokens) # [1920, 4040, 9552, 24417]
# Декодировать обратно
for token in tokens:
print(f"{token}: {encoder.decode_single_token_bytes(token)}")
# 1920: b'The'
# 4040: b' quick'
# 9552: b' brown'
# 24417: b' fox'
Преимущества BPE:
- Баланс: не слишком много токенов, не слишком мало
- Сжимает текст (компрессия)
- Обрабатывает OOV слова
Недостатки:
- Требует обучение на большом корпусе
- Могут разбить слово странно (например, мистер → м ис тер)
3.2 WordPiece (BERT)
Как работает: Похож на BPE, но объединяет пары на основе вероятности, а не частоты.
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
text = "The quick brown fox jumps"
tokens = tokenizer.tokenize(text)
print(tokens)
# ['the', 'quick', 'brown', 'fox', 'jumps']
# С неизвестным словом
text2 = "unbelievable"
tokens2 = tokenizer.tokenize(text2)
print(tokens2)
# ['un', '##believe', '##able'] ## означает подслово внутри слова
Отличие от BPE:
- Использует вероятность вместо частоты
- Более детерминировано
- Лучше для морфологических языков
3.3 SentencePiece
Как работает: Токенизирует текст как последовательность, не разделяя по пробелам.
import sentencepiece as spm
# Обучение SentencePiece модели
train_data = "hello world. this is a test.\nmore text here."
with open('train.txt', 'w') as f:
f.write(train_data)
spm.SentencePieceTrainer.train(
input='train.txt',
model_prefix='my_model',
vocab_size=1000
)
# Использование
sp = spm.SentencePieceProcessor('my_model.model')
tokens = sp.encode("hello world")
print(tokens) # [256, 571] # ID токенов
# Декодировать
text_back = sp.decode(tokens)
print(text_back) # "hello world"
Особенности:
- Работает с любым языком (не требует пробелов)
- Используется в T5, LLaMA, XLNet
- Пробел — часть словаря (обозначается как _)
Пример с многоязычностью:
# SentencePiece работает с китайским, японским, etc.
# Без явного разделения на слова
text_chinese = "你好世界"
tokens = sp.encode(text_chinese)
# SentencePiece разберется автоматически
3.4 Unigram Language Model
Как работает: Итеративно удаляет токены, которые уменьшают вероятность языковой модели.
# Используется в XLNet, ALBERT
# Более сложный алгоритм, реже используется в практике
Сравнение токенизаторов
| Метод | Размер vocab | Длина seq | Скорость | Язык | Примеры |
|---|---|---|---|---|---|
| Character | ~200 | Очень длинная | Медленно | Любой | Кастомные модели |
| Word | 50K-100K | Средняя | Быстро | Английский | Старые NLP |
| BPE | 30K-50K | Короче | Быстро | Англ, кодинг | GPT-2, GPT-3 |
| WordPiece | 30K | Короче | Быстро | Любой | BERT |
| SentencePiece | 32K | Короче | Очень быстро | Любой | T5, LLaMA |
Практический пример: сравнение токенизаторов
from transformers import AutoTokenizer
text = "The quick brown fox jumps over the lazy dog"
# BERT (WordPiece)
bert_tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
bert_tokens = bert_tokenizer.tokenize(text)
print(f"BERT: {len(bert_tokens)} tokens")
# Output: 11 tokens
# GPT-2 (BPE)
import tiktoken
gpt2_tokenizer = tiktoken.get_encoding("gpt2")
gpt2_tokens = gpt2_tokenizer.encode(text)
print(f"GPT-2: {len(gpt2_tokens)} tokens")
# Output: 11 tokens
# GPT-4 (BPE улучшенный)
gpt4_tokenizer = tiktoken.get_encoding("cl100k_base")
gpt4_tokens = gpt4_tokenizer.encode(text)
print(f"GPT-4: {len(gpt4_tokens)} tokens")
# Output: 14 tokens
Специальные токены
# [CLS] - начало последовательности (BERT)
# [SEP] - разделитель (BERT)
# [PAD] - padding
# [UNK] - неизвестное слово
# [MASK] - маска (для BERT masked language modeling)
# <s>, </s> - начало/конец (RoBERTa)
# <bos>, <eos> - (GPT-like модели)
bert_tokens = ["[CLS]", "hello", "world", "[SEP]"]
Как выбрать токенизатор
- Используешь существующую модель? → Используй токенизатор этой модели
- Обучаешь с нуля? → SentencePiece или BPE
- Нужна универсальность? → SentencePiece (работает с любыми языками)
- Только английский? → BPE или WordPiece
- Максимальная скорость? → BPE
- Лучше морфология? → WordPiece
Проблемы токенизации и как их решать
Проблема 1: Странное разбиение
text = "unbelievably"
tokens = ["un", "believably"] # или ["unbelievable", "ly"]
# Решение: это норма для subword токенизаторов
Проблема 2: Моноглотские токенизаторы
# BERT (англ) плохо работает с русским
# Решение: используй multilingual-bert или mBERT
Проблема 3: Специальные символы
text = "Hello @user #hashtag 🎉"
# Разные токенизаторы обрабатывают по-разному
# Решение: очистить текст перед токенизацией
Заключение
Токенизация — не просто препроцессинг, это критическая часть архитектуры NLP модели. Выбор токенизатора влияет на:
- Длину последовательности (влияет на скорость и память)
- Размер словаря (влияет на размер embeddings)
- Способность обрабатывать редкие слова и OOV
- Качество на разных языках
Современные модели (GPT, BERT, T5) используют subword токенизацию, которая балансирует между гибкостью character-level и эффективностью word-level токенизации.