Перейти к содержанию
С нуля
Программа курса
EN Открыть

Программа курса

Неделя 17. RLHF, GRPO, DPO

Фаза 4. Post-training · неделя 17 из 24

Учиться в приложении: тьютор, задачи с кодом →

Ядро: reward model и Брэдли–Терри, RLHF целиком, GRPO против PPO, DPO из цели RLHF · Глубина: Dr. GRPO, функции награды RLVR, Кондорсе и Эрроу, практика на настоящей модели · ≈ 14 ч ядро / 26 ч всё

Неделя 16 дала механику RL. Эта неделя о том, откуда берётся награда и как её не взломать. Reward model, GRPO и DPO дают три ответа на один вопрос: как превратить предпочтения или проверяемый ответ в градиент. Без этого не понять, как делают reasoning-модели и почему «PPO против GRPO» на самом деле вопрос про baseline, а не про новую конструкцию.

На пальцах. Reward model поставила ответу A оценку 2, а ответу B оценку 1. По Брэдли–Терри вероятность, что человек предпочтёт A, равна σ(2 − 1) = σ(1) ≈ 0.73. Человек предпочёл A. Лосс −log 0.73 ≈ 0.31. Это ровно бинарная кросс-энтропия, в которой роль «логита» играет разность наград. Метка всегда 1, потому что пару записывают так, что первым идёт выбранный ответ.

  • Reward model (модель, которая выдаёт ответу число-оценку), модель Брэдли–Терри (вероятность предпочтения σ(r_A − r_B)). Заметить, что её лосс на самом деле обычная бинарная кросс-энтропия с меткой, всегда равной 1
  • Полный конвейер RLHF: SFT → RM → PPO. KL-штраф к референсной модели (замороженной копии SFT-модели), на практике сворачивается в потокенную награду
  • Reward hacking (политика получает высокую награду, не делая того, что имелось в виду: например, пишет длинно, потому что RM любит длину)

Откуда сама формула. Брэдли–Терри (1952) вырастает из моделей случайной полезности. У Thurstone (1927) человек сравнивает не r_A и r_B, а зашумлённые r_A + ε_A и r_B + ε_B и выбирает большее. Нормальный шум даёт пробит Φ((r_A − r_B)/(σ√2)). Шум Гумбеля (распределение максимума) даёт логистическую разность шумов и ровно σ(r_A − r_B); к тому же ведёт аксиома выбора Льюса (1959), а для выбора из многих ответов получается softmax. Следствие: награда задана с точностью до сдвига, r + c даёт те же вероятности. Смысл имеют только разности оценок RM.

Когда предпочтения не укладываются в одно число. Одно число на ответ возможно, только если предпочтения полны (любые два ответа сравнимы) и транзитивны (из A ≻ B и B ≻ C следует A ≻ C). На пальцах. Три ответа. Разметчики выбирают A вместо B в 70% случаев, B вместо C в 70%, C вместо A тоже в 70%: цикл A ≻ B ≻ C ≻ A. Так бывает, когда люди сравнивают по разным признакам: один по краткости, другой по точности. Каждая пара просит разность ln(0.7/0.3) ≈ 0.85, но три разности по кругу в сумме обязаны дать 0, а не 2.54. Лучшее, что доступно числам: r_A = r_B = r_C, предсказание 0.5 в каждой паре, лосс ln 2 ≈ 0.693 на пару. Нижняя граница для любой модели равна энтропии разметки −(0.7·ln 0.7 + 0.3·ln 0.3) ≈ 0.611. Разрыв 0.082 нат на пару не закрыть никакой архитектурой RM: он заложен в постановку «одно число на ответ». Почему минимум при равных наградах: лосс пары выпуклый по разности, среднее трёх разностей 0, по неравенству Йенсена сумма лоссов не меньше трёх значений в нуле. «Лучшего» ответа при цикле нет вовсе: против смеси (⅓, ⅓, ⅓) каждый ответ выигрывает ровно в половине сравнений.

Цикл Кондорсе и теорема Эрроу. У такого цикла есть имя: цикл (парадокс) Кондорсе. Он возникает, даже когда каждый разметчик по отдельности рассуждает последовательно. Три разметчика: первый ставит A ≻ B ≻ C, второй B ≻ C ≻ A, третий C ≻ A ≻ B. В каждой паре счёт 2:1, и мнение большинства ходит по кругу A ≻ B ≻ C ≻ A. Теорема Эрроу (1951) говорит, что дело не в неудачном правиле голосования: при трёх и более вариантах нет способа свести порядки многих людей к одному общему порядку, который одновременно (1) работает при любых вкусах, (2) ставит A выше B, если так считают все, (3) решает спор A и B только по тому, как люди сравнили именно A и B, и (4) не сводится к вкусу одного человека («диктатора»). Вывод для RLHF: reward model учится на сравнениях многих разметчиков и обязана выдать одну шкалу, поэтому несовместимые вкусы она усредняет. Политика затем оптимизирует вкус «среднего разметчика», которого может не быть среди живых людей, а меньшинство с другим вкусом растворяется в среднем. Подробнее: MIT OCW 6.254, лекция 21 об общественном выборе (ссылка есть и в «Ресурсах»).

Reward hacking глазами экономиста. Экономисты назвали бы это задачей принципала и агента. Принципал (разработчик) хочет качества, но видит только прокси (заменитель цели), оценку RM. Агент (политика) получает плату за прокси, и когда стимулы расходятся, возникает моральный риск: агент делает то, за что платят, а не то, что нужно. Закон Гудхарта (1975) о том же: показатель, ставший целью, перестаёт хорошо измерять. Средства теории контрактов (Хольмстрём, 1979) узнаются сразу: не давать агенту далеко уйти от проверенного поведения (KL-штраф к референсу), платить за проверяемый результат (RLVR), брать несколько независимых сигналов вместо одного, вручную проверять выборку ответов. Это аналогия для интуиции, а не теория того, как устроен RLHF.

На пальцах. На один промпт сэмплируем 4 ответа, проверщик ставит награды (1, 0, 0, 1). Baseline равен среднему по группе, 0.5; advantages (+0.5, −0.5, −0.5, +0.5), после деления на std 0.5 получаем ±1. Value-модель не нужна: среднее измерено, а не предсказано. Две поломки видны на тех же числах. Группа (1, 1, 1, 0) почти целиком решена, но её std 0.43, и неверный ответ получает −1.73: по модулю больше, чем любой ответ информативной группы. Если advantage делится на длину ответа, неверный ответ из 16 токенов получает на токен −1/16, а из 2 токенов −1/2: длинная ошибка наказана в 8 раз слабее.

  • GRPO (Group Relative Policy Optimization) = три известные идеи вместе: off-policy суррогат (шаг 3) + клиппинг PPO (шаг 4)
    • групповая нормализация advantage. После недели 16 это не новая конструкция. Value head не нужна: baseline не выучивается, а измеряется сэмплированием. Больше вычислений (G генераций на промпт), меньше памяти
  • Dr. GRPO: две конкретные поломки GRPO. Деление на std(r) раздувает градиент на вырожденно лёгких и трудных группах. Нормировка по длине ответа приводит к тому, что среди неверных ответов длинные штрафуются слабее. Модель выучивает, что если не знаешь ответа, надо писать длинно
  • Вырожденные группы и задачи на границе возможностей. На пальцах. Модель решает задачу с вероятностью p, в группе G = 4 ответа. Если все 4 верны или все неверны, advantages нулевые и градиента нет. При p = 0.5 так выходит в 12.5% групп, при p = 0.9 уже в 66%, при p = 0.97 в 89%. Формула: доля пустых групп p^G + (1 − p)^G, дисперсия награды p(1 − p) максимальна при p = 0.5. Модель учится, и фиксированный набор задач становится лёгким: сигнал тает. Поэтому задачи подбирают так, чтобы p держалось в середине: отбрасывают вырожденные группы и досэмплируют новые, либо генерируют задачи программой с настраиваемой сложностью и двигают сложность вслед за моделью (Faro et al., Frontier Learning, 2026). Больший G тоже помогает: при p = 0.9 и G = 16 пустых групп 19%

На пальцах. Одна пара: выбранный ответ y_w и отвергнутый y_l, β = 0.1. На старте π_θ = π_ref, разность лог-отношений 0, лосс −log σ(0) = log 2 ≈ 0.693. Это контрольное значение, оно понадобится ниже. После обучения log π_θ(y_w) вырос относительно референса на 2, а log π_θ(y_l) упал на 3. Отступ β·(2 − (−3)) = 0.5, лосс −log σ(0.5) ≈ 0.474. Тот же лосс выйдет, если оба ответа упадут: выбранный на 1, отвергнутый на 6. DPO смотрит только на разность. Поэтому при DPO вероятность выбранного ответа может и снижаться.

  • DPO: вывести из цели RLHF. У KL-регуляризованной задачи есть замкнутое решение; выразить награду через отношение политик и подставить в Брэдли–Терри → лосс без reward-модели и без RL вообще
  • Сравнение PPO / GRPO / DPO / RLAIF (предпочтения размечает модель, а не человек): когда что
RLHF против DPO и честное разбиение данныхRLHF против DPO и честное разбиение данных
Схема 23. RLHF: три этапа и четыре модели в памяти. DPO: одна функция потерь на парах, без reward-модели и RL. Внизу правило недели 18: выбирать на одном наборе, отчитываться на другом.
  • RLVR (RL с проверяемой наградой: ответ сверяет программа), reasoning-модели, test-time compute (больше вычислений при ответе: длинное рассуждение, несколько попыток; подробно в неделе 18, подраздел «Test-time compute»)

Функции награды для RLVR

RLVR (обучение с проверяемой наградой) ставит вместо reward model программу-проверщик: она сверяет ответ с эталоном. Длиной и уверенным тоном программу не подкупить, но её пишет человек, и каждую дыру в ней политика найдёт: reward hacking никуда не делся, он переехал в код проверщика.

На пальцах. Задача в духе GSM8K (школьные текстовые задачи на арифметику): «3 коробки по 4 яблока, 2 яблока съели. Сколько осталось?», эталон 10. Модель учат писать рассуждение, а итог ставить после маркера ####. Награда складывается из двух частей: 1 за верное число после маркера и 0.1 за формат (маркер ровно один, за ним число).

ОтветПравильностьФорматНаграда
3·4 = 12, 12 − 2 = 10. #### 1010.11.1
3·4 = 12, 12 + 2 = 14. #### 1400.10.1
Осталось 10.000
#### 700.10.1

Третий ответ верен по сути, но проверщик числа не видит. Частичная награда, например 0.5 за верное число где угодно в тексте, дала бы ему 0.5. Но тогда ответ «1 2 3 … 100» получает 0.5 на любой задаче: перечислить все числа дешевле, чем решить.

  • Почему награда только за формат ведёт к взлому. Если платить только за #### число, ответ #### 7 без всякого рассуждения получает максимум. Политика быстро выучит формат, и все ответы группы получат одинаковые 0.1: сигнал исчезнет, а правильность не сдвинется. Бонус за формат полезен как подсказка на старте и только когда он мал по сравнению с правильностью (0.1 против 1): тогда верный ответ всегда выгоднее красивого
  • Пустые группы. Если все G ответов получили одинаковую награду (все 1.1 или все 0), group_advantages из nanolm/rl.py вычитает среднее и получает нули, деление на std + eps нули не меняет. Градиент от такой группы ровно нулевой, хотя на её генерацию ушли вычисления. Долю пустых групп (выше: p^G + (1 − p)^G) стоит писать в лог на каждом шаге. Бонус за формат и частичная награда разбивают ничьи: группа (0, 0.1, 0, 0) уже даёт градиент, но он учит формату, а не решению
  • Частичная награда нужна, когда полная почти всегда 0 (трудные задачи, маленькая модель): иначе почти все группы пустые. Каждую такую лазейку проверяют на взлом: читают глазами 20 ответов с наибольшей наградой
  • Практический ориентир. Модели меньше примерно 1.5B параметров редко начинают рассуждать от RLVR: базовая модель почти никогда не решает задачу, награда почти всегда 0, группы пустые, учить нечему. Средняя награда растёт не сразу: первые десятки или сотни шагов кривая почти плоская, сначала модель осваивает формат, потом поднимается правильность. Остановить запуск из-за плоского начала кривой частая ошибка

Один шаг GRPO целиком

Формулы GRPO выше записаны через лог-вероятности ответов. Здесь о том, как их посчитать и в каком порядке идут части одного шага: на этом стыке чаще всего ломается код, который выглядит рабочим.

На пальцах. Промпт «2 + 2 =», ответ из трёх токенов. Модель дала фактическим токенам ответа вероятности 0.5, 0.25 и 0.8. Вероятность ответа по цепному правилу (вероятность последовательности равна произведению условных вероятностей её токенов) равна 0.5 · 0.25 · 0.8 = 0.1, а её логарифм равен сумме ln 0.5 + ln 0.25 + ln 0.8 = −0.69 − 1.39 − 0.22 = −2.30 = ln 0.1. Среднее −0.77 даёт e^{−0.77} ≈ 0.46: это среднее геометрическое вероятностей токенов, а не вероятность ответа. Токены промпта в сумму не входят, их писала не модель. Паддинг (служебные токены, которыми короткие ответы добивают до общей длины T) тоже не входит. Сдвиг на один: выход модели на позиции t предсказывает токен t + 1, поэтому вероятность 0.5 первого токена ответа берут из выхода на последнем токене промпта.

  • Сумма или среднее. Отношение вероятностей целого ответа равно exp(Σ log π_θ − Σ log π_old) по токенам ответа, и здесь нужна сумма. Среднее вместо суммы означает деление на длину ответа, то есть ту самую нормировку 1/|o| из GRPO, которую Dr. GRPO считает перекосом (выше: длинная ошибка наказана слабее). В nanolm/rl.py этот выбор сделан явно: grpo_loss усредняет внутри каждого ответа (sequence_masked_mean), dr_grpo_loss делит на общее число токенов (masked_mean). Его делают сознательно, а не потому, что .mean() короче. Посчитать лог-вероятность ответа со сдвигом и маской можно в задаче тренажёра sequence_logprob
  • Упрощённый GRPO без KL (β = 0). Многие рецепты RLVR (Dr. GRPO, DAPO) убирают KL-штраф к референсной модели. Проверщик не подкупить гладким текстом так, как reward model, поэтому главный повод держаться у референса слабее. Референс требует ещё одну копию весов в памяти и ещё один проход на каждом шаге. KL к тому же тянет назад длинные рассуждения, ради которых всё и делается. KL возвращают, когда награду ставит обученная reward model (её взламывают), когда портится язык (ответы смешивают языки, зацикливаются) и когда много эпох идут на маленьком наборе задач. Без KL от ухода защищает только клиппинг, и только в пределах одного батча (неделя 16)

Порядок одного шага на B промптах, с функциями из nanolm/rl.py:

  1. Сэмплировать G ответов на каждый промпт текущей политикой с температурой больше 0: при жадной генерации все G ответов совпадут, и группа пустая заранее. Модель в режиме eval(), без градиента.
  2. Поставить награды проверщиком (задача тренажёра rlvr_reward) и записать в лог долю пустых групп.
  3. Преимущества по группам: group_advantages, награды формы (B, G).
  4. Старые лог-вероятности old_logprobs: проход той же модели под torch.no_grad() и в eval(). При β > 0 так же считают ref_logprobs замороженной референсной моделью.
  5. Новые лог-вероятности с градиентом: sequence_logprobs (потокенно, форма (B·G, T)) и маска ответа.
  6. Потери: grpo_loss или dr_grpo_loss; при β > 0 к ним прибавляют β · kl_penalty_k3(logprobs, ref_logprobs, mask).
  7. backward, обрезка нормы градиента, шаг оптимизатора. Если на одних роллаутах делают несколько шагов, old_logprobs не пересчитывают: они и задают π_old.

При одном шаге на батч отношение π_θ/π_old тождественно равно 1, клиппинг не срабатывает ни разу, и GRPO сводится к REINFORCE с групповым baseline (это проверяет test_surrogate_reduces_to_reinforce_at_theta_old из недели 16). π_old и клиппинг нужны, только когда на одних роллаутах делают несколько шагов.

Где ломается шаг

  • Ошибка режима модели. Генерацию и old_logprobs считают в режиме train(). Dropout (случайное обнуление части активаций при обучении) на каждом проходе гасит разные нейроны, и два прохода с одинаковыми весами дают разные лог-вероятности. На первом шаге отношение π_θ/π_old обязано быть ровно 1, а выходит 0.9 на одном токене и 1.15 на другом: клиппинг режет градиент там, где политика ещё никуда не сдвинулась. model.eval() выключает dropout, но граф вычислений строит; torch.no_grad() граф не строит, но dropout не трогает. Это два разных переключателя, и нужны оба. В RL-дообучении dropout обычно выключают и в проходе с градиентом (у современных LLM его и так почти нет, неделя 8). Проверка в одну строку: на первом шаге max |ratio − 1| порядка ошибки округления. Тот же симптом даёт генерация отдельным движком инференса в другой точности: тогда old_logprobs пересчитывают обучаемой моделью, а не берут у генератора
  • old_logprobs с градиентом. Старые лог-вероятности посчитаны без no_grad и без .detach() теми же весами. Тогда отношение exp(log π_θ − log π_old) зависит от θ и через числитель, и через знаменатель, и его производная равна нулю: лосс считается, а градиент ровно ноль. Памяти на граф уходит вдвое больше
  • Маска и сдвиг. Лог-вероятности промпта и паддинга попали в сумму, или маску не сдвинули вместе с целевыми токенами и потеряли первый токен ответа. Ловится сравнением с подсчётом в цикле на маленьком примере

Практика на настоящей модели (по желанию). Ноутбук GRPO от Unsloth (ссылка в «Ресурсах», раздел Post-training) запускается в бесплатном Colab на T4: LoRA (неделя 15) поверх модели от 1.5B параметров, задачи в духе GSM8K. Что измерить: награду за правильность и за формат по отдельности на каждом шаге; долю пустых групп; среднюю длину ответа; 20 ответов с наибольшей наградой (нет ли взлома). Сравни два запуска: с наградой только за формат и с полной. В первом формат быстро доходит до 100%, а точность на отложенных задачах стоит на месте. Функцию награды и долю пустых групп можно написать самому в задаче тренажёра rlvr_reward.

Второй путь: GRPO с нуля на MATH (по желанию). Книга Себастьяна Рашки Build a Reasoning Model (From Scratch) (глава 6, код в репозитории reasoning-from-scratch) и выпуск 6 его видеосерии к книге собирают RLVR и GRPO на PyTorch без библиотек RL, на задачах MATH (задачи олимпиадного уровня с ответом, который сверяет программа). Ссылки в «Ресурсах», раздел Post-training. Шаг GRPO там удобно сверять с подразделом «Один шаг GRPO целиком». Что измерить: точность на MATH-500 (500 задач из тестовой части MATH, принятый срез для быстрых замеров) до обучения и через каждые несколько десятков шагов; среднюю длину ответа отдельно для верных и неверных (рост длины неверных ответов выдаёт перекос нормировки длины); долю пустых групп; пиковую память GPU при разных G и разной максимальной длине ответа. Память растёт примерно пропорционально B · G · T (активации прохода с градиентом), а при β > 0 к ней добавляется референсная модель.

Код → nanolm/rl.py: group_advantages, grpo_loss, dr_grpo_loss, kl_penalty_k3, dpo_loss, bradley_terry_loss.

Контроль DPO: при π_θ = π_ref лосс обязан быть ровно log 2 ≈ 0.6931. Получилось другое? Дальше идти бессмысленно, ищи ошибку.

scripts/rl_demo.py показывает оба перекоса GRPO в числах: вырожденная группа получает advantage больше информативной, а ответ длиной 16 получает градиент на токен в 8 раз меньше, чем ответ длиной 2.

Математика (трек D): D25: замкнутое решение KL-регуляризованной задачи; D26: Брэдли–Терри и лосс DPO.

Интервью-вопрос недели: «В чём разница между PPO и GRPO?» Такой вопрос задают дословно. Ответ на 3 минуты, с формулами. После недели 16 он должен звучать как «обе строятся на одном суррогате, различаются только baseline'ом».

Источники: Ouyang et al., InstructGPT (2022); Rafailov et al., DPO (2023); Shao et al., DeepSeekMath (2024), где введён GRPO; Liu et al., Understanding R1-Zero-Like Training, Dr. GRPO (2025); Faro et al., Frontier Learning (2026), задачи на границе возможностей; Cobbe et al., GSM8K (2021); Hendrycks et al., MATH (2021); Lightman et al., Let's Verify Step by Step (2023), срез MATH-500; Yu et al., DAPO (2025); Raschka, Build a Reasoning Model (From Scratch), глава 6 (практика, ссылки в «Ресурсах»).

Глубже: 05-ГЛУБИНА, разделы «★★ Недели 16–17. Недостающее звено между REINFORCE и PPO» и «Недели 17 и 21. Немного теории игр».

Результаты недели

  • Могу вывести лосс DPO из KL-регуляризованной цели RLHF.
  • Могу ответить на «PPO против GRPO» за 3 минуты с формулами.
  • Могу объяснить две поломки GRPO, которые чинит Dr. GRPO, с числами из rl_demo.py.
  • Могу реализовать dpo_loss и проверить значение log 2 при π_θ = π_ref.
  • Могу на примере трёх разметчиков объяснить цикл Кондорсе и теорему Эрроу и что из них следует для одной reward model.
  • Могу расписать один шаг GRPO от сэмплирования до шага оптимизатора и сказать, где нужны eval(), no_grad и маска ответа.

Самопроверка

  1. Почему лосс Брэдли–Терри оказывается бинарной кросс-энтропией с меткой 1?
  2. Что такое reward hacking? Пример и способ защиты.
  3. Когда выбрать DPO, а когда GRPO?
  4. Разметка даёт цикл A ≻ B ≻ C ≻ A по 70%. Каков лучший лосс Брэдли–Терри и почему его не опустить до энтропии разметки?
  5. Почему GRPO перестаёт учиться на наборе задач, который модель почти решила? Посчитай долю пустых групп при p = 0.9, G = 8.
  6. Почему награда только за формат ведёт к reward hacking, а бонус 0.1 за формат вместе с наградой 1 за правильность полезен?
  7. Все 8 ответов группы получили награду 0. Что вернёт group_advantages и какой градиент даст группа? Что изменится, если двое из восьми получат бонус за формат?
  8. Почему RLVR на модели меньше примерно 1.5B параметров часто не учит рассуждать, хотя код верен? Какой показатель в логе это покажет?
  9. Три разметчика с последовательными вкусами по большинству голосов дают цикл A ≻ B ≻ C ≻ A. Как называется это явление, что утверждает теорема Эрроу и что это значит для одной reward model?
  10. Ответ из четырёх токенов получил вероятности 0.5, 0.5, 0.8 и 0.5. Чему равна его лог-вероятность, какие позиции исключает маска и как выход модели сдвинут относительно токенов? Что изменится в GRPO, если взять среднее вместо суммы?
  11. На первом шаге GRPO отношение π_θ/π_old на части токенов равно 0.9 и 1.15, хотя веса ещё не обновлялись. Какая ошибка режима это даёт и какой проверкой её поймать? Что станет с градиентом, если old_logprobs посчитать без no_grad?

В приложении у недели есть навыки для самооценки, вопросы с проверкой ответа, задачи с кодом на Python и тьютор по материалам курса.

Учиться в приложении: тьютор, задачи с кодом
← НазадНеделя 16. RL: от REINFORCE до PPO Дальше →Неделя 18. Оценка

С нуля
С нуля: курс по LLM

  • Главная
  • Программа курса
  • Приложение
  • Конфиденциальность
  • Условия

Текст курса распространяется по лицензии CC BY-NC-SA 4.0, код nanolm по лицензии Apache-2.0.