CS229: 7

深度学习, Deep Learning

深度学习

利用神经网络,将输入的特征赋予各种线性和非线性的运算,试图提取出新特征。

想象成这样一个结构,神经网络有很多层,每一层是若干个点组成的向量,这一层到下一层的运算是这一层的若干点连线到下一层的某个点。最后一层是损失函数,第一层是自己输入原始的数据。

首先,如果不引入非线性的成分,每一层到下一层的操作只是加权求和,那实际上无论多少层网络都只等效于一层。因为这样每一层到下一层的操作就是一个矩阵乘法,矩阵乘法怎么复合都是矩阵乘法,不能带给我们额外的信息。

在神经网络中引入非线性的成分称之为激活函数。目前最著名也是最常用的是

ReLu(x)=max(0,x)\text{ReLu}(x)=\max(0,x)

灵感来源可以认为是生物中的神经元。

引入激活函数时,可以想象在原本网络的每两层中间插入一层大小和上一层一样的点,每个点只有到上一层相同位置点的连线,运算代表的含义上一层的点传入的数据代入激活函数。然后下一层再对激活函数这一层进行加权求和。

这样网络中的每一个点被称为一个神经元。

神经网络的优越性相当于在人为设定网络结构后,可以自己寻找不同层次的特征,很大程度上弱化了手动提取特征的重要性。

全连接层(MLP)

考虑一个简单的情况,不人为设计上一层到下一层有哪些点连接,默认下一层的每个点都和上一层的所有点连接。

这样网络中只有两种元素,矩阵乘法和激活函数,记为

MMW,b(z)=Wz+bσ(z)MLP(z)=MMW[r],b[r](...σ(MMW[1],b[1](x)))MM_{W,b}(z)=Wz+b\\ \sigma(z)\\ MLP(z)=MM_{W^{[r]},b^{[r]}}(...\sigma(MM_{W^{[1]},b^{[1]}}(x)))

这样形成的一层矩阵乘法一层激活函数叫做一个LayerLayer

ResNet

理论上神经网络深度越大,能学习到的特征越多,至少是可以过拟合的。实际上并不是这样,随着网络深度的加大,性能会先升后降,最终甚至会欠拟合,不能大力出奇迹。

有一种解决方式是残差网络连接。数据xx在经过矩阵乘法,激活函数,矩阵乘法,激活函数这样四层后,将xx加到下一层里面

Res(z)=z+σ(MM(σ(MM(z))))\text{Res}(z)=z+\sigma(MM(\sigma(MM(z))))

再把MLP中的每个Layer换成一个Res就得到了ResNet。

ResNet-S(z)=MM(Res(Res(...Res(z))))\text{ResNet-S(z)}=MM(Res(Res(...Res(z))))

ResNet背后思路是什么呢?

首先,在没有ResNet的时候,

层标准化(Layer Normalization)

还是和之前的标准化相同的思想,为了消除不同维度的数据范围不同等等原因使得某个维度会造成主要影响,对每一维度都进行标准化

LN-S(z)=[z1μ^σ^z2μ^σ^...zmμ^σ^]μ^=i=1mzinσ^=i=1m(ziμ^)2m\text{LN-S}(z)=\left[\begin{matrix} \frac{z_1-\hat \mu}{\hat \sigma} \\ \frac{z_2-\hat \mu}{\hat \sigma} \\ ... \\ \frac{z_m-\hat \mu}{\hat \sigma} \end{matrix}\right]\\ \hat \mu=\frac{\sum_{i=1}^{m}z_i}{n}\\ \hat \sigma=\sqrt{\frac{\sum_{i=1}^{m}(z_i-\hat\mu)^2}{m}}

在此基础上我们可以人为调整数据的均值和方差。

LN(z)=β+γLN-S(z)=[β+γz1μ^σ^β+γz2μ^σ^...β+γzmμ^σ^]\text{LN}(z)=\beta+\gamma\text{LN-S}(z)=\left[\begin{matrix} \beta+\gamma\frac{z_1-\hat \mu}{\hat \sigma} \\ \beta+\gamma\frac{z_2-\hat \mu}{\hat \sigma} \\ ... \\ \beta+\gamma\frac{z_m-\hat \mu}{\hat \sigma} \end{matrix}\right]\\

然后再把LNLN视为一个参数为β,γ\beta,\gamma的层,可以加入到神经网络中。

性质(Scaling-invariant property)

LN-S(αz)=LN-S(z)LN(MMαW,αb(z))=β+γLN-S(MMαW,αb(z))=β+γLN-S(αMMW,b(z))=β+γLN-S(MMW,b(z))=LN(MMW,b(z)) \text{LN-S}(\alpha z)=\text{LN-S}(z)\\ \text{LN}(\text{MM}_{\alpha W,\alpha b}(z))=\beta+\gamma\text{LN-S}(\text{MM}_{\alpha W,\alpha b}(z))\\ =\beta+\gamma\text{LN-S}(\alpha\text{MM}_{W,b}(z))\\ =\beta+\gamma\text{LN-S}(\text{MM}_{W,b}(z))\\ =\text{LN}(\text{MM}_{ W, b}(z))

换句话来说,使用LNLN层映射出来的数据是带有某种不变性的,能反应数据本身的某种特征。

layer-normalization一般用于nlp。

其他的normalization方法还有batch-normalization,group-normalization,一般用于cv。

卷积层(Convolutional Layer)

就是对数据做局部的线性加权求和,以此来提取局部特征,比如一维或二维数据。

反向传播

怎么更新神经网络的参数呢?

如果还是用梯度下降,应该怎么求导呢?

我们之前将神经网络写成了一个多层的复合函数的形式,我们可以利用链式求导法则来求导。

现在我们来将单元函数的链式求导法则拓展到多元函数

zRmu=g(z)RnJ=f(u)Rz\in \R^m\\ u=g(z)\in\R^n\\ J=f(u)\in R

可以这么想,链式求导法则遍历了从zzJJ的每一条路径再全部加起来

1im,Jzi=j=1nJujgjzi\forall 1\leq i\leq m,\frac{\partial{J}}{\partial{z_i}}=\sum_{j=1}^{n}\frac{\partial{J}}{\partial{u_j}} \frac{\partial{g_j}}{\partial{z_i}}

如果写成矩阵

Jz=[g1z1g2z1...gnz1g1z2g2z2...gnz2...g1zng2zn...gnzn]Ju\frac{\partial{J}}{\partial{z}}=\left[\begin{matrix} \frac{\partial{g_1}}{\partial{z_1}} & \frac{\partial{g_2}}{\partial{z_1}} & ... & \frac{\partial{g_n}}{\partial{z_1}}\\ \frac{\partial{g_1}}{\partial{z_2}} & \frac{\partial{g_2}}{\partial{z_2}} & ... & \frac{\partial{g_n}}{\partial{z_2}}\\ ...\\ \frac{\partial{g_1}}{\partial{z_n}} & \frac{\partial{g_2}}{\partial{z_n}} & ... & \frac{\partial{g_n}}{\partial{z_n}} \end{matrix}\right]\frac{\partial{J}}{\partial{u}}

但是如果zz是矩阵,那么直接写出ggzz求偏导的矩阵会出来一个三阶张量,这时候就不用这种矩阵形式了,还是用上面的式子

i,k,Jzi,k=j=1nJujgjzi,k\forall i,k,\frac{\partial{J}}{\partial{z_{i,k}}}=\sum_{j=1}^{n}\frac{\partial{J}}{\partial{u_j}} \frac{\partial{g_j}}{\partial{z_{i,k}}}

通过链式求导法则,我们可以从后往前,逐层更新出损失函数对当前层的参数的导数

这个用来更新的函数记为

Jz=B(g,z)Ju\frac{\partial{J}}{\partial{z}}=B(g,z)\frac{\partial{J}}{\partial{u}}

先不考虑不同层的函数的区别,设M[i]M^{[i]}的参数是θi\theta_i

J=Mk(Mk1(...M1(x)))u[0]=xu[1]=M1(u[0])...u[k]=Mk(u[k1])J=M_k(M_{k-1}(...M_1(x)))\\ u^{[0]}=x\\ u^{[1]}=M_1(u^{[0]})\\ ...\\ u^{[k]}=M_k(u^{[k-1]})

我们希望能求出

Jθ[k],Jθ[k1],...,Jθ[1]\frac{\partial{J}}{\partial{\theta^{[k]}}},\frac{\partial{J}}{\partial{\theta^{[k-1]}}},...,\frac{\partial{J}}{\partial{\theta^{[1]}}}

现在可以直接求出来的是

Jθ[k]\frac{\partial{J}}{\partial{\theta^{[k]}}}

怎么传递到

u[k]=Mk(u[k1])Jθ[k1]u^{[k]}=M_k(u^{[k-1]})\\ \frac{\partial{J}}{\partial{\theta^{[k-1]}}}

先不考虑参数的问题,如果只要求

Ju[k],Ju[k1],...,Ju[1]\frac{\partial{J}}{\partial{u^{[k]}}},\frac{\partial{J}}{\partial{u^{[k-1]}}},...,\frac{\partial{J}}{\partial{u^{[1]}}}

那么

Ju[k]Ju[k1]=B(Mk,u[k1])Ju[k]\frac{\partial{J}}{\partial{u^{[k]}}}\\ \frac{\partial{J}}{\partial{u^{[k-1]}}}=B(M_k,u^{[k-1]})\frac{\partial{J}}{\partial{u^{[k]}}}

如果反过来将θ[k1]\theta^{[k-1]}视为变量,那么可以视为

u[k]=Mk(u[k1],θ[k])u[k1]=Mk1(u[k2],θ[k1])u^{[k]}=M_k(u^{[k-1]},\theta^{[k]})\\ u^{[k-1]}=M_{k-1}(u^{[k-2]},\theta^{[k-1]})\\

所以

Jθ[k1]=B(Mk1,θ[k1])Ju[k1]\frac{\partial{J}}{\partial{\theta^{[k-1]}}}=B(M_{k-1},\theta^{[k-1]})\frac{\partial{J}}{\partial{u^{[k-1]}}}

所以要用链式求导法则求

Jθ[k],Jθ[k1],...,Jθ[1]\frac{\partial{J}}{\partial{\theta^{[k]}}},\frac{\partial{J}}{\partial{\theta^{[k-1]}}},...,\frac{\partial{J}}{\partial{\theta^{[1]}}}

也必须同时求

Ju[k],Ju[k1],...,Ju[1]\frac{\partial{J}}{\partial{u^{[k]}}},\frac{\partial{J}}{\partial{u^{[k-1]}}},...,\frac{\partial{J}}{\partial{u^{[1]}}}

而要求这些量,需要

u[k],u[k1],...,u[1]u^{[k]},u^{[k-1]},...,u^{[1]}

也就是需要在前向传播的过程中保留这些量,网络很大时对缓存会有很高要求。

需要更直观地理解反向传播的计算顺序的时候,可以将每个量作为一个点,按计算的依赖关系画出所谓的计算图。

Backward Function

Matrix Multiplication(MM)

MMW,b(z)=Wz+bu=MMW,b(z)Jz=B(MM,z)JuB(MM,z)Rn×nB(MM,z)i,j=(Wz+b)jzi=k=1nWj,kzkzi=Wj,iB(MM,z)=WTB(MM,z)(v)=WTv\text{MM}_{W,b}(z)=Wz+b\\ u=\text{MM}_{W,b}(z)\\ \frac{\partial{J}}{\partial{z}}=B(MM,z)\frac{\partial{J}}{\partial{u}}\\ B(MM,z)\in R^{n\times n}\\ B(MM,z)_{i,j}=\frac{\partial{(Wz+b)_j}}{\partial{z_i}}= \frac{\partial{\sum_{k=1}^{n}W_{j,k}z_k}}{\partial{z_i}}=W_{j,i} \\ B(MM,z)=W^T\\ B(MM,z)(v)=W^Tv\\

对于B(MM,W)B(MM,W),如果直接求会引入三阶张量,不便于计算,直接考虑B(MM,W)(v)B(MM,W)(v)

使用一开始的定义式推导

B(MM,W)(v)i,j=k=1n(Wz+b)Wi,jvk=k=1nzjvk=vzTB(MM,W)(v)_{i,j}=\sum_{k=1}^{n}\frac{\partial{(Wz+b)}}{\partial{W_{i,j}}}v_k=\sum_{k=1}^{n} z_j v_k=vz^T

Activation Function σ\sigma

MLP的反向传播

下面我们来具体看MLP中的反向传播

可以设为

z[1]=z^{[1]}=


CS229: 7
http://llz3724.github.io/2025/04/22/2025-04-22-cs229_7/
作者
llz3724
发布于
2025年4月22日
许可协议