Задача минимизации функции потерь

Обучение модели — это задача оптимизации: найти параметры, при которых функция потерь минимальна.

Функция потерь (loss) — число, показывающее, насколько модель ошибается на данных. Обучить модель = найти параметры, минимизирующие потерю.

Что мы вообще оптимизируем

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

MSE — стандартная потеря для регрессии

Для задач, где предсказываем число (цена, температура), самая частая потеря — среднеквадратичная ошибка (MSE, mean squared error): средний квадрат разницы между предсказанием и правдой. Квадрат штрафует крупные промахи сильнее и делает функцию гладкой (дифференцируемой), что важно для градиентного спуска.

def mse(predictions, targets):
    n = len(targets)
    return sum((p - t) ** 2 for p, t in zip(predictions, targets)) / n

targets = [3.0, 5.0, 7.0, 9.0]

good = [3.1, 4.9, 7.2, 8.8]     # близко к правде
bad  = [1.0, 8.0, 4.0, 12.0]    # мимо

print("MSE хорошей модели:", round(mse(good, targets), 4))
print("MSE плохой модели :", round(mse(bad, targets), 4))

Вывод:

MSE хорошей модели: 0.025
MSE плохой модели : 7.75

Чем меньше MSE, тем лучше модель. Обучение — это поиск весов, дающих наименьший MSE.

Наивный способ: перебор

Возьмём простейшую модель y = w·x с одним параметром w. Можно тупо перебрать кучу значений w и выбрать то, что даёт наименьшую потерю. Для одного параметра это работает и наглядно показывает «ландшафт потерь».

xs = [1, 2, 3, 4]
ys = [2, 4, 6, 8]     # очевидно, что y = 2x

def loss_for_w(w):
    return sum((w * x - y) ** 2 for x, y in zip(xs, ys)) / len(xs)

# Перебираем w от 0 до 4 с шагом 0.5
best_w, best_loss = None, float("inf")
w = 0.0
while w <= 4.0:
    L = loss_for_w(w)
    print(f"w={w:.1f}  потеря={L:.2f}")
    if L < best_loss:
        best_loss, best_w = L, w
    w += 0.5

print("Лучшее w:", best_w, " потеря:", best_loss)

Вывод:

w=0.0  потеря=30.00
w=0.5  потеря=16.88
w=1.0  потеря=7.50
w=1.5  потеря=1.88
w=2.0  потеря=0.00
w=2.5  потеря=1.88
w=3.0  потеря=7.50
w=3.5  потеря=16.88
w=4.0  потеря=30.00
Лучшее w: 2.0  потеря: 0.0

Почему перебор не годится

Перебор нашёл w = 2 — но он спасает только в игрушечных случаях. У реальной модели не один параметр, а тысячи и миллионы. Если перебирать по 100 значений каждого из 1 000 000 весов, вариантов будет 100 в степени миллион — больше, чем атомов во Вселенной. Перебор невозможен. Нужен умный способ, который, стоя в одной точке, понимает, куда шагнуть, чтобы потеря уменьшилась — не пробуя все варианты. Этот способ — градиентный спуск, и его подсказывает производная: следующий урок.

Итог

  • Обучение модели = минимизация функции потерь по её параметрам (весам).
  • MSE — средний квадрат ошибки; стандартная потеря для регрессии.
  • Перебор работает для 1–2 параметров, но взрывается экспоненциально с их числом.
  • Нужен метод, который по наклону понимает, куда шагнуть — градиентный спуск.
Проверьте себя
1. Что значит «обучить модель» с точки зрения математики?
AЗагрузить как можно больше данных
BНайти параметры (веса), минимизирующие функцию потерь
CУвеличить число слоёв
DПеребрать все возможные ответы
2. Почему в MSE ошибку возводят в квадрат?
AЧтобы убрать отрицательные значения и сильнее штрафовать крупные промахи, сохранив гладкость
BЧтобы ускорить вычисления
CЧтобы потеря всегда была целым числом
DЭто случайный выбор
3. Почему перебор параметров не годится для реальных моделей?
AПеребор даёт неточный ответ
BЧисло комбинаций растёт экспоненциально с числом параметров и становится астрономическим
CPython не умеет перебирать числа
DПеребор работает только с текстом
Поддержать проект