← Назад к вопросам

Как работает Adam оптимизатор?

2.0 Middle🔥 241 комментариев
#Глубокое обучение#Машинное обучение

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как работает Adam оптимизатор

Введение

Adam (Adaptive Moment Estimation) — это адаптивный алгоритм оптимизации, который является одним из наиболее популярных методов для обучения нейросетей. Он комбинирует идеи из Momentum и RMSprop.

История: от SGD к Adam

  1. SGD (Stochastic Gradient Descent): простой градиентный спуск

    • Минусы: медленная сходимость, зависит от learning rate
  2. Momentum: добавляет "инерцию" к обновлениям

    • Плюс: быстрее сходится в плоских регионах
    • Минус: может "проскочить" оптимум
  3. RMSprop: адаптивная скорость обучения для каждого параметра

    • Плюс: хорошо работает с разреженными градиентами
    • Минус: требует корректировки параметров
  4. Adam: комбинирует Momentum и RMSprop

    • Плюс: хорошо работает на практике, мало нужно подстраивать

Математика Adam

Adam вычисляет экспоненциальное скользящее среднее (exponential moving average) градиентов и их квадратов:

m_t = beta1 * m_{t-1} + (1 - beta1) * g_t        # first moment (mean)
v_t = beta2 * v_{t-1} + (1 - beta2) * g_t^2    # second moment (variance)

Далее, делается bias correction (коррекция смещения), потому что в начале обучения m и v близки к нулю:

m_hat_t = m_t / (1 - beta1^t)
v_hat_t = v_t / (1 - beta2^t)

Наконец, обновление параметров:

theta_t = theta_{t-1} - learning_rate * m_hat_t / (sqrt(v_hat_t) + epsilon)

Реализация Adam с нуля

import numpy as np

class Adam:
    def __init__(self, learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8):
        """
        Инициализация Adam оптимизатора.
        
        learning_rate: скорость обучения (обычно 0.001)
        beta1: экспоненциальный decay для first moment (обычно 0.9)
        beta2: экспоненциальный decay для second moment (обычно 0.999)
        epsilon: малое число для численной стабильности
        """
        self.lr = learning_rate
        self.beta1 = beta1
        self.beta2 = beta2
        self.epsilon = epsilon
        
        self.m = {}  # first moment
        self.v = {}  # second moment
        self.t = 0   # timestep
    
    def update(self, params, grads):
        """
        Обновить параметры на основе градиентов.
        
        params: dict с параметрами
        grads: dict с градиентами (такой же ключ как params)
        """
        self.t += 1
        
        for key in params:
            if key not in self.m:
                self.m[key] = np.zeros_like(params[key])
                self.v[key] = np.zeros_like(params[key])
            
            g = grads[key]
            
            # Update biased first moment estimate
            self.m[key] = self.beta1 * self.m[key] + (1 - self.beta1) * g
            
            # Update biased second raw moment estimate
            self.v[key] = self.beta2 * self.v[key] + (1 - self.beta2) * g**2
            
            # Compute bias-corrected first moment estimate
            m_hat = self.m[key] / (1 - self.beta1 ** self.t)
            
            # Compute bias-corrected second raw moment estimate
            v_hat = self.v[key] / (1 - self.beta2 ** self.t)
            
            # Update parameters
            params[key] -= self.lr * m_hat / (np.sqrt(v_hat) + self.epsilon)

# Пример использования
params = {'w': np.array([1.0, 2.0]), 'b': np.array([0.5])}
grads = {'w': np.array([0.1, 0.2]), 'b': np.array([0.05])}

optimizer = Adam(learning_rate=0.01)

for step in range(5):
    # Симулируем градиенты
    grads['w'] = np.random.randn(2) * 0.1
    grads['b'] = np.random.randn(1) * 0.05
    
    print(f"Step {step}: w = {params['w']}, b = {params['b']}")
    optimizer.update(params, grads)

Пошаговый пример

import numpy as np

# Инициализация
lr = 0.01
beta1, beta2 = 0.9, 0.999
epsilon = 1e-8

w = 2.0  # параметр
m = 0.0  # first moment
v = 0.0  # second moment

print("Пошаговое обновление параметра w:")
print()

for t in range(1, 4):
    # Градиент (симулируем)
    g = 0.5  # dL/dw
    
    # Update first moment
    m = beta1 * m + (1 - beta1) * g
    print(f"Step {t}: m_t = {beta1} * {m - (1-beta1)*g:.4f} + {(1-beta1)*g:.4f} = {m:.4f}")
    
    # Update second moment
    v = beta2 * v + (1 - beta2) * g**2
    print(f"        v_t = {beta2} * {v - (1-beta2)*g**2:.4f} + {(1-beta2)*g**2:.4f} = {v:.4f}")
    
    # Bias correction
    m_hat = m / (1 - beta1**t)
    v_hat = v / (1 - beta2**t)
    print(f"        m_hat = {m:.4f} / (1 - {beta1}^{t}) = {m_hat:.4f}")
    print(f"        v_hat = {v:.4f} / (1 - {beta2}^{t}) = {v_hat:.4f}")
    
    # Update parameter
    w_old = w
    w = w - lr * m_hat / (np.sqrt(v_hat) + epsilon)
    print(f"        w = {w_old:.4f} - {lr} * {m_hat:.4f} / sqrt({v_hat:.4f}) = {w:.4f}")
    print()

Использование в PyTorch

import torch
import torch.nn as nn
import torch.optim as optim

# Создание модели
model = nn.Sequential(
    nn.Linear(10, 64),
    nn.ReLU(),
    nn.Linear(64, 1)
)

# Создание Adam оптимизатора
optimizer = optim.Adam(
    model.parameters(),
    lr=0.001,          # learning rate
    betas=(0.9, 0.999),  # (beta1, beta2)
    eps=1e-8,
    weight_decay=1e-5  # L2 регуляризация (опционально)
)

# Цикл обучения
criterion = nn.MSELoss()

for epoch in range(10):
    # Forward pass
    X = torch.randn(32, 10)
    y = torch.randn(32, 1)
    
    outputs = model(X)
    loss = criterion(outputs, y)
    
    # Backward pass
    optimizer.zero_grad()  # обнуляем градиенты
    loss.backward()        # вычисляем градиенты
    optimizer.step()       # обновляем параметры
    
    print(f"Epoch {epoch}: loss = {loss.item():.4f}")

Сравнение с другими оптимизаторами

# SGD vs Momentum vs Adam
import torch.optim as optim

# SGD
optimizer_sgd = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

# Adam (рекомендуется для большинства задач)
optimizer_adam = optim.Adam(model.parameters(), lr=0.001)

# RMSprop
optimizer_rmsprop = optim.RMSprop(model.parameters(), lr=0.001)

# AdamW (улучшенная версия Adam с лучшей weight decay)
optimizer_adamw = optim.AdamW(model.parameters(), lr=0.001)

# Сравнение скорости сходимости:
# SGD:      медленная, может застрять в локальных минимумах
# Momentum: быстрее SGD, но может перескочить
# Adam:     быстро, хорошо адаптируется (РЕКОМЕНДУЕТСЯ)
# RMSprop:  похож на Adam, но без bias correction
# AdamW:    лучше Adam для регуляризации

Ключевые параметры Adam

ПараметрЗначениеОписание
lr0.001Скорость обучения (важнейший параметр!)
beta10.9Decay rate для first moment (обычно 0.9)
beta20.999Decay rate для second moment (обычно 0.999)
epsilon1e-8Численная стабильность (редко менять)
weight_decay0L2 регуляризация

Когда использовать Adam

Используй Adam если:

  • Обучаешь нейросеть (default выбор)
  • У тебя есть ограниченное время (Adam сходится быстро)
  • Не уверен в выборе оптимизатора

Используй SGD с Momentum если:

  • Нужна хорошая обобщаемость на тестовых данных
  • У тебя много computational ресурсов
  • Работаешь с классификацией изображений (часто дает лучшие результаты)

Используй AdamW если:

  • Нужна регуляризация (weight decay работает корректнее)
  • Работаешь с современными трансформерами

Визуализация сходимости

import matplotlib.pyplot as plt

# Сравнение оптимизаторов на простой функции
def rastrigin(x, y):
    """Функция Растригина - многомерная функция оптимизации"""
    return 10*2 + (x**2 - 10*np.cos(2*np.pi*x)) + (y**2 - 10*np.cos(2*np.pi*y))

# Стартовая точка
x, y = 5.0, 5.0

# Обучение с Adam
history_adam = []
lr = 0.01
for step in range(100):
    grad_x = 2*x + 20*np.pi*np.sin(2*np.pi*x)
    grad_y = 2*y + 20*np.pi*np.sin(2*np.pi*y)
    
    x -= lr * grad_x
    y -= lr * grad_y
    
    history_adam.append(rastrigin(x, y))

plt.plot(history_adam, label='Adam (lr=0.01)')
plt.xlabel('Шаг оптимизации')
plt.ylabel('Loss')
plt.legend()
plt.show()

Практические советы

  1. Начни с lr=0.001 — это часто хороший стартовый learning rate
  2. Используй learning rate schedule — уменьшай lr во время обучения
  3. Комбинируй с gradient clipping — для стабильности при работе с RNN
  4. Проверяй weight decay — может улучшить обобщение
  5. Экспериментируй с beta1 и beta2 — редко требуется, но иногда помогает

Adam стал стандартом в современном deep learning и рекомендуется для большинства задач.

Как работает Adam оптимизатор? | PrepBro