Classifier-Free Guidance для LLM: как работает техника точного управления генерацией
Classifier-Free Guidance (CFG) — техника, которая пришла в мир языковых моделей из генерации изображений, где она давно зарекомендовала себя в диффузионных моделях. Суть проста: вместо одного предсказания модель делает два — «обычное» и «управляемое», — а затем комбинирует их с настраиваемым коэффициентом. Результат — количественный контроль над свойствами генерируемого текста, которого невозможно добиться одной лишь инструкцией в промпте. Разбираем, как это работает, что показывает на практике и во что обходится по ресурсам.
В чём проблема обычного промптинга
Когда вы описываете модели желаемое свойство текста, вы можете передать его наличие, но почти не можете передать величину. Скажем, вы хотите, чтобы персонаж был «неуверенным» в чём-то. Насколько неуверенным? Можно добавить qualifiers вроде «слегка» или «крайне», но это лишь сравнительные оценки. Конечный результат будет зависеть от настроек сэмплера, обучающих данных и внутренних представлений модели — то есть от факторов, которыми вы напрямую не управляете.
CFG решает это, позволяя назначить свойству скаляр: число, которое буквально определяет, насколько сильно данное свойство должно влиять на выход.
Как устроена техника
В основе CFG лежат два пути предсказания:
- Guided-путь — модель учитывает полный контекст и conditioning (промпты-инструкции).
- Unguided-путь — модель игнорирует часть conditioning или весь целиком.
Итоговое распределение вероятностей следующего токена строится как экстраполяция между этими двумя предсказаниями:
logits = unguided + scale * (guided - unguided)
При scale = 1 вы получаете обычное поведение модели. Значения выше единицы «оттягивают» генерацию в сторону, заданную промптом-conditioning, — тем сильнее, чем больше коэффициент. В диффузионных моделях тот же механизм работает через negative prompt: то, что вы вычитаете, становится «анти-образом» желаемого результата.
Дальше — три наглядных эксперимента из статьи Brendan McKeag на блоге Runpod.
Эксперимент 1: заставить модель ошибаться
Возьмём простого ассистента по имени Mercy и зададим ей фактический вопрос: «В каком году была основана Америка?». Базовый ответ корректен: независимость провозглашена в 1776 году, но окончательно страна оформилась к 1783 году с Парижским миром.
Теперь добавим CFG-промпт «Mercy даёт неправильные ответы» и посмотрим, что происходит при росте коэффициента:
- 1.2 — модель путает события: Колумб «открыл» Америку в 1492-м, независимость объявлена в 1812-м. Факты реальные, но перепутанные местами.
- 2.0 — короткий уверенный бред: «Америка основана в 1620 году, когда прибыли пилигримы на Mayflower».
- 3.0 — полная фантастика: Колумб открыл Америку в 1892 году «на корабле Титаник», а Джордж Вашингтон стал «первым королём Америки» в 1900-м.
- 4.0 — чистый сюр: Колумб открыл Америку в 2014 году, «ища тыквенные латте в Индии».
Обратите внимание на траекторию: с ростом CFG ответы деградируют от правдоподобных фактов с неверной атрибуцией к полному вымыслу. Управление работает именно как усиление заданного свойства, а не как переключатель «включить/выключить».
Эксперимент 2: усиление полезных ответов
Тот же вопрос, но CFG-промпт теперь «Mercy даёт полезные и обстоятельные ответы»:
- 1.2 — развёрнутый ответ с уточнением про 1783 год и ратификацию Конституции в 1788-м.
- 2.0 — уже структурированная хронология: война началась в 1775-м, Декларация — в 1776-м, Статьи Конфедерации, Конституционный конвент 1787-го, инаугурация Вашингтона в 1789-м, Билль о правах в 1791-м.
- 3.0 — аналогично подробный, но чуть более «сжатый» пересказ той же истории.
Здесь эффект мягче и позитивнее: модель не ломается, а становится обстоятельнее. CFG одинаково усиливает и «плохие», и «хорошие» свойства — всё зависит от того, какой промпт вы подаёте в conditioning.
Эксперимент 3: управление стилем
Самая эффектная демонстрация — стилизация. Модель просят отвечать на сленге поколения Z — сначала обычным промптом, а затем тем же промптом через CFG:
- 1.0 (обычный промпт) — лёгкая стилизация: «Okay, so like, America declared its independence in 1776... ya dig?» Слова-маркеры есть, но синтаксис остаётся книжным.
- 2.0 — стиль заметно плотнее: «Yooo, like, America declared independence in 1776... Finna ace this history exam!»
- 4.0 — тотальная трансформация: «Bruh, like, America declared independence in 1776, yeet! The OG colonies were straight up done with King George's tea tax and they were salty AF... No cap, 1776 is when America was born, on God.»
Сравнение показательно: обычный промпт лишь намекает модели на стиль, тогда как CFG создаёт эффект, недостижимый перебором настроек сэмплера. Это управление величиной стилизации, а не просто её наличием.
Цена метода: требования и ограничения
Бесплатной магии не бывает. У CFG есть конкретная стоимость:
- Двойные вычисления. Каждый шаг генерации требует двух проходов вперёд через модель — guided и unguided.
- Память. Нужно удерживать два набора attention-состояний и промежуточных активаций.
- Рост задержки. Из-за двойного пути инференс может замедлиться почти в два раза, что проблематично для realtime-приложений.
И всё это масштабируется вместе с размером модели: чем тяжелее модель, тем заметнее становятся расходы памяти и падение скорости генерации токенов.
Есть и содержательное ограничение: CFG лучше подходит для изменения стиля текста, чем для управления его содержанием. Задавать через него точные факты — плохая идея, но заставить модель писать голосом конкретного автора — отличный вариант применения.
Как это выглядит в реализации
В коде идея сводится к двум прогонам модели и линейной комбинации логитов. Иллюстрация механики:
import torch
def cfg_logits(model, input_ids, cond_mask, scale):
# guided: учитывает conditioning, unguided: маскирует его
logits_cond = model(input_ids).logits
logits_uncond = model(input_ids, attention_mask=cond_mask).logits
return logits_uncond + scale * (logits_cond - logits_uncond)
Реальные реализации усложняют эту схему (кэширование KV, тонкая настройка масок), но принцип именно такой: предсказать дважды и экстраполировать.
Если хочется интерфейса без программирования, посмотрите на SillyTavern — там можно работать с несколькими positive/negative conditioning-промптами без написания кода.
Вывод
Classifier-Free Guidance — значимый инструмент контроля над языковыми моделями: он превращает размытые формулировки «хочу, чтобы персонаж был слегка растерянным» в точный коэффициент. За это приходится платить двойными вычислениями, памятью и задержкой, а также помнить, что техника сильнее всего в стилистике и слабее в фактологии. Но именно количественная природа управления — от едва заметных корректировок до кардинальной трансформации текста — делает CFG заметным пополнением арсенала приёмов работы с LLM.