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

В чем разница между SGD и обычным градиентным спуском?

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

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

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

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

Разница между SGD и обычным градиентным спуском

Оба метода используют один и тот же принцип — движение в направлении антиградиента для минимизации функции потерь. Но они отличаются размером батча и, следовательно, скоростью, точностью и поведением оптимизации.

Основное отличие

Batch Gradient Descent (BGD) — обычный градиентный спуск

  • Обновляет веса на основе всего датасета
  • Один шаг = один проход по всем данным
  • Математика: θ := θ - α * ∇J(θ) [все примеры сразу]

Stochastic Gradient Descent (SGD)

  • Обновляет веса на основе одного примера (или mini-batch)
  • Один шаг = обновление на одной (или нескольких) точке
  • Математика: θ := θ - α * ∇J(θ; x_i, y_i) [один пример]

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

Batch Gradient Descent:
┌─────────────────────────────┐
│ Гладкая кривая              │
│ Медленно сходится            │
│ Может застрять в локальных   │
│ минимумах                    │
└─────────────────────────────┘

Stochastic Gradient Descent:
┌─────────────────────────────┐
│ Шумная, прерывистая кривая  │
│ Быстро движется              │
│ Может выскочить из локального│
│ минимума благодаря шуму      │
└─────────────────────────────┘

Код: практическое сравнение

import numpy as np
import matplotlib.pyplot as plt

# Простая квадратичная функция потерь
def loss_function(x):
    return x**2

def gradient(x):
    return 2*x

# Batch Gradient Descent
def batch_gd(x_init, learning_rate=0.1, iterations=50):
    x = x_init
    history = [x]
    for i in range(iterations):
        grad = gradient(x)  # Градиент всех данных (тут симуляция)
        x = x - learning_rate * grad
        history.append(x)
    return np.array(history)

# Stochastic Gradient Descent
def sgd(x_init, learning_rate=0.1, iterations=50):
    x = x_init
    history = [x]
    for i in range(iterations):
        # Случайно возмущаем градиент (симуляция шума от одного примера)
        grad = gradient(x) + np.random.randn() * 0.5
        x = x - learning_rate * grad
        history.append(x)
    return np.array(history)

bgd_path = batch_gd(x_init=5.0)
sgd_path = sgd(x_init=5.0)

plt.plot(bgd_path, label='BGD', marker='o', alpha=0.7)
plt.plot(sgd_path, label='SGD', marker='.', alpha=0.5)
plt.xlabel('Итерация')
plt.ylabel('Значение x')
plt.legend()
plt.grid(True)
plt.show()

Сравнение характеристик

ПараметрBGDSGD
БатчВсе данные1 пример
ПамятьВысокая (весь датасет)Низкая (один пример)
Скорость сходимостиМедленнаяБыстрая (много шагов)
Гладкость траекторииГладкаяШумная
Локальные минимумыМожет застрятьМожет выскочить (шум помогает)
МасштабируемостьПлохая (большие датасеты)Хорошая
ВычисленияМного за разЧасто обновлять

Mini-batch Gradient Descent

На практике используют золотую середину:

from torch.utils.data import DataLoader
import torch

# Mini-batch SGD
batch_size = 32  # Обновляем на 32 примерах за раз
learning_rate = 0.01

train_loader = DataLoader(dataset, batch_size=batch_size, shuffle=True)

for epoch in range(num_epochs):
    for batch_x, batch_y in train_loader:  # Mini-batch размер 32
        # Forward pass
        predictions = model(batch_x)
        loss = criterion(predictions, batch_y)
        
        # Backward pass
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()  # Обновляем на 32 примерах

Почему mini-batch лучше?

  • Лучше использует GPU (параллелизм)
  • Гладче сходится, чем pure SGD
  • Быстрее, чем BGD
  • Можно добавить регуляризацию

Практический пример на PyTorch

import torch
import torch.nn as nn
from torch.optim import SGD

# Модель
model = nn.Linear(10, 1)

# Оптимизатор SGD (по умолчанию mini-batch)
optimizer = SGD(model.parameters(), lr=0.01)  # Это mini-batch SGD!

# Данные
for epoch in range(100):
    for batch_x, batch_y in data_loader:  # batch_size = 32 (по умолчанию)
        # Предсказание
        pred = model(batch_x)
        loss = criterion(pred, batch_y)
        
        # Обновление
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()  # Обновляет один раз за batch

Математическое описание

BGD (Batch Gradient Descent):

θ := θ - α * (1/m) * Σ(∇J(θ; x_i, y_i)) for i=1 to m

where m = количество всех примеров

SGD (Stochastic Gradient Descent):

θ := θ - α * ∇J(θ; x_i, y_i)  for random (x_i, y_i)

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

Mini-batch SGD:

θ := θ - α * (1/b) * Σ(∇J(θ; x_i, y_i)) for i=1 to b

where b = размер мини-батча (32, 64, 128)

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

BGD:

  • Очень маленькие датасеты (< 1000 примеров)
  • Хочется гарантированной сходимости
  • Вычисления дёшевы

SGD (на практике mini-batch):

  • Большие датасеты (> 10000 примеров)
  • Ограничена память на GPU
  • Нужна скорость
  • Работа на реальных задачах

Усовершенствования SGD

from torch.optim import Adam, RMSprop, Momentum

# Momentum SGD — помнит предыдущие градиенты
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

# Adam — адаптивный learning rate
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

# RMSprop — масштабирует learning rate по координатам
optimizer = torch.optim.RMSprop(model.parameters(), lr=0.01)

Эти методы решают проблемы pure SGD (шумность, медленная сходимость).

Итого: BGD гарантирует сходимость на гладких функциях, но медленный. SGD (mini-batch) быстрее и масштабируется на больших данных, но более шумный. На практике используют mini-batch SGD с улучшениями (Momentum, Adam и т.п.).