Зачем градиенты по всем весам

Урок объясняет, почему обучение требует градиента по каждому параметру и зачем нужен умный способ его считать.

Чтобы сделать шаг градиентного спуска, нужно знать производную потери по каждому весу и смещению сети — иначе непонятно, куда двигать конкретную ручку.

Каждый вес отвечает за свой вклад

Потеря зависит от всех весов сразу, но «виноваты» в ней они по-разному. Производная 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 считает все градиенты за один проход.
Проверьте себя
1. Что отвечает на вопрос «насколько этот вес влияет на ошибку»?
AСам вес
BПроизводная потери по этому весу dL/dw
CФункция активации
DСкорость обучения
2. Почему численная оценка градиента не годится для больших сетей?
AОна даёт неверный знак
BТребует по два прогона сети на каждый вес — это слишком дорого
CНе работает с sigmoid
DВозвращает только нули
3. Что позволяет получить градиенты по всем весам за один обратный проход?
ASoftmax
BОбратное распространение (backpropagation)
CNumeric grad
DПерцептронное правило
Поддержать проект