Градиентный спуск для линейной регрессии

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

Линейная регрессия ищет прямую y = w·x + b, наилучшим образом приближающую данные. Параметры w (наклон) и b (сдвиг) подбираются минимизацией MSE градиентным спуском.

Модель и потеря

У нас есть пары (x, y), и мы хотим прямую предсказание = w·x + b. Качество меряем средним квадратом ошибки: MSE = среднее((w·x + b − y)²). Теперь параметров два — w и b, — значит, нужен градиент из двух частных производных.

Градиенты по w и b

Применим правило цепочки к (w·x + b − y)². Производная по w: 2·(w·x + b − y)·x. Производная по b: 2·(w·x + b − y). Усредняем по всем точкам — получаем градиент потери. Дальше — знакомое правило: шаг против градиента.

# Данные: примерно y = 2x + 1 с лёгким шумом
xs = [1, 2, 3, 4, 5]
ys = [3.1, 4.9, 7.2, 8.8, 11.1]

w, b = 0.0, 0.0       # стартовые параметры
lr = 0.01
n = len(xs)

for epoch in range(1, 2001):
    # считаем градиенты по w и b
    dw, db = 0.0, 0.0
    for x, y in zip(xs, ys):
        pred = w * x + b
        err = pred - y
        dw += 2 * err * x / n
        db += 2 * err / n
    # шаг против градиента
    w -= lr * dw
    b -= lr * db

    if epoch in (1, 100, 500, 2000):
        mse = sum((w * x + b - y) ** 2 for x, y in zip(xs, ys)) / n
        print(f"эпоха {epoch:4}: w={round(w, 3):5}  b={round(b, 3):6}  MSE={round(mse, 4)}")

Вывод:

эпоха    1: w=0.501  b=  0.14  MSE=33.3711
эпоха  100: w=2.081  b=  0.72  MSE=0.0412
эпоха  500: w=2.014  b= 0.965  MSE=0.0227
эпоха 2000: w= 1.99  b= 1.049  MSE=0.0214

Спуск сам нашёл w ≈ 2 и b ≈ 1 — почти точную прямую y = 2x + 1 (данные были с шумом, поэтому совпадение не идеальное). MSE упала с 33 до 0.02. Никакого перебора — только наклон и шаги.

Используем обученную модель

Обучив параметры, модель умеет предсказывать для новых x, которых не было в данных. Это и есть цель: обобщение на новые объекты.

xs = [1, 2, 3, 4, 5]
ys = [3.1, 4.9, 7.2, 8.8, 11.1]
w, b = 0.0, 0.0
lr = 0.01
n = len(xs)
for _ in range(5000):
    dw = sum(2 * (w * x + b - y) * x for x, y in zip(xs, ys)) / n
    db = sum(2 * (w * x + b - y)     for x, y in zip(xs, ys)) / n
    w -= lr * dw
    b -= lr * db

print("Обученная модель: y =", round(w, 3), "* x +", round(b, 3))
for x_new in [6, 10]:
    print(f"Предсказание для x={x_new}: y =", round(w * x_new + b, 3))

Вывод:

Обученная модель: y = 1.99 * x + 1.05
Предсказание для x=6: y = 12.99
Предсказание для x=10: y = 20.95

Что мы только что сделали

Это полный цикл машинного обучения в миниатюре, и в нём узнаются все темы курса:

ШагКакая математика
Предсказание w·x + bлинейная комбинация (векторы)
Функция потерь MSEфункция многих переменных (анализ)
Градиент dw, dbчастные производные, правило цепочки
Шаг w −= lr·dwградиентный спуск (оптимизация)

Итог

  • Линейная регрессия подбирает w и b прямой y = w·x + b под данные.
  • Градиенты: по w — среднее 2·err·x, по b — среднее 2·err.
  • Градиентный спуск шагает против градиента и сам находит лучшие параметры.
  • Обученная модель предсказывает y для новых x — это и есть машинное обучение.
Проверьте себя
1. Сколько параметров подбирает простая линейная регрессия y = w·x + b?
Aодин (w)
Bдва (w и b)
Cпо одному на каждый объект
Dноль, они фиксированы
2. Как выглядит градиент MSE по параметру w для одной точки?
A2·(w·x + b − y)·x
B2·(w·x + b − y)
C(w − y)²
Dx · y
3. Что позволяет делать обученная модель линейной регрессии?
AТолько повторять обучающие данные
BПредсказывать y для новых x, которых не было в обучении
CСортировать данные
DСчитать среднее по выборке
Поддержать проект