《南溪的目标检测学习笔记》——权重初始化

1 介绍

在使用CNN搭建目标检测模型时,有一个很重要的步骤就是需要进行权重初始化,那么为什么需要进行权重初始化呢?

2 权重初始化的原因

关于为什么要进行权重初始化,请阅读知乎文章《神经网络中的权重初始化一览:从基础到Kaiming》,以下简称为《初始化概览》;

原因一:防止深度神经网络在正向(前向)传播过程中层激活函数的输出损失梯度出现爆炸或消失

如果发生任何一种情况,梯度值太大或太小,就无法有效地向后传播,并且即便可以向后传播,网络也需要花更长时间来达到收敛。

猜想1:矩阵乘法的连乘会导致数值爆炸

《初始化概览》中提到:让我们假设有一个没有激活函数的简单的100层网络,并且每层都有一个包含这层权重的矩阵a。为了完成单个正向传播,我们必须对每层输入和权重进行矩阵乘法,总共100次连续的矩阵乘法。……呃!在这100次矩阵乘法某次运算中,层输出变得非常大,甚至计算机都无法识别其标准差和均值。

这里实际上模拟的是FC层中的矩阵乘法,我们复现了这个实验,结果如下:
在这里插入图片描述
实验代码请参考【exp_multiple_continued _matrix_multiplication】(check whether it would be blocked)
这说明矩阵乘法连乘是会导致数值爆炸的;

原因二:权重初始化使训练稳定(收敛加快)

既然不好的权重初始化会导致梯度消失等问题,那么好的初始化就会有助于收敛!
此原因来自于李沐老师的课程《14 数值稳定性 + 模型初始化和激活函数【动手学深度学习v2】》
权重初始化使训练稳定,其实现方式主要是使模型参数在训练过程中数值范围更加稳定,

李沐老师:“可以提高数值稳定性”。

这里可以看看有三老师的课件,
在这里插入图片描述

3 猜想:如何生成好的权重分布

在学习权重初始化时,我们一直在想一个奇怪的问题:为什么现在常用的初始化方法都是使用一些类似随机的分布,例如:随机分布或者正态分布,而不是使用一些类似确定性的初始化方法,例如:傅里叶变换基或者小波变换基呢?
后来想了一下,感觉还是不太容易实现的,
对于向量表示来说,我们期望找到的是尽可能“分布均匀”的一组向量表示,
在数学上来说,就是希望任意两个向量的点积的最大值尽可能小,也就是,
m i n   m a x   Θ ( ω i ⋅ ω j ) min\,max\,\Theta(\omega_i\cdot\omega_j) minmaxΘ(ωiωj)
其中, Θ ( ⋅ ) \Theta(\cdot) Θ()为取两向量夹角的函数, ω ∈ R m , 1 ⩽ i , j ⩽ N \omega\in R^m,1\leqslant i,j\leqslant N ωRm1i,jN N N N为需要生成向量的个数;
(这个跟正交基不太一样,正交基是希望两个向量的点积为0)
我之前以为卷积层的权重都是超定的,后来发现并不是,这里以ShuffleNetV2为例:
首先来看看论文中给出的通道结构图,
在这里插入图片描述

  1. Stage1 → \rightarrow Stage2存在维数超定的情况, 3 ∗ 3 ∗ 24 = 216 3*3*24=216 3324=216,可以看到在Stage1 → \rightarrow Stage2的过程中,shufflenetv2_2xStage2的维数是244,于是是维数超定的;
  2. 一般维数是欠定的,例如前面的0.5x1x1.5xStage2维数都小于216,都是欠定的情况。

3.1 总结

无法实现的原因,主要原因是:目前无法找到一个高效率( O ( n 3 ) O(n^3) O(n3))的算法,来快速生成这样一组分布尽可能均匀的向量。
所以目前使用的一个比较简单容易实现的方法:利用随机分布

4 PyTorch模块默认初始化方法

Conv2d: init.kaiming_uniform_

Conv2d默认使用的是Kaiming初始化,其代码如下:

def reset_parameters(self) -> None:
        # Setting a=sqrt(5) in kaiming_uniform is the same as initializing with
        # uniform(-1/sqrt(k), 1/sqrt(k)), where k = weight.size(1) * prod(*kernel_size)
        # For more details see: https://github.com/pytorch/pytorch/issues/15314#issuecomment-477448573
        init.kaiming_uniform_(self.weight, a=math.sqrt(5))
        if self.bias is not None:
            fan_in, _ = init._calculate_fan_in_and_fan_out(self.weight)
            bound = 1 / math.sqrt(fan_in)
            init.uniform_(self.bias, -bound, bound)

5 常用权重初始化方法

5.1 torch.nn.init.trunc_normal_()——截断正态分布

trunc_normal一个十分知名的应用就是Vit,所以还是很厉害的;
在看这个初始化函数之前,我们先来回顾一下trunc_normal的数学公式,(这里我们参考的是佛罗里达州立大学开源的 Truncated Normal Distribution的教材——《The Truncated Normal Distribution》by John Burkardt, Florida State University);

Truncated Normal Distribution

对于 Truncated Normal Distribution,其数学公式如下
ψ ( μ , σ , a , b ; x ) = { 0 if  x ≤ a ϕ ( x − μ σ ) Φ ( b − μ σ ) − Φ ( a − μ σ ) if  a < x < b 0 if  b ≤ x \psi \left(\mu,\sigma,a,b;x\right) = \left\{\begin{matrix} 0 & \text{if}\ x \leq a\\ \frac{\phi\left(\frac{x-\mu}{\sigma}\right)}{\Phi\left(\frac{b-\mu}{\sigma}\right)-\Phi\left(\frac{a-\mu}{\sigma}\right)} & \text{if}\ a <x<b\\ 0 & \text{if}\ b \leq x \end{matrix}\right. ψ(μ,σ,a,b;x)=0Φ(σbμ)Φ(σaμ)ϕ(σxμ)0if xaif a<x<bif bx
其中, ϕ ( x ) \phi(x) ϕ(x)表示标准正态分布(Standard Normal Distribution)的概率密度函数,

6 函数写作模板

这里我们参考李沐老师在课程中讲述的初始化模板进行写作,
在这里插入图片描述

7 为什么权重初始化要使用正态分布?

其实这个问题很难回答的,我们不妨从最简单的一步步来看:

7.1 初始化可以将卷积核权重全部设为0吗?

这个显然是不行,如果“权重全部设为0”,那么特征图输出全为0,那么后面的梯度根本无法传递,因为这一层的输出都是0,就没有梯度了
那么我们继续发散一下,

7.2 可以将卷积核每个通道都设置成一样吗?

这里我们需要通过实验来验证一下,为了使实验更加简单,这里我们选择的是“CIFAR10_world”数据集,(这也是《Deep Learning with PyTorch: A 60 Minute Blitz | Training an image classifier》教程中使用的数据集);
实验说明:这里我们会将所有参数都设置为相同的值0.0042,然后观察网络是否能够收敛,在没有训练的情况下,精度大概在10%左右;
训练之后的结果如下图所示,
在这里插入图片描述
训练后的精度可以达到23%,不过这个跟使用torch默认初始化设置的结果差远了,
为了达到这个结果,我做了几项“艰辛”的设置:

  1. 训练epoch数加到42:加长训练周期总会帮助模型渐渐收敛;
  2. batch-size加到16:大的batch-size有助于收敛;
  3. lr加到0.002:学习率随batch-size提高而增长,使用了“初始学习率线性提升策略”;

Colab代码:【Torch_exp_parameters_all_042
“训练epoch数增加”会大大延长训练时间,调参实验也花去了很多时间,尽管如此,才把精度提升到23%,说明了参数初始化算法的重要性!
最终证明如下结论
在参数初始化时卷积核每个通道是可以设置成一样的数值的,甚至于卷积层和全连接层中的每一个参数都可以设置为一样的值,不过这样的设置会使网络的收敛变得极为困难,所以这样的参数初始化是不可取的

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值