Какие знаешь оптимизаторы, в чем их идеи и различия?
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Оптимизаторы в глубоком обучении: полный обзор
Оптимизаторы — это алгоритмы обновления весов сети при обучении. Это фундамент successful training. Рассмотрю все популярные подробно.
Основная идея оптимизаторов
Задача: Минимизировать loss функцию L(w)
Итеративный процесс:
1. Вычисляем градиент: ∇L(w)
2. Обновляем веса: w_new = w_old - α * градиент
3. Повторяем
Разные оптимизаторы отличаются в шаге 2:
- Как быстро обновляем (learning rate)
- Используем ли историю градиентов
- Адаптируем ли rate к разным параметрам
1. SGD (Stochastic Gradient Descent) — базовый
Самый простой и понятный оптимизатор.
# Математика:
w_t = w_{t-1} - α * ∇L(w_{t-1})
Где:
α — learning rate (скорость обучения)
∇L(w) — градиент функции потерь
Реализация:
import torch
from torch.optim import SGD
model = MyModel()
optimizer = SGD(model.parameters(), lr=0.01) # lr = learning rate
for epoch in range(100):
for X_batch, y_batch in train_loader:
# Forward pass
outputs = model(X_batch)
loss = criterion(outputs, y_batch)
# Backward pass
optimizer.zero_grad() # Обнуляем старые градиенты
loss.backward() # Вычисляем градиенты
optimizer.step() # Обновляем веса
Плюсы:
- Простой и понятный
- Низкое потребление памяти
- Работает (если подобрать learning rate)
Минусы:
- Медленная сходимость
- Одинаковый learning rate для всех параметров
- Застревает в локальных минимумах
- Нужно подбирать learning rate вручную
2. Momentum — с инерцией
Добавляет инерцию (как мяч катится с горы).
# Математика:
v_t = β * v_{t-1} + ∇L(w_t) (накапливаем градиент)
w_t = w_{t-1} - α * v_t (используем накопленный импульс)
Обычно β = 0.9
Идея: Если градиент показывает в одном направлении несколько раз подряд, увеличиваем шаг в этом направлении.
optimizer = SGD(model.parameters(), lr=0.01, momentum=0.9)
# То же самое что и выше, но с momentum!
for epoch in range(100):
for X_batch, y_batch in train_loader:
outputs = model(X_batch)
loss = criterion(outputs, y_batch)
optimizer.zero_grad()
loss.backward()
optimizer.step() # Теперь с инерцией
Плюсы:
- Быстрее SGD
- Преодолевает локальные минимумы
- Ускоряет сходимость
Минусы:
- Может "перепрыгнуть" минимум
- Другой гиперпараметр (momentum = β)
3. Nesterov Momentum — улучшенный momentum
Заглядывает на один шаг вперёд перед вычислением градиента.
# Математика:
v_t = β * v_{t-1} + ∇L(w_{t-1} - α * v_{t-1}) # Заглядываем вперёд!
w_t = w_{t-1} - α * v_t
optimizer = SGD(model.parameters(), lr=0.01, momentum=0.9, nesterov=True)
Плюсы:
- Немного быстрее чем обычный momentum
- Умнее выбирает направление
Минусы:
- Сложнее понять
- Маргинальное улучшение
4. AdaGrad — адаптивный learning rate
Разные параметры обновляются с разной скоростью.
# Математика:
g_t = ∇L(w_t) # Текущий градиент
G_t = G_{t-1} + g_t² # Накапливаем квадраты
w_t = w_{t-1} - (α / √(G_t + ε)) * g_t # Адаптивный learning rate
Где:
G_t — накопленная сумма квадратов градиентов
ε — маленькое число для стабильности (1e-8)
Идея: Параметры с большими градиентами → уменьшаем их learning rate. Параметры с малыми градиентами → увеличиваем их learning rate.
optimizer = torch.optim.Adagrad(model.parameters(), lr=0.01)
Плюсы:
- Адаптивный learning rate
- Не требует подбора momentum
- Хорошо для sparse данных
Минусы:
- Learning rate монотонно падает → может зафиксироваться
- G_t растёт без ограничения
- В конце обучения learning rate может быть очень маленьким
5. RMSprop — улучшенный AdaGrad
Исправляет проблему зануляющегося learning rate в AdaGrad.
# Математика:
v_t = β * v_{t-1} + (1 - β) * (∇L(w_t))² # Экспоненциальное сглаживание
w_t = w_{t-1} - (α / √(v_t + ε)) * ∇L(w_t)
Обычно β = 0.9
Идея: Вместо накопления всех старых градиентов, берём их экспоненциально взвешенное среднее.
optimizer = torch.optim.RMSprop(model.parameters(), lr=0.001, alpha=0.99)
Плюсы:
- Фиксит проблему AdaGrad
- Адаптивный learning rate
- Хороший баланс
Минусы:
- Ещё один гиперпараметр (beta/alpha)
6. ADAM (Adaptive Moment Estimation) — КОРОЛЬ оптимизаторов
Комбинирует лучшее из Momentum и RMSprop.
# Математика:
m_t = β₁ * m_{t-1} + (1 - β₁) * ∇L(w_t) # 1st moment (mean)
v_t = β₂ * v_{t-1} + (1 - β₂) * (∇L(w_t))² # 2nd moment (variance)
m̂_t = m_t / (1 - β₁ᵗ) # Bias correction
v̂_t = v_t / (1 - β₂ᵗ)
w_t = w_{t-1} - α * m̂_t / (√v̂_t + ε)
Обычно β₁ = 0.9, β₂ = 0.999, ε = 1e-8
Идея:
- m_t = "импульс" (как momentum)
- v_t = "адаптивный rate" (как RMSprop)
- Combine both!
optimizer = torch.optim.Adam(model.parameters(), lr=0.001) # lr обычно 0.001
# Это самый популярный оптимизатор!
for epoch in range(100):
for X_batch, y_batch in train_loader:
outputs = model(X_batch)
loss = criterion(outputs, y_batch)
optimizer.zero_grad()
loss.backward()
optimizer.step() # ADAM делает "умное" обновление
Плюсы:
- Работает отлично на большинстве задач
- Мало гиперпараметров
- Быстрая сходимость
- Default learning rate часто подходит (0.001)
- Мало требует подбора
Минусы:
- Может сходиться к более плохому решению (на некоторых задачах)
- Требует больше памяти (хранит m и v)
- Может переобучиться если не добавить regularization
Сравнение оптимизаторов
┌─────────────┬──────────┬──────────┬────────┬──────────┬──────────┐
│ Оптимизатор │ Скорость │ Качество │ Память │ Гиперп. │ Популяр. │
├─────────────┼──────────┼──────────┼────────┼──────────┼──────────┤
│ SGD │ ✓ │ ★★★ │ ✓✓✓ │ ✓✓ │ ★★ │
│ Momentum │ ★★ │ ★★★ │ ✓✓ │ ★★ │ ★★★ │
│ Nesterov │ ★★★ │ ★★★ │ ✓✓ │ ★★ │ ★★ │
│ AdaGrad │ ★★ │ ★★ │ ✓ │ ★★★ │ ★ │
│ RMSprop │ ★★★ │ ★★★ │ ✓✓ │ ★★★ │ ★★ │
│ ADAM │ ★★★ │ ★★★★ │ ✓ │ ★★★★ │ ★★★★★ │
└─────────────┴──────────┴──────────┴────────┴──────────┴──────────┘
Другие современные оптимизаторы
AdamW (ADAM + Weight Decay)
# Правильная L2 регуляризация!
optimizer = torch.optim.AdamW(model.parameters(), lr=0.001, weight_decay=0.01)
# Vs просто Adam с L2:
optimizer = torch.optim.Adam(model.parameters(), lr=0.001, weight_decay=0.01) # Неправильно!
# AdamW лучше для регуляризации на больших моделях
LAMB (Layer-wise Adaptive Moments)
optimizer = torch.optim.LAMB(model.parameters(), lr=0.001)
# Хорош для очень больших batch sizes (DDP training)
RAdam (Rectified Adam)
from torch.optim import RAdam
optimizer = RAdam(model.parameters(), lr=0.001)
# Лучше на маленьких batch sizes
# Исправляет большую дисперсию в начале обучения
Learning Rate Schedulers (изменение скорости обучения)
import torch.optim.lr_scheduler as lr_scheduler
optimizer = torch.optim.Adam(model.parameters())
# 1. Step decay (каждые N эпох умножаем на 0.1)
scheduler = lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)
# 2. Exponential decay
scheduler = lr_scheduler.ExponentialLR(optimizer, gamma=0.95)
# 3. Cosine annealing (график как косинус)
scheduler = lr_scheduler.CosineAnnealingLR(optimizer, T_max=100)
# 4. Warmup + decay (популярно в Transformers)
from torch.optim.lr_scheduler import LambdaLR
def warmup_lambda(epoch):
if epoch < 10:
return epoch / 10
else:
return 1.0 - (epoch - 10) / 90
scheduler = LambdaLR(optimizer, lr_lambda=warmup_lambda)
# Использование:
for epoch in range(100):
train_one_epoch()
scheduler.step() # Обновляем learning rate
Практические советы
# 1. ДЛЯ БОЛЬШИНСТВА ЗАДАЧ:
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
# Просто работает!
# 2. ДЛЯ БОЛЬШИХ МОДЕЛЕЙ (BERT, GPT):
optimizer = torch.optim.AdamW(model.parameters(), lr=2e-5, weight_decay=0.01)
scheduler = lr_scheduler.LinearLR(optimizer, start_factor=0.1, total_iters=1000)
# 3. ДЛЯ CNN + Computer Vision:
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9, nesterov=True)
scheduler = lr_scheduler.StepLR(optimizer, step_size=30, gamma=0.1)
# 4. ДЛЯ ОЧЕНЬ БОЛЬШИХ BATCH SIZES (Multi-GPU):
optimizer = torch.optim.LAMB(model.parameters(), lr=0.1)
# 5. ДЛЯ МАЛЕНЬКИХ ДАТАСЕТОВ:
optimizer = torch.optim.RAdam(model.parameters(), lr=0.001)
# 6. С L2 РЕГУЛЯРИЗАЦИЕЙ:
optimizer = torch.optim.AdamW(model.parameters(), weight_decay=0.01)
Визуализация оптимизаторов
import numpy as np
import matplotlib.pyplot as plt
# Траектории разных оптимизаторов на контурной карте
fig, axes = plt.subplots(2, 3, figsize=(15, 10))
# Каждый subplot показывает как разный оптимизатор идёт к минимуму
for ax, (name, optimizer_class) in enumerate([
('SGD', torch.optim.SGD),
('Momentum', lambda p: torch.optim.SGD(p, momentum=0.9)),
('Adam', torch.optim.Adam),
('AdaGrad', torch.optim.Adagrad),
('RMSprop', torch.optim.RMSprop)
]):
# Симуляция оптимизации на 2D функции
# ...
# Рисуем trajectory
Как выбрать оптимизатор
Процесс выбора:
1. НАЧНИ с Adam
→ Работает 80% времени
→ Мало нужно подбирать
2. Если не работает хорошо:
→ Попробуй SGD + Momentum
→ Попробуй AdamW + scheduler
→ Попробуй RMSprop
3. Если очень большая модель:
→ AdamW или LAMB
→ С learning rate scheduler
4. Если маленькое количество данных:
→ RAdam (менее нестабильен в начале)
5. Если Computer Vision большие модели:
→ SGD + Momentum + scheduler
→ (исторически хорошо работает)
6. Если NLP Transformer:
→ AdamW + Linear scheduler + warmup
→ (стандарт в Hugging Face)
Заключение
Важные оптимизаторы:
- SGD — baseline, понимать как работает
- Momentum — добавляет инерцию
- Adam — король, используй по умолчанию
- AdamW — лучше Adam с регуляризацией
- RMSprop — хороший выбор для RNN
Главное правило:
┌─────────────────────────┐
│ Начни с Adam │
│ Добавь scheduler │
│ Если плохо → SGD + Mom │
│ Если ок → добавь L2 │
│ Готово! │
└─────────────────────────┘
Learning rate:
- Adam: 0.0001 - 0.01 (обычно 0.001)
- SGD: 0.01 - 0.1
- Трансформеры: 1e-5 - 5e-5
Главное: не бойся экспериментировать! Основы везде одинаковые.