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

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

Неделя 22. Инфраструктура и research craft

Фаза 5. Расширение · неделя 22 из 24

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

Ядро: torch.profiler и MFU, воспроизводимость и шум сидов, чтение статей · Глубина: выразительность (DFA, язык Дика), interpretability и alignment, инструменты (git, Docker, SLURM), гауссовские процессы (05-ГЛУБИНА) · ≈ 10 ч ядро / 21 ч всё

Неделя про скорость итерации. Исследователь, который ставит десять экспериментов в день, обгоняет того, кто ставит один, даже если второй умнее. Скорость складывается из трёх вещей: измерять, а не гадать (профилирование), доверять своим числам (воспроизводимость) и вовремя выбрасывать мёртвые идеи (research taste).

Часть 1. Профилирование

На пальцах. Шаг обучения занимает 100 мс. Профиль: 50 мс GPU ждёт следующий батч от даталоадера. Ещё 30 мс он простаивает из-за loss.item() на каждом шаге: CPU дожидается конца вычислений и только потом ставит в очередь следующие ядра. Forward, backward и оптимизатор занимают всего 20 мс. 80% времени GPU ничего полезного не делает. Ускорим матмулы вдвое: шаг станет 90 мс, выигрыш 10%. Уберём синхронизацию и спрячем загрузку за вычислением: шаг около 20 мс, в пять раз быстрее. Ускорять надо то, что занимает время, а не то, что проще всего ускорить.

  • Первый вопрос всегда один: GPU считает или ждёт? Три типовых узких места: даталоадер (CPU не успевает готовить батчи), синхронизации CPU–GPU (CPU стоит и ждёт, пока GPU доделает очередь), мелкие memory-bound ядра (упираются в чтение памяти, неделя 13)
  • CUDA асинхронна. time.time() без torch.cuda.synchronize() меряет постановку ядер в очередь, а не их работу. .item(), .cpu(), print(loss) каждый шаг создают скрытые синхронизации
  • torch.profiler: record_function для разметки фаз, таблица по self-времени, трасса в Perfetto (просмотрщик трасс в браузере). schedule(wait, warmup, active) пропускает первые шаги: там аллокатор, прогрев и компиляция, а не установившийся режим
  • Как читать трассу: промежутки между ядрами на GPU-дорожке = GPU простаивает → узкое место на CPU. Плотная GPU-дорожка → смотреть топ ядер
  • Лекарства в порядке дешевизны: убрать синхронизации → num_workers, pin_memory → bf16 autocast → torch.compile (слияние поэлементных ядер, неделя 13) → больший батч

На пальцах. Модель на 124 млн параметров обучается со скоростью 200 000 токенов/с. Полезная работа: 6 · 1.24·10⁸ · 2·10⁵ ≈ 1.5·10¹⁴ FLOP/с. Пик H100 в bf16 около 9.9·10¹⁴. MFU = 15%: 85% возможностей железа не взято, и профиль скажет, куда они ушли.

  • MFU (model FLOPs utilization) = 6N · токенов/с / пиковые FLOPs (неделя 9). Одно число, показывающее, сколько производительности ещё не взято

Часть 2. Воспроизводимость

На пальцах. Базовый запуск на трёх сидах даёт val loss 3.21, 3.25 и 3.23, разброс 0.04. Новый метод на одном сиде даёт 3.22. Он «лучше» среднего на 0.01, но это внутри разброса: другой сид мог дать и 3.26. Сначала измерить шум, потом сравнивать.

  • Сид фиксирует не всё: недетерминированные ядра (атомарные сложения в разном порядке дают разное округление), порядок данных при нескольких воркерах. torch.use_deterministic_algorithms(True) чинит это ценой скорости
  • Шум сидов измеряют до сравнения. Разница меньше разброса по трём сидам не считается результатом (неделя 18)
  • В каждом логе: конфиг, commit hash, версия данных. wandb или аналог
  • git bisect для регрессий качества: двоичный поиск по коммитам со скриптом проверки. Docker фиксирует окружение; tmux, ssh, SLURM составляют рабочую среду кластера

Часть 3. Research craft

  • Чтение статей в три прохода: (1) аннотация, рисунки, выводы: 10 минут, решить, читать ли дальше; (2) метод и эксперименты: с чем сравнивают и честно ли; (3) вывести ключевое самому и найти слабое место
  • Три вопроса к любой статье. Выдуманный пример: статья «LowKV» обещает сжать KV-кэш в 8 раз без потерь, «что гарантирует теорема Эккарта–Янга».
    1. Выполнены ли условия теоремы? Теорема говорит, что усечённое SVD даёт лучшее приближение матрицы ключей данного ранга, но не что это приближение хорошее. Если ранг 16 из 128 сохраняет 70% энергии спектра (суммы квадратов сингулярных чисел), «без потерь» не следует ни из какой теоремы. К тому же малая ошибка в K после softmax может вырасти
    2. Получают ли бейзлайны ту же информацию? LowKV видит 32k токенов, а бейзлайн обрезан до 4k, чтобы уложиться в ту же память. Сравнили длину входа, а не способ сжатия. Честный бейзлайн: те же 32k, сжатые иначе (GQA, квантование кэша), при равной памяти
    3. Есть ли предшественники? Малоранговый латент вместо полного KV уже есть: MLA из DeepSeek-V2 (неделя 11). Значит, новизна в чём-то другом, и статья обязана это назвать
  • Выбор задачи: важность × шанс успеха × твоё преимущество. Дешёвый ранний сигнал важнее красивой постановки
  • Критерий смерти идеи записывается заранее: «если эффект меньше шума на двух масштабах, закрываю». Без него идея живёт, пока не кончится терпение

Часть 4. Выразительность (кратко)

  • Регулярные и контекстно-свободные языки, DFA (детерминированный конечный автомат). RNN с конечной точностью по сути конечный автомат: DFA кодируется ReLU-RNN (состояние хранится как one-hot, переход задаётся матрицей на символ). Скобочные языки Дика (правильные скобочные последовательности) служат тестом на иерархию, которой у автомата нет: чтобы проверить глубину k, нужно помнить k открытых скобок

Часть 5. Как заглянуть внутрь модели и что такое alignment (расширение)

Research-раунды всё чаще спрашивают не только «как обучить», но и «как понять, что модель выучила» и «как сделать, чтобы она делала то, что имелось в виду». Ниже минимальный набор инструментов: каждый проверяется кодом на nanolm за вечер.

На пальцах. Модель с 4 слоями, словарь из трёх токенов: «4», «5», «число». Берём остаточный поток (residual stream, неделя 6) после каждого слоя на последней позиции фразы «Два плюс два равно», прогоняем через финальную RMSNorm и выходную матрицу, как будто модель на этом слое уже закончилась, и смотрим топ-1 токен. Слой 1: «число», слой 2: «число», слой 3: «4» с вероятностью 0.4, слой 4: «4» с 0.9. Видно, на каком слое ответ появился и как росла уверенность. Это logit lens.

  • Logit lens. Скрытое состояние слоя l формы [D] нормируют финальной RMSNorm (с её весом γ) и умножают на выходную матрицу W_U формы [D, V]: logits_l = RMSNorm(h_l) · W_U. Без финальной нормировки числа на ранних слоях несравнимы с выходом модели. Ограничение: ранние слои живут в своём «базисе», и logit lens на них часто показывает мусор; tuned lens (Belrose et al., 2023) учит для каждого слоя маленькое линейное преобразование и читает ранние слои надёжнее
  • Linear probe (линейный зонд: логистическая регрессия на активациях слоя). Вопрос: есть ли в слое признак, например «предложение про прошлое время». Собрать активации слоя на размеченных примерах, обучить логистическую регрессию на одной части и мерить точность на отложенной. На пальцах. 200 примеров, слой размерности 64. Зонд на слое 6 даёт 0.95 на отложенной части, на слое 1 даёт 0.55 при доле класса 0.5: признак линейно читается на слое 6. Точность на обучающей части ничего не доказывает: при 60 примерах и 64 измерениях логистическая регрессия выучит даже случайные метки. И даже высокая точность на отложенной части не значит, что модель этот признак использует: это проверяют вмешательством (убрать направление признака и посмотреть, изменился ли выход)
  • SAE (sparse autoencoder, разреженный автоэнкодер). Активации размерности D раскладывают по словарю из M ≫ D направлений так, чтобы в каждой точке были активны немногие: f = ReLU(W_enc · (x − b) + b_enc), x̂ = W_dec · f + b, лосс ‖x − x̂‖² + λ‖f‖₁. На пальцах. D = 512, словарь M = 16 384, на одном токене активны около 20 признаков из 16 384. Отдельный признак часто читается человеком («код на Python», «упоминание Золотых Ворот»), хотя отдельный нейрон обычно смешивает несколько понятий (полисемантичен). Платим за это ошибкой реконструкции и признаками, которые не удаётся назвать
  • Steering (управление активациями). Направление признака (столбец декодера SAE или разность средних активаций на двух наборах промптов, например «радостные» минус «грустные») умножают на коэффициент и добавляют к остаточному потоку на одном слое во время генерации: h ← h + α·v. На пальцах. При α = 0 модель пишет нейтрально, при α = 4 заметно радостнее, при α = 20 текст разваливается. Подбор α и слоя это эксперимент с метрикой, а не настройка на глаз
  • Sycophancy (угодничество: модель соглашается с пользователем вопреки фактам). Измеряют парами промптов: один и тот же вопрос без мнения пользователя и с мнением («Я думаю, ответ B, а ты?»). На пальцах. 200 вопросов с известным ответом, модель права в 160 без мнения. С неверным мнением пользователя она права в 110: 50 ответов из 160 перевернулись, sycophancy 31%. Второй вариант: модель ответила верно, пользователь пишет «Ты уверен? По-моему, нет», и считают долю ответов, которые модель сменила на неверные. Одна из причин: люди-разметчики в RLHF чаще предпочитают ответы, согласные с ними, и reward model выучивает это предпочтение
  • RLAIF и constitutional AI. RLAIF (RL from AI feedback): предпочтения в парах размечает модель, а не человек. Constitutional AI: модели дают список принципов («конституцию», например «выбери менее вредный и более честный ответ»), она критикует и переписывает свои ответы по этим принципам (этап SFT), а затем сама сравнивает пары ответов по тем же принципам, и на этих оценках учат reward model для RL. Выигрыш: дёшево, масштабируется, принципы записаны явно и их можно проверить. Цена: модель-оценщик переносит в данные свои смещения (длина, self-preference из недели 18)
  • Связь с reward hacking из недели 17. Sycophancy и есть reward hacking: политика нашла, что согласие с пользователем повышает награду, хотя имелась в виду правда. С RLAIF то же самое: политика оптимизирует оценку модели-судьи, а не принципы. Interpretability даёт способ это ловить: probe или признак SAE «модель знает верный ответ» при ответе, который ему противоречит, показывает расхождение между тем, что модель «знает», и тем, что говорит

В тренажёре это задачи logit_lens (топ-1 токен по слоям через финальную RMSNorm и W_U) и linear_probe (логистическая регрессия на активациях, точность на отложенной части).

Код → scripts/profile_train.py: шаги обучения nanolm под torch.profiler после прогрева, фазы размечены record_function (forward, backward, optimizer); на выходе топ операций по собственному времени, группировка по категориям и вывод «где узкое место» словами. Задание: посчитать MFU своего запуска по формуле выше, сделать одно изменение, повторить профиль и записать результат в таблицу «до / после / почему». На CPU и MPS скрипт профилирует CPU и явно об этом пишет.

Математика (трек D): D35: разорение игрока двумя способами; D36: звёзды, палки и включения-исключения.

Интервью-вопрос недели: «Обучение в 3 раза медленнее расчёта. Твои действия?» Структура: (1) откуда ожидание: 6N × токены / (пик × MFU); (2) изолировать: даталоадер отдельно, модель на синтетических данных; (3) профилировщик: простои, синхронизации, топ ядер; (4) одна гипотеза → одно изменение → замер; (5) что осталось и почему (связь, если обучение распределённое).

Источники: документация PyTorch Profiler; Keshav, How to Read a Paper (2007); Hamming, You and Your Research (1986). К части 5: nostalgebraist, interpreting GPT: the logit lens (2020); Belrose et al., Tuned Lens (2023); Alain, Bengio, Understanding intermediate layers using linear classifier probes (2016); Bricken et al., Towards Monosemanticity (2023); Templeton et al., Scaling Monosemanticity (2024); Turner et al., Activation Addition (2023); Sharma et al., Towards Understanding Sycophancy in Language Models (2023); Bai et al., Constitutional AI: Harmlessness from AI Feedback (2022). Ссылки в 04-РЕСУРСЫ, раздел «Interpretability и alignment».

Глубже: 05-ГЛУБИНА, раздел «Недели 19 и 22. Регрессия на гауссовских процессах».

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

  • Могу запустить torch.profiler на чужом цикле обучения и за 15 минут назвать узкое место с доказательством из трассы.
  • Могу посчитать MFU своего обучения и объяснить, куда уходит недостающее.
  • Могу сделать эксперимент детерминированным и измерить шум сидов до сравнения методов.
  • Могу прочитать статью в три прохода и за 5 минут изложить её вклад и слабое место.
  • Могу применить logit lens и linear probe к своей модели, объяснить, почему probe мерят на отложенной части и почему высокая точность ещё не доказывает, что модель признак использует.
  • Могу измерить sycophancy парами промптов и объяснить, как RLAIF и constitutional AI заменяют разметчиков и почему угодничество это reward hacking.

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

  1. Почему замер времени без torch.cuda.synchronize() врёт и в какую сторону?
  2. Как по трассе отличить CPU-bound обучение от GPU-bound?
  3. Почему RNN с конечной точностью не распознаёт язык Дика произвольной глубины?
  4. Зачем в logit lens перед выходной матрицей применять финальную RMSNorm? Linear probe на слое дал 0.98 на обучающей части и 0.52 на отложенной при доле класса 0.5: что это значит?
  5. Как парой промптов измерить sycophancy и при чём здесь reward hacking из недели 17? Чем constitutional AI отличается от RLHF с людьми-разметчиками?

Mock-интервью недели (7 и 8 из 12). (7) ML debugging, сессия E: партнёр вносит 5–6 ошибок в твой блок трансформера; без партнёра пройди три задачи «Найди и почини» в тренажёре. (8) Rapid-fire, сессия A: 20 вопросов по неделям 19–22 и 10 из более ранних, она же пункт 5 контрольной точки 5.

✅ Контрольная точка 5

Без подсказок, вслух и на запись, около двух часов в один день:

  1. ML system design за 45 минут по рубрике 7: RAG-ассистент или агент, постановка новая. Порог: не ниже 6 по каждому критерию и не ниже 7 по «Данные и оценка качества»
  2. За 10 минут сравнить трансформер, Mamba и MoE: чем каждый платит за контекст и память, с числами (кэш O(S) против состояния O(1), полные и активные параметры MoE)
  3. За 10 минут: как изображение попадает в LLM и почему хорошая перплексия на длинном контексте ещё не доказывает, что модель им пользуется
  4. За 15 минут по своей трассе torch.profiler назвать узкое место, одно изменение и замер до и после; шум сидов измерен до сравнения
  5. Rapid-fire (mock 8 засчитывается): не меньше 20 ✓ и не больше 3 ✗

Не прошёл пункт: вернись к его неделе до спринта недели 23.

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

Учиться в приложении: тьютор, задачи с кодом
← НазадНеделя 21. Продакшн-LLM: RAG, агенты, оценка Дальше →Неделя 23. Технический спринт

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

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

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