NLP до эпохи трансформеров
Чтобы понять революцию BERT, нужно знать, что было до него — и почему это не работало достаточно хорошо.
Word2Vec и GloVe: статические эмбеддинги
В 2013 году Томас Миколов (Google) представил word2vec — первый практичный метод получения плотных векторных представлений слов. Идея проста: слова, встречающиеся в похожих контекстах, должны иметь близкие векторы.
Два варианта архитектуры:
max Σ Σ log P(wₒ | wc)
для каждого центрального слова wc и контекстного wₒ в окне размера k
P(wₒ | wc) = exp(uₒᵀ · vc) / Σⱼ exp(uⱼᵀ · vc)
# vc — эмбеддинг центрального слова; uₒ — эмбеддинг контекстного
Знаменитый пример: king − man + woman ≈ queen. Арифметика над векторами отражает семантические отношения.
GloVe (Pennington et al., Stanford, 2014) использует глобальную матрицу совместной встречаемости. Цель — чтобы скалярное произведение векторов приближало логарифм вероятности совместной встречаемости: wᵢ · wⱼ ≈ log P(i|j).
ELMo: первые контекстуальные эмбеддинги
ELMo (Embeddings from Language Models, Peters et al., AllenAI, 2018) — переломный момент перед BERT. Вместо одного вектора на слово ELMo строит представление на основе всего контекста, используя двунаправленный LSTM.
# hₖ — скрытое состояние k-го слоя biLSTM
# sₖ — обучаемые веса для каждого слоя
# γ — масштабирующий параметр задачи
ELMo предобучается на задаче языкового моделирования: предсказать следующее слово (вперёд) и предыдущее (назад). Это первый пример transfer learning в NLP в современном понимании — предобучение на большом корпусе, затем добавление эмбеддингов в downstream-модель.
Ограничение ELMo: два отдельных однонаправленных LSTM — не по-настоящему двунаправленная модель. Forward и backward сети обучаются независимо, их представления просто конкатенируются. BERT решит это с помощью по-настоящему двунаправленного attention.
BERT: двунаправленный трансформер
«BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding» — статья, изменившая NLP. Авторы: Devlin, Chang, Lee, Toutanova (Google AI).
Задача 1: Masked Language Modeling (MLM)
Это центральная инновация BERT. Суть: случайно заменить 15% токенов на [MASK] и обучить модель их восстанавливать, имея доступ к обоим контекстам — левому и правому. Это делает модель по-настоящему двунаправленной.
Задача 2: Next Sentence Prediction (NSP)
BERT также предобучается предсказывать, является ли предложение B продолжением предложения A или взято случайно из корпуса.
Вектор [CLS] после BERT подаётся на бинарный классификатор IsNext/NotNext. Цель — научить модель понимать межпредложенческие отношения, что важно для задач QA и NLI.
Архитектурные детали BERT
| Параметр | BERT-Base | BERT-Large |
|---|---|---|
| Слои (L) | 12 | 24 |
| Скрытый размер (H) | 768 | 1024 |
| Головы внимания (A) | 12 | 16 |
| Параметров | 110M | 340M |
| Корпус предобучения | BooksCorpus (800M слов) + English Wikipedia (2500M слов) | |
| Токенизация | WordPiece, vocab 30 522 токена | |
| Макс. длина | 512 токенов | |
| Время предобучения | 4 дня на 16 TPU v3 | 4 дня на 64 TPU v3 |
Варианты и улучшения BERT
За год после выхода BERT исследователи опубликовали десятки вариантов. Вот самые важные и их архитектурные новшества.
RoBERTa (Facebook AI, июль 2019)
RoBERTa (Robustly Optimized BERT Approach, Лю и др.) — это не новая архитектура, а тщательное исследование того, что реально важно при обучении BERT. Вывод: оригинальный BERT был недообучен.
Убрали NSP
Next Sentence Prediction не помогала или даже вредила. Убрали, обучали только на MLM.
Динамическое маскирование
BERT маскировал токены один раз при создании данных. RoBERTa генерирует новые маски на каждом шаге — сложнее переобучиться.
Больше данных и батч
160GB текста вместо 16GB. Батч 8K примеров вместо 256. Обучение 500K шагов.
Длинные последовательности
Обучение на полных предложениях длиной до 512 токенов с самого начала, без коротких последовательностей.
Результат: RoBERTa превзошла BERT на всех бенчмарках GLUE, SQuAD и RACE — просто за счёт правильного обучения. Ключевой вывод: масштаб данных и вычислений имеет огромное значение.
DistilBERT (Hugging Face, октябрь 2019)
Виктор Санс и соавторы предложили дистилляцию знаний (knowledge distillation): маленькая «студенческая» сеть учится имитировать большую «учительскую».
L = α · L_MLM + β · L_distil + γ · L_cosine
L_distil = KL(softmax(zₛ/T) ‖ softmax(zₜ/T)) ← «мягкие» метки учителя
L_cosine = 1 − cos(hₛ, hₜ) ← выровнять скрытые состояния
# T — температура; высокая T смягчает распределение учителя
| BERT-Base | DistilBERT | Изменение | |
|---|---|---|---|
| Параметров | 110M | 66M | −40% |
| Скорость инференса | ×1 | ×1.6 | +60% |
| Размер модели | 438 MB | 255 MB | −42% |
| GLUE score | 79.6 | 77.0 | −97% качества сохранено |
| Слои | 12 | 6 | Убраны нечётные слои |
ALBERT (Google Research, сентябрь 2019)
ALBERT (A Lite BERT) решает проблему памяти BERT с помощью двух архитектурных новшеств:
Декодерные модели: GPT-серия
Пока Google шёл путём encoder-only (двунаправленный контекст для понимания), OpenAI сделал ставку на decoder-only (авторегрессионная генерация).
GPT и GPT-2: авторегрессионное языковое моделирование
GPT (Generative Pre-trained Transformer, Radford et al., 2018) использует только decoder-часть трансформера. Задача предобучения — Causal Language Modeling (CLM): предсказать следующий токен, зная все предыдущие.
# U — корпус токенов, k — размер контекстного окна
# Внимание — только влево (causal / masked attention)
GPT-2 (февраль 2019) — та же архитектура, но в 10× крупнее: 1.5B параметров (GPT-2 XL), обучен на WebText (40GB текста с Reddit). Openai первоначально отказалась публиковать полную модель из-за опасений по поводу дипфейков и дезинформации. GPT-2 продемонстрировал zero-shot способности: без дообучения показал конкурентные результаты на задачах чтения с пониманием и суммаризации.
GPT-3: масштаб как стратегия
GPT-3 (Brown et al., OpenAI, май 2020) — 175B параметров, обучен на 300B токенов (Common Crawl, WebText, Books, Wikipedia). Архитектурно — тот же decoder-only трансформер, но огромный.
| Версия | Параметры | Слои | d_model | Головы | Контекст |
|---|---|---|---|---|---|
| GPT-3 Small | 125M | 12 | 768 | 12 | 2048 |
| GPT-3 Medium | 350M | 24 | 1024 | 16 | 2048 |
| GPT-3 Large | 760M | 24 | 1536 | 16 | 2048 |
| GPT-3 (full) | 175B | 96 | 12288 | 96 | 2048 |
In-context learning — главное открытие GPT-3. Не нужно обновлять веса. Достаточно показать несколько примеров прямо в prompt:
# Few-shot перевод без fine-tuning: """ Переведи на французский: sea otter → loutre de mer peppermint → menthe poivrée plush giraffe → girafe en peluche cheese → """ # GPT-3 продолжит: fromage
Encoder-Decoder модели: T5 и BART
Что если сформулировать любую NLP-задачу как преобразование текста в текст? T5 и BART реализуют именно этот подход.
T5: Text-to-Text Transfer Transformer
T5 (Raffel et al., Google, 2019) унифицирует все NLP-задачи под один формат: вход и выход — всегда текст. Это устраняет необходимость в задача-специфичных головах.
T5 предобучается на задаче Span Corruption — вариант MLM, но маскируются и восстанавливаются целые отрезки текста (spans), а не отдельные токены. Вход: «Thank you
T5 обучался на C4 (Colossal Clean Crawled Corpus) — 750GB очищенного CommonCrawl. Самая большая версия T5-11B имеет 11 миллиардов параметров.
BART: двунаправленный авторегрессионный трансформер
BART (Lewis et al., Facebook AI, 2019) — encoder-decoder модель, предобученная на задаче реконструкции повреждённого текста. Ключевое отличие от T5: BART использует BERT-подобный энкодер (полное двунаправленное внимание) и GPT-подобный декодер (авторегрессионный).
BART экспериментировал с разными схемами «порчи» текста:
Token Masking
Как в BERT: случайные токены заменяются на [MASK]. Декодер восстанавливает их.
Token Deletion
Токены удаляются (без [MASK]). Модель должна решить, где были пропуски — сложнее.
Text Infilling
Span из 0-нескольких токенов заменяется одним [MASK]. Похоже на T5 Span Corruption.
Sentence Permutation
Предложения в документе перемешиваются случайно. Модель восстанавливает порядок.
Document Rotation
Документ начинается с случайного токена — модель определяет «настоящее» начало.
BART показал SOTA на задачах суммаризации (CNN/DM, XSum), машинного перевода и диалоговых систем. Для суммаризации особенно эффективен: энкодер кодирует полный документ, декодер генерирует краткое изложение.
Дообучение BERT для downstream-задач
Предобученный BERT — это универсальная основа. Добавив минимальный «голос» поверх неё и дообучив на задача-специфичных данных, получаем SOTA на большинстве NLP-задач.
Общая стратегия fine-tuning
BertModel.from_pretrained('bert-base-uncased')Классификация текста (Sequence Classification)
Для классификации (тональность, тематика, NLI) используется вектор специального токена [CLS] — BERT обучен вкладывать в него «резюме» всего предложения. Поверх него — линейный слой с softmax.
from transformers import BertForSequenceClassification, BertTokenizer import torch tokenizer = BertTokenizer.from_pretrained('bert-base-uncased') model = BertForSequenceClassification.from_pretrained( 'bert-base-uncased', num_labels=2 # positive / negative ) text = "This film is absolutely great!" inputs = tokenizer(text, return_tensors='pt', truncation=True, max_length=512) # inputs = {input_ids, attention_mask, token_type_ids} with torch.no_grad(): outputs = model(**inputs) logits = outputs.logits # (1, 2) probs = logits.softmax(dim=-1) # [0.08, 0.92] label = probs.argmax() # 1 → Positive # Fine-tuning loop: optimizer = torch.optim.AdamW(model.parameters(), lr=2e-5) loss_fn = torch.nn.CrossEntropyLoss() for batch in train_loader: outputs = model(**batch['inputs'], labels=batch['labels']) loss = outputs.loss # BertForSequenceClassification считает loss сам loss.backward() optimizer.step() optimizer.zero_grad()
Named Entity Recognition (NER)
NER — задача на уровне токенов. Каждому токену нужно присвоить метку: PER (персона), ORG (организация), LOC (локация), O (нет сущности). Используем выходы BERT для каждого токена, а не только [CLS].
from transformers import BertForTokenClassification label2id = {"O":0, "B-PER":1, "I-PER":2, "B-ORG":3, "I-ORG":4, "B-LOC":5, "I-LOC":6} model = BertForTokenClassification.from_pretrained( 'bert-base-cased', # cased важен для NER! num_labels=len(label2id) ) # BertForTokenClassification внутри: # self.bert → скрытые состояния (B, T, 768) # self.dropout # self.classifier = Linear(768, num_labels) ← для каждого токена # Важно: для WordPiece субтокенов используем метку только первого субтокена # "Barack" → ["Bar", "##ack"] → метка B-PER только для "Bar", ##ack → -100 labels = [1, -100, 2, 0, 5] # -100 игнорируется в CrossEntropy
Question Answering на SQuAD
SQuAD (Stanford Question Answering Dataset) — задача extractive QA: дан контекст-абзац и вопрос, нужно найти отрезок (span) в контексте, являющийся ответом.
BERT решает это элегантно: вход = [CLS] вопрос [SEP] контекст [SEP]. Для каждого токена контекста предсказываем: является ли он началом ответа (start) или концом ответа (end) — два отдельных линейных слоя.
score_end(i) = hᵢ · Wₑ
P_start = softmax(score_start) ← вероятность того, что i — начало ответа
P_end = softmax(score_end)
answer = tokens[argmax(P_start) : argmax(P_end)+1]
Результаты на SQuAD 2.0: BERT-Large достиг F1 = 83.1 (человек ~86.8), превзойдя все предыдущие методы сразу после выхода.
Алгоритмы токенизации
Токенизатор — первый и критически важный компонент любой языковой модели. От его выбора зависит эффективность словаря, качество на редких словах и кросс-языковое обобщение.
Зачем субслова, а не целые слова?
Проблема словарного подхода (word-level): Английский имеет 170 000+ слов; OOV (out-of-vocabulary) слова — постоянная проблема. «Нейрокомпьютер», «GPT-4o», «anti-establishment» — новые слова постоянно появляются.
Проблема символьного подхода (char-level): Слишком длинные последовательности. «Hello» = 5 токенов; документ из 1000 слов = ~5000 токенов. Контекстное окно BERT = 512 токенов.
Субсловный подход — золотая середина: редкие слова разбиваются на известные подстроки, частые слова остаются целыми. «Tokenization» → [«Token», «##ization»].
BPE — Byte Pair Encoding
Предложен Сеннрихом (2015) для машинного перевода; используется в GPT, GPT-2, GPT-3, RoBERTa.
Алгоритм обучения:
WordPiece (BERT)
WordPiece — вариант BPE, разработанный Google (Schuster & Nakamura, 2012) для системы голосового ввода японского и корейского, затем адаптированный для BERT. Ключевое отличие: критерий слияния основан на вероятности, а не частоте.
# Выбираем пару, которая максимизирует likelihood корпуса
# Эквивалентно: maximize P(corpus | vocabulary)
Два ключевых отличия от BPE в контексте BERT:
##. «playing» → [«play», «##ing»]. Это позволяет восстановить исходное слово.# WordPiece токенизация: пример вручную vocab = {"un", "##believ", "##able", "unbelievable", ...} word = "unbelievable" # Greedy: «unbelievable» → в словаре? Нет. # «unbelievabl» → нет. ... → «un» → ДА. Берём. # остаток «believable» → «##believ» → ДА. Берём. # остаток «able» → «##able» → ДА. Берём. tokens = ["un", "##believ", "##able"] # BERT tokenizer через HuggingFace: from transformers import BertTokenizer tok = BertTokenizer.from_pretrained('bert-base-uncased') print(tok.tokenize("unbelievable")) # → ['un', '##believ', '##able'] print(tok.tokenize("The cat sat on the mat.")) # → ['the', 'cat', 'sat', 'on', 'the', 'mat', '.']
SentencePiece (T5, LLaMA)
SentencePiece (Kudo & Richardson, Google, 2018) — универсальная библиотека токенизации, реализующая BPE и Unigram Language Model. Ключевое отличие от WordPiece и BPE: работает напрямую с необработанным текстом, без предварительной токенизации по пробелам.
SentencePiece поддерживает два алгоритма обучения словаря:
BPE в SentencePiece
Тот же алгоритм слияний, что и оригинальный BPE, но без пре-токенизации. Используется в XLM, некоторых версиях T5.
Unigram Language Model
Начинает с большого словаря, итеративно удаляет наименее полезные токены. Используется в T5, ALBERT, mBART. Позволяет вероятностную токенизацию (data augmentation).
import sentencepiece as spm # Обучение spm.SentencePieceTrainer.train( input='corpus.txt', model_prefix='spm_model', vocab_size=32000, character_coverage=0.9995, # для не-латинских скриптов model_type='bpe' # или 'unigram' ) # Применение sp = spm.SentencePieceProcessor() sp.load('spm_model.model') print(sp.encode('Hello World', out_type=str)) # → ['▁Hello', '▁World'] # ▁ = пробел перед словом print(sp.encode('Непредсказуемость', out_type=str)) # → ['▁Не', 'пред', 'сказ', 'уем', 'ость']
| Алгоритм | Модели | Vocab | Пре-токенизация | OOV | Особенность |
|---|---|---|---|---|---|
| BPE | GPT, GPT-2/3, RoBERTa | 50K | По пробелам | Нет (byte-level) | Частотный критерий слияния |
| WordPiece | BERT, DistilBERT, ALBERT | 30K | По пробелам | [UNK] | ## для субтокенов; likelihood критерий |
| SentencePiece (BPE) | XLM-R, некоторые T5 | 32K–250K | Нет (▁ = пробел) | Нет | Language-agnostic |
| SentencePiece (Unigram) | T5, ALBERT, mBART, LLaMA | 32K | Нет | Нет | Вероятностная токенизация |
Большое сравнение: какую модель выбрать?
Быстрая навигация по типам задач, сильным и слабым сторонам каждого семейства.
| Модель | Тип | Параметры | Задача pretraining | Лучшие задачи | Слабости |
|---|---|---|---|---|---|
| BERT | Encoder | 110M / 340M | MLM + NSP | Классификация, NER, QA, NLI | Не генерирует текст; NSP слаба |
| RoBERTa | Encoder | 125M / 355M | MLM (динамическое) | Все задачи понимания; лучше BERT | Не генерирует; большой |
| DistilBERT | Encoder | 66M | Дистилляция BERT | Production: быстрый инференс | −3% качества vs BERT |
| ALBERT | Encoder | 12M–235M | MLM + SOP | Эффективность по памяти; GLUE SOTA 2019 | Медленный инференс (итерационные слои) |
| GPT-2 | Decoder | 117M–1.5B | Causal LM | Генерация текста, zero-shot | Нет двунаправленного контекста |
| GPT-3 | Decoder | 175B | Causal LM (масштаб) | Few-shot всего; кодинг; reasoning | Дорого; нет публичных весов |
| T5 | Enc-Dec | 60M–11B | Span Corruption | Перевод, суммаризация, QA | Медленнее encoder-only для классификации |
| BART | Enc-Dec | 140M / 400M | Denoising (5 схем) | Суммаризация (SOTA), перефразирование | Специфичен для seq2seq |
Что читать дальше
Оригинальные работы
«BERT» (2018), «RoBERTa» (2019), «DistilBERT» (2019), «ALBERT» (2019), «T5» (2019), «GPT-3» (2020), «BPE» Sennrich (2015).
Hugging Face Transformers
docs.huggingface.co — лучший ресурс для практики. Курс NLP (course.huggingface.co) охватывает все модели из этой лекции.
GLUE & SuperGLUE
gluebenchmark.com — стандартные наборы задач для оценки всех упомянутых моделей. SQuAD для QA.