这里介绍求解矩阵或者向量梯度的一个便捷方法。
符号定义#
为了方便讨论,我们统一采用梯度张量的形式,而不是Jacobian 矩阵的形式,特此说明。
例如,设有函数 y=J(x),其中 y∈Rm×1,x∈Rn×1,则其梯度张量定义为:
∇xy=∂x∂y=∂x1∂y1∂x2∂y1⋮∂xn∂y1∂x1∂y2∂x2∂y2⋮∂xn∂y2⋯⋯⋱⋯∂x1∂ym∂x2∂ym⋮∂xn∂ym∈Rn×m这个形状的设定是基于对微分的考量, dy=(∂x∂y)⊤dx,这个形式更符合矩阵向量的点乘形式,因此梯度张量的形状是 n×m 才能正好符合这个微分公式。
链式法则#
基于上述梯度张量的定义,我们可以使用链式法则来求解复合函数的梯度。
例如,对于复合函数 y=f(w),w=g(z),z=h(x),有
∇xy=∇xz ∇zw ∇wy或者换成”偏导”符号的写法为
∂x∂y=∂x∂z∂z∂w∂w∂y注意,最内层函数的局部梯度要写在最左边。不妨拿个例子验证一下,设 y∈R2×1,w∈R3×1,z∈R4×1,x∈R5×1,则
∂x∂z∈R5×4,∂z∂w∈R4×3,∂w∂y∈R3×2由此 ∂x∂y∈R5×2,符合我们对梯度张量的定义。
如何求矩阵向量梯度张量#
虽然通常的矩阵分析书中都给出了常见的矩阵向量梯度张量的公式,但是对于复杂的函数,直接采用向量形式推导并不是一个好方法,通常会由于不清楚某个向量的导数公式而导致无从下手。因此这里更推荐的方法是,大不了就变成标量形式的导数 ∂xi∂yj,然后根据具体的形状重新排列即可。
例如,给定函数
J(θ)=−N1[y⊤logs+(1−y)⊤log(1−s)]其中 s,y∈RN×1,J(θ)∈R,log(⋅) 是逐元素的对数函数, N 为标量常数。
我们可以先计算每个元素的导数
∂si∂J=∂si∂[−N1i=1∑N(yilogsi+(1−yi)log(1−si))]=−N1[siyi−1−si1−yi]=N1si(1−si)si−yi然后将其整理成梯度张量的形式。注意到标量导数中并没有涉及到其他下标元素的值,所以这里的运算可以统统用逐元素计算表示
∇sJ=N1s⊙(1−s)s−y其中 ⊙ 表示逐元素乘法, 除法也是逐元素的。
例子:Logistic 回归的梯度#
设 h(x)=σ(θ⊤x),x,θ∈Rd×1,假设有数据集 X∈RN×d,y∈RN×1,则交叉熵损失为
J(θ)=−N1i=1∑N[yilogh(xi)+(1−yi)log(1−h(xi))]=−N1[y⊤logh(X)+(1−y)⊤log(1−h(X))]我们可以先计算每个元素的导数
∂θk∂J=∂θk∂[−N1i=1∑N[yilogh(xi)+(1−yi)log(1−h(xi))]]=−N1i=1∑N[yih(xi)1∂θk∂h(xi)−(1−yi)1−h(xi)1∂θk∂h(xi)]=−N1i=1∑N[yih(xi)1h(xi)(1−h(xi))xik−(1−yi)1−h(xi)1h(xi)(1−h(xi))xik]=−N1i=1∑N[yi(1−h(xi))xik−(1−yi)h(xi)xik]=−N1i=1∑N[(yi−h(xi))xik]其中 xi=(X[i,:])⊤ 是第 i 个样本的特征向量,xik=X[i,k] 是第 i 个样本的第 k 个特征。
然后将其整理成梯度张量的形式,得到
∇θJ=−N1i=1∑N(yi−h(xi))xi1xi2⋮xid=−N1i=1∑N(yi−h(xi))(X[i,:])⊤=−N1X⊤(y−h(X))=−N1X⊤(y−σ(Xθ))当然,这个结果也可以直接使用链式法则来推导得到,此处不赘述。