Задача минимизации функции потерь
Обучение модели — это задача оптимизации: найти параметры, при которых функция потерь минимальна.
Функция потерь (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 параметров, но взрывается экспоненциально с их числом.
- Нужен метод, который по наклону понимает, куда шагнуть — градиентный спуск.