ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

D2L 多元微积分:从偏导数、梯度与 Hessian 到反向传播与矩阵微分

D2L 多元微积分:从偏导数、梯度与 Hessian 到反向传播与矩阵微分 文档教程人工智能深度学习NLP计算机视觉强化学习【免费下载链接】d2l-enInteractive deep learning book with multi-framework code, math, and discussions. Adopted at 500 universities from 70 countries including Stanford, MIT, Harvard, and Cambridge.项目地址https://gitcode.com/gh_mirrors/d2/d2l-en点击查看免费下载导读当损失函数拥有数十亿个权重时一元微积分显然不再够用。本文基于 multivariable-calculus.md 展开系统讲解深度学习中多元微积分的全部核心工具偏导数与梯度梯度下降方向的几何解释、多元链式法则与反向传播算法训练神经网络时梯度如何从损失反向流回每个参数、Hessian 矩阵与二阶近似理解牛顿法的基础以及最后实用的矩阵微积分技巧矩阵分解等场景的求导捷径。读完本文你将能理解autograd自动求导背后的一阶原理并掌握用手算推导任意复合函数梯度、用一元结果 转置修正快速猜测矩阵导数的方法。高阶微分从一元导数到梯度在一元微积分中我们得知若只改变数十亿权重中的一个 $w_1$、其余权重全部固定损失函数的行为就是一个一元函数可以写作$$L(w_1\epsilon_1, w_2, \ldots, w_N) \approx L(w_1, w_2, \ldots, w_N) \epsilon_1 \frac{d}{dw_1} L(w_1, w_2, \ldots, w_N).$$固定其余变量、只对某一个变量求导得到的导数称为偏导数partial derivative记作 $\frac{\partial}{\partial w_1}$。多变量同时扰动的一阶近似现在让 $w_2$ 也变化 $w_2 \to w_2 \epsilon_2$对式eq_part_der反复套用一阶近似并丢弃 $\epsilon_1\epsilon_2$ 这样的高阶小量可得$$L(w_1\epsilon_1, w_2\epsilon_2, \ldots, w_N\epsilon_N) \approx L(w_1, w_2, \ldots, w_N) \sum_i \epsilon_i \frac{\partial}{\partial w_i} L(w_1, w_2, \ldots, w_N).$$右边的求和恰好是一个点积。定义扰动向量与**梯度gradient**向量$$\boldsymbol{\epsilon} [\epsilon_1, \ldots, \epsilon_N]^\top, \qquad \nabla_{\mathbf{x}} L \left[\frac{\partial L}{\partial x_1}, \ldots, \frac{\partial L}{\partial x_N}\right]^\top,$$就得到贯穿全书的核心公式$$L(\mathbf{w} \boldsymbol{\epsilon}) \approx L(\mathbf{w}) \boldsymbol{\epsilon}\cdot \nabla_{\mathbf{w}} L(\mathbf{w}).$$它与一元情形具有完全相同的结构只是把标量替换成了向量、把乘法替换成了点积。它告诉我们给定任意微小扰动梯度可以预测函数 $L$ 将如何变化——这正是下一节梯度下降几何理解的基础。用一个具体函数验证近似精度以 $f(x, y) \log(e^x e^y)$ 为例其梯度为 $\nabla f (x, y) \left[\frac{e^x}{e^xe^y}, \frac{e^y}{e^xe^y}\right]$。在点 $(0, \log(2))$ 处$f \log(3)$梯度为 $[1/3, 2/3]$于是$$f(\epsilon_1, \log(2) \epsilon_2) \approx \log(3) \frac{1}{3}\epsilon_1 \frac{2}{3}\epsilon_2.$$取扰动 $\boldsymbol{\epsilon} [0.01, -0.03]$用代码对比近似值与真实值PyTorch 版本%matplotlib inline from d2l import torch as d2l from IPython import display from mpl_toolkits import mplot3d import torch import numpy as np def f(x, y): return torch.log(torch.exp(x) torch.exp(y)) def grad_f(x, y): return torch.tensor([torch.exp(x) / (torch.exp(x) torch.exp(y)), torch.exp(y) / (torch.exp(x) torch.exp(y))]) epsilon torch.tensor([0.01, -0.03]) grad_approx f(torch.tensor([0.]), torch.log( torch.tensor([2.]))) epsilon.dot( grad_f(torch.tensor([0.]), torch.log(torch.tensor(2.)))) true_value f(torch.tensor([0.]) epsilon[0], torch.log( torch.tensor([2.])) epsilon[1]) fapproximation: {grad_approx}, true Value: {true_value}MXNet 与 TensorFlow 的等价实现如下#tab mxnet %matplotlib inline from d2l import mxnet as d2l from IPython import display from mpl_toolkits import mplot3d from mxnet import autograd, np, npx npx.set_np() def f(x, y): return np.log(np.exp(x) np.exp(y)) def grad_f(x, y): return np.array([np.exp(x) / (np.exp(x) np.exp(y)), np.exp(y) / (np.exp(x) np.exp(y))]) epsilon np.array([0.01, -0.03]) grad_approx f(0, np.log(2)) epsilon.dot(grad_f(0, np.log(2))) true_value f(0 epsilon[0], np.log(2) epsilon[1]) fapproximation: {grad_approx}, true Value: {true_value}#tab tensorflow %matplotlib inline from d2l import tensorflow as d2l from IPython import display from mpl_toolkits import mplot3d import tensorflow as tf import numpy as np def f(x, y): return tf.math.log(tf.exp(x) tf.exp(y)) def grad_f(x, y): return tf.constant([(tf.exp(x) / (tf.exp(x) tf.exp(y))).numpy(), (tf.exp(y) / (tf.exp(x) tf.exp(y))).numpy()]) epsilon tf.constant([0.01, -0.03]) grad_approx f(tf.constant([0.]), tf.math.log( tf.constant([2.]))) tf.tensordot( epsilon, grad_f(tf.constant([0.]), tf.math.log(tf.constant(2.))), axes1) true_value f(tf.constant([0.]) epsilon[0], tf.math.log( tf.constant([2.])) epsilon[1]) fapproximation: {grad_approx}, true Value: {true_value}这里引入的d2l.plot等绘图与数值工具正是《动手学深度学习》工具库中提供的通用设施在 MXNet、PyTorch、TensorFlow、JAX 四个后端中均有对应实现见 d2l/torch.py、d2l/mxnet.py、d2l/tensorflow.py、d2l/jax.py。梯度的几何意义与梯度下降再次审视核心公式eq_nabla_use。假设我们要最小化损失 $L$梯度下降的直觉算法是随机初始化参数 $\mathbf{w}$找出使 $L$ 下降最快的方向 $\mathbf{v}$沿该方向迈出一小步$\mathbf{w} \rightarrow \mathbf{w} \epsilon\mathbf{v}$重复。关键问题在第二步如何计算 $\mathbf{v}$利用几何线性代数中关于点积的几何理解$\mathbf{a}\cdot\mathbf{b} |\mathbf{a}||\mathbf{b}|\cos\theta$把方向归一化为单位长度后$$L(\mathbf{w} \mathbf{v}) \approx L(\mathbf{w}) \mathbf{v}\cdot \nabla_{\mathbf{w}} L(\mathbf{w}) L(\mathbf{w}) |\nabla_{\mathbf{w}} L(\mathbf{w})|\cos(\theta),$$其中 $\theta$ 是 $\mathbf{v}$ 与 $\nabla_{\mathbf{w}} L(\mathbf{w})$ 的夹角。要让 $L$ 下降得最快就必须让 $\cos(\theta) -1$即夹角为 $\pi$ 弧度180 度——方向 $\mathbf{v}$ 必须与梯度完全相反。这就是机器学习最重要的数学结论之一最陡下降方向就是 $-\nabla_{\mathbf{w}}L(\mathbf{w})$。于是算法重写为随机初始化参数 $\mathbf{w}$计算 $\nabla_{\mathbf{w}} L(\mathbf{w})$沿相反方向迈出小步$\mathbf{w} \leftarrow \mathbf{w} - \epsilon\nabla_{\mathbf{w}} L(\mathbf{w})$重复。这就是 autograd.md:label:sec_autograd中首次介绍的梯度下降的完整几何来源。此后研究者对这一基础算法做了大量修改与适配动量、学习率调度、各种自适应方法等但核心思想始终未变用梯度找到损失下降最快的方向并朝该方向更新参数。关于数学优化的注记临界点与极值判定深度学习中所有函数都过于复杂无法显式求最小解因此全书聚焦数值优化。但上面的几何直觉也告诉我们如何直接验证一个点是否可能是最小值。设 $\mathbf{x}0$ 是 $L$ 的最小值点。若 $\nabla{\mathbf{x}} L(\mathbf{x}0) \neq 0$由eq_nabla_use可知沿方向 $-\epsilon \nabla{\mathbf{x}} L(\mathbf{x}_0)$ 走一小步就能得到更小的 $L$ 值与最小值矛盾。因此$$\nabla_{\mathbf{x}} L(\mathbf{x}_0) 0,$$我们把梯度为零的点称为临界点critical point。在少数情形下可以显式求出全部临界点再比较函数值。具体例子$f(x) 3x^4 - 4x^3 -12x^2$其导数$$\frac{df}{dx} 12x^3 - 12x^2 -24x 12x(x-2)(x1),$$临界点为 $x -1, 0, 2$函数值分别为 $-5, 0, -32$因此最小值在 $x 2$ 处取得。用d2l.plot快速绘图验证#tab all x torch.arange(-2, 3, 0.01) # pytorch 版本 f (3 * x**4) - (4 * x**3) - (12 * x**2) d2l.plot(x, f, x, f(x))MXNet 用np.arange(-2, 3, 0.01)TensorFlow 用tf.range(-2, 3, 0.01)其余代码相同。这个例子凸显了一个必须牢记的事实函数的最小值或最大值只可能出现在梯度为零的点但并非每个梯度为零的点都是真正的全局极值点——临界点可能是局部极小、局部极大或鞍点。多元链式法则神经网络的损失函数正是大量简单函数复合而成。考虑一个四变量函数由多层复合构成$$\begin{aligned}f(u, v) (uv)^{2} \u(a, b) (ab)^{2}, \qquad v(a, b) (a-b)^{2}, \a(w, x, y, z) (wxyz)^{2}, \qquad b(w, x, y, z) (wx-y-z)^2.\end{aligned}$$下图清晰地展示了变量间的依赖关系节点代表值边代表函数依赖直接展开为什么不可行理论上可以直接把 $f(w, x, y, z)$ 全部展开成关于四个变量的显式表达式然后只使用一元微分求导。但 $\frac{\partial f}{\partial w}$ 展开后将出现大量重复项再求 $\frac{\partial f}{\partial x}$ 又会出现另一大批项且与前者共享大量重复子式。这种计算方式浪费惊人——如果深度学习时代必须这样手动求导整个领域在起步阶段就会停滞。从路径视角理解链式法则拆解问题先只关注 $f$ 随 $a$ 的变化。对 $a$ 施加小扰动 $\epsilon$依次利用偏导数定义与梯度定义可得$$\frac{\partial f}{\partial a} \frac{\partial f}{\partial u}\frac{\partial u}{\partial a}\frac{\partial f}{\partial v}\frac{\partial v}{\partial a}.$$其含义非常直观$a$ 的变化有两条传导路径——$a \rightarrow u \rightarrow f$ 与 $a \rightarrow v \rightarrow f$链式法则要求把两条路径的贡献各自导数之积相加。对于更复杂的依赖网络结论推广为某个中间变量到最终输出的偏导等于它到输出之间所有路径上相邻导数的乘积之和。例如对下图所示依赖关系$$\frac{\partial f}{\partial y} \frac{\partial f}{\partial a} \frac{\partial a}{\partial u} \frac{\partial u}{\partial y} \frac{\partial f}{\partial u} \frac{\partial u}{\partial y} \frac{\partial f}{\partial b} \frac{\partial b}{\partial v} \frac{\partial v}{\partial y}.$$此处 $y \to f$ 共有 3 条路径需全部求和。这种沿路径求和的理解在后续理解梯度如何在网络中流动时回报巨大它解释了为什么 LSTM见 lstm.md 的sec_lstm或残差层见 resnet.md 的sec_resnet等架构选择能通过控制梯度流动来塑造学习过程——LSTM 的门控与记忆单元让梯度可以跨越多步不消失残差连接则让梯度可以直接经恒等捷径回传。反向传播算法回到上一节的复合函数例子。若想计算 $\frac{\partial f}{\partial w}$可以按分母对齐的方式套用多元链式法则$$\begin{aligned} \frac{\partial f}{\partial w} \frac{\partial f}{\partial u}\frac{\partial u}{\partial w} \frac{\partial f}{\partial v}\frac{\partial v}{\partial w}, \ \frac{\partial u}{\partial w} \frac{\partial u}{\partial a}\frac{\partial a}{\partial w}\frac{\partial u}{\partial b}\frac{\partial b}{\partial w}, \ \frac{\partial v}{\partial w} \frac{\partial v}{\partial a}\frac{\partial a}{\partial w}\frac{\partial v}{\partial b}\frac{\partial b}{\partial w}. \end{aligned}$$只需各类单步偏导$$\begin{aligned} \frac{\partial f}{\partial u} 2(uv), \quad\frac{\partial f}{\partial v} 2(uv), \ \frac{\partial u}{\partial a} 2(ab), \quad\frac{\partial u}{\partial b} 2(ab), \ \frac{\partial v}{\partial a} 2(a-b), \quad\frac{\partial v}{\partial b} -2(a-b), \ \frac{\partial a}{\partial w} 2(wxyz), \quad\frac{\partial b}{\partial w} 2(wx-y-z). \end{aligned}$$从输入到输出的手动实现取 $w, x, y, z -1, 0, -2, 1$先算函数值再算单步偏导最后从前往后组合#tab all # Compute the value of the function from inputs to outputs w, x, y, z -1, 0, -2, 1 a, b (w x y z)**2, (w x - y - z)**2 u, v (a b)**2, (a - b)**2 f (u v)**2 print(f f at {w}, {x}, {y}, {z} is {f}) # Compute the single step partials df_du, df_dv 2*(u v), 2*(u v) du_da, du_db, dv_da, dv_db 2*(a b), 2*(a b), 2*(a - b), -2*(a - b) da_dw, db_dw 2*(w x y z), 2*(w x - y - z) # Compute the final result from inputs to outputs du_dw, dv_dw du_da*da_dw du_db*db_dw, dv_da*da_dw dv_db*db_dw df_dw df_du*du_dw df_dv*dv_dw print(fdf/dw at {w}, {x}, {y}, {z} is {df_dw})这种写法有一个根本缺陷它只算出了 $\frac{\partial f}{\partial w}$却很难顺带得到 $\frac{\partial f}{\partial x}$。原因在于我们始终把 $w$ 放在分母上——即沿着一个输入如何影响所有下游的方向应用链式法则。但深度学习的真实需求恰恰相反我们想知道每个参数如何影响最终的损失也就是要尽量把 $\partial f$ 放在分子上。从输出到输入真正的反向传播改为保持 $\partial f$ 在分子上$$\begin{aligned} \frac{\partial f}{\partial w} \frac{\partial f}{\partial a}\frac{\partial a}{\partial w} \frac{\partial f}{\partial b}\frac{\partial b}{\partial w}, \ \frac{\partial f}{\partial a} \frac{\partial f}{\partial u}\frac{\partial u}{\partial a}\frac{\partial f}{\partial v}\frac{\partial v}{\partial a}, \ \frac{\partial f}{\partial b} \frac{\partial f}{\partial u}\frac{\partial u}{\partial b}\frac{\partial f}{\partial v}\frac{\partial v}{\partial b}. \end{aligned}$$同样的中间量 $\frac{\partial f}{\partial u}, \frac{\partial f}{\partial v}, \frac{\partial f}{\partial a}, \frac{\partial f}{\partial b}$ 可以被 $\frac{\partial f}{\partial x}, \frac{\partial f}{\partial y}, \frac{\partial f}{\partial z}$ 复用$$\begin{aligned} \frac{\partial f}{\partial x} \frac{\partial f}{\partial a}\frac{\partial a}{\partial x} \frac{\partial f}{\partial b}\frac{\partial b}{\partial x}, \ \frac{\partial f}{\partial y} \frac{\partial f}{\partial a}\frac{\partial a}{\partial y}\frac{\partial f}{\partial b}\frac{\partial b}{\partial y}, \ \frac{\partial f}{\partial z} \frac{\partial f}{\partial a}\frac{\partial a}{\partial z}\frac{\partial f}{\partial b}\frac{\partial b}{\partial z}. \end{aligned}$$实现如下——这一次从输出 $f$ 出发逐层向输入回推#tab all # Compute the value of the function from inputs to outputs w, x, y, z -1, 0, -2, 1 a, b (w x y z)**2, (w x - y - z)**2 u, v (a b)**2, (a - b)**2 f (u v)**2 print(ff at {w}, {x}, {y}, {z} is {f}) # Compute the derivative using the decomposition above # First compute the single step partials df_du, df_dv 2*(u v), 2*(u v) du_da, du_db, dv_da, dv_db 2*(a b), 2*(a b), 2*(a - b), -2*(a - b) da_dw, db_dw 2*(w x y z), 2*(w x - y - z) da_dx, db_dx 2*(w x y z), 2*(w x - y - z) da_dy, db_dy 2*(w x y z), -2*(w x - y - z) da_dz, db_dz 2*(w x y z), -2*(w x - y - z) # Now compute how f changes when we change any value from output to input df_da, df_db df_du*du_da df_dv*dv_da, df_du*du_db df_dv*dv_db df_dw, df_dx df_da*da_dw df_db*db_dw, df_da*da_dx df_db*db_dx df_dy, df_dz df_da*da_dy df_db*db_dy, df_da*da_dz df_db*db_dz print(fdf/dw at {w}, {x}, {y}, {z} is {df_dw}) print(fdf/dx at {w}, {x}, {y}, {z} is {df_dx}) print(fdf/dy at {w}, {x}, {y}, {z} is {df_dy}) print(fdf/dz at {w}, {x}, {y}, {z} is {df_dz})正是从 $f$ 回推到输入、而不是从输入前推到输出这一方向赋予了算法**反向传播backpropagation**之名。它由两个阶段构成前向传播forward pass从前往后计算函数值可与单步偏导的计算合并反向传播backward pass从后往前计算 $f$ 对各个中间节点与输入的梯度。这个分解之所以惊人在于它让一次遍历即可算出损失对所有参数的梯度——这正是每一个深度学习框架自动求导引擎所实现的算法。交给自动微分以上全部工作可以通过一行调用完成。PyTorch 利用requires_gradTrue与f.backward()#tab pytorch # Initialize as ndarrays, then attach gradients w torch.tensor([-1.], requires_gradTrue) x torch.tensor([0.], requires_gradTrue) y torch.tensor([-2.], requires_gradTrue) z torch.tensor([1.], requires_gradTrue) # Do the computation like usual, tracking gradients a, b (w x y z)**2, (w x - y - z)**2 u, v (a b)**2, (a - b)**2 f (u v)**2 # Execute backward pass f.backward() print(fdf/dw at {w.data.item()}, {x.data.item()}, {y.data.item()}, f{z.data.item()} is {w.grad.data.item()}) print(fdf/dx at {w.data.item()}, {x.data.item()}, {y.data.item()}, f{z.data.item()} is {x.grad.data.item()}) print(fdf/dy at {w.data.item()}, {x.data.item()}, {y.data.item()}, f{z.data.item()} is {y.grad.data.item()}) print(fdf/dz at {w.data.item()}, {x.data.item()}, {y.data.item()}, f{z.data.item()} is {z.grad.data.item()})MXNet 通过attach_grad()与autograd.record()上下文、f.backward()后读取.grad#tab mxnet # Initialize as ndarrays, then attach gradients w, x, y, z np.array(-1), np.array(0), np.array(-2), np.array(1) w.attach_grad() x.attach_grad() y.attach_grad() z.attach_grad() # Do the computation like usual, tracking gradients with autograd.record(): a, b (w x y z)**2, (w x - y - z)**2 u, v (a b)**2, (a - b)**2 f (u v)**2 # Execute backward pass f.backward() print(fdf/dw at {w}, {x}, {y}, {z} is {w.grad}) print(fdf/dx at {w}, {x}, {y}, {z} is {x.grad}) print(fdf/dy at {w}, {x}, {y}, {z} is {y.grad}) print(fdf/dz at {w}, {x}, {y}, {z} is {z.grad})TensorFlow 则用tf.Variable与tf.GradientTape#tab tensorflow # Initialize as ndarrays, then attach gradients w tf.Variable(tf.constant([-1.])) x tf.Variable(tf.constant([0.])) y tf.Variable(tf.constant([-2.])) z tf.Variable(tf.constant([1.])) # Do the computation like usual, tracking gradients with tf.GradientTape(persistentTrue) as t: a, b (w x y z)**2, (w x - y - z)**2 u, v (a b)**2, (a - b)**2 f (u v)**2 # Execute backward pass w_grad t.gradient(f, w).numpy() x_grad t.gradient(f, x).numpy() y_grad t.gradient(f, y).numpy() z_grad t.gradient(f, z).numpy() print(fdf/dw at {w.numpy()}, {x.numpy()}, {y.numpy()}, f{z.numpy()} is {w_grad}) print(fdf/dx at {w.numpy()}, {x.numpy()}, {y.numpy()}, f{z.numpy()} is {x_grad}) print(fdf/dy at {w.numpy()}, {x.numpy()}, {y.numpy()}, f{z.numpy()} is {y_grad}) print(fdf/dz at {w.numpy()}, {x.numpy()}, {y.numpy()}, f{z.numpy()} is {z_grad})自动微分的完整使用范式attach_grad/requires_grad/GradientTape、.backward()、读取.grad正是 autograd.md 这一章的主题。Hessian 矩阵与二阶近似与一元情形一样利用高阶导数可以得到比梯度更好的函数近似。多元函数 $f(x_1, \ldots, x_n)$ 共有 $n^2$ 个二阶偏导$$\frac{d^2f}{dx_idx_j} \frac{d}{dx_i}\left(\frac{d}{dx_j}f\right),$$把它们组装成矩阵即Hessian$$\mathbf{H}_f \begin{bmatrix} \frac{d^2f}{dx_1dx_1} \cdots \frac{d^2f}{dx_1dx_n} \ \vdots \ddots \vdots \ \frac{d^2f}{dx_ndx_1} \cdots \frac{d^2f}{dx_ndx_n} \ \end{bmatrix}.$$并非所有元素独立只要混合偏导存在且连续则对任意 $i, j$$$\frac{d^2f}{dx_idx_j} \frac{d^2f}{dx_jdx_i}.$$理由先沿 $x_i$ 扰动再沿 $x_j$ 扰动与先 $x_j$ 后 $x_i$ 两种顺序对 $f$ 输出的最终改变相同。因此 Hessian 是对称矩阵。点附近的最佳二次近似设 $f(x_1, x_2) a b_1x_1 b_2x_2 c_{11}x_1^{2} c_{12}x_1x_2 c_{22}x_2^{2}$二元二次的一般形式在原点处有$$\begin{aligned} f(0,0) a, \ \nabla f (0,0) \begin{bmatrix}b_1 \ b_2\end{bmatrix}, \ \mathbf{H} f (0,0) \begin{bmatrix}2 c_{11} c_{12} \ c_{12} 2c_{22}\end{bmatrix}, \end{aligned}$$于是可精确还原原多项式$$f(\mathbf{x}) f(0) \nabla f (0) \cdot \mathbf{x} \frac{1}{2}\mathbf{x}^\top \mathbf{H} f (0) \mathbf{x}.$$推广到任意点 $\mathbf{x}_0$、任意维输入最佳逼近二次式为$$f(\mathbf{x}) f(\mathbf{x}_0) \nabla f (\mathbf{x}_0) \cdot (\mathbf{x}-\mathbf{x}_0) \frac{1}{2}(\mathbf{x}-\mathbf{x}_0)^\top \mathbf{H} f (\mathbf{x}_0) (\mathbf{x}-\mathbf{x}_0).$$三维可视化验证对 $f(x, y) xe^{-x^2-y^2}$其梯度与 Hessian 为$$\nabla f(x, y) e^{-x^2-y^2}\begin{pmatrix}1-2x^2 \ -2xy\end{pmatrix}, \qquad \mathbf{H}f(x, y) e^{-x^2-y^2}\begin{pmatrix} 4x^3 - 6x 4x^2y - 2y \ 4x^2y-2y 4xy^2-2x\end{pmatrix}.$$经过简单代数运算在 $[-1,0]^\top$ 处的逼近二次式为$$f(x, y) \approx e^{-1}\left(-1 - (x1) (x1)^2y^2\right).$$用mplot3d同时绘制原函数与逼近二次式紫色线框可直观看到曲面在展开点附近被二次式紧密贴合PyTorch 版本#tab pytorch # Construct grid and compute function x, y torch.meshgrid(torch.linspace(-2, 2, 101), torch.linspace(-2, 2, 101)) z x*torch.exp(- x**2 - y**2) # Compute approximating quadratic with gradient and Hessian at (1, 0) w torch.exp(torch.tensor([-1.]))*(-1 - (x 1) 2 * (x 1)**2 2 * y**2) # Plot function ax d2l.plt.figure().add_subplot(111, projection3d) ax.plot_wireframe(x.numpy(), y.numpy(), z.numpy(), **{rstride: 10, cstride: 10}) ax.plot_wireframe(x.numpy(), y.numpy(), w.numpy(), **{rstride: 10, cstride: 10}, colorpurple) d2l.plt.xlabel(x) d2l.plt.ylabel(y) d2l.set_figsize() ax.set_xlim(-2, 2) ax.set_ylim(-2, 2) ax.set_zlim(-1, 1) ax.dist 12MXNet 版本用np.meshgrid/np.linspaceTensorFlow 版本用tf.meshgrid/tf.linspace绘图代码其余部分一致注意三个框架中二次式系数 $2$ 的写法差异来自索引顺序约定。这种不断寻找最佳逼近二次式并精确最小化它的迭代思想正是 gd.md 中**牛顿法Newtons Method**的基础牛顿法利用二阶信息Hessian构造二次近似并直接跳到其最小值在凸问题上收敛远快于梯度下降但在非凸问题上可能因 Hessian 为负而走向函数增大的方向详见该章Newtons Method一节。一点矩阵微积分涉及矩阵的函数求导结果往往异常简洁。本节记号较重可首读跳过但矩阵运算在深度学习中无处不在掌握其求导规律非常值得。分母布局约定机器学习中常用分母布局denominator layout把偏导数组装成与微分分母形状一致的向量/矩阵/张量。例如固定列向量 $\boldsymbol{\beta}$对 $f(\mathbf{x}) \boldsymbol{\beta}^\top\mathbf{x}$ 有$$\frac{df}{d\mathbf{x}} \begin{bmatrix} \frac{df}{dx_1} \ \vdots \ \frac{df}{dx_n} \end{bmatrix}.$$把函数按分量展开 $f(\mathbf{x}) \sum_{i 1}^{n} \beta_ix_i$逐项求偏导得 $\frac{df}{dx_i} \beta_i$重组后即$$\frac{df}{d\mathbf{x}} \boldsymbol{\beta}.$$这与一元结果 $\frac{d}{dx}(bx) b$ 惊人地相似。由此可总结矩阵微积分的三个常见特征中间计算往往繁琐最终结果通常比中间过程简洁且总是与一元情形形似转置常常凭空出现——根因是匹配分母形状的约定做矩阵乘法时必须借助转置把形状配回分母的形状。用 Einstein 求和约定推导二次型求 $\frac{d}{d\mathbf{x}}(\mathbf{x}^\top A \mathbf{x})$。用 Einstein 记号写为 $\mathbf{x}^\top A \mathbf{x} x_ia_{ij}x_j$对第 $k$ 个分量用乘积法则$$\frac{d}{dx_k}x_ia_{ij}x_j \frac{dx_i}{dx_k}a_{ij}x_j x_ia_{ij}\frac{dx_j}{dx_k}.$$$\frac{dx_i}{dx_k}$ 仅在 $ik$ 时为 1否则为 0故第一项只剩 $ik$、第二项只剩 $jk$$$\frac{d}{dx_k}x_ia_{ij}x_j a_{kj}x_j x_ia_{ik}.$$Einstein 记号下指标名可随意重命名$i$ 与 $j$ 是否不同无关紧要统一改用 $i$ 得$$\frac{d}{dx_k}x_ia_{ij}x_j a_{ki}x_i x_ia_{ik} (a_{ki} a_{ik})x_i.$$而 $a_{ki} a_{ik}$ 正是 $(\mathbf{A} \mathbf{A}^\top)$ 的 $(k,i)$ 分量于是$$\frac{d}{d\mathbf{x}}(\mathbf{x}^\top A \mathbf{x}) (\mathbf{A} \mathbf{A}^\top)\mathbf{x}.$$对照一元结果 $\frac{d}{dx}(xax) (aa)x$多元结果再次形似一元 转置。为什么会这样因为矩阵导数若可写成矩阵表达式它就必须对 $1\times 1$ 矩阵也成立而 $1\times 1$ 情形下矩阵乘积退化为数乘、转置不产生任何作用——因此最终表达式必须与一元表达式一致。这一观察带来实用技巧只要知道对应的一元导数形式往往就能猜出矩阵导数。猜解与验证矩阵分解中的求导设 $\mathbf{X}$ 是 $n \times m$$\mathbf{U}$ 是 $n \times r$$\mathbf{V}$ 是 $r \times m$计算$$\frac{d}{d\mathbf{V}} |\mathbf{X} - \mathbf{U}\mathbf{V}|_2^{2} ;?$$这是矩阵分解领域的核心计算。先看 $1\times 1$ 情形$\frac{d}{dv} (x-uv)^{2} -2(x-uv)u$。直接翻译成矩阵会得到 $-2(\mathbf{X} - \mathbf{U}\mathbf{V})\mathbf{U}$但维度对不上$\mathbf{X} - \mathbf{U}\mathbf{V}$ 是 $n\times m$$\mathbf{U}$ 是 $n \times r$无法相乘。目标 $\frac{d}{d\mathbf{V}}$ 形状应为 $r\times m$于是猜测需要借助转置$$\frac{d}{d\mathbf{V}} |\mathbf{X} - \mathbf{U}\mathbf{V}|_2^{2} -2\mathbf{U}^\top(\mathbf{X} - \mathbf{U}\mathbf{V}).$$严格推导可跳过对每个元素 $v_{ab}$$$\frac{d}{dv_{ab}} |\mathbf{X} - \mathbf{U}\mathbf{V}|2^{2} \frac{d}{dv{ab}} \sum_{i, j}\left(x_{ij} - \sum_k u_{ik}v_{kj}\right)^2.$$把导数移入求和并对平方用链式法则$$\frac{d}{dv_{ab}} |\mathbf{X} - \mathbf{U}\mathbf{V}|2^{2} \sum{i, j}2\left(x_{ij} - \sum_k u_{ik}v_{kj}\right)\left(-\sum_k u_{ik}\frac{dv_{kj}}{dv_{ab}} \right).$$$\frac{dv_{kj}}{dv_{ab}}$ 仅在 $ka$ 且 $jb$ 时非零其余项全部为零可丢弃得到$$\frac{d}{dv_{ab}} |\mathbf{X} - \mathbf{U}\mathbf{V}|2^{2} -2\sum{i}\left(x_{ib} - \sum_k u_{ik}v_{kb}\right)u_{ia}.$$注意内层求和中的 $k$ 是哑变量不参与 $ka$ 的判断类比 $\frac{d}{dx_1} \left(\sum_i x_i \right)^{2} 2\left(\sum_i x_i \right)$ 即可理解。继续识别矩阵分量$$\sum_k u_{ik}v_{kb} [\mathbf{U}\mathbf{V}]{ib}, \qquad x{ib} - \sum_k u_{ik}v_{kb} [\mathbf{X}-\mathbf{U}\mathbf{V}]_{ib},$$于是$$\frac{d}{dv_{ab}} |\mathbf{X} - \mathbf{U}\mathbf{V}|2^{2} -2\sum{i}[\mathbf{X}-\mathbf{U}\mathbf{V}]{ib}u{ia}.$$利用 $u_{ia} [\mathbf{U}^\top]_{ai}$ 交换指标顺序、将其整理成矩阵乘积$$\frac{d}{dv_{ab}} |\mathbf{X} - \mathbf{U}\mathbf{V}|2^{2} -2[\mathbf{U}^\top(\mathbf{X}-\mathbf{U}\mathbf{V})]{ab},$$最终得到与猜解一致的结论$$\frac{d}{d\mathbf{V}} |\mathbf{X} - \mathbf{U}\mathbf{V}|_2^{2} -2\mathbf{U}^\top(\mathbf{X} - \mathbf{U}\mathbf{V}).$$为什么不把所有矩阵求导规则一次背下来Petersen Pedersen 的《The Matrix Cookbook》提供了系统总结但矩阵运算的组合方式远多于标量规则数量庞大。实践中更稳妥的做法是优先用指标逐项推导或直接交给自动微分。小结在高维情形梯度与一元导数扮演相同角色它告诉我们多元函数在输入受到任意微小扰动时如何变化。反向传播算法可以看作多元链式法则的一种组织形式它让大量偏导数可以被高效地一次性计算出来。矩阵微积分让我们得以把矩阵表达式的导数写成简洁形式其最终结果往往形似一元导数 必要的转置修正。练习给定列向量 $\boldsymbol{\beta}$分别计算 $f(\mathbf{x}) \boldsymbol{\beta}^\top\mathbf{x}$ 与 $g(\mathbf{x}) \mathbf{x}^\top\boldsymbol{\beta}$ 的导数。为什么两者答案相同设 $\mathbf{v}$ 是 $n$ 维向量$\frac{\partial}{\partial\mathbf{v}}|\mathbf{v}|_2$ 是什么设 $L(x, y) \log(e^x e^y)$计算其梯度。梯度各分量之和是多少设 $f(x, y) x^2y xy^2$证明其唯一临界点是 $(0,0)$。通过考察 $f(x, x)$判断 $(0,0)$ 是极大值、极小值还是都不是。设我们在最小化 $f(\mathbf{x}) g(\mathbf{x}) h(\mathbf{x})$如何从几何上解释 $\nabla f 0$ 对 $g$ 与 $h$ 的含义练习之外读者还可以继续阅读本书的配套章节深化理解单变量微积分与 Taylor 级数一阶近似的源头、几何与线性代数运算点积的几何含义、自动微分反向传播的工程实现、梯度下降与牛顿法一阶与二阶优化算法以及 lstm.md、resnet.md 中链式法则与梯度流动的实际应用。赞分享文档教程人工智能深度学习NLP计算机视觉强化学习【免费下载链接】d2l-enInteractive deep learning book with multi-framework code, math, and discussions. Adopted at 500 universities from 70 countries including Stanford, MIT, Harvard, and Cambridge.项目地址https://gitcode.com/gh_mirrors/d2/d2l-en点击查看免费下载相关推荐Maths-CS-AI Compendium 多元微积分实战从偏导数、梯度与 Hessian 到 JAX 自动微分与自研反向传播引擎Maths CS AI Compendium 多元微积分实战从偏导数、梯度与 Hessian 到 JAX 自动微分与自研反向传播引擎 多元微积分把导数和积分从文档教程知识库终极机器学习梯度计算指南从偏导数到反向传播的完整路径终极机器学习梯度计算指南从偏导数到反向传播的完整路径 在机器学习领域梯度计算是优化算法的核心引擎决定了模型能否高效收敛到最优解。本指南将带你从基础的偏导数示例工程机器学习深度学习教程TensorFlow自动微分完全指南掌握梯度计算与反向传播的5个关键技巧TensorFlow自动微分完全指南掌握梯度计算与反向传播的5个关键技巧 TensorFlow Course项目为初学者提供了简单易用的TensorFlow教教程深度学习机器学习上一篇发现macOS上的新宠Picture in Picture下一篇Jan开源AI助手构建完全离线的ChatGPT替代方案为开发者和隐私意识用户提供安全可控的本地AI解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表