Обучение LLM — основы
~12 мин

Training Pipeline

Как обучают LLM: pre-training → mid-training → SFT → RLHF. Общая картина процесса.

Как обучают LLM: от сырого текста до ChatGPT

Обучить LLM — это не "нажал кнопку train и ушёл пить кофе". Это конвейер из нескольких этапов, где каждый делает своё дело: сначала модель учит язык, потом учится не быть бесполезным автодополнением, и наконец — быть полезной и не советовать делать бомбы. Разбираемся.

Training Pipeline: Pre-training → Mid-training → SFT → RLHF/DPO
Четыре этапа обучения LLM. Каждый уменьшает объём данных, но увеличивает качество.

Pre-training: модель учит язык

На первом этапе модель тупо читает интернет. Буквально весь: веб-страницы, книги, код, Wikipedia — триллионы токенов. Задача ровно одна: предсказать следующий токен. "Столица Франции —" → "Париж". И вот так, через миллиарды угадаек, модель выучивает всё — от грамматики до квантовой физики. One trick pony, который работает до неприличия хорошо.

  • GPT-3 (2020): 175B параметров, 300B токенов — по современным меркам это мало данных
  • Qwen3 (2025): 36T токенов — в 120 раз больше данных, чем GPT-3
  • SmolLM3 (2025): 3B параметров, 11T токенов — маленькая модель, но обучена на огромном корпусе
  • Compute: сотни GPU, месяцы работы, миллионы долларов. GPT-4 стоил ~$100M на обучение

Сколько это стоит в вычислениях? Есть удивительно простая формула:

Бюджет вычислений: C — FLOPs, N — параметры, D — токены. Умножаем на 6, потому что forward + backward pass ≈ 6 операций на параметр на токен.

А целевая функция — старый добрый cross-entropy loss. Ничего хитрого: модель предсказывает вероятность следующего токена, а мы наказываем её за неуверенность в правильном ответе:

Cross-entropy loss для language modeling. T — количество токенов, p(xₜ | x<ₜ) — вероятность правильного токена.

# Pre-training: всё что нужно — предсказать следующий токен
import torch.nn.functional as F

def pretraining_loss(model, input_ids):
    """Стандартный language modeling loss."""
    logits = model(input_ids[:, :-1])     # предсказания для позиций 1..T-1
    targets = input_ids[:, 1:]             # реальные токены на позициях 1..T
    loss = F.cross_entropy(
        logits.reshape(-1, logits.size(-1)),
        targets.reshape(-1),
        ignore_index=-100  # padding не считаем
    )
    return loss  # скаляр: среднее -log p(правильный токен)

# Бюджет: SmolLM3 (3B params, 11T tokens)
flops = 6 * 3e9 * 11e12  # ≈ 2e23 FLOPs
# При A100 ~150 TFLOPS effective → ~370K GPU-часов → ~46 дней на 256 GPU

Mid-training: усиливаем слабые стороны

Mid-training — опциональный этап между pre-training и SFT. Зачем? После pre-training модель может считать как первоклассник, кодить как джун после пятницы, и падать в обморок от длинных документов. Mid-training фиксит это: подкидываем целевые данные (код, математику, научные статьи) и продолжаем тренировку.

  • Расширение контекста: 4K → 128K токенов. Модель учится работать с длинными документами
  • Доменная специализация: добавляем код → модель лучше кодит, добавляем math → лучше считает
  • Long-context training: используют меньший LR и специальный data mix для длинных последовательностей
  • Пример: SmolLM3 использует mid-training для расширения контекста и усиления STEM-навыков

SFT: учим модель быть ассистентом

После pre-training модель — это просто навороченный autocomplete. Ты ей "Как приготовить борщ?", а она тебе "Как приготовить плов? Как приготовить...". SFT (Supervised Fine-Tuning) чинит эту беду: берём ~100K примеров "вопрос → ответ" и дообучаем. После SFT модель наконец понимает, что ты задал вопрос, и отвечает на него.

  • Dataset: пары instruction → response. Качество данных важнее количества
  • SmolLM3: ~100K примеров, 76M токенов. Think/no_think пары для reasoning
  • Chat template: system/user/assistant с специальными токенами. Каждая модель — свой формат
  • Loss считается только на assistant tokens — модель учится отвечать, а не повторять вопросы
# SFT данные: пары instruction → response в chat template
sft_example = {
    "messages": [
        {"role": "system", "content": "Ты полезный ассистент."},
        {"role": "user", "content": "Объясни backpropagation в 2 предложениях"},
        {"role": "assistant", "content": "Backpropagation считает градиент "
         "loss по каждому весу через chain rule — от выхода к входу. "
         "Это позволяет обновить все веса нейросети за один проход."}
    ]
}

# При SFT loss считается ТОЛЬКО на assistant tokens!
# Модель учится отвечать, а не повторять вопросы пользователя
def sft_loss(model, input_ids, label_mask):
    logits = model(input_ids[:, :-1])
    targets = input_ids[:, 1:]
    loss = F.cross_entropy(
        logits.reshape(-1, logits.size(-1)),
        targets.reshape(-1),
        reduction="none"
    )
    # label_mask: 1 для assistant tokens, 0 для system/user
    loss = (loss * label_mask[:, 1:].reshape(-1)).sum() / label_mask.sum()
    return loss

RLHF/DPO: alignment — учим быть полезной

SFT учит модель подражать датасету. Но мы хотим большего — чтобы модель была лучше своих учителей. Более полезной, честной и без советов "как растворить тело в кислоте". Для этого есть RLHF и DPO. Идея проста: люди сравнивают ответы модели, а модель учится генерить те, которые люди предпочитают.

  • RLHF: обучаем reward model → RL оптимизирует policy → модель генерирует лучшие ответы
  • DPO: без reward model, напрямую учим из пар preferred/rejected. Проще и стабильнее
  • RLVR (DeepSeek-R1): RL с верифицируемыми ответами (math, code). Правильно = +1, неправильно = 0
  • Результат: модель отказывается от вредных запросов, даёт структурированные ответы, рефлексирует

Evaluation: проверяем качество

После каждого этапа нужно проверить — модель стала умнее или мы что-то сломали? Для этого есть бенчмарки — стандартизированные экзамены для AI:

  • MMLU: общие знания (57 предметов от истории до физики). «Экзамен для AI»
  • GPQA: сложные вопросы уровня PhD. Даже эксперты ошибаются в 35% случаев
  • AIME: математические олимпиады. Проверяет рассуждение, а не просто знание формул
  • SWE-bench: реальные GitHub issues. Модель должна написать patch, который проходит тесты
  • LiveCodeBench: свежие задачи с Codeforces/LeetCode, которых не было в train data

🎯 Запомни

Training pipeline = 4 этапа: Pre-training (жрём интернет, триллионы токенов) → Mid-training (подтягиваем слабые места) → SFT (учимся быть ассистентом, ~100K примеров) → RLHF/DPO (учимся быть хорошим ассистентом). Каждый следующий этап — меньше данных, но качественнее. Как воронка: от сырья к бриллианту.