Как определить направление изменения x при градиентном спуске
Что проверяют
Базовую механику оптимизации: знаете ли вы, куда смотрит градиент и почему шаг делается против него. Раз вопрос из раздела задач, скорее всего попросят написать цикл спуска и объяснить, что будет при слишком большом шаге.
Как отвечать
Градиент это вектор частных производных, он указывает направление наискорейшего роста функции. Потери мы минимизируем, поэтому идём в противоположную сторону: x_new = x - lr * grad(x).
Для одной переменной всё решает знак производной:
f'(x) > 0: функция растёт при увеличенииx, значитxуменьшаем;f'(x) < 0: функция убывает при увеличенииx, значитxувеличиваем;f'(x) = 0: стационарная точка, это минимум, максимум или седло, сам спуск их не различает.
Пример: f(x) = (x - 3)^2, производная 2(x - 3). В точке x = 5 она равна 4, при lr = 0.1 шаг даёт 5 - 0.4 = 4.6, то есть движение к минимуму в тройке. Для этой функции расстояние до минимума на каждом шаге умножается на 1 - 2*lr: при lr = 1 точка скачет между 5 и 1, при lr > 1 спуск расходится.
Код пишите с критерием остановки:
def descend(grad, x, lr=0.1, tol=1e-6, max_iter=10_000):
for _ in range(max_iter):
g = grad(x)
if abs(g) < tol:
break
x -= lr * g
return xАналитическую производную проверяют центральной разностью (f(x + h) - f(x - h)) / (2 * h). В PyTorch тот же шаг скрыт за loss.backward() и optimizer.step(). Momentum и Adam строят шаг по истории градиентов и масштабируют его по координатам, поэтому их шаг может отклоняться от текущего антиградиента.
Где спотыкаются
Ставят плюс вместо минуса. Получается градиентный подъём, и потери растут с каждой итерацией.
Путают направление и величину шага. Антиградиент задаёт направление, а длину определяют lr и модуль градиента, и большой lr ломает сходимость даже при правильном знаке.
Забывают optimizer.zero_grad() в PyTorch. Градиенты накапливаются между итерациями, и шаг идёт по сумме старых градиентов.