Pre-training - обучение на триллионах неразмеченных токенов с задачей предсказания следующего слова; стоит $15–150 млн за одну тренировку.
Pre-training даёт фундамент: на 5% токенов - грамматика, на 15% - синтаксис, на 30% - факты, на 50% - логика, на 70% - контекст.
SFT (Supervised Fine-Tuning) - дообучение на парах «инструкция → идеальный ответ»; превращает «предсказателя текста» в ассистента.
SFT не добавляет знаний, а учит формату диалога: как начинать ответ, как структурировать, как завершать.
RLHF (Reinforcement Learning from Human Feedback) - люди выбирают лучшие ответы, на этих данных обучается reward model (модель вознаграждения).
RLHF оптимизирует три цели
полезность (helpfulness), честность (honesty), безопасность (harmlessness), которые часто конфликтуют.
Три этапа RLHF
сбор предпочтений → обучение reward model → дообучение основной модели через PPO.
Метрики RLHF: на примере LLaMA-2 - helpfulness +37%, honesty +100%, harmlessness +17%, но креативность и качество языка немного падают.
RLHF решает проблему нюансов: модель учится понимать «покороче», «попроще», «как для эксперта» - то, что невозможно закодировать в SFT.
Полный цикл обучения
pre-training (энциклопедия) → SFT (ассистент) → RLHF (вежливый и безопасный ассистент).
1. Какие этапы проходит модель в процессе обучения от «сырой» до «вежливого ассистента»?
2. Почему pre-training стоит десятки миллионов долларов и кто может себе это позволить?
3. Какие проблемы возникают при сборе данных для обучения и как их решают инженеры?
4. Чем SFT отличается от pre-training по сути (не по механике, а по результату)?
5. Объясните на примере, почему SFT не может научить модель понимать нюансы вроде «покороче, пожалуйста».
6. Три этапа RLHF: что происходит на каждом?
7. Какие три цели оптимизирует RLHF и почему они часто конфликтуют?
Представьте, что вы печёте многослойный торт по одному и тому же рецепту много раз подряд (это процесс генерации текста моделью).
Без KV ‑ Cache
Каждый раз, когда вам нужно добавить новый корж, вы заново перечитываете весь рецепт с самого начала, заново взбиваете яйца, заново просеиваете муку, заново смешиваете ингредиенты - даже если предыдущие коржи уже готовы и лежат перед вами. Это дико медленно и расточительно.
С KV ‑ Cache
Вы готовите первый корж и записываете в блокнот (кэш) все промежуточные результаты: сколько муки ушло, сколько сахара, при какой температуре выпекать. Когда приходит время второго коржа, вы не лезете в книгу рецептов, а просто заглядываете в свой блокнот, берёте уже готовые расчёты и сразу приступаете к сборке. Время сокращается в разы.
Применительно к модели
При генерации каждого нового слова (токена) модель должна "вспомнить" все предыдущие слова в контексте. Без KV‑Cache она каждый раз заново пересчитывает связи между всеми словами. С KV‑Cache она сохраняет уже вычисленные "ключи" и "значения" для предыдущих слов и использует их как готовые заготовки, вычисляя только для нового слова.
Технический уровень
При авторегрессионной генерации модель на каждом шаге пересчитывает внимание. Чтобы не пересчитывать старые токены, вычисленные K и V сохраняются в кэш. Без этого сложность была бы O(n²), с кэшем - O(n).
СРАВНЕНИЕ: Без KV Cache vs С KV Cache
БЕЗ KV CACHE (каждый шаг - пересчет всего)
Шаг 1: [A] → [B]: A(новый) → считаем K,V для A заново
Шаг 2: [A][B] → [C]: A(старый) B(новый) → пересчитали A заново (зря)
Шаг 3: [A][B][C] → [D]: A(старый) B(старый) C(новый) → опять пересчет A и B
ПАМЯТЬ: почти 0 (ничего не храним)
ВРЕМЯ: O(n²) → 100 токенов = 10 000 операций
С KV CACHE (сохраняем всё)
Шаг 1: [A] → [B]: Сохранили: KV_A в кэш
Шаг 2: [A][B] → [C]: Используем: KV_A(из кэша) + считаем KV_B(новое) → сохраняем KV_B
Шаг 3: [A][B][C] → [D]: Используем: KV_A, KV_B(из кэша) + считаем KV_C(новое)
ПАМЯТЬ: O(n) → 100 токенов = 100 KV-пар в памяти
ВРЕМЯ: O(n) → 100 токенов = 100 операций
ВЫИГРЫШ: в 100 раз при длине 100 токенов
Мы разобрались, как KVCache превращает квадратичную сложность в линейную: не пересчитываем старые токены, а берём их из памяти.
Но у этой медали есть обратная сторона: кэш растёт с каждым новым токеном. При длинном контексте (32K и выше) один слой модели может держать в памяти гигабайты ключей и значений. А слоёв - десятки. Что делать?
Жадность до памяти - это та же проблема, только в другой проекции. Значит, нужно уменьшать размер хранимых K и V, не теряя при этом способности модели различать нюансы.
Именно здесь на сцену выходит Grouped Query Attention - компромисс между скоростью, памятью и качеством.