Машинное обучение
Оптимизаторы: SGD, Adam, RMSProp
Одна и та же нейросеть с одной и той же архитектурой может обучиться за 10 минут или не сойтись вообще никогда. Разница - в выборе оптимизатора и learning rate. Команда Google Brain потратила миллионы GPU-часов на эксперименты и выяснила, что для больших языковых моделей переход с Adam на SGD с Momentum меняет время обучения в 3-5 раз. При бюджете в десятки миллионов долларов за один запуск обучения, правильный оптимизатор - это не академический вопрос, а решение ценой в миллионы. В этом уроке мы разберём, как работают главные оптимизаторы и когда какой применять.
- **Обучение GPT и LLM** - OpenAI, Google, Meta используют AdamW с warmup и cosine scheduling для обучения моделей стоимостью в десятки миллионов долларов, и неправильный выбор lr schedule может удвоить бюджет
- **Computer Vision в продакшене** - Tesla Autopilot, медицинская диагностика, промышленный контроль качества: SGD + Momentum с cosine annealing остаётся стандартом, потому что даёт лучшую generalization на реальных данных
- **Fine-tuning предобученных моделей** - адаптация BERT, GPT, Stable Diffusion к конкретной задаче требует крошечного lr (2e-5) с warmup, иначе модель забывает предобученные знания (catastrophic forgetting)
Полвека идей, сошедшихся в Adam
Современные оптимизаторы - это наслоение идей, копившихся полвека. В 1964 году советский математик Борис Поляк предложил momentum (метод тяжёлого шарика), сглаживающий шаги градиентного спуска за счёт инерции. В 1983 году Юрий Нестеров улучшил его ускоренным градиентом, который «заглядывает вперёд». В 2011 году Джон Дучи с соавторами представили AdaGrad - первый адаптивный метод с индивидуальным learning rate для каждого параметра. Около 2012 года Джеффри Хинтон в своём курсе на Coursera предложил RMSprop, исправивший затухание шага в AdaGrad. Наконец, в 2014 году Дидерик Кингма и Джимми Ба объединили momentum и адаптивный шаг в Adam, который стал оптимизатором по умолчанию для большинства глубоких сетей. Каждая идея решала слабость предыдущей - и вместе они слились в стандарт индустрии.
Предварительные знания
Momentum - физическая интуиция
Обычный SGD (Stochastic Gradient Descent) обновляет веса строго по направлению градиента на текущем шаге. Проблема в том, что поверхность функции потерь (loss surface) редко бывает гладкой и круглой. Чаще она вытянутая, как узкое ущелье: вдоль одной оси потери меняются медленно, а вдоль другой - резко. SGD начинает **осциллировать** поперёк ущелья (где градиент большой), почти не продвигаясь вдоль него (где градиент маленький). Результат - обучение идёт мучительно медленно.
**Momentum** решает эту проблему по аналогии с физикой: представьте шар, катящийся по поверхности. Шар не просто следует наклону в каждой точке - он **накапливает скорость** (velocity). Если наклон постоянно направлен в одну сторону, скорость растёт. Если наклон меняет направление (осцилляции), скорости в противоположных направлениях гасят друг друга. В итоге шар быстро движется вдоль ущелья и не осциллирует поперёк.
**Почему beta = 0.9?** При beta = 0.9 momentum "помнит" примерно 10 последних градиентов (1 / (1 - 0.9) = 10). Градиенты, указывающие в одном направлении, суммируются и ускоряют движение. Градиенты в противоположных направлениях (осцилляции) взаимно гасятся. - **beta = 0** - нет momentum, обычный SGD - **beta = 0.9** - стандарт, хорошо работает почти всегда - **beta = 0.99** - сильный momentum, медленнее реагирует на изменения - **beta -> 1** - почти не забывает прошлое, может проскочить минимум
**Nesterov Momentum** - улучшение обычного momentum. Идея: прежде чем вычислить градиент, сделать предварительный шаг по текущей скорости ("заглянуть вперёд"). Если momentum несёт нас в неправильном направлении, Nesterov корректирует курс раньше. На практике Nesterov даёт небольшое, но стабильное улучшение сходимости - поэтому `nesterov=True` рекомендуется как значение по умолчанию при использовании SGD + Momentum.
Почему SGD с Momentum сходится быстрее, чем обычный SGD, на вытянутых (ill-conditioned) loss surfaces?
RMSProp - адаптивный learning rate
Momentum решает проблему осцилляций, но у него есть ограничение: **один и тот же learning rate для всех параметров**. А что если одни параметры получают большие градиенты (и их нужно обновлять осторожно), а другие - маленькие (и их можно обновлять смелее)? Представьте словарь embeddings: слово "the" встречается в каждом батче и получает огромные градиенты, а слово "quasar" - раз в тысячу батчей с крошечным градиентом. Один lr не подходит обоим.
**RMSProp** (Root Mean Square Propagation) адаптирует learning rate для каждого параметра отдельно. Идея: отслеживать **скользящее среднее квадратов градиентов** для каждого параметра. Если параметр регулярно получает большие градиенты, его lr уменьшается. Если градиенты маленькие - lr увеличивается. Результат: все параметры обновляются с примерно одинаковой "скоростью" независимо от масштаба градиентов.
**Историческая справка:** RMSProp был предложен **Geoffrey Hinton** в лекции на Coursera в 2012 году. Он **никогда не был формально опубликован** как научная статья - просто слайд в онлайн-курсе. Несмотря на это, RMSProp стал одним из самых популярных оптимизаторов и используется миллионами практиков. Это редкий случай, когда важный алгоритм распространился исключительно через устную традицию и неформальные ссылки. Предшественник RMSProp - **AdaGrad** (2011). Проблема AdaGrad: он накапливает ВСЕ квадраты градиентов с начала обучения, и lr монотонно падает до нуля. RMSProp исправляет это скользящим средним - старые градиенты "забываются".
**Learning rate для адаптивных оптимизаторов:** Для SGD типичный lr: 0.01 - 0.1 Для RMSProp/Adam типичный lr: 0.0001 - 0.001 Адаптивные методы уже масштабируют lr для каждого параметра, поэтому базовый lr должен быть меньше. Если взять lr=0.01 для RMSProp, обучение может разойтись (diverge).
Что делает RMSProp с параметром, который регулярно получает очень большие градиенты?
Adam - лучшее из двух миров
Adam (Adaptive Moment Estimation) объединяет идеи **Momentum** и **RMSProp** в одном оптимизаторе. Momentum накапливает первый момент (среднее градиентов, направление), RMSProp - второй момент (среднее квадратов градиентов, масштаб). Adam отслеживает оба: первый момент определяет **направление** обновления, второй момент - **размер шага** для каждого параметра. Результат - быстрая сходимость (Momentum) с адаптивным learning rate (RMSProp).
**Зачем нужна Bias Correction?** В начале обучения m и v инициализированы нулями. На первом шаге: - m = 0.9 * 0 + 0.1 * g = 0.1 * g - сильно занижено! - v = 0.999 * 0 + 0.001 * g^2 = 0.001 * g^2 - ещё сильнее занижено! Bias correction компенсирует это: - m_hat = m / (1 - 0.9^1) = 0.1*g / 0.1 = g - правильная оценка - v_hat = v / (1 - 0.999^1) = 0.001*g^2 / 0.001 = g^2 - правильно Через 10-20 шагов коррекция становится незначительной (beta^t -> 0), но на первых шагах она критически важна для стабильности.
Почему Adam стал **оптимизатором по умолчанию** для большинства задач? Он почти не требует подбора гиперпараметров: значения beta1=0.9, beta2=0.999, lr=0.001 работают на удивление хорошо для широкого спектра архитектур и задач. Adam особенно хорош для: sparse gradients (NLP, embeddings), зашумлённых градиентов (маленькие батчи), нестационарных задач (reinforcement learning). Если не знаете, какой оптимизатор выбрать - начинайте с Adam.
**AdamW vs Adam:** В обычном Adam weight decay (L2 регуляризация) применяется к градиенту до адаптации, что ослабляет его эффект для параметров с большими градиентами. **AdamW** (decoupled weight decay) применяет weight decay напрямую к весам, независимо от адаптации. Это даёт более равномерную регуляризацию. AdamW стал стандартом для обучения Transformers - BERT, GPT, Vision Transformer все используют именно AdamW. Если вы работаете с Transformer-архитектурами, используйте AdamW.
Что отслеживает Adam помимо скользящего среднего квадратов градиентов (второй момент)?
Learning Rate Scheduling
Даже с адаптивными оптимизаторами вроде Adam, **базовый learning rate** остаётся важнейшим гиперпараметром. Постоянный lr - это компромисс: большой lr позволяет быстро исследовать пространство параметров в начале, но мешает точной настройке в конце (модель "прыгает" вокруг минимума). Маленький lr даёт точную настройку, но начало обучения занимает вечность. Решение - **менять lr во время обучения**: начать с большого и постепенно уменьшать.
- **Step Decay** - уменьшаем lr в N раз каждые K эпох (например, lr /= 10 каждые 30 эпох). Простая и эффективная стратегия, стандарт для ResNet
- **Exponential Decay** - lr = lr_0 * gamma^epoch (например, gamma=0.95). Плавное убывание, но lr может стать слишком маленьким раньше времени
- **Cosine Annealing** - lr следует косинусной кривой от начального значения до минимального. Плавнее step decay, популярна для state-of-the-art моделей
- **Warmup** - lr начинается с очень маленького значения и линейно растёт до целевого за первые N шагов. Критически важен для Transformers: без warmup обучение часто расходится
- **One-Cycle Policy** (Leslie Smith) - lr сначала растёт от min до max, потом падает обратно ниже min. Одна из лучших стратегий по соотношению простота/результат
| Стратегия | Когда использовать | Плюсы | Минусы |
|---|---|---|---|
| Step Decay | CNN (ResNet, VGG) | Простота, предсказуемость | Резкие скачки lr |
| Cosine Annealing | Большинство задач | Плавное убывание | Нужно знать T_max |
| Warmup + Cosine | Transformers (BERT, GPT) | Стабильность + плавность | Два гиперпараметра |
| One-Cycle | Быстрое обучение | Часто лучший результат | Нужен max_lr |
| Exponential | Простые задачи | Один параметр gamma | lr падает слишком быстро |
**Warmup - почему он нужен для Transformers?** На первых шагах обучения веса случайные, а значит gradient нестабилен и может быть очень большим. Если сразу применить большой lr, обновления будут огромными и модель "разлетится" (diverge). Warmup начинает с крошечного lr и линейно повышает его за 5-10% обучения. За это время веса получают разумные значения, градиенты стабилизируются, и модель готова к обучению с полным lr. Для Adam + Transformer стандарт: warmup 5-10% шагов, затем cosine decay.
Adam всегда лучше SGD, поэтому SGD устарел и его не стоит использовать
SGD с Momentum и правильным learning rate scheduling часто обобщает лучше Adam в задачах computer vision, достигая более высокой accuracy на тестовых данных
Итоги
- **Momentum** накапливает "скорость" обновления весов: градиенты в одном направлении суммируются и ускоряют сходимость, а осцилляции в противоположных направлениях взаимно гасятся. Beta=0.9 означает инерцию за последние ~10 шагов
- **RMSProp** адаптирует learning rate для каждого параметра отдельно: параметры с большими градиентами получают маленький lr, с маленькими - большой. Это выравнивает скорость обновления всех параметров
- **Adam** объединяет Momentum (первый момент - направление) и RMSProp (второй момент - масштаб), добавляя bias correction для первых шагов. Дефолтные параметры (lr=0.001, beta1=0.9, beta2=0.999) работают для большинства задач
- **Learning rate scheduling** меняет lr во время обучения: warmup стабилизирует начало, cosine annealing или step decay обеспечивают точную сходимость в конце. Для Transformers warmup обязателен
- **Нет универсально лучшего оптимизатора:** Adam - для прототипов и Transformers, SGD + Momentum - для computer vision, AdamW - для fine-tuning. Тот же выбор оптимизатора и lr, который отделяет 10-минутное обучение от бесконечного расхождения, может стоить миллионы долларов GPU-времени при масштабе Google Brain
Связанные темы
Оптимизаторы - центральный элемент обучения любой нейросети, связывающий теорию градиентного спуска с практикой глубокого обучения:
- Gradient Descent — Фундамент всех оптимизаторов: SGD, Momentum, RMSProp, Adam - это надстройки над базовым градиентным спуском. Понимание ландшафта loss surface и проблемы локальных минимумов критично для выбора оптимизатора
- CNN (Convolutional Neural Networks) — Для обучения CNN стандартом остаётся SGD + Momentum с cosine scheduling, а не Adam. Архитектура влияет на выбор оптимизатора: свёрточные слои лучше обобщают с SGD, attention-слои - с AdamW
- Transformers — Transformers требуют AdamW с warmup + cosine decay. Без warmup attention-механизм генерирует нестабильные градиенты на случайных весах, и обучение расходится
Вопросы для размышления
- Почему Adam с дефолтными параметрами работает хорошо для большинства задач, но SGD + Momentum часто даёт лучшую generalization в computer vision? Какое свойство минимумов loss surface может это объяснять?
- Если бы вы обучали модель на датасете, где 99% слов - частотные (the, is, a) и 1% - редкие специализированные термины, какой оптимизатор вы бы выбрали и почему?
- Warmup критически важен для Transformers, но не нужен для простых CNN. Что в архитектуре Transformer делает начало обучения особенно нестабильным?
Связанные уроки
- ml-09-gradient-descent — Оптимизаторы расширяют обычный градиентный спуск
- ml-26-backpropagation — Они потребляют градиенты, что выдаёт бэкпроп
- ml-43-hyperparameters — Скорость обучения и беты - ключевые гиперпараметры
- calc-19-gradient — Каждый шаг идёт вдоль градиента потерь
- opt-01 — Adam и SGD - методы оптимизации первого порядка
- alg-20-greedy