RLHF — reward model и PPO
Как превратить человеческие «этот ответ лучше» в награду: сбор предпочтений, модель Брэдли–Терри, reward model, PPO для языковой модели, почему это дорого и как модель «взламывает» награду.
Зачем это нужно
Заголовок раздела «Зачем это нужно»В прошлом уроке награда бралась «из воздуха»: правильный ответ на «7·8» легко проверить. Но как проверить, что письмо вежливое, объяснение понятное, а шутка смешная? Формулы нет. Есть люди, которые могут сравнить два ответа и сказать, какой лучше.
RLHFобучение с подкреплением на основе отзывов людей (RLHF)EN reinforcement learning from human feedback (RLHF) (reinforcement learning from human feedback — обучение с подкреплением на отзывах людей) превращает такие сравнения в награду. Сначала на них учат отдельную нейросеть — reward modelмодель вознагражденияEN reward model (RM, модель вознаграждения), а потом RL-алгоритмом PPO оптимизируют модель против этой RM. Так OpenAI сделала InstructGPT (2022), предшественника ChatGPT. Напомним главный результат статьи из урока 6.1.1: ответы InstructGPT на 1.3 млрд параметров люди предпочли ответам GPT-3 на 175 млрд — модели более чем в 100 раз больше. Выравнивание (alignmentвыравнивание (alignment)EN alignment) дало больше, чем стократный рост размера.
Этот урок — про три части RLHF: данные предпочтений, reward model и PPO. И про то, почему всё это дорого и хрупко.
flowchart LR S["SFT-модель"] -->|"K ответов на промпт"| H["Люди ранжируют ответы"] H --> D["Пары: chosen ≻ rejected"] D --> RM["Reward model: r(x, y) ∈ ℝ"] S --> PPO["PPO: политика + критик + референс + RM"] RM --> PPO PPO --> A["Выровненная модель"]
Шаг 1. Сбор предпочтений
Заголовок раздела «Шаг 1. Сбор предпочтений»Почему сравнения, а не оценки по шкале 1–10? Люди плохо держат абсолютную шкалу: у одного «7» — это хорошо, у другого — средне, и сегодня не так, как вчера. А «A лучше B» люди говорят гораздо согласованнее.
Как это устроено в InstructGPT:
- Промпты — запросы пользователей API и задания, написанные разметчиками.
- SFT-модель генерирует на промпт от до ответов.
- Около 40 нанятых разметчиков ранжируют их от лучшего к худшему.
- Ранжирование из ответов даёт пар: для это 36 сравнений за один просмотр.
Результат — данные предпочтенийданные предпочтенийEN preference dataТройки (промпт, лучший ответ, худший ответ) — chosen / rejected.: тройки «промпт, лучший ответ (chosen, ), худший (rejected, )». Именно в таком формате лежат открытые датасеты: Anthropic HH-RLHF, PKU-SafeRLHF и десятки других.
Разметка дорогая и медленная, поэтому всё чаще сравнения делает сильная LLM по написанным людьми принципам — RLAIF (RL from AI feedback). Формат данных и вся математика ниже от этого не меняются.
Шаг 2. Модель Брэдли–Терри
Заголовок раздела «Шаг 2. Модель Брэдли–Терри»Нужно связать «скрытое качество» ответа — число — с вероятностью, что человек выберет этот ответ. Модель Брэдли–Терримодель Брэдли–ТерриEN Bradley–Terry modelP(A ≻ B) = σ(r_A − r_B). Та же модель стоит за рейтингом Эло и лидербордом Chatbot Arena. (1952) предлагает самое простое:
где — сигмоидасигмоида (логистическая функция)EN sigmoid (logistic function)σ(z) = 1 / (1 + e^(−z)) — превращает любое число в вероятность от 0 до 1., а знак читается «лучше, чем». Второе равенство получается делением числителя и знаменателя на : . Важна только разница наград:
| Разница | 0 | 1 | 2 | 3 |
|---|---|---|---|---|
| 0.50 | 0.73 | 0.88 | 0.95 |
Это та же модель, что стоит за рейтингом Эло в шахматах и за лидербордом Chatbot Arena, где модели сравнивают вслепую парами. По сути — логистическая регрессиялогистическая регрессияEN logistic regressionНесмотря на название, это метод классификации. У Чжоу Чжихуа («арбузная книга») — «регрессия логарифма шансов», у Ли Хана («Методы статистического обучения») — фонетическая запись английского слова logistic. из урока 2.2.2: бинарная классификация «лучше ли A, чем B» с логитом .
Максимизируем правдоподобие наблюдённых предпочтений — получаем loss reward model:
Три полезных факта:
- Проверка здравого смысла. В начале обучения награды почти равны, , и loss . Видите на первом шаге 5.0 — ищите баг.
- Градиент по разнице равен : большой, когда RM ошибается, и почти нулевой на выученных парах.
- Сдвиг не важен. Прибавьте ко всем наградам 100 — loss не изменится. Награда определена с точностью до константы, поэтому её нормируют перед RL.
Шаг 3. Reward model
Заголовок раздела «Шаг 3. Reward model»Архитектура RM — та же LLM (обычно инициализированная SFT-моделью), только вместо LM-головы на выходов стоит линейный слой на один выход. Промпт и ответ пропускают через трансформер и берут скаляр на последнем токене:
import torchimport torch.nn as nn
class RewardModel(nn.Module): def __init__(self, backbone, d_model): super().__init__() self.backbone = backbone # трансформер без LM-головы self.v_head = nn.Linear(d_model, 1) # d_model → одно число
def forward(self, input_ids, last_idx): h = self.backbone(input_ids) # [B, T, d_model] h_last = h[torch.arange(len(h)), last_idx] # скрытое состояние последнего токена ответа return self.v_head(h_last).squeeze(-1) # [B] — наградыВ InstructGPT reward model была на 6 млрд параметров — в 30 раз меньше политики на 175B: большие RM учились нестабильно и стоили слишком дорого. Все пар одного промпта клали в один элемент батча: каждый ответ проходит через сеть один раз, и RM меньше переобучается на повторяющихся ответах.
Шаг 4. PPO для языковой модели
Заголовок раздела «Шаг 4. PPO для языковой модели»Теперь у нас есть награда. Можно взять REINFORCE из прошлого урока, но у него две беды:
- Один шаг на одну генерацию. Генерация — самая дорогая часть, а градиент по устаревшим ответам неверен.
- Слишком большой шаг может за одно обновление испортить политику, и она начнёт генерировать мусор, на котором уже ничему не научится.
PPOпроксимальная оптимизация политики (PPO)EN proximal policy optimization (PPO)Schulman и др., 2017. Ограничивает шаг обновления «клиппингом» отношения вероятностей. (Schulman и др., 2017) решает обе проблемы. Сам алгоритм вы разобрали в уроке 6.0.3: отношение вероятностей, клиппинг, критик, GAE, энтропия и несколько эпох на одном батче. Здесь — только то, что меняется, когда политика — LLM.
Отношение вероятностей и клиппинг по токенам
Заголовок раздела «Отношение вероятностей и клиппинг по токенам»Ответы сгенерированы старой политикой , а учим новую , поэтому каждый токен ответа взвешивают отношением вероятностейвыборка по значимости (importance sampling)EN importance samplingПеревзвешивание сэмплов старой политики отношением π_new / π_old — основа PPO. (importance sampling) и обрезают его до :
Здесь — промпт плюс уже написанные токены, — токен ответа, обычно . Правило из таблицы пяти случаев урока 6.0.3: PPO не даёт уйти слишком далеко в «выгодную» сторону, но всегда даёт исправить ошибку. Например, при и цель обрезана до 1.2 и градиента нет: вероятность хорошего токена уже подняли на 50%. При и градиент есть: плохой токен стал чаще, это надо исправить.
Важная для LLM оговорка: поправка учитывает только вероятность токена, но не то, что новая политика писала бы другие продолжения. Поэтому политики не должны расходиться далеко — за этим, кроме клиппинга, следит и KL-штраф к референсной модели.
Критик и преимущество для каждого токена
Заголовок раздела «Критик и преимущество для каждого токена»Откуда ? В PPO baseline — отдельная нейросеть, критиккритик, value-модельEN critic / value modelСеть, предсказывающая ожидаемую награду из текущего состояния; в PPO служит baseline для каждого токена. : она по началу ответа предсказывает, какую награду он в итоге получит. Обычно это копия RM или SFT-модели со скалярной головой; учат её регрессией , где — возврат (return): сумма наград, фактически полученных от токена до конца ответа.
Награда в RLHF складывается так: на каждом токене — KL-штраф из прошлого урока, а на последнем токене к нему добавляется оценка RM. Преимущество считают методом GAEобобщённая оценка преимущества (GAE)EN generalized advantage estimation (GAE)Schulman и др., 2015. Смешивает оценки преимущества разной длины с коэффициентом λ. (вывод и пример с роботом-курьером — в уроке 6.0.3), обычно с :
Пример на токенах. Ответ из трёх токенов, RM поставила 1.0 (KL для простоты опустим), критик оценил состояния перед каждым токеном как , после последнего токена (ответ закончен), . Награды по токенам , поэтому : второй токен поднял «шансы ответа» с 0.6 до 0.9 — критик считает его ключевым.
- При : — это просто , как в REINFORCE с baseline.
- При : — заслуга достаётся тому токену, после которого оценка выросла.
- При типичном : — компромисс между шумом и смещением.
Так критик раздаёт заслугу по токенам — то, чего нет у REINFORCE и GRPO, где все токены ответа получают одно преимущество. Но для этого критик должен быть точным на каждом токене, хотя награда приходит только в конце, — это его главная слабость в LLM.
Один шаг RLHF с PPO
Заголовок раздела «Один шаг RLHF с PPO»- Генерация. Политика отвечает на батч промптов. Это самая медленная часть шага.
- Оценка. RM ставит награды; референсная модель считает свои log-вероятности для KL; критик — значения .
- Преимущества по GAE, их нормируют по батчу.
- Обновление. 1–4 эпохи по мини-батчам: политика — по , критик — по MSE (полный loss — урок 6.0.3).
- Повторить с новым батчем промптов.
В InstructGPT к цели добавили ещё слагаемое с градиентами обычного претрейна (вариант PPO-ptx). Оно уменьшает налог на выравниваниеналог на выравниваниеEN alignment taxПадение качества на обычных задачах после выравнивания под предпочтения. — падение качества на обычных NLP-задачах после выравнивания.
Почему это дорого: четыре модели
Заголовок раздела «Почему это дорого: четыре модели»flowchart TB P["Политика π_θ — обучается"] -->|"ответы"| RM["Reward model — заморожена"] P -->|"log π"| REF["Референс π_ref — заморожена"] P -->|"состояния"| C["Критик V_ψ — обучается"] RM -->|"награда"| G["GAE: преимущества"] REF -->|"KL-штраф"| G C -->|"V(s_t)"| G G --> P G --> C
Прикинем память для политики на 7B. Как вы считали в уроке 6.2.1, обучение с Adam в смешанной точности требует примерно 16 байт на параметр (веса BF16, градиенты, FP32-копия весов и два момента Adam), то есть ~112 ГБ. Замороженная модель в BF16 — 2 байта на параметр, ~14 ГБ. Активации и KV-кэш генерации — сверху.
| Метод | Модели в памяти | Веса + оптимизатор |
|---|---|---|
| SFT | политика | ~112 ГБ |
| PPO | политика + критик (обучаются), референс + RM (заморожены) | 112 + 112 + 14 + 14 ≈ 252 ГБ |
| DPO (урок 6.3.3) | политика + референс | ~126 ГБ |
| GRPO (модуль 6.4) | политика + референс (+ RM, если нужна) | ~126–140 ГБ |
Кроме памяти, у PPO много чувствительных гиперпараметров: два learning rate, , , , , число эпох, нормировки наград и преимуществ. Неудачная комбинация — и обучение разваливается. Поэтому о «секретах» PPO написано столько работ, в том числе китайских (см. ниже), а DeepSeek в итоге избавились от критика совсем (GRPO).
Reward hacking: когда мера становится целью
Заголовок раздела «Reward hacking: когда мера становится целью»Закон Гудхартазакон ГудхартаEN Goodhart's law«Когда мера становится целью, она перестаёт быть хорошей мерой».: когда мера становится целью, она перестаёт быть хорошей мерой. Reward model — лишь приближение к мнению людей, обученное на конечных данных. Политика, которую оптимизируют против неё тысячи шагов, находит места, где RM ошибается. Это взлом наградывзлом награды (reward hacking)EN reward hackingПолитика находит способ получить высокую награду, не делая того, что задумали люди..
Классика из RL для игр: в 2016 году OpenAI описала агента гоночной игры CoastRunners. Он нашёл лагуну, где можно бесконечно кружить и собирать бонусы, и набирал больше очков, чем люди, так ни разу и не доехав до финиша. У LLM то же самое выглядит так:
- Длина. RM привыкла, что подробные ответы лучше, и награждает воду.
- Угодничествоугодничество (sycophancy)EN sycophancyСклонность модели соглашаться с пользователем и льстить ему вместо правдивого ответа — частый побочный эффект RLHF. (sycophancy). Согласиться с пользователем выгоднее, чем поправить его.
- Форма вместо содержания: списки, жирный шрифт, уверенный тон — при неверных фактах.
Исследование OpenAI 2022 года (Gao и др., «Scaling Laws for Reward Model Overoptimization») измерило это на синтетической «золотой» RM. По мере удаления политики от исходной (рост KL) оценка обучаемой RM растёт монотонно, а «настоящее» качество сначала растёт, потом падает. Чем больше RM, тем выше удаётся поднять настоящее качество до спада.
Чем лечат:
- KL-штраф и ранняя остановка по KL;
- ансамбль RM и пессимистичная оценка (минимум или среднее минус разброс);
- переобучение RM на свежих ответах текущей политики — итеративный, онлайн-RLHF;
- штрафы за длину и формат;
- там, где это возможно, — правиловые награды: проверка ответа или запуск тестов. Так сделал DeepSeek-R1.
К закону Гудхарта мы вернёмся на ступени 9: в уроке 9.3.3 reward hacking разобран как часть общей задачи выравнивания — шумная прокси против прокси с лазейкой, угодничество, Constitutional AI и эксперименты лабораторий, где взлом награды переходил в другие виды плохого поведения.
Практика
Заголовок раздела «Практика»Задание: loss Брэдли–Терри
Заголовок раздела «Задание: loss Брэдли–Терри»Реализуйте вероятность и устойчивый loss Брэдли–Терри, его градиент, превращение ранжирования из ответов в пары и «reward model» с одним числом на ответ — как рейтинг Chatbot Arena.
import numpy as np
def sigmoid(x):
"""Устойчивая сигмоида — уже готова. Работает и для x = ±1000."""
x = np.asarray(x, dtype=float)
return np.exp(-np.logaddexp(0.0, -x))
def bt_prob(r_chosen, r_rejected):
"""Вероятность по Брэдли–Терри, что chosen лучше rejected: sigmoid(r_c - r_r).
Аргументы — числа или массивы одинаковой формы.
"""
# TODO: ваш код
...
def bt_loss(r_chosen, r_rejected):
"""Loss reward model: среднее по парам -log sigmoid(r_c - r_r).
Вернуть float. Должен быть устойчив: для Δ = -1000 ответ ≈ 1000, а не inf.
Подсказка: -log sigmoid(Δ) = log(1 + exp(-Δ)) = np.logaddexp(0, -Δ).
"""
# TODO: ваш код
...
def bt_grad(r_chosen, r_rejected):
"""Градиенты bt_loss (СРЕДНЕГО по N парам) по r_chosen и по r_rejected.
Вернуть кортеж (g_chosen, g_rejected) — два массива формы как у входа.
"""
# TODO: ваш код
...
def ranking_to_pairs(ranking):
"""Разметчик упорядочил K ответов от лучшего к худшему: например [3, 0, 2, 1].
Вернуть список ВСЕХ пар (победитель, проигравший) — их C(K, 2):
[(3, 0), (3, 2), (3, 1), (0, 2), (0, 1), (2, 1)].
"""
# TODO: ваш код
...
def fit_scores(pairs, n_items, steps=500, lr=1.0):
"""«Reward model» с одним числом на ответ: s = нули, затем `steps` шагов
градиентного спуска s -= lr * grad, где grad — градиент bt_loss
по s (собрать из bt_grad для s[winners] и s[losers]).
Вернуть s - s.mean() (награда определена с точностью до сдвига).
Внимание: один ответ входит во многие пары — используйте np.add.at или цикл.
"""
# TODO: ваш код
...
# Проверьте себя кнопкой «Запустить»:
print(bt_prob(1.0, 0.0)) # ≈ 0.7311
print(ranking_to_pairs([3, 0, 2, 1]))
print(fit_scores([(0, 1), (0, 1), (1, 0), (1, 2), (2, 1), (0, 2)], 3))
Локально: reward model на PyTorch и взлом награды
Заголовок раздела «Локально: reward model на PyTorch и взлом награды»Сгенерируем синтетические ответы с тремя свойствами: верен ли ответ, насколько он подробен (люди это ценят) и какой длины. «Люди» выбирают по Брэдли–Терри на основе верности и подробности. А reward model видит только верность и длину — подробность ей приходится угадывать по длине. Как обычно и бывает: «понятность» измерить трудно, а длина — вот она.
import torchimport torch.nn.functional as F
torch.manual_seed(0)
def answers(n): """Признаки ответа: верен ли он, насколько подробен (это ценят люди) и его длина.""" correct = torch.bernoulli(torch.full((n,), 0.5)) detail = torch.rand(n) # 0…1, модель вознаграждения его НЕ видит length = 3 * detail + 0.3 * torch.randn(n).abs() # сотни токенов; подробнее → длиннее utility = 2 * correct + detail # «истинное» мнение людей return torch.stack([correct, length], 1), utility
# 1) Данные предпочтений: пары ответов, человек выбирает по Брэдли–Терриxa, ua = answers(4000)xb, ub = answers(4000)a_wins = torch.bernoulli(torch.sigmoid(ua - ub)).bool()chosen = torch.where(a_wins[:, None], xa, xb)rejected = torch.where(a_wins[:, None], xb, xa)
# 2) Reward model: линейная голова над признаками, loss Брэдли–Терриrm = torch.nn.Linear(2, 1)opt = torch.optim.Adam(rm.parameters(), lr=0.05)for step in range(300): margin = rm(chosen) - rm(rejected) loss = -F.logsigmoid(margin).mean() opt.zero_grad() loss.backward() opt.step()
w = rm.weight.data[0]acc = (margin > 0).float().mean()print(f"loss {loss.item():.3f}, точность на парах {acc:.2f}")print(f"веса RM: за верность {w[0]:.2f}, за каждые 100 токенов длины {w[1]:.2f}")
# 3) «Политика» ищет ответ, который RM оценит выше всегоshort_ok = torch.tensor([1.0, 1.0]) # верный ответ на 100 токеновlong_bad = torch.tensor([0.0, 20.0]) # неверная «простыня» на 2000 токеновprint(f"RM: верный короткий {rm(short_ok).item():.2f}, неверная простыня {rm(long_bad).item():.2f}")loss 0.533, точность на парах 0.71веса RM: за верность 1.95, за каждые 100 токенов длины 0.29RM: верный короткий 2.90, неверная простыня 6.49RM честно выучилась: вес за верность 1.95 (у «людей» 2), точность 71%. Потолок здесь задаёт шум самих предпочтений, как у живых разметчиков: даже идеальная RM, знающая истинную полезность, угадала бы лишь около 73% пар. Но длина для неё — признак подробности, и неверная простыня на 2000 токенов получает награду на 3.6 выше верного короткого ответа. Сравнивать награды можно только разностью (сдвиг не важен), и по Брэдли–Терри это значит: RM на «уверена», что простыня лучше. Таких длинных ответов в обучающих данных не было — RM экстраполирует линейный тренд туда, где его никто не проверял. RL-политика, которую не держит KL-штраф, рано или поздно найдёт эту область.
Проверь себя
Заголовок раздела «Проверь себя»- RLHF превращает сравнения «A лучше B» в награду: данные предпочтений → reward model → PPO.
- Брэдли–Терри: ; loss RM — , в начале он равен .
- PPO переиспользует ответы через отношение вероятностей и клиппингом не даёт политике уйти далеко за шаг. Критик и GAE дают преимущество каждому токену.
- Цена — четыре модели в памяти (~250 ГБ для 7B без активаций), медленная генерация и капризные гиперпараметры.
- Reward hacking неизбежен при сильной оптимизации прокси-награды; от него спасают KL, обновление RM и проверяемые награды.
Дальше: DPO — как из той же формулы получить обучение на предпочтениях без reward model и без PPO.