Перейти к содержанию
С нуля
Программа курса
EN Открыть

Программа курса

Неделя 15. SFT и данные

Фаза 4. Post-training · неделя 15 из 24

Учиться в приложении: тьютор, задачи с кодом →

Ядро: SFT и маскирование лосса, чат-шаблоны, LoRA и QLoRA, дедупликация и фильтры данных · Глубина: дистилляция и прунинг, лаборатория данных 15b · ≈ 11 ч ядро / 21 ч всё

С этой недели модель не предобучают, а доводят: предобученная LLM продолжает текст, а не отвечает на вопросы. SFT это первый этап post-training, и RL недель 16–17 стартует с SFT-модели. Здесь же два инструмента, без которых дообучение не помещается в бюджет, а бенчмарк ничего не доказывает (неделя 18): LoRA и чистые данные с деконтаминацией.

  • Instruction tuning (SFT, дообучение на парах «инструкция → ответ»), чат-шаблоны (формат, склеивающий диалог в одну строку), спецтокены ролей (отмечают, где реплика пользователя, а где ассистента)

На пальцах. Пример: <user> Сколько будет 2 + 2? <assistant> 4 <end>. Пусть это 8 токенов промпта и 2 токена ответа. Без маски лосс считается на всех позициях, и около 80% сигнала уходит на предсказание вопроса пользователя. Модель учится писать как пользователь, а не отвечать. С маской метки промпта заменены на ignore_index (−100), и лосс считается только там, где предсказываются 4 и <end>. При длинных промптах перекос сильнее: документ на 900 токенов и ответ на 100: без маски на ответ пришлось бы 10% градиента.

  • Маскирование лосса на промпте, и почему без этого модель учится не тому

На пальцах. Учитель на вопрос «столица Австралии?» выдаёт распределение: Канберра 0.7, Сидней 0.2, Мельбурн 0.1. One-hot-метка сообщает только «Канберра». Мягкая метка добавляет больше: Сидней это правдоподобная ошибка, Мельбурн менее правдоподобная. Ученик, обученный на (0.7, 0.2, 0.1), получает больше информации с одного примера. Лосс здесь кросс-энтропия с распределением учителя, и log softmax ученика считают через logsumexp (неделя 4).

  • Синтетические данные, дистилляция (ученик учится на выходах учителя; в т.ч. по логитам; тут как раз всплывает нестабильность logsumexp)
  • Курирование данных: дедупликация (MinHash/LSH), фильтры качества, деконтаминация (удаление из обучения текстов, пересекающихся с тестовыми наборами)

На пальцах. Матрица слоя W размером 4096×4096 содержит 16.8 млн чисел, её не трогают. Поверх кладут поправку ΔW = B·A: B размером 4096×8, A размером 8×4096, вместе 65 536 чисел, 0.4% от W. Поправка ограничена по форме. Ранг 1 это b·aᵀ: при b = (1, 2) и a = (3, 0, 1) выходит [[3, 0, 1], [6, 0, 2]], и вторая строка обязана быть кратной первой. Ранг 8 это не больше 8 независимых направлений правки на весь слой. Этого хватает, если нужная правка почти низкоранговая, и не хватает, если нет.

  • LoRA / QLoRA: низкоранговое разложение (поправка весов как произведение двух узких матриц), где вставлять адаптеры, что экономит память. QLoRA это то же поверх замороженной модели, сжатой до 4 бит (квантование, подробно в неделе 14)
LoRA: замороженный W и поправка B·ALoRA: замороженный W и поправка B·A
Схема 21. W заморожена, обучается поправка B·A ранга r с масштабом α/r. На старте B = 0, поэтому выход не меняется; после обучения поправка вливается в W.

Код → nanolm/lora.py: LoRALinear, apply_lora, mark_only_lora_trainable, merge_lora, parameter_summary. Задание в exercises/lora.py, проверка: NANOLM_IMPL=exercises pytest tests/test_lora.py -v.

Проверь три вещи руками: на старте выход модели не меняется (B инициализирован нулями); после mark_only_lora_trainable у замороженных параметров .grad остаётся None; слияние не меняет выход.

И отдельно test_lora_quality_is_bounded_by_rank: ранг это потолок, а не «побольше, значит лучше». Если ΔW полноранговая, низкий ранг её не закроет никогда.

Код → nanolm/compress.py: magnitude_prune (прунинг, то есть обнуление самых маленьких весов: глобальный и послойный), prune_ffn_neurons (удаление нейронов SwiGLU целиком, матрицы становятся уже), low_rank_approximate через SVD (разложение по сингулярным числам), distillation_loss с температурой и множителем T². Задание в exercises/compress.py, проверка: NANOLM_IMPL=exercises pytest tests/test_compress.py -v. Дистилляция из списка выше здесь в коде: при alpha = 0 лосс равен обычной кросс-энтропии, а без множителя T² градиент мягкой части падал бы как 1/T². Ошибка низкого ранга совпадает с теоремой Эккарта–Янга.

Код → nanolm/data.py: конвейер претрейн-корпуса из функций normalize_unicode, extract_text, detect_language, quality_filters, mask_pii, exact_dedup, minhash_signature, lsh_buckets, fuzzy_dedup, decontaminate, run_pipeline с отчётом по этапам. Задание в exercises/data.py, проверка: NANOLM_IMPL=exercises pytest tests/test_data.py -v. python scripts/data_pipeline.py даёт отчёт конвейера и обучение одной и той же TINY-модели на сыром и на чистом корпусе. Это отдельная неделя 15b: лаборатория данных: теория (NFKC, MinHash, выбор b и r, деконтаминация, PII и лицензии), задания и вопросы интервью. Если идёшь строго по 24 неделям, сделай на неделе 15 её сжатый вариант на 8 часов (описан там же).

Математика (трек D): D21: MinHash и LSH для дедупликации; D22: смещение, дисперсия и shrinkage.

Интервью-вопрос недели: «Как работает LoRA и когда её не хватит?» Структура на 3 минуты: (1) первым идёт формула: W заморожена, обучается поправка ΔW = B·A ранга r; (2) цифра: W 4096×4096 это 16.8 млн чисел, адаптер при r = 8 всего 65 536, 0.4%; градиенты и состояние Adam нужны только адаптерам, поэтому из 16 байт на параметр (неделя 9) у замороженного веса остаются 2, у QLoRA полбайта; (3) инициализация: B = 0, на старте выход не меняется; после обучения B·A вливается в W, и инференс ничего не стоит сверху; (4) главный вывод: ранг это потолок, а не ручка «побольше, значит лучше»: если нужная правка полноранговая, низкий ранг её не закроет никогда; (5) жди «а если обнулить и A, и B»: градиент по каждой пропорционален другой, оба нулевые, обучение не стартует.

Результаты недели

  • Могу реализовать LoRALinear, apply_lora, merge_lora и пройти все тесты модуля.
  • Могу посчитать число обучаемых параметров и экономию памяти LoRA для заданного ранга и набора слоёв.
  • Могу объяснить, что именно выучит модель, если не маскировать лосс на промпте.
  • Могу описать конвейер near-duplicate дедупликации через MinHash и LSH.

Самопроверка

  1. Почему B инициализируют нулями, а A случайно, и что будет, если наоборот?
  2. Почему ранг это потолок качества LoRA, а не ручка «побольше, значит лучше»?
  3. Что такое деконтаминация и почему без неё бенчмарк ничего не доказывает?

В приложении у недели есть навыки для самооценки, вопросы с проверкой ответа, задачи с кодом на Python и тьютор по материалам курса.

Учиться в приложении: тьютор, задачи с кодом
← НазадНеделя 14. Scaling laws, точность, параллелизм Дальше →Неделя 16. RL: от REINFORCE до PPO

С нуля
С нуля: курс по LLM

  • Главная
  • Программа курса
  • Приложение
  • Конфиденциальность
  • Условия

Текст курса распространяется по лицензии CC BY-NC-SA 4.0, код nanolm по лицензии Apache-2.0.