Разбираем PPO — алгоритм, лежащий в основе ChatGPT. Простое объяснение, код на Python и практические выводы. Начните обучение сегодня!
Когда спрашивают, как обучили ChatGPT, ответ обычно включает RLHF — обучение с подкреплением на основе человеческой обратной связи. А RL-часть в RLHF — это PPO. Сегодня разберем PPO — и окажется, что это проще, чем вы думали. Если вы уже знакомы с Actor-Critic, PPO — это небольшой, но важный шаг вперед.
Actor-Critic (из предыдущей статьи) работал, но у него была проблема нестабильности. Один эпизод с необычно высоким или низким вознаграждением мог слишком сильно сдвинуть веса сети. Политика менялась кардинально, иногда забывая то, что уже выучила. Обучение могло разрушиться.
Решение элегантное: ограничить скорость обучения.
После каждого обновления PPO сравнивает новую политику со старой:
ratio = new_probability / old_probabilityЗатем PPO обрезает (клиппует) это отношение. Он говорит: «Я не позволю изменить вероятность более чем на 20% за одно обновление».
clipped_ratio = clip(ratio, 0.8, 1.2)
loss = -min(ratio * advantage, clipped_ratio * advantage)И это буквально всё. Один клип. Один минимум. В этом вся разница между PPO и Actor-Critic.
Градиент от обрезанного обновления становится нулевым, как только ratio достигает границы. Политика перестает обновляться для этого действия на этом шаге. Вернитесь на следующем батче и подтолкните её снова, если нужно. Маленькие стабильные шаги на каждом обновлении.
Не дает политике меняться слишком сильно за один раз.
Actor-Critic использует каждый эпизод один раз. PPO собирает батч эпизодов и затем выполняет 4 обновления градиента на этих же данных. Больше обучения на эпизод, выше эффективность использования данных.
Энтропия измеряет, насколько распределены вероятности действий. Высокая энтропия означает, что агент все еще рассматривает много вариантов. Низкая — что он схлопнулся до выбора одного действия. PPO добавляет небольшое вознаграждение за энтропию:
total_loss = policy_loss + critic_loss - 0.01 * entropyЭто заставляет агента дольше исследовать, прежде чем зафиксироваться. Без этого политика может слишком рано схлопнуться к одному действию и застрять.
for iteration in range(200):
# собираем 10 эпизодов с текущей политикой
batch = collect_batch(actor, critic, episodes=10)
# PPO-эпохи: выжимаем 4 обновления из этого батча
for epoch in range(4):
actor_loss = clipped_ppo_loss(batch)
critic_loss = value_loss(batch)
update(actor, critic)Два цикла. Внешний собирает данные. Внутренний извлекает обучение из этих данных. У Actor-Critic был один цикл. Именно поэтому PPO обучается быстрее на каждый собранный эпизод.
Оценки ценности от критика после обучения:
состояния близко к цели: +0.6 до +0.8
безопасный средний путь: +0.1 до +0.4
состояния возле дыр: -0.3 до -0.6Критик разметил всю сетку-мир, просто наблюдая за успехами и неудачами актера. Никто не говорил ему, где дыры. Он сам понял.
Стрелки политики выстроились четко. Тот же результат, что и в Q-learning (День 4), DQN (День 5), REINFORCE (День 6), Actor-Critic (День 7). Разные алгоритмы каждый раз. Одно и то же выученное поведение. Этот паттерн постоянно меня поражает. Интуиция Беллмана пронизывает всё это.
Три причины: стабильность (клип предотвращает коллапс), простота (одна дополнительная строка к Actor-Critic) и универсальность (дискретные действия, непрерывные действия, тонкая настройка LLM — всё тот же алгоритм). Когда OpenAI обучал ChatGPT, люди ранжировали ответы. Эти ранжирования стали сигналом вознаграждения. PPO оптимизировал языковую модель против этого сигнала. Цикл RL, который вы только что реализовали — тот же цикл, просто с другим окружением и другой функцией вознаграждения.
Когда я создавал проект forge (тренер GRPO), я не до конца понимал, почему он работает так, как работает. GRPO — это PPO с одним изменением: вместо одного критика, оценивающего преимущество, он запускает группу эпизодов и сравнивает их вознаграждения между собой. Тот же клип. Та же стабильность. Групповое сравнение заменяет критика.
Пять дней назад я не мог бы этого объяснить. Теперь могу.
Возьмите свою реализацию Actor-Critic и добавьте клиппинг отношения вероятностей (как показано выше). Запустите обучение на той же задаче и сравните стабильность. Затем добавьте бонус энтропии и несколько эпох на батч. Вы увидите, как обучение становится более устойчивым. Это и есть PPO.
День 9: Haiku — библиотека нейросетей от DeepMind. Перепишем всё это в разы меньшим кодом, и это станет похоже на настоящий исследовательский JAX.
Весь код этой серии, организованный по дням, на моем GitHub: https://github.com/MadhumithaKolkar/jax-rl-lab
Удачного обучения!
Хочешь закрепить знания на практике?
Решай задачи на Algolit — интерактивная платформа для обучения
Начать бесплатно →