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

Ответ

Разница заключается в объеме данных, используемых для вычисления градиента и обновления весов модели на одной итерации (шаге).

Метод Объем данных на шаг Скорость / Вычисления Сходимость / Шум
Batch Gradient Descent (Пакетный GD) Весь тренировочный набор данных. Медленно. Требует больших вычислительных ресурсов и памяти, так как нужно обработать все данные перед одним обновлением. Плавная, детерминированная сходимость по направлению к локальному минимуму. Может застрять в нем.
Stochastic Gradient Descent (Стохастический GD) Один случайный тренировочный пример. Очень быстро. Обновление весов происходит после каждого примера, что позволяет быстро делать много шагов. Очень шумная, нестабильная траектория. Шум может помочь "выпрыгнуть" из плохих локальных минимумов, но усложняет точную сходимость.
Mini-batch Gradient Descent Небольшая случайная подвыборка (mini-batch), например, 32 или 128 примеров. Компромисс. Достаточно быстрый и эффективный по памяти. Является стандартом на практике. Умеренный шум, баланс между скоростью и стабильностью сходимости.

Почему Mini-batch SGD стал стандартом?

  1. Эффективность GPU: Позволяет полностью загрузить вычислительные ядра графического процессора параллельной обработкой батча.
  2. Стабильность: Градиент, усредненный по нескольким примерам, менее шумный, чем от одного примера, что ведет к более устойчивой сходимости.
  3. Скорость: Одно обновление на батч быстрее, чем проход по всему датасету (Batch GD).

Иллюстрация на псевдокоде:

# Псевдокод для сравнения логики обновления весов (w)

# Batch Gradient Descent
for epoch in range(num_epochs):
    gradient = compute_gradient(w, entire_training_set)  # ДОРОГО!
    w = w - learning_rate * gradient  # Одно обновление за эпоху

# Stochastic Gradient Descent (SGD)
for epoch in range(num_epochs):
    for x_i, y_i in training_set:  # Итерация по КАЖДОМУ примеру
        gradient = compute_gradient(w, x_i, y_i)  # Дешево, но шумно
        w = w - learning_rate * gradient  # Много обновлений за эпоху

# Mini-batch Gradient Descent (ПРАКТИЧЕСКИЙ СТАНДАРТ)
for epoch in range(num_epochs):
    for batch in dataloader:  # Итерация по БАТЧАМ (например, по 32 примера)
        x_batch, y_batch = batch
        gradient = compute_gradient(w, x_batch, y_batch)  # Оптимально
        w = w - learning_rate * gradient

В современных фреймворках (PyTorch, TensorFlow) оптимизатор SGD по умолчанию реализует именно Mini-batch SGD. Пакетный градиентный спуск на больших данных практически не используется из-за непрактичных требований к памяти.

Ответ 18+ 🔞

Слушай, давай разберем эту дичь с градиентным спуском, а то у меня уже терпения ноль, ебать. Представь, что тебе надо спуститься с горы, но ты слепой и можешь только тыкать палкой, чтобы понять, куда склон. Вот эти методы — разные способы, как ты эту палку используешь.

Пакетный (Batch) — это как упрямый мужик, который хочет всё измерить дохуя точно. Он стоит, вынимает теодолит, ёпта, и меряет уклон ВСЕЙ горы целиком, глядя на каждый камень. Потом делает ОДИН, но оверточный шаг. Ебать мои старые костыли, это ж сколько времени! Памяти нужно овердохуища, и если он встал в ямку (локальный минимум), то ему похер, он считает, что дальше только вверх — и застревает. Скорость? Да хуй с горы скатится быстрее.

Стохастический (Stochastic) — это как пьяный в стельку, который спускается с горы. Он вообще не смотрит. Херак — шагнул куда попало, чих-пых тебя в сраку, упал, встал, опять шагнул. Обновляет веса после КАЖДОГО примера. Быстро? О, да, он за секунду сделает сто шагов! Но траектория у него — пиздопроебибна, зигзагами по всему склону. Шум дикий, но зато есть шанс, что он из ямки выпрыгнет, потому что его так шатает.

Мини-батч (Mini-batch) — это золотая середина, и поэтому все его и используют. Это как взять небольшую, но адекватную компанию друзей. Не одного пьяного и не всех жителей города, а, скажем, 32 человека. Ты спрашиваешь у них: «Ну что, пацаны, вниз тут?». Они вразнобой, но в целом показывают верное направление. Быстрее, чем опрашивать весь город, стабильнее, чем слушать одного алкаша. Вот это и есть стандарт, ёпта.

Почему мини-батч рулит?

  1. Видеокарты это любят. Им проще пачками данные жрать, чем по одному. Это как кормить слона не семечками, а целыми арбузами.
  2. Стабильность. Градиент усредненный, не такой манда с ушами, как в стохастике.
  3. Скорость. Идеальный баланс. Не будешь же ты, внатуре, ждать, пока модель весь интернет переварит за один шаг?

Смотри, как это в коде выглядит. Блоки я не трогаю, они святые.

# Batch GD — старомодный и тормозной дед
for epoch in range(num_epochs):
    gradient = compute_gradient(w, entire_training_set)  # Ёб твою мать, вся память кончилась!
    w = w - learning_rate * gradient  # Одно обновление, и ты уже седой

# Stochastic GD — гиперактивный шизоид
for epoch in range(num_epochs):
    for x_i, y_i in training_set:  # На каждый чих — обновление!
        gradient = compute_gradient(w, x_i, y_i)  # Градиент — полная случайность, доверия ебать ноль
        w = w - learning_rate * gradient  # Бешеный танец с саблями

# Mini-batch GD — адекватный работяга (ВОТ ЭТО ПРАКТИКА)
for epoch in range(num_epochs):
    for batch in dataloader:  # Пришла пачка данных — отработали
        x_batch, y_batch = batch
        gradient = compute_gradient(w, x_batch, y_batch)  # Всё чётко, ясно, по делу
        w = w - learning_rate * gradient

Запомни: когда в PyTorch пишешь torch.optim.SGD, то под капотом у тебя работает именно мини-батч. Пакетный спуск в наши дни — это как приехать на таксофоне в мир смартфонов. Да похуй на него.