Стохастический спуск, мини-батчи и локальные минимумы

На больших данных считать градиент по всей выборке дорого — спасают стохастический и мини-батч спуск, а их шум ещё и помогает не застрять.

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

Проблема полного (batch) спуска

В уроках выше мы на каждом шаге считали градиент по всем данным. Это называется полный (batch) градиентный спуск. Он точен, но если объектов миллионы, один шаг требует пройти весь датасет — обучение ползёт. Идея SGD: зачем смотреть на все данные, чтобы понять направление вниз? Достаточно оценки градиента по части данных — она шумная, но в среднем верная, зато шагов в секунду в сотни раз больше.

SGD: один объект за шаг

Стохастический спуск берёт случайный объект, считает градиент только по нему и сразу делает шаг. Каждый отдельный шаг «дёрганый», но направление в среднем правильное, и за то же время мы делаем гораздо больше обновлений. Реализуем SGD для той же линейной регрессии.

import random
random.seed(0)

xs = [1, 2, 3, 4, 5]
ys = [3.1, 4.9, 7.2, 8.8, 11.1]   # около y = 2x + 1

w, b = 0.0, 0.0
lr = 0.01

for epoch in range(300):
    # перемешиваем и идём по одному объекту
    order = list(range(len(xs)))
    random.shuffle(order)
    for i in order:
        x, y = xs[i], ys[i]
        err = w * x + b - y          # ошибка на ОДНОМ объекте
        w -= lr * 2 * err * x        # градиент по одной точке
        b -= lr * 2 * err

print("SGD нашёл: w =", round(w, 3), ", b =", round(b, 3))

Вывод:

SGD нашёл: w = 1.995 , b = 1.04

SGD пришёл примерно туда же (w ≈ 2, b ≈ 1), что и полный спуск, но обновлялся по одному объекту за раз — на огромных данных это решающее преимущество.

Мини-батч — золотая середина

На практике берут мини-батч: не один объект и не всю выборку, а порцию из 16–256 объектов. Это компромисс — меньше шума, чем у чистого SGD, но всё ещё быстрые шаги и эффективная работа на видеокартах. Почти всё современное глубокое обучение — это мини-батч спуск.

import random
random.seed(1)

xs = list(range(1, 21))
ys = [3 * x + 2 for x in xs]      # точная зависимость y = 3x + 2

def batches(indices, size):
    for start in range(0, len(indices), size):
        yield indices[start:start + size]

w, b = 0.0, 0.0
lr = 0.001
n = len(xs)

for epoch in range(2000):
    order = list(range(n))
    random.shuffle(order)
    for batch in batches(order, 4):       # мини-батч из 4 объектов
        dw = sum(2 * (w * xs[i] + b - ys[i]) * xs[i] for i in batch) / len(batch)
        db = sum(2 * (w * xs[i] + b - ys[i])         for i in batch) / len(batch)
        w -= lr * dw
        b -= lr * db

print("Мини-батч спуск: w =", round(w, 3), ", b =", round(b, 3), " (цель 3 и 2)")

Вывод:

Мини-батч спуск: w = 3.001 , b = 1.983  (цель 3 и 2)

Шум помогает выбираться из ловушек

У стохастичности есть бонус. Полный спуск, скатившись в локальный минимум невыпуклой функции, застревает там навсегда: градиент равен нулю, шагать некуда. А шумные шаги SGD иногда «выталкивают» точку из мелкой ямки, давая шанс найти яму поглубже. Поэтому случайность — не только про скорость, но и про качество решения на сложных, невыпуклых ландшафтах нейросетей.

МетодДанных на шагКогда применять
Полный (batch)вся выборкамаленькие данные, нужна точность
SGDодин объекточень большие данные, онлайн-обучение
Мини-батч16–256 объектовстандарт глубокого обучения

Итог

  • Полный спуск точен, но считает градиент по всем данным — медленно на больших выборках.
  • SGD обновляет параметры по одному объекту: шумно, зато много шагов.
  • Мини-батч (16–256 объектов) — компромисс и стандарт глубокого обучения.
  • Шум стохастичности помогает выбираться из локальных минимумов невыпуклых функций.
Проверьте себя
1. Чем стохастический градиентный спуск (SGD) отличается от полного?
AОн считает градиент по всей выборке точнее
BОн обновляет параметры по одному случайному объекту, а не по всем данным сразу
CОн не использует learning rate
DОн работает только с выпуклыми функциями
2. Почему мини-батч спуск — стандарт глубокого обучения?
AОн единственный даёт точный результат
BЭто компромисс: меньше шума, чем у SGD, быстрые шаги и эффективность на видеокартах
CОн не требует данных
DОн не использует градиент
3. Как шум стохастического спуска связан с локальными минимумами?
AОн гарантирует попадание в локальный минимум
BСлучайные шаги иногда выталкивают точку из мелкой ямки, помогая найти минимум поглубже
CОн полностью убирает локальные минимумы
DШум не влияет на минимумы
Поддержать проект