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

GD, SGD и Mini-Batch SGD: различия, плюсы и минусы каждого

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

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

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

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

Градиентный спуск: GD, SGD и Mini-Batch SGD

Это три варианта одного алгоритма оптимизации, отличающихся тем, на скольких примерах вычисляется градиент перед обновлением весов.

1. Batch Gradient Descent (GD)

Вычисляет градиент на всём обучающем наборе перед каждым обновлением:

L = (1/N) * sum(loss_i)  для всех N примеров
w = w - lr * dL/dw

Python реализация:

import numpy as np

def batch_gradient_descent(X, y, learning_rate=0.01, epochs=100):
    n_samples, n_features = X.shape
    w = np.zeros(n_features)
    b = 0
    
    for epoch in range(epochs):
        # Предсказание на всем наборе
        y_pred = X.dot(w) + b
        error = y_pred - y
        
        # Градиент на ВСЕМ наборе
        dw = (2/n_samples) * X.T.dot(error)
        db = (2/n_samples) * np.sum(error)
        
        # Обновление один раз за эпоху
        w -= learning_rate * dw
        b -= learning_rate * db
        
        loss = np.mean(error ** 2)
        print(f'Epoch {epoch}, Loss: {loss:.4f}')
    
    return w, b

# Использование
w, b = batch_gradient_descent(X_train, y_train)

Плюсы:

  • Стабильный, гладкий gradient
  • Хорошая convergence гарантия
  • Легко распараллелить
  • Детерминированный

Минусы:

  • Медленно на больших датасетах (нужно весь набор в памяти)
  • Может застрять в локальных минимумах
  • Часто требует много итераций
  • Неэффективен для online learning

2. Stochastic Gradient Descent (SGD)

Обновляет веса после каждого примера:

для каждого примера (x_i, y_i):
    L_i = loss(y_i, predict(x_i))
    w = w - lr * dL_i/dw

Python реализация:

def stochastic_gradient_descent(X, y, learning_rate=0.01, epochs=100):
    n_samples, n_features = X.shape
    w = np.zeros(n_features)
    b = 0
    
    for epoch in range(epochs):
        # Перемешиваем данные
        indices = np.random.permutation(n_samples)
        X_shuffled = X[indices]
        y_shuffled = y[indices]
        
        for i in range(n_samples):
            # Градиент на ОДНОМ примере
            y_pred = X_shuffled[i].dot(w) + b
            error = y_pred - y_shuffled[i]
            
            # Обновление после каждого примера
            dw = 2 * X_shuffled[i] * error
            db = 2 * error
            
            w -= learning_rate * dw
            b -= learning_rate * db
    
    return w, b

Плюсы:

  • Очень быстро на больших данных
  • Может выбраться из локальных минимумов (шум помогает)
  • Хорош для online learning
  • Память очень экономная

Минусы:

  • Очень шумный gradient (нестабильная траектория)
  • Может не сходиться (вибрирует около оптимума)
  • Много update операций (медленнее на GPU/параллель)
  • Требует тщательный выбор learning rate

3. Mini-Batch Gradient Descent

Компромисс между GD и SGD. Обновляет после небольших батчей (например, 32 примера):

для каждого батча из B примеров:
    L = (1/B) * sum(loss_i)
    w = w - lr * dL/dw

Python реализация:

def mini_batch_gradient_descent(X, y, batch_size=32, learning_rate=0.01, epochs=100):
    n_samples, n_features = X.shape
    w = np.zeros(n_features)
    b = 0
    
    for epoch in range(epochs):
        # Перемешиваем
        indices = np.random.permutation(n_samples)
        X_shuffled = X[indices]
        y_shuffled = y[indices]
        
        for i in range(0, n_samples, batch_size):
            # Берем батч
            X_batch = X_shuffled[i:i + batch_size]
            y_batch = y_shuffled[i:i + batch_size]
            
            # Градиент на батче
            y_pred = X_batch.dot(w) + b
            error = y_pred - y_batch
            
            dw = (2/len(X_batch)) * X_batch.T.dot(error)
            db = (2/len(X_batch)) * np.sum(error)
            
            # Одно обновление за батч
            w -= learning_rate * dw
            b -= learning_rate * db
    
    return w, b

Плюсы:

  • Лучший выбор на практике
  • Быстро на больших данных
  • Стабильнее, чем SGD (менее шумно)
  • Хорошо использует GPU параллелизм
  • Может выбраться из локальных минимумов

Минусы:

  • Нужно выбирать batch size
  • Требует некоторую память
  • Чуть сложнее в реализации

Визуальное сравнение

       Loss
        |
    100 |  GD: плавная траектория
        |  /
     80 | /          SGD: очень шумная
        |/      /\   /\
     60|/      /  \ /  \
        |     /     X     \    Mini-Batch:
     40|    /     / \    средний уровень
        |   /    /   \  шума и стабильности
     20|  /    /     \
        | /    /       \
      0 +-----+--------+-----> Iterations

TensorFlow реализация

import tensorflow as tf

model = tf.keras.Sequential([
    tf.keras.layers.Dense(64, activation='relu', input_shape=(10,)),
    tf.keras.layers.Dense(1)
])

# GD (batch_size = len(X_train))
model.compile(
    optimizer=tf.keras.optimizers.SGD(learning_rate=0.01),
    loss='mse'
)
model.fit(X_train, y_train, epochs=100, batch_size=len(X_train))

# SGD (batch_size = 1)
model.fit(X_train, y_train, epochs=100, batch_size=1)

# Mini-Batch SGD (batch_size = 32) - РЕКОМЕНДУЕТСЯ
model.fit(X_train, y_train, epochs=100, batch_size=32)

# С валидацией
model.fit(
    X_train, y_train,
    batch_size=32,
    epochs=100,
    validation_data=(X_val, y_val)
)

Выбор batch size

# Общие рекомендации
if dataset_size < 10_000:
    batch_size = 32 or 64  # Маленькие батчи
elif dataset_size < 100_000:
    batch_size = 128  # Стандарт
elif dataset_size < 1_000_000:
    batch_size = 256
else:
    batch_size = 512 или 1024  # Большие данные

# Зависит от:
# - Памяти GPU/CPU
# - Скорости сходимости (часто 32-128)
# - Типа модели (больше слоев -> меньше батч)

Динамическое обучение

from tensorflow.keras.callbacks import LearningRateScheduler

def lr_schedule(epoch, lr):
    if epoch > 0 and epoch % 10 == 0:
        return lr * 0.5  # Уменьшаем learning rate
    return lr

lr_callback = LearningRateScheduler(lr_schedule)
model.fit(
    X_train, y_train,
    batch_size=32,
    epochs=100,
    callbacks=[lr_callback]
)

Best Practices

  1. Всегда используй Mini-Batch (обычно 32 или 64)
  2. Shuffle данные перед каждой эпохой
  3. Выбирай batch_size в зависимости от памяти
  4. Уменьшай learning rate со временем (если не используешь Adam)
  5. Используй modern optimizers (Adam, RMSprop вместо vanilla SGD)
  6. Мониторь валидационную ошибку для early stopping
  7. На production используй достаточно большой batch для стабильности
GD, SGD и Mini-Batch SGD: различия, плюсы и минусы каждого | PrepBro