最近花了些时间补充了Pytorch相关的知识,正好借着Pytorch的官方文档补充下深度学习的基础知识,主要是看看Pytorch中封装有哪些库函数,搞清楚这些库函数后面具体使用的算法,由于面比较广,可能深度不是很够
卷积层的目的主要是提取特征,in_channels和out_channels分别控制着输入通道和输出通道的数量,kerner_size, stride和padding组合控制这卷积后输出特征层的大小,另外:
dilation为空洞卷积的间隔,在图像分割领域,在dilation提出来之前,主要通过pooling和up sampling来提高单个像素的感受野,dilation的主要作用就是在不用pooling的情况下也能够增大像素的感受野,以达到更好的分割效果,如下图所示:
groups为分组卷积,所谓分组卷积就是将32通道的卷积任务分为两个16通道卷积进行,主要作用是减少参数量,因为减少了参数量,对于网络来说相当于进行了正则化。
bias为卷积偏置,偏置的存在主要是为两个更好地拟合数据
池化层的作用主要是去掉特征中的冗余信息,相当于下采样操作,当return_indices设置为True时,函数会输出最大值的序号,而最大反池化则等同于上采样,输入为最大池化操作的输出以及序号,将非最大值部分设置为0
pytorch中出来最大池化操作,池化操作还包括AvgPool2d, FractionalMaxPool2d, LPPool2d, AdaptiveMaxPool2d, AdaptiveAvgPool2d
非线性激活层存在的目的是为了让网络对非线性的数学模型具有拟合效果,与其类似的激活函数还包括ELU, PReLU, LeakyReLU, Threshold, Sigmoid, Tanh等等等等
批归一化层相对来说会复杂一些,起主要目的是改变小批量数据的分布(均值和方差),批归一化的位置如果放在激活层之前则是对节点的输出进行归一化,如果放在激活后则是对下一个节点的输入进行归一化,都是可以的,批归一化层的公式如下 y = x − mean [ x ] Var [ x ] + ϵ ∗ gamma + beta y=\frac{x-\operatorname{mean}[x]}{\sqrt{\operatorname{Var}[x]}+\epsilon} * \text { gamma }+\text { beta } y=Var[x]+ϵx−mean[x]∗ gamma + beta 其中 m e a n mean mean和 v a r var var分别为批数据的均值和方差, g a m m a gamma gamma和 b e t a beta beta为可以学习的参数,在训练过程中通过反向传播更新该参数,而在预测过程中则将该参数固定,Batch Normalization(BN)超详细解析对批归一化层进行了详细的解释,参考其总结一下加入批归一层带来的好处:
随机梯度下降法的定义是随机选取批量数据中单个样本梯度进行梯度下降,其优势是算法收敛速度快,但是精度会有所损失,在实际应用为了权衡速度和精度,通常我们是批量样本中随机选取小批量样本进行梯度计算,例如我们随机随机了 m m m个样本 { x ( 1 ) , … , x ( m ) } \left\{x^{(1)}, \ldots, x^{(m)}\right\} { x(1),…,x(m)},对应的目标为 y ( i ) y^{(i)} y(i),进行梯度估计有 g ← 1 m ∇ w ∑ i L ( f ( x ( i ) ; w ) , y ( i ) ) g \leftarrow \frac{1}{m} \nabla_{w} \sum_{i} L\left(f\left(x^{(i)} ;w \right), y^{(i)}\right) g←m1∇wi∑L(f(x(i);w),y(i))进行权重更新有 w ← w + g w \leftarrow w+g w←w+g随机梯度下降法中有如下几个参数:
动量因子momentum,在上面例子的基础上,多了一步速度更新 v ← α v − ϵ g v \leftarrow \alpha v-\epsilon g v←αv−ϵg然后在进行权重更新 w ← w + v w \leftarrow w+v w←w+v这样改进之后,当前时刻的梯度与历史时刻梯度相似时,这种趋势在当前时刻会加强,如果不同,则当前时刻的梯度方向减弱,由此动量因子可以让那些因为学习率太大而来回摆动的参数梯度前后抵消,从而阻止发散。
权重衰减系数weight_decay,该系数和L2正则化有关,所谓L2正则化就是在代价函数后面再加上一个正则化项 C = C 0 + λ 2 n ∑ w w 2 C=C_{0}+\frac{\lambda}{2 n} \sum_{w} w^{2} C=C0+2nλw∑w2L2正则化的作用主要是的权重 w w w变小,防止过拟合。我们对加入L2正则化后的代价函数进行推导有: ∂ C ∂ w = ∂ C 0 ∂ w + λ n w \frac{\partial C}{\partial w}=\frac{\partial C_{0}}{\partial w}+\frac{\lambda}{n} w ∂w∂C=∂w∂C0+nλw ∂ C ∂ b = ∂ C 0 ∂ b \frac{\partial C}{\partial b}=\frac{\partial C_{0}}{\partial b} ∂b∂C=∂b∂C0我们发现,L2正则化后对偏置 b b b没有影响,但是对于权重 w w w的更新有影响:KaTeX parse error: Undefined control sequence: \alphaC at position 56: …frac{\partial \̲a̲l̲p̲h̲a̲C̲_{0}}{\partial …在不适用L2正则化时,求导结果中的 w w w之前的系数是1,而 1 − η λ n 1-\frac{\eta \lambda}{n} 1−nηλ小于1,其效果是减小 w w w,这就是权重衰减系数的由来,在he实际应用中,学习率衰减通常有线性衰减(间隔固定epoch学习率减半)和指数衰减(间隔固定epoch学习率乘以0.9998)两种。
Nesterov加速梯度是在动量因子的基础上可以进一步加快收敛速度,使得收敛曲线更加稳定,经典动量的公式如下: v t = α v t − 1 − ϵ g ( w t − 1 ) v_{t}=\alpha v_{t-1}-\epsilon g\left(w_{t-1}\right) vt=αvt−1−ϵg(wt−1) w t = w t − 1 + v t w_{t}=w_{t-1}+v_{t} wt=wt−1+vt
而Nesterov加速梯度后的公式如下: w t − 1 a h e a d = w t − 1 + μ v t − 1 w_{t-1}^{a h e a d}=w_{t-1}+\mu v_{t-1} wt−1ahead=wt−1+μvt−1 v t = α v t − 1 − ϵ g ( w t − 1 a h e a d ) v_{t}=\alpha v_{t-1}-\epsilon g\left(w_{t-1}^{a h e a d}\right) vt=αvt−1−ϵg(wt−1ahead) w t = w t − 1 + v t w_{t}=w_{t-1}+v_{t} wt=wt−1+vt即Nesterov加速梯度中计算的梯度是在当前权重加上累计速度后的梯度
Adagrad算法相对SGD算法能够更加有效地收敛,能够在数据分布系数的场景,更好利用系数梯度的信息,我们计算梯度有: g ← 1 m ∇ w ∑ i L ( f ( x ( i ) ; w ) , y ( i ) ) g \leftarrow \frac{1}{m} \nabla_{\boldsymbol{w}} \sum_{i} L\left(f\left(\boldsymbol{x}^{(i)} ; \boldsymbol{w}\right), \boldsymbol{y}^{(i)}\right) g←m1∇wi∑L(f(x(i);w),y(i))累积平方梯度: r ← r + g ⊙ g r \leftarrow r+g \odot g r←r+g⊙g计算更新 Δ θ ← − ϵ δ + r ⊙ g \Delta \boldsymbol{\theta} \leftarrow-\frac{\epsilon}{\delta+\sqrt{r}} \odot g Δθ←−δ+rϵ⊙g应用更新 θ ← θ + Δ θ \theta \leftarrow \theta+\Delta \theta θ←θ+Δθ通常Adagrad算法一开始是激励收敛的,后面慢慢就变成惩罚收敛,这也就导致了会出现学习绿收缩到太小而无法进行有效收敛的情况
RMSprop算法与Adagrad算法唯一的不同就在于累积平方梯度的方法不同,其累积平方梯度的方式为: r ← ρ r + ( 1 − ρ ) g ⊙ g r \leftarrow \rho r+(1-\rho) g \odot g r←ρr+(1−ρ)g⊙g其实就是添加了一个衰减系数来控制历史信息获取多少,在该函数中同样可以配置动量因子momentum以及权重衰减系数weight_decay
Adam算法全称为adaptive moment estimation,Adam算法其实就是momentum和RMSporp的结合,其通过计算梯度的一阶矩估计和二阶矩估计而为不同的参数设计独立的自适应学习率,具体算法如下,同样先估计梯度: g ← 1 m ∇ w ∑ i L ( f ( x ( i ) ; w ) , y ( i ) ) \boldsymbol{g} \leftarrow \frac{1}{m} \nabla_{\boldsymbol{w}} \sum_{i} L\left(f\left(\boldsymbol{x}^{(i)} ; \boldsymbol{w}\right), \boldsymbol{y}^{(i)}\right) g←m1∇wi∑L(f(x(i);w),y(i))然后是更新一阶矩估计,也就是momenturm项: s ← ρ 1 s + ( 1 − ρ 1 ) g s \leftarrow \rho_{1} s+\left(1-\rho_{1}\right) g s←ρ1s+(1−ρ1)g更新二阶矩估计,相当于二阶矩估计: r ← ρ 2 r + ( 1 − ρ 2 ) g ⊙ g r \leftarrow \rho_{2} r+\left(1-\rho_{2}\right) g \odot g r←ρ2r+(1−ρ2)g⊙g然后分别修正一阶矩偏差和二阶矩偏差 s ^ ← s 1 − ρ 1 t \hat{\boldsymbol{s}} \leftarrow \frac{\boldsymbol{s}}{1-\rho_{1}^{t}} s^←1−ρ1ts r ^ ← r 1 − ρ 2 t \hat{\boldsymbol{r}} \leftarrow \frac{\boldsymbol{r}}{1-\rho_{2}^{t}} r^←1−ρ2tr然后逐元素计算更新 Δ θ = − ϵ s ^ r ^ + δ \Delta \theta=-\epsilon \frac{\hat{\boldsymbol{s}}}{\sqrt{\hat{\boldsymbol{r}}}+\delta} Δθ=−ϵr^+δs^最后应用更新: θ ← θ + Δ θ \theta \leftarrow \theta+\Delta \theta θ←θ+ΔθAdam算法的优势是适合解决大规模数据的参数优化问题,同时适用于非稳态目标
pytorch中还有的优化方法有Adadelta,Adamax,ASGD,LBFGS以及RProp
计算输入 x x x和目标 y y y之间的绝对值的平均值 loss ( x , y ) = 1 / n ∑ ∣ x i − y i ∣ \operatorname{loss}(x, y)=1 / n \sum \mid x_{i}-y_{i}| loss(x,y)=1/n∑∣xi−yi∣
计算输入 x x x和目标 y y y之间的均方误差 loss ( x , y ) = 1 / n ∑ ( x i − y i ) 2 \operatorname{loss}(x, y)=1 / n \sum\left(x_{i}-y_{i}\right)^{2} loss(x,y)=1/n∑(xi−yi)2
用于多分类器的交叉熵损失 loss ( x , class ) = − log exp ( x [ class ] ) ∑ j exp ( x [ j ] ) ) = − x [ class ] + log ( ∑ j exp ( x [ j ] ) ) \operatorname{loss}(x, \text { class })=-\log \frac{\exp (x[\text { class }])}{\left.\sum_{j} \exp (x[j])\right)} \quad=-x[\text { class }]+\log \left(\sum_{j} \exp (x[j])\right) loss(x, class )=−log∑jexp(x[j]))exp(x[ class ])=−x[ class ]+log(j∑exp(x[j]))
pytorch中还有的损失函数有NLLLoss,KLDivLoss,BCELoss,MarginRankingLoss,HingeEmbeddingLoss,MultiLabelMarginLoss,SmoothL1Loss,SoftMarginLoss,MultiLabelSoftMarginLOss,CosineEmbeddingLoss,MultiMarginLoss
从给定的上下界的均匀分布中生成值,然后填充入张量或者变量进行初始化
从给定的均值和方差的正态分布中生成值,然后填充入张量或者变量进行初始化
将给定的常量填充入张量或者变量进行初始化
为了使得网络中信息更好的流动,每一层输出的方差应该尽量相同,这就是xavier算法的核心思想,对于一层卷积有
y = w 1 x 1 + ⋯ + w n i x n i + b y=w_{1} x_{1}+\cdots+w_{n_{i}} x_{n_{i}}+b y=w1x1+⋯+wnixni+b其中 n i n_i ni表示输入个数,根据概率统计知识我们有如下方差公式: Var ( w i x i ) = E [ w i ] 2 Var ( x i ) + E [ x i ] 2 Var ( w i ) + Var ( w i ) Var ( x i ) \operatorname{Var}\left(w_{i} x_{i}\right)=E\left[w_{i}\right]^{2} \operatorname{Var}\left(x_{i}\right)+E\left[x_{i}\right]^{2} \operatorname{Var}\left(w_{i}\right)+\operatorname{Var}\left(w_{i}\right) \operatorname{Var}\left(x_{i}\right) Var(wixi)=E[wi]2Var(xi)+E[xi]2Var(wi)+Var(wi)Var(xi)特别地,当我们假设输入和权重都是0均值时有 Var ( w i x i ) = Var ( w i ) Var ( x i ) \operatorname{Var}\left(w_{i} x_{i}\right)=\operatorname{Var}\left(w_{i}\right) \operatorname{Var}\left(x_{i}\right) Var(wixi)=Var(wi)Var(xi)进一步假设输入的 x x x和 w w w都是独立同分布,则有: Var ( y ) = n i Var ( w i ) Var ( x i ) \operatorname{Var}(y)=n_{i} \operatorname{Var}\left(w_{i}\right) \operatorname{Var}\left(x_{i}\right) Var(y)=niVar(wi)Var(xi)于是,为了保证输入与输出方差一致,则应该有: Var ( w i ) = 1 n i \operatorname{Var}\left(w_{i}\right)=\frac{1}{n_{i}} Var(wi)=ni1对于一个多层网络,某一层的方差可以用累计的形式表达: Var [ z i ] = Var [ x ] ∏ i ′ = 0 i − 1 n i ′ Var [ W i ′ ] \operatorname{Var}\left[z^{i}\right]=\operatorname{Var}[x] \prod_{i^{\prime}=0}^{i-1} n_{i^{\prime}} \operatorname{Var}\left[W^{i^{\prime}}\right] Var[zi]=Var[x]i′=0∏i−1ni′Var[Wi′]反向传播时具有类似的形式: Var [ ∂ Cost ∂ s i ] = Var [ ∂ Cost ∂ s d ] ∏ i ′ = i d n i ′ + 1 Var [ W i ′ ] \operatorname{Var}\left[\frac{\partial \text { Cost }}{\partial s^{i}}\right]=\operatorname{Var}\left[\frac{\partial \text { Cost }}{\partial s^{d}}\right] \prod_{i^{\prime}=i}^{d} n_{i^{\prime}+1} \operatorname{Var}\left[W^{i^{\prime}}\right] Var[∂si∂ Cost ]=Var[∂sd∂ Cost ]i′=i∏dni′+1Var[Wi′]则为了保证前向传播和反向传播时每一层的方差一致,则应该满足 ∀ i , n i Var [ W i ] = 1 \forall i, \quad n_{i} \operatorname{Var}\left[W^{i}\right]=1 ∀i,niVar[Wi]=1 ∀ i , n i + 1 Var [ W i ] = 1 \forall i, \quad n_{i+1} \operatorname{Var}\left[W^{i}\right]=1 ∀i,ni+1Var[Wi]=1但是实际中输入和输出的个数通常不相等,因此最终我们的权重方差应该满足: ∀ i , Var [ W i ] = 2 n i + n i + 1 \forall i, \quad \operatorname{Var}\left[W^{i}\right]=\frac{2}{n_{i}+n_{i+1}} ∀i,Var[Wi]=ni+ni+12对于[a, b]区间中的均匀分布的方差为: Var = ( b − a ) 2 12 \operatorname{Var}=\frac{(b-a)^{2}}{12} Var=12(b−a)2那么,满足xavier算法的均匀分布是 W ∼ U [ − 6 n j + n j + 1 , 6 n j + n j + 1 ] W \sim U\left[-\frac{\sqrt{6}}{\sqrt{n_{j}+n_{j+1}}}, \frac{\sqrt{6}}{\sqrt{n_{j}+n_{j+1}}}\right] W∼U[−nj+nj+16,nj+nj+16]同理我们可知满足xavier算法的高斯分布是 W ∼ N [ 0 , 2 n j + n j + 1 ] W\sim N\left[0, \frac{\sqrt{2}}{\sqrt{n_{j}+n_{j+1}}}\right] W∼N[0,nj+nj+12]
上述xavier初始化的问题主要在只适用于线性激活函数,但实际上,对于深层神经网络来说,线性激活函数没有价值。kaiming算法就是针对是非线性的Relu激活函数设计的一种初始化方法。对于均值为0的输出来说,Relu激活函数会将小于零的部分都置为0,这样上述xavier初始化中均值为0的假设就不成立了,具体的推到可以参考论文Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification
pytorch中还有的初始化方式有eye,dirac,sparse