Дообучение LLM методом ORPO
Представьте: вам нужно дообучить языковую модель под конкретные предпочтения — например, чтобы она строго следовала стилю кода в компании. Классический подход DPO требует двух моделей в памяти, а SFT не умеет штрафовать за плохие ответы. Мы часто сталкиваемся с этим на практике, и решение — ORPO (Odds Ratio Preference Optimization), метод, объединяющий SFT и preference optimization в одном цикле без отдельной reference model.
Почему ORPO экономит память и время?
ORPO — метод, предложенный Hong et al. Ключевое отличие от DPO: ORPO объединяет Instruction Tuning и Preference Optimization в одном шаге, не требует отдельной reference model и использует odds ratio для penalization нежелательных ответов. Это значит, что вы можете выравнивать модель на одной видеокарте, а не на двух.
| Метод | Win Rate (AlpacaEval 2.0) | Память (7B) | Время обучения |
|---|---|---|---|
| SFT only | ~5% | 1× | 1× |
| DPO | ~15–20% | 2× (ref model) | 1.3× |
| ORPO | ~18–22% | 1× | 1× |
| SimPO | ~20–25% | 1× | 1× |
ORPO превосходит DPO по эффективности памяти при сопоставимом качестве: он использует вдвое меньше памяти, чем DPO, и не требует дополнительной модели. SimPO (Simple Preference Optimization) — более свежий метод, часто показывающий чуть лучшие результаты, но требует подбора двух гиперпараметров.
Как работает ORPO: математика и практика
Функция потерь:
L_ORPO = L_SFT + λ * L_OR L_SFT = -log P(y_w | x) # обычный SFT loss на chosen ответах L_OR = -log(sigmoid(log(odds_ratio(y_w, x) / odds_ratio(y_l, x)))) где odds_ratio(y, x) = P(y|x) / (1 - P(y|x)) Гиперпараметр λ (в библиотеке TRL называется beta) определяет вес preference loss. Мы рекомендуем начинать с beta=0.1 и регулировать в сторону увеличения, если модель недостаточно штрафует плохие ответы.
Как собрать качественный датасет предпочтений?
Формат датасета идентичен DPO — пары prompt, chosen, rejected:
dataset = { "prompt": "Как правильно написать техническое задание?", "chosen": "Техническое задание включает несколько обязательных разделов: цель проекта, функциональные требования (с приоритетами по MoSCoW), нефункциональные требования (производительность, безопасность), ограничения, критерии приёмки...", "rejected": "Пишите что хотите чтобы разработчики поняли задачу" } Важно: rejected должен быть не просто плохим, а типично нежелательным — чтобы модель выучила границы. Собирайте пары с помощью экспертных оценок или LLM-as-Judge.
Реализация ORPO через TRL (пошагово)
from trl import ORPOTrainer, ORPOConfig from peft import LoraConfig from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained( "meta-llama/Meta-Llama-3.1-8B-Instruct", torch_dtype=torch.bfloat16, device_map="auto" ) orpo_config = ORPOConfig( output_dir="./orpo-model", num_train_epochs=3, per_device_train_batch_size=2, gradient_accumulation_steps=8, learning_rate=8e-6, # ORPO обычно требует меньший lr, чем SFT lr_scheduler_type="linear", warmup_ratio=0.1, beta=0.1, # λ в ORPO — вес OR loss (в TRL называется beta) max_length=2048, max_prompt_length=512, bf16=True, remove_unused_columns=False, logging_steps=10, ) trainer = ORPOTrainer( model=model, args=orpo_config, train_dataset=train_dataset, eval_dataset=eval_dataset, peft_config=LoraConfig( r=16, lora_alpha=32, target_modules=["q_proj", "v_proj", "k_proj", "o_proj"], task_type="CAUSAL_LM", ), ) trainer.train() Когда выбирать ORPO вместо DPO?
Выбирайте ORPO при ограниченных GPU-ресурсах, отсутствии хорошей SFT reference model или задачах средней сложности alignment. DPO лучше подходит, если уже есть высококачественная SFT reference model и нужна точная настройка KL-дивергенции. SimPO стоит использовать, когда максимальный win rate на бенчмарках важнее простоты реализации. В таблице ниже — сравнение гиперпараметров.
| Гиперпараметр | ORPO | DPO | SimPO |
|---|---|---|---|
| λ (beta) | 0.1-0.5 | 0.1-0.5 | γ: 0.5-1.5, β: 0.1-0.5 |
| Learning rate | 5e-6 – 8e-6 | 1e-6 – 5e-6 | 1e-6 – 5e-6 |
| Reference model | Не требуется | Требуется | Не требуется |
| Чувствительность к качеству rejection | Средняя | Высокая | Высокая |
Практический кейс: выравнивание модели code-review под стандарты финтех-команды
Из нашей практики. Клиент — финтех-компания с жёсткими стандартами безопасности кода. Задача: дообучить Qwen2.5-Coder-7B-Instruct для автоматического code review, выявляющего все нарушения. Проблема с чистым SFT: модель хорошо воспроизводит «правильные» ревью, но не штрафует за игнорирование нарушений. Нужна штрафная составляющая.
ORPO-датасет: 1800 пар. Chosen — ревью, выявляющий все нарушения стандартов. Rejected — ревью, пропустивший критические нарушения или сгенерировавший ложные замечания.
Конфигурация: ORPO, β=0.1, lr=5e-6, 2 эпохи, LoRA rank 16. Результаты:
- Recall нарушений стандартов: 0.67 → 0.91
- Precision замечаний (нет ложных): 0.71 → 0.88
- False negative rate (пропуск критических нарушений): 28% → 7%
- Время обучения: 3.5ч на 1×A100 40GB (без reference model overhead)
Что входит в нашу работу по ORPO-дообучению
- Анализ вашей задачи и сбор требований
- Подготовка датасета предпочтений (выбор или генерация пар chosen/rejected)
- Выбор базовой модели и схемы PEFT (обычно LoRA)
- Обучение ORPO с подбором гиперпараметров λ/β
- Оценка с помощью LLM-as-Judge и эксперта
- Документация пайплайна и рекомендации по дальнейшему использованию
- Обучение вашей команды работе с моделью
- Поддержка в течение 2 недель после сдачи
Сроки и как начать
Ориентировочные сроки:
- Сбор датасета предпочтений: от 3 недель (под ключ)
- Обучение ORPO (7B, LoRA, A100): 3–8 часов
- Итерации λ/β: 3–5 дней
- Оценка (LLM-as-judge + человек): 1 неделя
- Итого: 5–8 недель в зависимости от сложности
Свяжитесь с нами для бесплатной оценки вашего проекта. Мы подберём оптимальный метод alignment и предложим план работ. Закажите консультацию — наши инженеры проанализируют задачу и дадут рекомендации.







