Перейти к содержимому
Ступень 66.3 Предпочтения — RLHF и DPO

DPO — предпочтения без RL

Как из оптимальной политики RLHF за три шага получить DPO — обучение на парах «лучше/хуже» без reward model и без PPO; роль β, сравнение с PPO и обзор IPO, KTO, SimPO.

УРОКstage-6/6-3-preferences/03-dpo.mdx1 ч 40 минУрок 3 из 3
После урока вы сможете
  • Вывести loss DPO из цели RLHF с KL-штрафом и модели Брэдли–Терри и объяснить, куда делась reward model
  • Посчитать DPO loss и неявные награды по лог-вероятностям ответов, включая маскирование промпта
  • Объяснить роль β\beta и сравнить DPO с PPO — по памяти, стабильности и тому, где каждый метод сильнее
  • Различать варианты IPO, KTO и SimPO по тому, какую проблему DPO они решают

В прошлом уроке RLHF с PPO потребовал четыре модели, генерацию на каждом шаге и десяток капризных гиперпараметров. В 2023 году группа из Стэнфорда (Rafailov и др.) показала, что для той же цели — максимум награды при KL-поводке к референсной модели — reward model и RL не нужны вовсе. Достаточно одного loss по парам предпочтений, который учится так же просто, как SFT.

Метод назвали DPOпрямая оптимизация предпочтений (DPO)EN direct preference optimization (DPO)Rafailov и др., 2023. Обучение на парах предпочтений без reward model и без RL-цикла. (Direct Preference Optimization), а подзаголовок статьи объясняет главный трюк: «ваша языковая модель тайно является reward model». В 2024 году DPO стал стандартной ступенью пост-трейнинга открытых моделей, включая DeepSeek LLM Chat и Qwen2. Сегодня он остаётся одним из основных способов подогнать стиль, тон и безопасность, когда награду нельзя проверить автоматически.

flowchart LR
subgraph PPO["RLHF с PPO"]
  direction LR
  A1["Пары предпочтений"] --> A2["Обучить reward model"]
  A2 --> A3["PPO: генерация, RM, критик, референс"]
  A3 --> A4["Политика"]
end
subgraph DPO["DPO"]
  direction LR
  B1["Пары предпочтений"] --> B2["Один loss: политика + замороженный референс"]
  B2 --> B4["Политика"]
end
DPO выбрасывает два этапа из конвейера RLHF

Нам понадобятся две формулы из прошлых уроков: оптимальная политика при KL-штрафе (урок 6.3.1) и модель Брэдли–Терри (урок 6.3.2).

Цель RLHF — максимизировать Ey∼π[r(x,y)]−β KL(π ∥ πref)\mathbb{E}_{y \sim \pi}[r(x, y)] - \beta\, \mathrm{KL}(\pi \,\Vert\, \pi_{\text{ref}}). Её решение мы уже видели:

π∗(y∣x)=1Z(x) πref(y∣x) exp⁡ ⁣(r(x,y)β),Z(x)=∑yπref(y∣x) er(x,y)/β\begin{gathered} \pi^*(y \mid x) = \frac{1}{Z(x)}\, \pi_{\text{ref}}(y \mid x)\, \exp\!\Big(\frac{r(x, y)}{\beta}\Big), \\ Z(x) = \sum_y \pi_{\text{ref}}(y \mid x)\, e^{r(x, y)/\beta} \end{gathered}

Почему именно так? Распишем KL(π ∥ π∗)\mathrm{KL}(\pi \,\Vert\, \pi^*) по определению и подставим log⁡π∗=log⁡πref+r/β−log⁡Z(x)\log \pi^* = \log \pi_{\text{ref}} + r/\beta - \log Z(x):

KL(π ∥ π∗)=Ey∼π[log⁡π−log⁡πref−rβ+log⁡Z(x)]=KL(π ∥ πref)−Ey∼π[r]β+log⁡Z(x)\begin{aligned} \mathrm{KL}(\pi \,\Vert\, \pi^*) &= \mathbb{E}_{y \sim \pi}\Big[\log \pi - \log \pi_{\text{ref}} - \frac{r}{\beta} + \log Z(x)\Big] \\ &= \mathrm{KL}(\pi \,\Vert\, \pi_{\text{ref}}) - \frac{\mathbb{E}_{y \sim \pi}[r]}{\beta} + \log Z(x) \end{aligned}

Умножим обе части на −β-\beta и перенесём βlog⁡Z(x)\beta \log Z(x) в другую сторону: цель RLHF равна −β KL(π ∥ π∗)+βlog⁡Z(x)-\beta\, \mathrm{KL}\big(\pi \,\Vert\, \pi^*\big) + \beta \log Z(x). Второе слагаемое от π\pi не зависит, а KL неотрицательна и равна нулю только при π=π∗\pi = \pi^* (урок 1.3.3). Значит, максимум цели достигается ровно в π∗\pi^*.

Проблема в Z(x)Z(x) — нормировочной константе, которая делает сумму вероятностей равной 1 (в статьях её называют статсуммой, partition function): это сумма по всем возможным текстам, посчитать её нельзя. Поэтому RLHF и идёт обходным путём через PPO.

Прологарифмируем формулу для π∗\pi^* и выразим из неё rr:

r(x,y)=βlog⁡π∗(y∣x)πref(y∣x)+βlog⁡Z(x)r(x, y) = \beta \log \frac{\pi^*(y \mid x)}{\pi_{\text{ref}}(y \mid x)} + \beta \log Z(x)

Это поворот всего вывода: любая политика задаёт свою награду, для которой она оптимальна. Награда «спрятана» в отношении вероятностей политики и референса. Её называют неявной наградойнеявная наградаEN implicit rewardВ DPO: r(x, y) = β · log(π(y|x) / π_ref(y|x)) — награда, «спрятанная» в самой политике..

Модели предпочтений нужна только разность наград двух ответов на один и тот же промпт. Слагаемое βlog⁡Z(x)\beta \log Z(x) зависит только от промпта и сокращается:

P(yw≻yl∣x)=σ(βlog⁡π∗(yw∣x)πref(yw∣x)−βlog⁡π∗(yl∣x)πref(yl∣x))P(y_w \succ y_l \mid x) = \sigma\Big(\beta \log \frac{\pi^*(y_w \mid x)}{\pi_{\text{ref}}(y_w \mid x)} - \beta \log \frac{\pi^*(y_l \mid x)}{\pi_{\text{ref}}(y_l \mid x)}\Big)

Неизвестная Z(x)Z(x) исчезла. Осталось заменить π∗\pi^* на обучаемую политику πθ\pi_\theta и максимизировать правдоподобие наблюдённых предпочтений — ровно как reward model в прошлом уроке:

LDPO(θ)=− E(x,yw,yl)[log⁡σ(βlog⁡πθ(yw∣x)πref(yw∣x)⏟r^w−βlog⁡πθ(yl∣x)πref(yl∣x)⏟r^l)]\mathcal{L}_{\text{DPO}}(\theta) = -\,\mathbb{E}_{(x, y_w, y_l)}\Big[\log \sigma\Big( \underbrace{\beta \log \frac{\pi_\theta(y_w \mid x)}{\pi_{\text{ref}}(y_w \mid x)}}_{\hat r_w} - \underbrace{\beta \log \frac{\pi_\theta(y_l \mid x)}{\pi_{\text{ref}}(y_l \mid x)}}_{\hat r_l}\Big)\Big]

Смысл: это тот же loss reward model, только награда здесь не отдельная сеть, а r^=βlog⁡(πθ/πref)\hat r = \beta \log(\pi_\theta / \pi_{\text{ref}}). Учим «reward model» — и оптимальная для неё политика получается бесплатно, потому что это она сама.

Для каждой пары нужны четыре числа — лог-вероятности ответов под политикой и под референсом:

  1. Склеить «промпт + chosen» и «промпт + rejected», прогнать через политику, взять log-вероятности токенов.
  2. Сложить их только по токенам ответа — та же маска, что в SFT (урок 6.1.2). Получаем log⁡πθ(yw∣x)\log \pi_\theta(y_w \mid x) и log⁡πθ(yl∣x)\log \pi_\theta(y_l \mid x).
  3. То же для референсной модели без градиентов. Референс не меняется, поэтому его лог-вероятности можно посчитать один раз заранее и не держать модель в памяти.
  4. Неявные награды, их разность, −log⁡σ-\log\sigma, среднее по батчу.

Пример с числами. log⁡πθ(yw)=−10\log \pi_\theta(y_w) = -10, log⁡πθ(yl)=−12\log \pi_\theta(y_l) = -12, у референса оба −11-11, β=0.1\beta = 0.1. Награды: r^w=0.1⋅(−10+11)=+0.1\hat r_w = 0.1 \cdot (-10 + 11) = +0.1 и r^l=−0.1\hat r_l = -0.1. Отрыв 0.20.2, loss =log⁡(1+e−0.2)=0.598= \log(1 + e^{-0.2}) = 0.598.

Проверка здравого смысла: на первом шаге πθ=πref\pi_\theta = \pi_{\text{ref}}, все награды нулевые, и loss равен ln⁡2=0.693\ln 2 = 0.693 — как у reward model. TRL и другие библиотеки логируют rewards/chosen, rewards/rejected, rewards/margins и rewards/accuracies (доля пар, где r^w>r^l\hat r_w > \hat r_l). Смотрите на все четыре, а не только на loss.

∇θLDPO=−β E[ σ(r^l−r^w)⏟вес пары(∇θlog⁡πθ(yw∣x)−∇θlog⁡πθ(yl∣x))]\nabla_\theta \mathcal{L}_{\text{DPO}} = -\beta\, \mathbb{E}\Big[\, \underbrace{\sigma(\hat r_l - \hat r_w)}_{\text{вес пары}} \big(\nabla_\theta \log \pi_\theta(y_w \mid x) - \nabla_\theta \log \pi_\theta(y_l \mid x)\big)\Big]

Поднимаем вероятность хорошего ответа, опускаем плохого, а вес пары тем больше, чем сильнее неявная награда ошибается. При отрыве −2-2 (перепутан порядок) вес σ(2)=0.88\sigma(2) = 0.88, при отрыве +2+2 — уже 0.120.12. Авторы DPO показали, что без этого веса (просто «вверх chosen, вниз rejected») модель быстро деградирует.

β\beta — тот же коэффициент KL-штрафа из RLHF. Он стоит внутри сигмоиды, поэтому задаёт, насколько сильно политика должна разойтись с референсом, чтобы loss стал маленьким. Пусть мы хотим loss 0.1 на паре, то есть βh≈2.25\beta h \approx 2.25 (потому что −log⁡σ(2.25)≈0.1-\log \sigma(2.25) \approx 0.1), где hh — разность лог-отношений, а нужное hh получаем делением: h=2.25/βh = 2.25 / \beta:

β\betaНужная разность hh (в натах)Поведение
0.54.5короткий поводок: политика остаётся близко к референсу
0.122.5стандарт (по умолчанию в статье DPO и в TRL)
0.01225длинный поводок: модель может уйти далеко и «сломаться»

Маленький β\beta — сильнее подгонка под пары и выше риск деградации. Большой — осторожные изменения.

Возьмём один промпт и 4 возможных ответа со скрытыми «истинными» наградами. Предпочтения сгенерируем по Брэдли–Терри, обучим DPO и сравним результат с формулой π∗∝πref er/β\pi^* \propto \pi_{\text{ref}}\, e^{r/\beta}. Чтобы не зависеть от случайных сэмплов, используем «бесконечные данные»: все пары с вероятностями предпочтений.

import itertools
import torch
import torch.nn.functional as F
# Один промпт, 4 возможных ответа. Политика — просто логиты над ответами.
answers = ["верно и кратко", "верно, но с водой", "уверенно неверно", "отказ"]
r_true = torch.tensor([2.0, 1.5, -1.0, 0.0]) # скрытая «истинная» награда
ref = torch.log_softmax(torch.tensor([0.0, 1.0, 0.5, -0.5]), 0) # π_ref (после SFT)
beta = 1.0
# Все пары (i, j); вероятность, что человек предпочтёт i, — по Брэдли–Терри
pairs = list(itertools.combinations(range(4), 2))
i_idx = torch.tensor([i for i, _ in pairs])
j_idx = torch.tensor([j for _, j in pairs])
p_human = torch.sigmoid(r_true[i_idx] - r_true[j_idx])
logits = ref.clone().requires_grad_(True) # старт: π = π_ref
opt = torch.optim.Adam([logits], lr=0.05)
for step in range(2001):
logp = torch.log_softmax(logits, 0)
h = beta * ((logp - ref)[i_idx] - (logp - ref)[j_idx]) # разница неявных наград
loss = -(p_human * F.logsigmoid(h) + (1 - p_human) * F.logsigmoid(-h)).mean()
opt.zero_grad()
loss.backward()
opt.step()
if step in (0, 2000):
print(f"шаг {step:4d}: DPO loss = {loss.item():.4f}")
pi_dpo = torch.softmax(logits, 0).detach()
pi_star = torch.softmax(ref + r_true / beta, 0) # теория: π* ∝ π_ref·exp(r/β)
for a, p0, p1, p2 in zip(answers, ref.exp(), pi_dpo, pi_star):
print(f"{a:<18} π_ref={p0:.3f} DPO={p1:.3f} π*={p2:.3f}")
шаг 0: DPO loss = 0.6931
шаг 2000: DPO loss = 0.4241
верно и кратко π_ref=0.167 DPO=0.356 π*=0.356
верно, но с водой π_ref=0.455 DPO=0.586 π*=0.586
уверенно неверно π_ref=0.276 DPO=0.029 π*=0.029
отказ π_ref=0.102 DPO=0.029 π*=0.029

DPO пришёл точно в π∗\pi^*, ни разу не построив reward model. Обратите внимание: «верно, но с водой» в итоге вероятнее, чем «верно и кратко», хотя его награда ниже. Референс любил этот ответ, а KL-поводок сохраняет его вкусы. Чтобы «кратко» победило, нужен меньший β\beta — или другой референс.

RLHF с PPODPO
Модели4, две обучаются2, обучается одна (референс можно заменить готовыми логпробами)
Reward modelотдельная, обучается заранеенеявная, внутри политики
Генерация во время обученияна каждом шаге (on-policy)нет — готовые пары (offline)
Гиперпараметрыlr ×2, β\beta, ε\varepsilon, γ\gamma, λ\lambda, эпохи…в основном β\beta и lr
Стабильностькапризныйкак у SFT
Исследованиемодель учится на своих новых ответахтолько на ответах из датасета
Где сильнеерассуждения, код, задачи с проверяемой наградойстиль, тон, безопасность, «вкус»

У простоты DPO есть цена — четыре известные слабости:

  1. Сдвиг распределения. Пары часто сгенерированы другими моделями. DPO смотрит только на разность двух ответов и может поднять вероятность третьих, которых нет ни в одной паре. Исследование Tsinghua (Xu и др., 2024) показало: аккуратно настроенный PPO обгоняет DPO во всех их тестах, включая соревновательное программирование. Лекарство — онлайн- или итеративный DPO: свежие пары из текущей политики, размеченные reward model.
  2. Обе вероятности падают. Loss зависит только от разности. Если log⁡π(yw)\log \pi(y_w) упал с −10-10 до −15-15, а log⁡π(yl)\log \pi(y_l) — с −12-12 до −17-17, loss не изменился, хотя хороший ответ стал в e5≈150e^5 \approx 150 раз менее вероятен. Такое часто видно в логах: rewards/chosen уходит в минус. Помогает, например, добавка SFT-loss на chosen-ответах.
  3. Переобучение на однозначных парах. Если предпочтение в паре абсолютное, оптимум Брэдли–Терри — бесконечный отрыв. DPO будет раздвигать лог-отношения без конца, и KL-поводок фактически перестаёт работать.
  4. Длина. Chosen-ответы в датасетах обычно длиннее, и DPO выучивает многословие — тот же reward hacking, только офлайн.

Каждый вариант лечит одну из слабостей DPO:

МетодНужен референс?ДанныеИдея
IPO (DeepMind, 2023)дапарыквадратичный loss (h−12β)2(h - \frac{1}{2\beta})^2: цель — конечный отрыв, нет переобучения (слабость № 3)
KTO (2024)даодиночные ответы с меткой «хорошо/плохо»пары не нужны; loss построен по мотивам теории перспектив Канемана–Тверски: выигрыш и проигрыш относительно «точки отсчёта» весят по-разному
SimPO (2024)нетпарынаграда — средняя лог-вероятность на токен β∣y∣log⁡πθ(y∣x)\frac{\beta}{\lvert y \rvert} \log \pi_\theta(y \mid x) и отступ γ\gamma в сигмоиде: экономит память и борется с длиной (№ 4)
ORPO (2024)нетпарыSFT и предпочтения в одном этапе через отношение шансов (odds ratio)

SimPO целиком:

LSimPO=−log⁡σ(β∣yw∣log⁡πθ(yw∣x)−β∣yl∣log⁡πθ(yl∣x)−γ)\mathcal{L}_{\text{SimPO}} = -\log \sigma\Big(\frac{\beta}{\lvert y_w \rvert} \log \pi_\theta(y_w \mid x) - \frac{\beta}{\lvert y_l \rvert} \log \pi_\theta(y_l \mid x) - \gamma\Big)

KTO особенно практичен: кнопки 👍/👎 в чат-интерфейсе дают ровно такие данные. А IPO вы реализуете в задании ниже.

Реализуйте сумму лог-вероятностей ответа с маской, устойчивый DPO loss с неявными наградами (как dpo_loss в TRL), вес пары в градиенте и loss IPO.

DPO и IPO по логпробамnumpy · нужен интернет7 тестов
import numpy as np


def sequence_logprob(token_logprobs, mask):
    """log π(y|x) для каждой строки батча.

    token_logprobs — массив [B, T]: лог-вероятности токенов последовательности «промпт + ответ»;
    mask — массив [B, T] из 0/1: 1 только у токенов ОТВЕТА (промпт и паддинг не считаем).
    Вернуть массив [B] — сумму лог-вероятностей токенов ответа.
    """
    # TODO: ваш код
    ...


def dpo_loss(pi_chosen, pi_rejected, ref_chosen, ref_rejected, beta=0.1):
    """DPO loss по логпробам целых ответов (массивы [B] или числа).

    Неявные награды: r_c = beta * (pi_chosen - ref_chosen),
                     r_r = beta * (pi_rejected - ref_rejected).
    loss = mean( -log sigmoid(r_c - r_r) )  — считать УСТОЙЧИВО (np.logaddexp).

    Вернуть кортеж (loss: float, r_c: массив, r_r: массив) — по образцу dpo_loss в TRL
    (только TRL возвращает loss каждого примера, а мы — сразу среднее).
    """
    # TODO: ваш код
    ...


def dpo_weight(pi_chosen, pi_rejected, ref_chosen, ref_rejected, beta=0.1):
    """Вес каждого примера в градиенте DPO: sigmoid(r_r - r_c).

    Близок к 1, когда неявная награда «ошибается» (r_r > r_c), и к 0, когда пара уже выучена.
    """
    # TODO: ваш код
    ...


def ipo_loss(pi_chosen, pi_rejected, ref_chosen, ref_rejected, beta=0.1):
    """IPO (Azar и др., 2023): mean( (h - 1/(2*beta))**2 ),
    где h = (pi_chosen - ref_chosen) - (pi_rejected - ref_rejected) — БЕЗ умножения на beta.
    """
    # TODO: ваш код
    ...


# Проверьте себя кнопкой «Запустить»:
lp = np.array([[-0.5, -1.0, -2.0, -0.1]])
print(sequence_logprob(lp, [[0, 0, 1, 1]]))                 # ≈ [-2.1]
print(dpo_loss(-10.0, -12.0, -11.0, -11.0, beta=0.1))      # loss ≈ 0.598, награды 0.1 и -0.1
print(dpo_weight([-10.0, -12.0], [-12.0, -10.0], [-11.0, -11.0], [-11.0, -11.0], beta=0.1))

Полный цикл DPO на PyTorch: модель предсказывает следующий токен, у каждой пары общий промпт из 4 токенов и ответ из 8. Chosen-ответы состоят из «хороших» токенов 0–9, rejected — из «плохих» 40–49. Код почти без изменений переносится на настоящую модель из transformers: меняется только model(ids) на model(ids).logits.

import copy
import torch
import torch.nn as nn
import torch.nn.functional as F
torch.manual_seed(0)
V, d, B, P, T = 50, 16, 8, 4, 12 # словарь, ширина, батч, длина промпта, полная длина
policy = nn.Sequential(nn.Embedding(V, d), nn.Linear(d, V)) # «LLM»: логиты следующего токена
ref = copy.deepcopy(policy).requires_grad_(False) # замороженная копия = π_ref
def seq_logp(model, ids, mask):
"""log π(y|x): сумма log-вероятностей токенов ОТВЕТА (сдвиг на 1, как в SFT)."""
logits = model(ids[:, :-1]) # предсказания для позиций 1..T-1
# для каждой позиции берём log-вероятность того токена, который там действительно стоит
logp = torch.log_softmax(logits, -1).gather(-1, ids[:, 1:, None]).squeeze(-1)
return (logp * mask[:, 1:]).sum(-1)
def dpo_loss(chosen, rejected, mask, beta=0.1):
pi_c, pi_r = seq_logp(policy, chosen, mask), seq_logp(policy, rejected, mask)
with torch.no_grad(): # референс не обучается
ref_c, ref_r = seq_logp(ref, chosen, mask), seq_logp(ref, rejected, mask)
r_c, r_r = beta * (pi_c - ref_c), beta * (pi_r - ref_r) # неявные награды
loss = -F.logsigmoid(r_c - r_r).mean()
return loss, r_c.detach(), r_r.detach(), pi_c.detach(), pi_r.detach()
prompt = torch.randint(0, V, (B, P))
chosen = torch.cat([prompt, torch.randint(0, 10, (B, T - P))], 1) # «хорошие» токены 0..9
rejected = torch.cat([prompt, torch.randint(40, 50, (B, T - P))], 1) # «плохие» токены 40..49
mask = torch.cat([torch.zeros(B, P), torch.ones(B, T - P)], 1) # loss только по ответу
opt = torch.optim.Adam(policy.parameters(), lr=1e-2)
for step in range(101):
loss, r_c, r_r, pi_c, pi_r = dpo_loss(chosen, rejected, mask)
if step % 50 == 0:
acc = (r_c > r_r).float().mean()
print(f"шаг {step:3d}: loss {loss.item():.3f} | награды chosen {r_c.mean():+.2f}, "
f"rejected {r_r.mean():+.2f} | точность {acc:.2f} | log π: {pi_c.mean():.1f} / {pi_r.mean():.1f}")
opt.zero_grad()
loss.backward()
opt.step()
шаг 0: loss 0.693 | награды chosen +0.00, rejected +0.00 | точность 0.00 | log π: -33.7 / -32.8
шаг 50: loss 0.005 | награды chosen +1.32, rejected -3.94 | точность 1.00 | log π: -20.5 / -72.3
шаг 100: loss 0.001 | награды chosen +1.37, rejected -5.15 | точность 1.00 | log π: -19.9 / -84.3

Старт — ровно ln⁡2\ln 2, точность 0, потому что награды равны (строгое «больше» не выполняется). Дальше заметна асимметрия: rejected «утопили» гораздо сильнее (награда −5.15-5.15), чем подняли chosen (+1.37+1.37). DPO охотнее выигрывает отрыв за счёт плохих ответов. На настоящих данных, где chosen и rejected похожи, это и превращается в слабость № 2.

Проверь себя6 вопросов
1 Каким будет DPO loss на самом первом шаге, если политика инициализирована референсной моделью? Округлите до двух знаков.
2 log⁡πθ(yw)=−20\log \pi_\theta(y_w) = -20, log⁡πref(yw)=−21\log \pi_{\text{ref}}(y_w) = -21, log⁡πθ(yl)=−30\log \pi_\theta(y_l) = -30, log⁡πref(yl)=−29\log \pi_{\text{ref}}(y_l) = -29, β=0.5\beta = 0.5. Чему равен DPO loss? Округлите до двух знаков.
3 Почему в DPO не нужно считать статсумму Z(x)Z(x)?
4 Какие утверждения о DPO верны?Можно выбрать несколько ответов
5 В логах DPO loss падает, rewards/margins растут, но и rewards/chosen, и rewards/rejected уходят в минус. Что это значит?
6 Какой метод не требует референсной модели и использует среднюю лог-вероятность на токен с отступом γ\gamma? (одно слово)
  • Оптимальная политика RLHF π∗∝πrefer/β\pi^* \propto \pi_{\text{ref}} e^{r/\beta} позволяет выразить награду через политику: r^=βlog⁡(πθ/πref)\hat r = \beta \log(\pi_\theta / \pi_{\text{ref}}). Статсумма Z(x)Z(x) сокращается в модели Брэдли–Терри.
  • DPO — это loss reward model, где награда спрятана в самой политике. Две модели, нет генерации, обучение как SFT. Старт — ln⁡2\ln 2.
  • β\beta — длина KL-поводка. Вес пары в градиенте σ(r^l−r^w)\sigma(\hat r_l - \hat r_w) фокусирует обучение на ошибках.
  • Слабости DPO — офлайн-данные, падение вероятности chosen, переобучение, длина. Их лечат онлайн-DPO, IPO, KTO, SimPO. Для рассуждений индустрия перешла к онлайн-RL — GRPO.

Дальше: модуль 6.4 — GRPO из DeepSeekMath и путь DeepSeek-R1: RL без критика, с проверяемыми наградами и группой ответов вместо value-модели.