Зачем градиенты по всем весам
Урок объясняет, почему обучение требует градиента по каждому параметру и зачем нужен умный способ его считать.
Чтобы сделать шаг градиентного спуска, нужно знать производную потери по каждому весу и смещению сети — иначе непонятно, куда двигать конкретную ручку.
Каждый вес отвечает за свой вклад
Потеря зависит от всех весов сразу, но «виноваты» в ней они по-разному. Производная dL/dw отвечает на вопрос: если чуть-чуть увеличить именно этот вес, насколько изменится общая потеря? Большая по модулю производная — вес сильно влияет на ошибку, его надо двигать решительно. Близкая к нулю — этот вес почти ни при чём. Без производной по каждому весу мы не знаем, как настроить именно его.
Численная оценка градиента «в лоб»
Производную можно оценить определением: чуть сдвинуть вес на крошечное eps, посмотреть, как изменилась потеря, и поделить. Это работает и помогает прочувствовать смысл градиента.
# Модель y = w1*x1 + w2*x2, потеря MSE на одном примере
x = [1.0, 2.0]
target = 1.0
W = [0.5, 0.5]
def predict(W):
return W[0]*x[0] + W[1]*x[1]
def loss(W):
return (predict(W) - target) ** 2
def numeric_grad(W, i, eps=1e-6):
W_plus = list(W); W_plus[i] += eps
W_minus = list(W); W_minus[i] -= eps
return (loss(W_plus) - loss(W_minus)) / (2 * eps)
print("Текущая потеря:", round(loss(W), 4))
for i in range(len(W)):
print(f"dL/dw{i+1} ≈ {numeric_grad(W, i):.4f}")
Вывод:
Текущая потеря: 0.25 dL/dw1 ≈ 1.0000 dL/dw2 ≈ 2.0000
Производная по w2 вдвое больше, чем по w1 — логично, ведь вход x2 = 2 вдвое сильнее влияет на выход. Сделав шаг спуска по этим градиентам, мы уменьшим потерю.
Почему численный способ не годится для сетей
Чтобы оценить производную по одному весу численно, надо дважды прогнать всю сеть (forward pass). В сети со ста миллионами весов это сто миллионов пар прогонов на каждый шаг обучения — астрономически дорого. Численный градиент хорош только для проверки правильности кода на крошечных примерах (так называемая gradient check).
Нужен умный алгоритм
Хочется получить производные по всем весам за один проход. Именно это делает обратное распространение ошибки (backpropagation): один forward pass, один обратный проход — и готовы градиенты по всем параметрам сразу. Это сердце обучения нейросетей и тема следующего раздела.
Где численный градиент всё же полезен
Хотя для обучения численная оценка не годится, у неё есть важная роль — проверка корректности аналитического backprop. Когда программируешь градиенты вручную, легко ошибиться в формуле или знаке. Тогда на крошечной сети считают градиент двумя способами: аналитически (backprop) и численно (как в примере выше), и сравнивают. Если числа совпали до нескольких знаков — реализация backprop верна; если разошлись — где-то баг. Этот приём называют gradient checking, и он спас не одного инженера от неуловимой ошибки в обучении.
Обратите внимание на форму численной производной: мы сдвигали вес и в плюс, и в минус (центральная разность). Это точнее, чем односторонний сдвиг, потому что симметрично учитывает поведение функции по обе стороны от точки — мелочь, которая заметно повышает точность оценки.
Итог
- Для шага спуска нужна производная потери по каждому весу и смещению.
- Величина производной показывает, насколько вес влияет на ошибку.
- Численный градиент нагляден, но слишком дорог; backprop считает все градиенты за один проход.