Files
simple-llm/doc/bpe_algorithm.md
2025-07-12 11:19:54 +03:00

214 lines
8.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Byte Pair Encoding (BPE) Algorithm
## Введение
Byte Pair Encoding (BPE) - это алгоритм компрессии данных, адаптированный для токенизации текста в обработке естественного языка. В контексте языковых моделей BPE используется для создания эффективного словаря подстрок (токенов).
## Основные понятия
- **Токен** - элементарная единица текста (символ или последовательность символов)
- **Словарь** - набор уникальных токенов, используемых для представления текста
- **Частота пары** - количество раз, когда два токена встречаются вместе в тексте
## Алгоритм работы
### 1. Инициализация
```python
Исходный текст Разбить на символы Первоначальный словарь
```
Пример:
```
"мама" → ['м', 'а', 'м', 'а']
```
### 2. Основной цикл
```mermaid
graph TD
A[Подсчет частот пар] --> B[Выбор наиболее частой пары]
B --> C[Создание нового токена]
C --> D[Обновление последовательности]
D --> E{Достигнут лимит словаря?}
E -->|Нет| A
E -->|Да| F[Конец]
```
### 3. Детализация шагов
#### Шаг 1: Подсчет частот пар
Для текущей последовательности токенов подсчитываем все пары соседних токенов:
```
Текст: "мама мыла"
Токены: ['м', 'а', 'м', 'а', ' ', 'м', 'ы', 'л', 'а']
Пары: ('м','а'), ('а','м'), ('м','а'), ('а',' '), (' ','м'), ('м','ы'), ('ы','л'), ('л','а')
```
#### Шаг 2: Выбор пары для слияния
Находим пару с максимальной частотой. При равенстве частот выбираем пару, которая встречается раньше в тексте.
#### Шаг 3: Слияние
Объединяем выбранную пару в новый токен и заменяем все её вхождения в тексте:
```
Выбранная пара: ('м', 'а')
Новый токен: 'ма'
Обновленная последовательность: ['ма', 'ма', ' ', 'м', 'ы', 'л', 'а']
```
#### Шаг 4: Обновление словаря
Добавляем новый токен в словарь:
```
Словарь: ['м', 'а', ' ', 'ы', 'л', 'ма']
```
### 4. Критерии остановки
1. Достижение заданного размера словаря
2. Отсутствие пар для слияния (все возможные пары уже добавлены)
3. Достижение максимального числа итераций
## Псевдокод
```python
def train_bpe(text, vocab_size):
# Инициализация
tokens = list(text)
vocab = set(tokens)
while len(vocab) < vocab_size:
# Подсчет пар
pairs = get_pairs(tokens)
if not pairs:
break
# Выбор наиболее частой пары
best_pair = max(pairs, key=pairs.get)
# Слияние
new_tokens = []
i = 0
while i < len(tokens):
if i < len(tokens)-1 and (tokens[i], tokens[i+1]) == best_pair:
new_tokens.append(best_pair[0] + best_pair[1])
i += 2
else:
new_tokens.append(tokens[i])
i += 1
tokens = new_tokens
# Обновление словаря
vocab.add(best_pair[0] + best_pair[1])
return vocab
```
## Пример работы
**Исходный текст**: "мама мыла раму"
**Итерация 1**:
- Пара ('м','а') встречается 2 раза
- Новый токен: 'ма'
- Текст: ['ма', 'ма', ' ', 'м', 'ы', 'л', 'а', ' ', 'р', 'а', 'м', 'у']
**Итерация 2**:
- Пара ('ма',' ') встречается 1 раз
- Новый токен: 'ма '
- Текст: ['ма ', 'ма', 'мы', 'л', 'а', ' ', 'р', 'а', 'м', 'у']
**Результирующий словарь** (частично):
['м', 'а', ' ', 'ы', 'л', 'р', 'у', 'ма', 'ма ', 'мы']
## Алгоритм энкодинга (токенизации)
После обучения BPE-модели (создания словаря), энкодинг текста происходит по следующему алгоритму:
```mermaid
graph TD
A[Начало] --> B[Разбить текст на символы]
B --> C[Инициализировать пустой список токенов]
C --> D[Установить i=0 'начало последовательности']
D --> E{i < длины текста?}
E -->|Нет| F[Заменить токены на их ID]
E -->|Да| G[Найти все токены в словаре, начинающиеся с text_i]
G --> H[Выбрать самый длинный подходящий токен]
H --> I[Добавить токен в результат]
I --> J[Увеличить i на длину токена]
J --> E
F --> K[Конец]
```
Пошаговое описание:
1. **Инициализация**:
- Исходный текст разбивается на символы
- Создается пустой список для результата
- Указатель `i` устанавливается в 0
2. **Основной цикл**:
- Для текущей позиции `i` находим все токены в словаре, которые:
- Начинаются с символа `text[i]`
- Совпадают с подстрокой `text[i:i+len(token)]`
- Из подходящих токенов выбираем самый длинный
- Добавляем найденный токен в результат
- Сдвигаем указатель `i` на длину добавленного токена
3. **Завершение**:
- Когда весь текст обработан, заменяем токены на их ID из словаря
Пример:
```python
Словарь: ['ма', 'мама', ' ', 'мыл', 'а', 'раму']
Текст: "мама мыла раму"
Энкодинг:
1. Находим самый длинный токен, начинающийся с 'м' -> 'мама'
2. Добавляем 'мама', i += 4
3. Токен ' ' (пробел), i += 1
4. Токен 'мыл', i += 3
5. Токен 'а', i += 1
6. Токен ' ', i += 1
7. Токен 'раму', i += 4
Результат: ['мама', ' ', 'мыл', 'а', ' ', 'раму']
```
## Алгоритм декодирования
### Принцип работы
1. Преобразование списка ID обратно в текст
2. Замена каждого ID на соответствующий токен
3. Обработка неизвестных ID (`[UNK]`)
```mermaid
flowchart TD
A[Список ID] --> B{ID ∈ словарь?}
B -->|Да| C[Добавить токен]
B -->|Нет| D[Добавить UNK]
C --> E[Следующий ID]
D --> E
E --> F{Конец списка?}
F -->|Нет| B
F -->|Да| G[Объединить токены]
```
Пример:
```python
decode([0,1,2]) "абра" # Для словаря {0:"а", 1:"б", 2:"ра"}
```
## Применение в языковых моделях
1. Эффективное представление редких слов
2. Снижение размерности входных данных
3. Возможность обработки OOV (Out-of-Vocabulary) слов
## Ограничения
1. Чувствительность к регистру (можно решить предварительной нормализацией)
2. Зависимость от обучающего корпуса
3. Не всегда выделяет лингвистически осмысленные морфемы
## Дополнительные материалы
1. [Original BPE paper](https://arxiv.org/abs/1508.07909)
2. [BPE in HuggingFace](https://huggingface.co/docs/transformers/tokenizer_summary)
3. [Practical guide to BPE](https://towardsdatascience.com/byte-pair-encoding-subword-based-tokenization-algorithm-77828a70bee0)