Градиент — направление наискорейшего роста
Градиент — вектор частных производных, указывающий направление самого быстрого роста функции.
Градиент $\nabla f(x)=\left(\dfrac{\partial f}{\partial x_1},\dots,\dfrac{\partial f}{\partial x_n}\right)$ — вектор, направленный в сторону наискорейшего возрастания $f$; его длина равна крутизне этого роста.
Зачем нужен градиент
Слепой путник на склоне, чтобы спускаться, должен чувствовать наклон под ногами. Математический аналог этого наклона в многомерии — градиент. Если двигаться в сторону $+\nabla f$, функция растёт быстрее всего; в сторону $-\nabla f$ — убывает быстрее всего. Именно поэтому почти все методы непрерывной оптимизации делают шаг против градиента — это и есть градиентный спуск.
Для функции одной переменной градиент — это просто производная $f'(x)$. Для функции $n$ переменных каждая координата градиента — частная производная: насколько меняется $f$, если чуть-чуть подвинуть только одну переменную, а остальные заморозить.
Пример руками
Возьмём $f(x,y)=x^2+3y^2$. Частные производные:
$$\frac{\partial f}{\partial x}=2x,\qquad \frac{\partial f}{\partial y}=6y,\qquad \nabla f(x,y)=(2x,\,6y).$$
В точке $(1,1)$ градиент равен $(2,6)$: по оси $y$ функция растёт втрое круче, чем по оси $x$. Длина градиента $\lVert\nabla f\rVert=\sqrt{4+36}=\sqrt{40}\approx 6.32$ — это скорость роста в самом крутом направлении.
Численный градиент
Когда формулы производной нет (или функция задана кодом), градиент считают численно конечными разностями:
$$\frac{\partial f}{\partial x_i}\approx \frac{f(x+\varepsilon e_i)-f(x-\varepsilon e_i)}{2\varepsilon},$$
где $e_i$ — орт $i$-й оси, $\varepsilon$ — малый шаг. Это центральная разность, точная до $O(\varepsilon^2)$.
def f(v):
x, y = v
return x ** 2 + 3 * y ** 2
def numeric_grad(f, v, eps=1e-6):
g = []
for i in range(len(v)):
plus = list(v); plus[i] += eps
minus = list(v); minus[i] -= eps
g.append((f(plus) - f(minus)) / (2 * eps))
return g
point = [1.0, 1.0]
g = numeric_grad(f, point)
print("Численный градиент:", [round(c, 4) for c in g])
print("Точный градиент: [2, 6]")
length = sum(c * c for c in g) ** 0.5
print("Длина:", round(length, 4))Вывод:
Численный градиент: [2.0, 6.0] Точный градиент: [2, 6] Длина: 6.3246
Численный градиент совпал с точным до знаков — этот приём незаменим для проверки аналитических формул в реальном коде.
Градиент перпендикулярен линии уровня
Важный геометрический факт: $\nabla f$ в точке всегда перпендикулярен линии уровня, проходящей через эту точку. Интуиция: вдоль линии уровня $f$ не меняется, значит наклон вдоль неё нулевой; а самый крутой рост — строго поперёк. Этот факт лежит в основе условия Лагранжа для задач с ограничениями.
Как работает под капотом
Численный градиент стоит $2n$ вычислений $f$ (по два на каждую переменную). Для нейросети с миллионами весов это неприемлемо дорого, поэтому там используют обратное распространение (backpropagation) — способ получить весь градиент за стоимость примерно одного-двух вычислений $f$ через правило цепочки. Но идея та же: градиент — вектор частных производных. Слишком маленький $\varepsilon$ в численной формуле приводит к катастрофическому сокращению (вычитание близких чисел), слишком большой — к ошибке аппроксимации; $\varepsilon\sim 10^{-6}$ — разумный компромисс для float64.
Частые ошибки
- Шаг $\varepsilon$ наугад. Слишком мал — теряется точность из-за округления; слишком велик — формула неверна.
- Односторонняя разность вместо центральной. $(f(x+\varepsilon)-f(x))/\varepsilon$ точна лишь до $O(\varepsilon)$ — вдвое хуже по порядку.
- Путать градиент и производную по направлению. Производная вдоль вектора $u$ равна $\nabla f\cdot u$, а не самому градиенту.
Итоги
- Градиент $\nabla f$ — вектор частных производных, указывает наискорейший рост; $-\nabla f$ — наискорейшее убывание.
- Длина градиента — крутизна; направление перпендикулярно линии уровня.
- Численный градиент через центральную разность точен до $O(\varepsilon^2)$ и удобен для проверки.