Базовая LLaMA 7B умеет продолжать текст, но не следует инструкциям и часто генерирует мусор. RLHF решает эту проблему через обучение на предпочтениях людей. StackLLaMA - реальный пример: модель, дообученная отвечать на вопросы Stack Exchange, проходит полный цикл из трёх этапов. В этом руководстве разобран каждый шаг: от сбора данных до финальной оптимизации политики. Вы получите готовый рецепт с кодом, настройками и диагностикой типичных ошибок.
Главный фокус - практическая реализация на ограниченном железе. LoRA-адаптеры и 8-битная квантизация позволяют обучать 7B-модель на одной GPU с 24 ГБ памяти. Библиотека TRL берёт на себя основную механику RLHF. Разбираем подводные камни: скачки вознаграждения, reward hacking, отрицательную KL-дивергенцию. Всё с конкретными решениями и примерами конфигураций.
Введение: зачем нужен RLHF для LLaMA и что такое StackLLaMA
LLaMA 7B после предобучения на общем корпусе текста предсказывает следующее слово, но не понимает формат «вопрос-ответ». Если спросить её о программировании, она может выдать продолжение форума, а не прямой ответ. RLHF выравнивает модель под ожидания пользователя: сначала supervised fine-tuning на доменных парах, затем обучение reward-модели на сравнениях, затем PPO с KL-штрафом.
StackLLaMA - модель, обученная на данных Stack Exchange. Она демонстрирует полный пайплайн: SFT на парах «вопрос-ответ», reward-модель на предпочтениях пользователей, PPO для оптимизации политики. Датасет собирается из открытых дампов Stack Exchange. Код и конфигурации воспроизводимы на одной GPU.
Для более широкого контекста по эффективному RLHF на 24 ГБ GPU смотрите разбор RLHF для 20B-модели с PEFT и квантизацией. Там детально показана комбинация LoRA, 8-битной загрузки и disable_adapters для расчёта логитов двух моделей без дублирования весов.
Обзор RLHF: три этапа обучения
Полный цикл RLHF для StackLLaMA состоит из трёх последовательных шагов. Каждый этап готовит модель к следующему: SFT даёт базовое следование формату, reward-модель учится оценивать качество ответов, PPO оптимизирует генерацию под эту оценку с ограничением отклонения от SFT-политики.
Этап 1: Supervised Fine-Tuning (SFT)
SFT обучает LLaMA 7B на парах «вопрос - качественный ответ» из Stack Exchange. Модель учится генерировать ответы в стиле платформы: конкретные, с примерами кода, без воды. Используется техника packing - несколько коротких примеров упаковываются в один контекст для эффективного использования максимальной длины последовательности. Это критично, потому что ответы на Stack Exchange часто короче 512 токенов, а контекст LLaMA - 2048 токенов.
Формат промпта простой: Вопрос: {question}\n\nОтвет: {answer}. Модель обучается предсказывать только часть после Ответ:, лосс считается по токенам ответа, а не вопроса.
Этап 2: Обучение reward-модели
Reward-модель обучается на парах ответов, где один предпочтительнее другого. Датасет собирается из Stack Exchange: ответы с более высоким рейтингом считаются предпочтительными. Модель принимает вопрос и ответ, выдаёт скалярную награду. Кастомная loss-функция максимизирует разницу между наградами предпочтительного и непредпочтительного ответов.
Архитектурно reward-модель - та же LLaMA 7B, но с линейным слоем на выходе вместо языковой головы. Она наследует веса SFT-модели, что ускоряет сходимость. Обучение идёт на парах сравнений, а не на абсолютных оценках: модель учится ранжировать, а не предсказывать точный балл.
Этап 3: Оптимизация политики с PPO
PPO обновляет политику (SFT-модель) на основе наград от reward-модели. Модель генерирует ответ, reward-модель оценивает его, PPO вычисляет градиент для увеличения вероятности высоко оценённых ответов. KL-штраф удерживает новую политику близко к исходной SFT-модели. Без него модель быстро находит способы эксплуатировать reward-модель: генерирует бессмысленные, но высоко оценённые последовательности.
Формула награды: reward = reward_model_score - kl_penalty * KL(active_policy || reference_policy). Коэффициент KL-штрафа обычно подбирается в диапазоне 0.02–0.2. Слишком маленький - модель уходит в reward hacking. Слишком большой - модель перестаёт улучшаться.
Эффективное обучение на ограниченном железе: LoRA и 8-битная квантизация
Полное fine-tuning LLaMA 7B в FP16 требует около 112 ГБ видеопамяти для оптимизатора, градиентов и активаций. На одной GPU с 24 ГБ это невозможно. LoRA и 8-битная квантизация сокращают потребление до приемлемого уровня: обучение идёт на одной карте, например RTX 4090 или A10G.
LoRA: Low-Rank Adaptation
LoRA замораживает все исходные веса модели и добавляет обучаемые низкоранговые матрицы к слоям внимания. Для LLaMA 7B при ранге 16 и alpha 32 количество обучаемых параметров составляет около 8–16 миллионов - примерно 0.1% от общего числа. Градиенты считаются только для этих матриц, что радикально снижает потребление памяти оптимизатором.
Практический пример настройки: r=16, lora_alpha=32, target_modules=["q_proj", "v_proj"], lora_dropout=0.05. Этого достаточно для SFT и reward-модели. Для PPO адаптеры активной и референсной моделей разделяются через контекстный менеджер disable_adapters, что позволяет считать логиты обеих политик без загрузки двух полных копий весов.
Подробный разбор PEFT-методов и их влияния на память - в статье о сжатии RLHF до одной 24 ГБ GPU. Там же показан полный конвейер от датасета IMDB до PPO.
8-битная квантизация
Квантизация весов до 8 бит через библиотеку bitsandbytes снижает точность представления, но экономит примерно половину памяти под веса. Для LLaMA 7B загрузка в 8-бит вместо FP16 уменьшает потребление с 14 ГБ до 7 ГБ. Обучение при этом идёт в смешанной точности: веса хранятся в 8 бит, вычисления - в FP16 или BF16.
Комбинация LoRA и 8-битной квантизации даёт суммарный эффект: модель 7B помещается в 24 ГБ вместе с оптимизатором, градиентами и батчем. Скорость обучения падает на 10–20% из-за деквантизации на лету, но это приемлемая цена за возможность запуска на одной карте.
Сбор и подготовка датасета из Stack Exchange
Stack Exchange публикует дампы данных под лицензией CC BY-SA. Для StackLLaMA используются вопросы и ответы из разделов, связанных с программированием: Stack Overflow, Software Engineering, Code Review. Датасет собирается через API или из XML-дампов.
Фильтрация и очистка данных
Не все ответы пригодны для обучения. Фильтры: минимальная длина ответа - 100 символов, минимальный рейтинг - 3 голоса, отсутствие markdown-мусора и ссылок на изображения. Вопросы с закрытыми или дублирующими формулировками удаляются. Ответы, содержащие только код без объяснений, исключаются - модель должна учиться объяснять, а не просто выдавать сниппет.
Итоговый датасет для SFT обычно содержит 50–100 тысяч пар «вопрос-ответ». Для reward-модели нужны пары сравнений: ответ с более высоким рейтингом против ответа с более низким. Таких пар собирается 100–200 тысяч.
Форматирование для SFT
Каждый пример форматируется в текстовый шаблон. Packing объединяет несколько примеров в одну последовательность длиной до 2048 токенов, разделяя их специальным токеном EOS. Это увеличивает эффективную утилизацию контекста с 30–40% до 90%+ для коротких ответов Stack Exchange.
Код для подготовки датасета использует datasets от Hugging Face: загрузка JSON, токенизация, packing через pack_dataset. Важно правильно выставить attention_mask, чтобы модель не училась на паддинге между упакованными примерами.
Настройка пайплайна обучения с библиотекой TRL
TRL (Transformer Reinforcement Learning) предоставляет готовые классы для всех трёх этапов RLHF. Интеграция с Hugging Face transformers и peft позволяет собрать пайплайн из стандартных компонентов.
Загрузка модели и применение LoRA
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import LoraConfig, get_peft_model
import torch
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-2-7b-hf",
load_in_8bit=True,
device_map="auto",
)
lora_config = LoraConfig(
r=16,
lora_alpha=32,
target_modules=["q_proj", "v_proj"],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM",
)
model = get_peft_model(model, lora_config)
Загрузка в 8 бит через load_in_8bit=True требует установленной библиотеки bitsandbytes. device_map="auto" распределяет слои по доступным GPU.
Обучение reward-модели с TRL
from trl import RewardTrainer, RewardConfig
from transformers import AutoModelForSequenceClassification
reward_model = AutoModelForSequenceClassification.from_pretrained(
"meta-llama/Llama-2-7b-hf",
num_labels=1,
load_in_8bit=True,
)
reward_config = RewardConfig(
output_dir="./reward_model",
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
learning_rate=1e-5,
max_length=2048,
)
trainer = RewardTrainer(
model=reward_model,
args=reward_config,
train_dataset=comparison_dataset,
tokenizer=tokenizer,
)
trainer.train()
Кастомная loss-функция в RewardTrainer уже реализует сравнение предпочтений: loss = -log(sigmoid(reward_chosen - reward_rejected)). Модель учится максимизировать разницу между выбранным и отклонённым ответом.
Запуск PPO с KL-штрафом
from trl import PPOTrainer, PPOConfig, AutoModelForCausalLMWithValueHead
ppo_model = AutoModelForCausalLMWithValueHead.from_pretrained(
sft_model,
peft_config=lora_config,
load_in_8bit=True,
)
ppo_config = PPOConfig(
model_name="stackllama-ppo",
learning_rate=1.4e-5,
batch_size=8,
mini_batch_size=4,
ppo_epochs=4,
kl_penalty="kl",
kl_coef=0.1,
cliprange=0.2,
)
ppo_trainer = PPOTrainer(
config=ppo_config,
model=ppo_model,
ref_model=ref_model,
tokenizer=tokenizer,
)
Ключевые параметры: kl_coef=0.1 задаёт силу KL-штрафа, cliprange=0.2 ограничивает шаг обновления политики. Референсная модель - замороженная SFT-модель, её адаптеры отключаются через disable_adapters при расчёте логитов.
Типичные проблемы RLHF и их решение
RLHF нестабилен по своей природе. Даже при правильной настройке гиперпараметров возникают специфические проблемы. Ниже - самые частые и способы их устранения.
Скачки вознаграждения и нестабильность
Внезапный рост среднего reward на 50–100% за несколько шагов обычно означает reward hacking: модель нашла паттерн, который reward-модель оценивает высоко, но который бесполезен для пользователя. Например, модель начинает повторять одни и те же фразы или добавлять «спасибо за вопрос» в каждый ответ.
Решения: уменьшить learning rate до 1e-6, увеличить KL-коэффициент до 0.2, добавить gradient clipping на уровне 0.5. Ранняя остановка по валидационной метрике также помогает: если reward растёт, а качество ответов по BLEU или человеческой оценке падает - обучение пора останавливать.
Отрицательная KL-дивергенция
KL-дивергенция по определению неотрицательна. Отрицательные значения в логах PPO возникают из-за аппроксимации при сэмплировании: когда используется ограниченное число сэмплов для оценки распределений, оценка KL может стать отрицательной. Это чаще проявляется при сложных стратегиях генерации: top-k, top-p, beam search.
Решения: увеличить число сэмплов для оценки KL с 4 до 16, использовать жадную генерацию вместо сэмплирования для расчёта KL, применить более стабильную оценку через kl_penalty="abs" вместо "kl". Если отрицательная KL сохраняется, проверьте корректность отключения адаптеров референсной модели - частая причина в том, что активная и референсная модели считаются с одними и теми же весами.
Результаты StackLLaMA и выводы
После полного цикла RLHF StackLLaMA генерирует ответы, которые по качеству приближаются к ответам опытных участников Stack Exchange. Модель даёт конкретные решения с примерами кода, объясняет причины, указывает на ограничения. Базовая LLaMA 7B на тех же вопросах выдаёт общие рассуждения без практической ценности.
RLHF оправдан, когда задача требует выравнивания с предпочтениями пользователей: ответы на вопросы, диалоговые системы, генерация кода по описанию. Для задач, где важна фактическая точность, одного RLHF недостаточно - нужны дополнительные механизмы проверки фактов.
Ограничения подхода: необходимость собирать данные предпочтений, вычислительные затраты на три этапа обучения, нестабильность PPO. Для небольших доменов с ограниченным бюджетом альтернативой может быть чистое SFT с последующей фильтрацией через reward-модель без полного PPO. Сравнение методов дообучения и их влияния на сохранение навыков модели - в статье о катастрофическом забывании при SFT, continued pre-training и RL.
Заключение: готовый рецепт для вашего RLHF
Полный цикл RLHF для LLaMA 7B на одной GPU: соберите датасет из открытых источников, выполните SFT с LoRA и packing, обучите reward-модель на парах предпочтений, запустите PPO с KL-штрафом. Ключевые компоненты: LoRA с рангом 16, 8-битная квантизация через bitsandbytes, библиотека TRL для всех этапов.
Мониторьте метрики на каждом шаге: loss SFT, accuracy reward-модели на валидации, средний reward и KL-дивергенцию в PPO. При скачках reward увеличивайте KL-коэффициент. При отрицательной KL проверяйте корректность разделения активной и референсной моделей.
Для воспроизводимого запуска LoRA-дообучения с проверкой метрик и сохранением артефактов смотрите пошаговое руководство по LoRA в Colab. Принципы верификации обновления весов и интерпретации метрик применимы и к RLHF-пайплайну.