ai_learning/common/foundations/calculus_and_matrix_calculus.md

305 lines
9.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Дифференциальное и матричное исчисление
## Зачем это нужно
Обучение модели обычно означает минимизацию функции потерь. Производная
отвечает на локальный вопрос: как изменится результат при малом изменении
параметра? Градиент обобщает ответ на много параметров, а матричное исчисление
позволяет записать вычисление без циклов по каждому весу.
## Предел, производная и локальная линейность
Производная функции \(f:\mathbb{R}\to\mathbb{R}\) в точке \(x\):
\[
f'(x)=\lim_{h\to0}\frac{f(x+h)-f(x)}{h}.
\]
Это не просто наклон касательной. Если производная существует, то при малом
\(h\)
\[
f(x+h)=f(x)+f'(x)h+o(h),
\]
где \(o(h)/h\to0\). Главная идея — гладкая функция локально ведёт себя как
линейная. Например, для \(f(x)=x^2\):
\[
\frac{(x+h)^2-x^2}{h}
=\frac{2xh+h^2}{h}=2x+h\to2x.
\]
Отсюда \(d(x^2)/dx=2x\).
## Правила дифференцирования
\[
(f+g)'=f'+g',\qquad
(fg)'=f'g+fg',\qquad
\left(\frac fg\right)'=\frac{f'g-fg'}{g^2}.
\]
Для композиции \(y=f(g(x))\) правило цепочки:
\[
\frac{dy}{dx}
=\frac{df}{dg}\frac{dg}{dx}.
\]
Пример: \(L(w)=(wx-y)^2\). Введём \(r=wx-y\), тогда
\[
\frac{dL}{dw}
=\frac{d(r^2)}{dr}\frac{dr}{dw}
=2r\,x
=2(wx-y)x.
\]
Промежуточная переменная делает структуру обратного распространения явной:
локальные производные перемножаются от выхода к входу.
## Частные производные и градиент
Для \(f:\mathbb{R}^d\to\mathbb{R}\) частная производная меняет одну координату,
фиксируя остальные. Градиент собирает их:
\[
\nabla_{\mathbf{x}}f=
\begin{bmatrix}
\partial f/\partial x_1\\
\cdots\\
\partial f/\partial x_d
\end{bmatrix}.
\]
Дифференцируемость означает
\[
f(\mathbf{x}+\Delta\mathbf{x})
=f(\mathbf{x})
+\nabla f(\mathbf{x})^\top\Delta\mathbf{x}
+o(\|\Delta\mathbf{x}\|).
\]
По неравенству Коши—Буняковского изменение первого порядка максимально при
\(\Delta\mathbf{x}\) в направлении градиента. Поэтому
\(-\nabla f\) — направление быстрейшего локального убывания при евклидовой
норме.
## Якобиан и многомерное правило цепочки
Для \(\mathbf{g}:\mathbb{R}^d\to\mathbb{R}^m\)
якобиан имеет размер \(m\times d\):
\[
(\mathbf{J}_{\mathbf{g}})_{ij}
=\frac{\partial g_i}{\partial x_j}.
\]
Если \(L=f(\mathbf{g}(\mathbf{x}))\), где \(f:\mathbb{R}^m\to\mathbb{R}\), то
\[
\nabla_{\mathbf{x}}L
=\mathbf{J}_{\mathbf{g}}(\mathbf{x})^\top
\nabla_{\mathbf{g}}f.
\]
Размерности дают проверку:
\((d\times m)(m\times1)=d\times1\).
## Гессиан и кривизна
Гессиан содержит вторые производные:
\[
\mathbf{H}_f=\nabla^2f,\qquad
f(\mathbf{x}+\Delta)
\approx f(\mathbf{x})+\nabla f^\top\Delta
+\frac12\Delta^\top\mathbf{H}_f\Delta.
\]
Если \(\mathbf{H}_f\succeq0\) во всей области, гладкая функция выпукла.
В стационарной точке положительно определённый гессиан указывает на строгий
локальный минимум, отрицательно определённый — на максимум, смешанные знаки
собственных значений — на седловую точку.
## Дифференциалы и матрицы
Дифференциал удобен тем, что подчиняется обычной алгебре:
\[
d(\mathbf{A}\mathbf{X}\mathbf{B})
=\mathbf{A}\,d\mathbf{X}\,\mathbf{B}
\]
для постоянных \(\mathbf{A},\mathbf{B}\), а
\[
d(\mathbf{X}^\top)=d\mathbf{X}^\top.
\]
Для скалярной \(f(\mathbf{X})\) приводим дифференциал к форме
\[
df=\operatorname{tr}\left(
(\nabla_{\mathbf{X}}f)^\top d\mathbf{X}\right).
\]
Полезны свойства следа:
\[
\operatorname{tr}(\mathbf{A}\mathbf{B})
=\operatorname{tr}(\mathbf{B}\mathbf{A}),\qquad
\operatorname{tr}(\mathbf{A}^\top d\mathbf{X})
=\langle\mathbf{A},d\mathbf{X}\rangle_F.
\]
## Вывод градиента линейной регрессии
Пусть
\[
L(\mathbf{w})
=\frac{1}{2n}\|\mathbf{X}\mathbf{w}-\mathbf{y}\|_2^2.
\]
Обозначим \(\mathbf{r}=\mathbf{X}\mathbf{w}-\mathbf{y}\). Тогда
\[
L=\frac1{2n}\mathbf{r}^\top\mathbf{r}.
\]
Последовательно:
\[
dL
=\frac1{2n}\left(d\mathbf{r}^\top\mathbf{r}
+\mathbf{r}^\top d\mathbf{r}\right)
=\frac1n\mathbf{r}^\top d\mathbf{r}.
\]
Поскольку \(d\mathbf{r}=\mathbf{X}\,d\mathbf{w}\),
\[
dL
=\frac1n\mathbf{r}^\top\mathbf{X}\,d\mathbf{w}
=\left(\frac1n\mathbf{X}^\top\mathbf{r}\right)^\top d\mathbf{w}.
\]
Следовательно,
\[
\boxed{\nabla_{\mathbf{w}}L
=\frac1n\mathbf{X}^\top(\mathbf{X}\mathbf{w}-\mathbf{y})}.
\]
Ещё одно дифференцирование даёт
\(\nabla^2L=\mathbf{X}^\top\mathbf{X}/n\succeq0\), поэтому задача выпукла.
## Производные часто встречающихся выражений
\[
\nabla_{\mathbf{x}}(\mathbf{a}^\top\mathbf{x})=\mathbf{a},
\qquad
\nabla_{\mathbf{x}}(\mathbf{x}^\top\mathbf{A}\mathbf{x})
=(\mathbf{A}+\mathbf{A}^\top)\mathbf{x}.
\]
Для симметричной \(\mathbf{A}\) последнее равно \(2\mathbf{A}\mathbf{x}\).
\[
d\log\det\mathbf{X}
=\operatorname{tr}(\mathbf{X}^{-1}d\mathbf{X}),
\qquad
\nabla_{\mathbf{X}}\log\det\mathbf{X}
=\mathbf{X}^{-\top}.
\]
Последняя формула требует обратимой матрицы; для вещественного логарифма
обычно предполагают \(\mathbf{X}\succ0\).
## Разобранный пример
Пусть
\[
\mathbf{X}=\begin{bmatrix}1&2\\2&0\end{bmatrix},\quad
\mathbf{w}=\begin{bmatrix}1\\-1\end{bmatrix},\quad
\mathbf{y}=\begin{bmatrix}0\\1\end{bmatrix}.
\]
Предсказания: \(\mathbf{Xw}=(-1,2)^\top\), остаток
\(\mathbf{r}=(-1,1)^\top\), \(n=2\). Тогда
\[
L=\frac1{4}(1+1)=0.5,
\]
\[
\nabla L
=\frac12\mathbf{X}^\top\mathbf{r}
=\frac12
\begin{bmatrix}1&2\\2&0\end{bmatrix}
\begin{bmatrix}-1\\1\end{bmatrix}
=\begin{bmatrix}0.5\\-1\end{bmatrix}.
\]
```python
import numpy as np
X = np.array([[1.0, 2.0], [2.0, 0.0]])
w = np.array([1.0, -1.0])
y = np.array([0.0, 1.0])
r = X @ w - y
loss = r @ r / (2 * len(y))
grad = X.T @ r / len(y)
print(loss) # 0.5
print(grad) # [ 0.5 -1. ]
```
## Численная проверка градиента
Центральная разность
\[
\frac{\partial f}{\partial x_j}
\approx\frac{f(\mathbf{x}+h\mathbf{e}_j)
-f(\mathbf{x}-h\mathbf{e}_j)}{2h}
\]
имеет ошибку усечения порядка \(O(h^2)\), но слишком малое \(h\) усиливает
ошибку округления.
```python
def finite_difference(f, x, h=1e-5):
grad = np.zeros_like(x, dtype=float)
for j in range(x.size):
step = np.zeros_like(x, dtype=float)
step[j] = h
grad[j] = (f(x + step) - f(x - step)) / (2 * h)
return grad
f = lambda v: np.sum(v**2)
print(finite_difference(f, np.array([1.0, -3.0])))
```
## Типичные ошибки
- Производная по вектору должна иметь проверяемую размерность.
- Поэлементное `*` не заменяет матричное `@`.
- \(\nabla(\mathbf{x}^\top\mathbf{A}\mathbf{x})=2\mathbf{Ax}\) только при
симметричной \(\mathbf{A}\).
- Нулевой градиент не гарантирует минимум.
- Градиент зависит от выбранной геометрии; утверждение о быстрейшем спуске
выше относится к евклидовой норме.
- Численная производная служит проверкой, а не точной заменой аналитической.
## Резюме
Производная — коэффициент локального линейного приближения. Градиент задаёт
чувствительность скаляра ко всем координатам, якобиан — чувствительность
вектора, гессиан — кривизну. Дифференциалы, след и контроль размерностей дают
надёжный способ выводить матричные градиенты.