梯度求解汇总

梯度,我觉得不用过多介绍了吧。当今 AI 时代,大家应该或多或少都听说过反向传播、自动微分。像梯度下降、学习率这些内容,我之前在最大似然函数的文章中也提到过。

简单来说,梯度描述的是函数在某一点附近如何变化。无论是优化问题、机器学习中的反向传播,还是自动微分求解器,本质上都离不开梯度。

阅读路线

  • 从一元的导数到多元函数梯度介绍
  • 向量梯度
  • 雅可比矩阵
  • 矩阵梯度

梯度类型概览

类型输入输出梯度形状简单例子梯度怎么求
一元函数标量 x标量 f一个数f(x)=x²普通微积分,直接求导
向量梯度向量 x标量 f和输入向量同形f(x,y)=x²+y²对每个分量分别求偏导,拼成梯度向量
雅可比矩阵向量 x向量 fm×n 矩阵f(x,y)=(x²+y, xy)每个输出分量分别对输入求梯度,再组成矩阵
矩阵梯度矩阵 X标量 f和输入矩阵同形f 是 X 的 Frobenius 范数平方用迹技巧,把 df 写成 tr(GᵀdX),则 G 就是梯度

至于矩阵到矩阵的函数类型,只给一个简单例子:

Y=AXY=AXY=AX

其中 A 是常量矩阵,则:

dY=A dXdY=A\,dXdY=AdX


梯度介绍

我们最熟悉的是一元函数的导数。对于一个函数:

y=f(x)y=f(x)y=f(x)

因为自变量只有一个,所以函数只能沿着 x 轴这一个方向变化。这个时候导数:

f′(x)f'(x)f(x)

就可以表示函数在这一点附近变化得快不快。

但是多元函数就不一样了。比如:

z=f(x,y)z=f(x,y)z=f(x,y)

它的自变量有两个,点 (x,y) 可以在平面上向很多方向移动。也就是说,函数值 z 的变化不再只对应一个方向,而是和移动方向有关。

这时如果只说“导数”,就不够准确了。因为沿着不同方向走,函数值可能增加得快,也可能增加得慢,甚至可能减少。所以在多元函数中,我们需要一个新的工具来描述函数在某一点附近的变化情况,这个工具就是梯度。

对于二元函数:

z=f(x,y)z=f(x,y)z=f(x,y)

它的梯度定义为:

∇f(x,y)=(∂f∂x,∂f∂y)\nabla f(x,y)=\left(\frac{\partial f}{\partial x},\frac{\partial f}{\partial y}\right)f(x,y)=(xf,yf)

所以可以这样理解:梯度就是把函数在各个坐标方向上的变化率放在一起,组成的一个向量。

具体例子:

f(x,y)=x2+y2f(x,y)=x^2+y^2f(x,y)=x2+y2

这个函数的图像就是一个碗形曲面,在点 (1,2) 处,梯度为:

∇f(x,y)=(∂f∂x,∂f∂y)=(2x,2y)\nabla f(x,y)=\left(\frac{\partial f}{\partial x},\frac{\partial f}{\partial y}\right)=(2x,2y)f(x,y)=(xf,yf)=(2x,2y)

所以:

∇f(1,2)=(2,4)\nabla f(1,2)=(2,4)f(1,2)=(2,4)

这个向量 (2,4) 告诉你什么?

它告诉你在 (1,2) 这个点,往哪个方向走函数值涨得最大。


向量梯度

在梯度介绍中就已经说了向量梯度了。

这其中最重要的是链式法则。我记得我之前看 Andrej Karpathy 的一个很出名的人工智能课,他写的反向传播求解器,本质上就是链式法则。

以逻辑回归为例,直接看怎么把梯度算出来。

目标是对 w 求梯度,注意观察这里有三层嵌套:

w⟶z=wTx⟶y^=σ(z)⟶Lw \longrightarrow z=w^T x \longrightarrow \hat{y}=\sigma(z) \longrightarrow Lwz=wTxy^=σ(z)L

链式法则就是把每一层分别求导再连乘:

∂L∂w=∂L∂y^⋅∂y^∂z⋅∂z∂w\frac{\partial L}{\partial w}=\frac{\partial L}{\partial \hat{y}}\cdot\frac{\partial \hat{y}}{\partial z}\cdot\frac{\partial z}{\partial w}wL=y^Lzy^wz

三层分别算:

∂L∂y^=y−y^y^(1−y^)\frac{\partial L}{\partial \hat{y}}=\frac{y-\hat{y}}{\hat{y}(1-\hat{y})}y^L=y^(1y^)yy^

∂y^∂z=y^(1−y^)\frac{\partial \hat{y}}{\partial z}=\hat{y}(1-\hat{y})zy^=y^(1y^)

∂z∂w=x\frac{\partial z}{\partial w}=xwz=x

连乘之后,中间项直接约掉:

∂L∂w=y−y^y^(1−y^)⋅y^(1−y^)⋅x\frac{\partial L}{\partial w}=\frac{y-\hat{y}}{\hat{y}(1-\hat{y})}\cdot\hat{y}(1-\hat{y})\cdot xwL=y^(1y^)yy^y^(1y^)x

所以:

∂L∂w=(y−y^)x\frac{\partial L}{\partial w}=(y-\hat{y})xwL=(yy^)x

对所有样本求和,梯度就出来了:

∇wL=∑i=1n(yi−y^i)xi\nabla_w L=\sum_{i=1}^{n}(y_i-\hat{y}_i)x_iwL=i=1n(yiy^i)xi

这就是向量梯度最典型的计算过程:拆层、逐层求导、连乘。


雅可比矩阵

前面讨论的大多数情况,输出都是一个标量。不管输入是一个 x,还是一堆变量,最终函数值 f 都是一个数。梯度向量做的事情,就是把这个标量对每个输入方向求偏导,拼成一个向量。

那现在问题来了:如果输出也是一个向量呢?

比如这样一个函数:

f:Rn→Rmf:\mathbb{R}^n\to\mathbb{R}^mf:RnRm

输入是 n 维向量,输出是 m 维向量。这时候“梯度”长什么样?

先从直觉出发

我们先想一个最简单的情况:

f:R2→R2f:\mathbb{R}^2\to\mathbb{R}^2f:R2R2

也就是:

f(x,y)=(f1(x,y)f2(x,y))f(x,y)=\begin{pmatrix}f_1(x,y)\\f_2(x,y)\end{pmatrix}f(x,y)=(f1(x,y)f2(x,y))

两个输出,每个输出都是一个标量函数。对第一个输出来说,它的梯度是:

∇f1=(∂f1∂x,∂f1∂y)\nabla f_1=\left(\frac{\partial f_1}{\partial x},\frac{\partial f_1}{\partial y}\right)f1=(xf1,yf1)

对第二个输出来说,它的梯度是:

∇f2=(∂f2∂x,∂f2∂y)\nabla f_2=\left(\frac{\partial f_2}{\partial x},\frac{\partial f_2}{\partial y}\right)f2=(xf2,yf2)

既然有两个输出,就有两个梯度向量。雅可比矩阵做的事情非常朴素:把这两个梯度向量叠在一起,变成一个矩阵。

J=(∇f1∇f2)=(∂f1∂x∂f1∂y∂f2∂x∂f2∂y)J=\begin{pmatrix}\nabla f_1\\\nabla f_2\end{pmatrix}=\begin{pmatrix}\frac{\partial f_1}{\partial x}&\frac{\partial f_1}{\partial y}\\\frac{\partial f_2}{\partial x}&\frac{\partial f_2}{\partial y}\end{pmatrix}J=(f1f2)=(xf1xf2yf1yf2)

这就是雅可比矩阵。第 i 行就是第 i 个输出分量的梯度向量。

定义

对于:

f:Rn→Rmf:\mathbb{R}^n\to\mathbb{R}^mf:RnRm

雅可比矩阵 J 的定义为:

Jij=∂fi∂xjJ_{ij}=\frac{\partial f_i}{\partial x_j}Jij=xjfi

写成完整矩阵的形式:

J=(∂f1∂x1⋯∂f1∂xn⋮⋱⋮∂fm∂x1⋯∂fm∂xn)J=\begin{pmatrix}\frac{\partial f_1}{\partial x_1}&\cdots&\frac{\partial f_1}{\partial x_n}\\\vdots&\ddots&\vdots\\\frac{\partial f_m}{\partial x_1}&\cdots&\frac{\partial f_m}{\partial x_n}\end{pmatrix}J=x1f1x1fmxnf1xnfm

记住形状:m 行对应 m 个输出,n 列对应 n 个输入。

例子

设:

f(x,y)=(x2+yxy)f(x,y)=\begin{pmatrix}x^2+y\\xy\end{pmatrix}f(x,y)=(x2+yxy)

两个输出分量分别是:

f1=x2+yf_1=x^2+yf1=x2+y

f2=xyf_2=xyf2=xy

逐个求偏导,填进矩阵:

J=(∂f1∂x∂f1∂y∂f2∂x∂f2∂y)=(2x1yx)J=\begin{pmatrix}\frac{\partial f_1}{\partial x}&\frac{\partial f_1}{\partial y}\\\frac{\partial f_2}{\partial x}&\frac{\partial f_2}{\partial y}\end{pmatrix}=\begin{pmatrix}2x&1\\y&x\end{pmatrix}J=(xf1xf2yf1yf2)=(2xy1x)

在点 (1,2) 处,雅可比矩阵的值为:

J(1,2)=(2121)J(1,2)=\begin{pmatrix}2&1\\2&1\end{pmatrix}J(1,2)=(2211)

这个矩阵告诉你:在点 (1,2) 附近,如果 x 和 y 发生很小的变化,那么两个输出会大约怎么变。

更具体地说,如果输入有一个很小的变化:

dx=(dxdy)d\mathbf{x}=\begin{pmatrix}dx\\dy\end{pmatrix}dx=(dxdy)

那么输出变化近似为:

df≈Jdxdf\approx Jd\mathbf{x}dfJdx

在这个例子中:

df≈(2121)(dxdy)=(2dx+dy2dx+dy)df\approx\begin{pmatrix}2&1\\2&1\end{pmatrix}\begin{pmatrix}dx\\dy\end{pmatrix}=\begin{pmatrix}2dx+dy\\2dx+dy\end{pmatrix}df(2211)(dxdy)=(2dx+dy2dx+dy)

也就是说,在点 (1,2) 附近,两个输出的一阶变化趋势是一样的。


矩阵梯度

梯度的形状

这一点先说清楚,避免困惑。

不管输入是标量、向量还是矩阵,梯度的形状通常都和输入保持一致。

  • 输入是标量 x,梯度是一个数
  • 输入是向量 x,梯度是一个向量
  • 输入是矩阵 X,梯度是一个矩阵

如果:

X∈Rm×nX\in\mathbb{R}^{m\times n}XRm×n

那么:

∂f∂X∈Rm×n\frac{\partial f}{\partial X}\in\mathbb{R}^{m\times n}XfRm×n

其中第 (i,j) 个元素就是:

(∂f∂X)ij=∂f∂Xij\left(\frac{\partial f}{\partial X}\right)_{ij}=\frac{\partial f}{\partial X_{ij}}(Xf)ij=Xijf

也就是说,矩阵梯度的每一个位置,对应的就是 f 对 X 在那个位置上的元素求偏导。概念上没有任何新东西,只是元素变多了。

概念非常简单,但如果每次都展开成元素,写成求和式,再一个个求偏导,非常容易出错,所以就引入了迹技巧。

迹技巧的核心公式

记住一个关键结论:

df=tr(GTdX)⟹∂f∂X=Gdf=\mathrm{tr}(G^T dX)\quad\Longrightarrow\quad\frac{\partial f}{\partial X}=Gdf=tr(GTdX)Xf=G

需要记住的运算规则

微分的线性性:

d(A+B)=dA+dBd(A+B)=dA+dBd(A+B)=dA+dB

乘积法则:

d(AB)=(dA)B+A(dB)d(AB)=(dA)B+A(dB)d(AB)=(dA)B+A(dB)

迹的交换性:

tr(AB)=tr(BA)\mathrm{tr}(AB)=\mathrm{tr}(BA)tr(AB)=tr(BA)

迹对转置不变:

tr(A)=tr(AT)\mathrm{tr}(A)=\mathrm{tr}(A^T)tr(A)=tr(AT)

这几条规则就够用了,大部分矩阵梯度都能靠这几条推出来。

例子:Frobenius 范数

设:

f=∥X∥F2=tr(XTX)f=\|X\|_F^2=\mathrm{tr}(X^T X)f=XF2=tr(XTX)

第一步,对 f 求微分:

df=d tr(XTX)=tr(d(XTX))df=d\,\mathrm{tr}(X^T X)=\mathrm{tr}(d(X^T X))df=dtr(XTX)=tr(d(XTX))

用乘积法则展开括号里的部分:

d(XTX)=(dX)TX+XT(dX)d(X^T X)=(dX)^T X+X^T(dX)d(XTX)=(dX)TX+XT(dX)

所以:

df=tr((dX)TX+XTdX)df=\mathrm{tr}((dX)^T X+X^T dX)df=tr((dX)TX+XTdX)

也就是:

df=tr((dX)TX)+tr(XTdX)df=\mathrm{tr}((dX)^T X)+\mathrm{tr}(X^T dX)df=tr((dX)TX)+tr(XTdX)

第二步,利用迹的性质统一形式。

注意:

tr((dX)TX)=tr(XTdX)\mathrm{tr}((dX)^T X)=\mathrm{tr}(X^T dX)tr((dX)TX)=tr(XTdX)

所以两项合并:

df=2tr(XTdX)df=2\mathrm{tr}(X^T dX)df=2tr(XTdX)

第三步,对号入座。

现在 df 已经是下面这种形式:

df=tr(GTdX)df=\mathrm{tr}(G^T dX)df=tr(GTdX)

其中:

GT=2XTG^T=2X^TGT=2XT

所以:

G=2XG=2XG=2X

于是:

∂f∂X=2X\frac{\partial f}{\partial X}=2XXf=2X

这和我们对标量函数的直觉完全一致:

f(x)=x2⟹f′(x)=2xf(x)=x^2\quad\Longrightarrow\quad f'(x)=2xf(x)=x2f(x)=2x

只不过这里的输入变成了矩阵。


尾记

最近更新较慢,主要是因为我所在的学校实行的是小学期制,第八周直接迎来了期末周。加上数学专业的专业课确实硬核,实在没法简单糊弄过去,还望大家见谅。

此外,本人目前也只是一名本科生,文章中若有不当或疏漏之处,欢迎大家在评论区多加指正!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐