Стохастический градиентный спуск (SGD) - Лена Капаца
Стохастический градиентный спуск (SGD) by Лена Капаца April 19, 2024 Основы

Стохастический градиентный спуск (Stochastic Gradient Descent) — это итеративный метод оптимизации, используемый для минимизации функции потерь при обучении различных моделей машинного обучения, включая линейные модели и нейронные сети. Он представляет собой упрощённую версию обычного градиентного спуска, где вместо расчёта градиента на всём наборе данных используется только один случайно выбранный элемент данных. Это делает процесс обучения быстрее, особенно на больших данных.

В классическом градиентном спуске для обновления параметров модели используется градиент функции потерь, вычисленный на всём тренировочном датасете. В случае SGD, параметры обновляются для каждого образца из тренировочного набора:

1. Выбор случайного образца из тренировочного датасета.
2. Вычисление градиента функции потерь по отношению к параметрам модели на основе этого одного образца.
3. Обновление параметров модели в направлении, противоположном градиенту.

Эти шаги повторяются множество раз для различных случайных образцов данных.

Преимущества:
- Высокая скорость обучения на больших датасетах.
- Хорошая сходимость, когда функция потерь нерегулярна.
- Возможность "онлайн" или постепенного обучения.

Недостатки:
- Высокая дисперсия обновлений может привести к нестабильности процесса сходимости.
- Необходимость тщательного подбора размера шага (learning rate).

Давайте рассмотрим пример реализации SGD для линейной регрессии:


import numpy as np

 

Функция для вычисления предсказаний:


def predict(X, weights):
    return X.dot(weights)

 

Функция для вычисления градиента функции потерь:


def compute_gradient(X, y, weights):
    predictions = predict(X, weights)
    errors = predictions - y
    gradient = X.T.dot(errors) / len(X)
    return gradient

 

Функция для выполнения SGD:


def stochastic_gradient_descent(X, y, learning_rate=0.01, epochs=100):
    weights = np.random.rand(X.shape[1])  # Инициализация весов
    for epoch in range(epochs):
        for i in range(len(X)):
            idx = np.random.randint(len(X))  # Выбор случайного индекса
            X_i = X[idx:idx+1]
            y_i = y[idx:idx+1]
            gradient = compute_gradient(X_i, y_i, weights)
            weights -= learning_rate * gradient
        print(f'Эпоха {epoch+1}, Веса: {weights}')
    return weights

 

Пример данных:


X = np.array([[1, 2], [2, 3], [3, 4], [4, 5]])
y = np.array([2, 3, 4, 5])

 

Обучение модели:


model_weights = stochastic_gradient_descent(X, y)


Результат:

Эпоха 1, Веса: [0.04192404 0.84973152]
Эпоха 1, Веса: [0.06526989 0.87891383]
Эпоха 1, Веса: [0.06992426 0.88589539]
Эпоха 1, Веса: [0.07397357 0.89196935]
Эпоха 2, Веса: [0.07539445 0.89481111]
Эпоха 2, Веса: [0.08436911 0.90602944]
Эпоха 2, Веса: [0.08966417 0.91264826]
Эпоха 2, Веса: [0.09131871 0.91513006]
Эпоха 3, Веса: [0.09328441 0.91775101]
...
Эпоха 99, Веса: [0.07607725 0.94098184]
Эпоха 100, Веса: [0.07657525 0.94172884]
Эпоха 100, Веса: [0.07697492 0.94252818]
Эпоха 100, Веса: [0.0761533 0.94150115]
Эпоха 100, Веса: [0.07631936 0.94172257]

 

Ноутбук, не требующий дополнительной настройки на момент написания статьи, можно скачать здесь.

© Лена Капаца. Все права защищены.