深度学习之权重初始化

在深度学习中,神经网络的权重初始化方法( w e i g h t weight weight i n i t i a l i z a t i o n initialization initialization)对模型的收敛速度和性能有着至关重要的影响。说白了,神经网络其实就是对权重参数 w w w的不停迭代更新,以达到更好的性能。因此,对权重 w w w的初始化则显得至关重要,一个好的权重初始化虽然不能完全解决梯度消失和梯度爆炸的问题,但是对于处理这两个问题是有很大的帮助的,并且十分有利于模型性能和收敛速度。

本文将介绍以下五种常见的权重初始化的方法:

权重初始化为 0 0 0
权重随机初始化
X a v i e r Xavier Xavier i n i t i a l i z a t i o n initialization initialization
H e He He i n i t i a l i z a t i o n initialization initialization
预训练权重
权重初始化为 0 0 0

如果将权重初始化全部为 0 0 0的话,这样的操作等同于等价于一个线性模型,将所有权重设为 0 0 0时,对于每一个 w w w而言,损失函数的导数都是相同的,因此在随后的迭代过程中所有权重都具有相同的值,这会使得隐藏单元变得对称,并继续运行设置的 n n n次的迭代,会导致网络中同一个神经元的不同权重都是一样的。下面代码为权重初始化为 0 0 0的代码:

def initialize_parameters_zeros(layers_dims):
    """
    Arguments:
    layer_dims -- python array (list) containing the size of each layer.
    Returns:
    parameters -- python dictionary containing your parameters "W1", "b1", ..., "WL", "bL":
                    W1 -- weight matrix of shape (layers_dims[1], layers_dims[0])
                    b1 -- bias vector of shape (layers_dims[1], 1)
                    ...
                    WL -- weight matrix of shape (layers_dims[L], layers_dims[L-1])
                    bL -- bias vector of shape (layers_dims[L], 1)
    """
    parameters = {
    
    }
    np.random.seed(3)
    L = len(layers_dims)  # number of layers in the network
    for l in range(1, L):
        parameters['W' + str(l)] = np.zeros((layers_dims[l], layers_dims[l - 1]))
        parameters['b' + str(l)] = np.zeros((layers_dims[l], 1))
    return parameters

让我们来看看权重初始化为 0 0 0之后其 c o s t cost cost f u n c t i o n function function是如何变化的,从图中可以看出,当代价函数降到 0.64 0.64 0.64(迭代 1000 1000 1000次)后,梯度逐渐消失,再训练迭代已经不起什么作用了。
在这里插入图片描述
权重随机初始化

权重随机初始化是比较常见的做法,即 W W W随机初始化。随机初始化的代码如下:

def initialize_parameters_random(layers_dims):
    """
    Arguments:
    layer_dims -- python array (list) containing the size of each layer.
    Returns:
    parameters -- python dictionary containing your parameters "W1", "b1", ..., "WL", "bL":
                    W1 -- weight matrix of shape (layers_dims[1], layers_dims[0])
                    b1 -- bias vector of shape (layers_dims[1], 1)
                    ...
                    WL -- weight matrix of shape (layers_dims[L], layers_dims[L-1])
                    bL -- bias vector of shape (layers_dims[L], 1)
    """
    np.random.seed(3)  # This seed makes sure your "random" numbers will be the as ours
    parameters = {
    
    }
    L = len(layers_dims)  # integer representing the number of layers
    for l in range(1, L):
        parameters['W' + str(l)] = np.random.randn(layers_dims[l], layers_dims[l - 1])*0.01
        parameters['b' + str(l)] = np.zeros((layers_dims[l], 1))
    return parameters

上述代码中权重乘 0.01 0.01 0.01是因为要把 W W W随机初始化到一个相对较小的值,因为如果 X X X很大的话, W W W又相对较大,会导致 Z Z Z非常大,这样如果激活函数是 s i g m o i d sigmoid sigmoid,就会导致 s i g m o i d sigmoid sigmoid的输出值 1 1 1或者 0 0 0,然后会导致一系列问题(比如 c o s t cost cost f u n c t i o n function function计算的时候, l o g log log里是 0 0 0,这样会有点麻烦)。随机初始化后, c o s t cost cost f u n c t i o n function function随着迭代次数的变化示意图如下图 2 2 2所示为
在这里插入图片描述
能够看出, c o s t cost cost f u n c t i o n function function的变化是比较正常的。但是随机初始化也有缺点, n p . r a n d o m . r a n d n ( ) np.random.randn() np.random.randn()其实是一个均值为 0 0 0,方差为 1 1 1的高斯分布中采样。当神经网络的层数增多时,会发现越往后面的层的激活函数(使用 t a n H tanH tanH)的输出值几乎都接近于 0 0 0,极易出现梯度消失。如下图 3 3 3所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1yDWJSjh-1688910304932)(ttps://files.mdnice.com/user/15207/1ab6da2d-591a-4780-b095-5630b7b50d87.png#pic_center)]

X a v i e r Xavier Xavier i n i t i a l i z a t i o n initialization initialization

在使用以上两种方法来初始化权重极易出现梯度消失的问题,而 X a v i e r Xavier Xavier i n i t i a l i z a t i o n initialization initialization出现就解决了上面问题。其思想倒就是尽可能的让输入和输出服从相同的分布,这样就能够避免后面层的激活函数的输出值趋向于 0 0 0。本文主要介绍 P y t o r c h Pytorch Pytorch当中 X a v i e r Xavier Xavier均匀分布和 X a v i e r Xavier Xavier正态分布初始化这两种方式。

我们来简单推导一下 X a v i e r Xavier Xavier初始化的原理:首先我们定义一层的卷积运算为如下公式,其中 n i {n_i} ni表示输入的个数。

扫描二维码关注公众号,回复: 15914752 查看本文章

y = w 1 x 1 + ⋅ ⋅ ⋅ + w n i x n i + b y = w_1x_1 + ··· + w_{ni}x_{ni}+ b y=w1x1+⋅⋅⋅+wnixni+b

根据我们学过的概率论统计知识可以得到如下的方差公式:

V a r ( w i x i ) = E [ w i ] 2 V a r ( x i ) + E [ x i ] 2 V a r ( w i ) + V a r ( w i ) V a r ( x i ) Var(w_ix_i)=E[w_i]^2Var(x_i) + E[x_i]^2Var(w_i) + Var(w_i)Var(x_i) Var(wixi)=E[wi]2Var(xi)+E[xi]2Var(wi)+Var(wi)Var(xi)

当我们假设输入和输入的权重的均值都是 0 0 0(使用BN层以后很容易就可以满足)时,上式可以简化为:

V a r ( w i x i ) = V a r ( w i ) V a r ( x i ) Var(w_ix_i)=Var(w_i)Var(x_i) Var(wixi)=Var(wi)Var(xi)

进一步我们假设输入 x x x和权重 w w w都是独立同分布,则可以得到:

V a r ( y ) = n i V a r ( w i ) V a r ( x i ) Var(y) = n_iVar(w_i)Var(x_i) Var(y)=niVar(wi)Var(xi)

于是按照 X a v i e r Xavier Xavier的要求保证输入和输出的方差要一致,则可以得到:

V a r ( w i ) = 1 n i Var(w_i) = \frac{1}{n_i} Var(wi)=ni1

对于一个多层的网络,某一层的方差可以用累积的形式表达:

V a r [ z i ] = V a r [ x ] ∏ i = 0 i − 1 n i V a r [ W i ‘ ] Var[z^i] = Var[x]\prod_{i^{}=0}^{i-1}n_i^Var[W^{i^`}] Var[zi]=Var[x]i=0i1niVar[Wi]

对于误差反向传播也有类似的表达形式,如下所示,其中 n i + 1 n_{i+1} ni+1表示输出个数

V a r [ ∂ C o s t ∂ s i ] = V a r [ ∂ C o s t ∂ s d ] ∏ i = i d n i + 1 V a r [ W i ‘ ] Var[\frac{\partial Cost}{\partial s^i}] = Var[\frac{\partial Cost}{\partial s^d}]\prod_{i^{}=i}^{d}n_{i^+1}Var[W^{i^`}] Var[siCost]=Var[sdCost]i=idni+1Var[Wi]

综上,为了保证前向传播和反向传播时每一层的方差一致,应满足:

∀ i , n i V a r [ W i ] = 1 \forall_i ,n_iVar[W^i]=1 iniVar[Wi]=1

∀ i , n i + 1 V a r [ W i ] = 1 \forall_i ,n_{i+1}Var[W^i]=1 ini+1Var[Wi]=1

但是,实际当中输入与输出的个数往往不相等,于是为了均衡考量输出和输入,最终我们的权重的方差应满足如下要求:

∀ i , V a r [ W i ] = 2 n i + n i + 1 \forall_i ,Var[W^i]= \frac{2}{n_i + n_{i+1}} iVar[Wi]=ni+ni+12

1、 X a v i e r Xavier Xavier均匀分布初始化

对于均匀分布来说,我们都知道区间 [ a , b ] [a,b] [a,b]的方差为:

V a r = ( b − a ) 2 12 Var=\frac{(b-a)^2}{12} Var=12(ba)2

那么就需要将均匀分布的方差等于我们在上面推导出来的 X a v i e r Xavier Xavier的权重方差,即:

( b − a ) 2 12 = 2 n i + n i + 1 \frac{(b-a)^2}{12} = \frac{2}{n_i + n_{i+1}} 12(ba)2=ni+ni+12

经过化解后 ( a + b = 0 ) (a+b=0) (a+b=0)可以得到 X a v i e r Xavier Xavier均匀初始化后权重的取值范围为:

W − U [ − 6 n i + n i + 1 , 6 n i + n i + 1 ] W - U[-\frac{\sqrt{6}}{\sqrt{n_i+n_{i+1}}}, \frac{\sqrt{6}}{\sqrt{n_i+n_{i+1}}}] WU[ni+ni+1 6 ,ni+ni+1 6 ]

原理我们讲完了,现在来看一下在 P y t o r c h Pytorch Pytorch中是如何调用 X a v i e r Xavier Xavier均匀分布初始化的:

# tensor表示要初始化的张量,gain表示缩放因子
torch.nn.init.xavier_uniform(tensor, gain=1)

# 举例说明:
w = torch.Tensor(3, 5)
nn.init.xavier_uniform(w, gain=math.sqrt(2))

2、 X a v i e r Xavier Xavier正态分布初始化

我们都知道均值为 0 0 0,标准差为 σ \sigma σ的正态分布方差为

V a r = σ 2 Var=\sigma^2 Var=σ2

同样的,需要将正态分布的方差等于我们在上面推导出来的 X a v i e r Xavier Xavier的权重方差,即:

σ 2 = 2 n i + n i + 1 \sigma^2 = \frac{2}{n_i + n_{i+1}} σ2=ni+ni+12

经过化解后可以得到 X a v i e r Xavier Xavier正态分布初始化后权重的标准差为:

σ = 2 n i + n i + 1 \sigma = \sqrt{\frac{2}{n_i + n_{i+1}}} σ=ni+ni+12

那么我们再来看一下在 P y t o r c h Pytorch Pytorch中是如何调用 X a v i e r Xavier Xavier正态分布初始化的:

# tensor表示要初始化的张量,gain表示缩放因子
torch.nn.init.xavier_normal(tensor, gain=1)

# 举例说明:
w = torch.Tensor(3, 5)
nn.init.xavier_normal(w)

3、 X a v i e r Xavier Xavier权重初始化表现效果

如下图 4 4 4所示为采用 X a v i e r Xavier Xavier i n i t i a l i z a t i o n initialization initialization后每层的激活函数输出值的分布,从图中我们可以看出,深层的激活函数输出值还是非常服从标准高斯分布。
在这里插入图片描述
虽然 X a v i e r Xavier Xavier i n i t i a l i z a t i o n initialization initialization能够很好的适用于 t a n H tanH tanH 激活函数,但对于目前神经网络中最常用的 R e L U ReLU ReLU激活函数,还是无能能力,如下图 5 5 5所示为采用 R e L U ReLU ReLU激活函数后, X a v i e r Xavier Xavier i n i t i a l i z a t i o n initialization initialization初始化的每层激活函数输出值的分布,从图中可以看出当达到 5 5 5 6 6 6层后几乎又开始趋向于 0 0 0,更深层的话很明显又会趋向于 0 0 0
在这里插入图片描述
由此可见, X a v i e r Xavier Xavier权重初始化方式比较适用于 t a n H tanH tanH S i g m o i d Sigmoid Sigmoid激活函数,而对于 R e L U ReLU ReLU这种非对称性的激活函数还是容易出现梯度消失的现象。

H e He He i n i t i a l i z a t i o n initialization initialization

H e He He i n i t i a l i z a t i o n initialization initialization是由何凯明大神提出的一种针对 R e L U ReLU ReLU激活函数的初始化方法。 H e He He i n i t i a l i z a t i o n initialization initialization的思想是:和 X a v i e r Xavier Xavier初始化方式一样,都希望初始化使得正向传播时,状态值的方差保持不变,反向传播时,关于激活值的梯度的方差保持不变。由于小于 0 0 0的值经过 R e L U ReLU ReLU激活函数都会变成 0 0 0,而大于 0 0 0的值则保持原值。因此在 R e L U ReLU ReLU网络中,假定每一层有一半的神经元被激活,另一半为 0 0 0,所以,要保持 v a r i a n c e variance variance不变,只需要在 X a v i e r Xavier Xavier的基础上再除以2即可。本文主要介绍 P y t o r c h Pytorch Pytorch当中 H e He He i n i t i a l i z a t i o n initialization initialization均匀分布和 H e He He i n i t i a l i z a t i o n initialization initialization正态分布初始化这两种方式。

对于 H e He He i n i t i a l i z a t i o n initialization initialization的推导来说前面和 X a v i e r Xavier Xavier i n i t i a l i z a t i o n initialization initialization是相似的,但在方差推到过程中,需要将式子左侧除以 2 2 2,如下所示:

V a r ( y ) = 1 2 n i V a r ( w i ) V a r ( x i ) Var(y) = \frac{1}{2}n_iVar(w_i)Var(x_i) Var(y)=21niVar(wi)Var(xi)

为了保证输出和输入的方差一直,则可以得到权重的方差为:

V a r ( w i ) = 2 n i Var(w_i) = \frac{2}{n_i} Var(wi)=ni2

对于 B a c k w a r d Backward Backward来说和 F o r w a r d Forward Forward思路是相似的,只不过需要考虑到链式求导法则,这里不予以推导,只给出最终的结果为:

V a r ( w i + 1 ) = 2 n i + 1 Var(w_{i+1}) = \frac{2}{n_{i+1}} Var(wi+1)=ni+12

1、 H e He He i n i t i a l i z a t i o n initialization initialization均匀分布初始化

X a v i e r Xavier Xavier均匀分布初始化操作一样我们得到 H e He He i n i t i a l i z a t i o n initialization initialization的取值范围为:

W − U [ − 6 n i + ( a 2 + 1 ) , 6 n i + ( a 2 + 1 ) ] W - U[-\frac{\sqrt{6}}{\sqrt{n_i+(a^2+1)}}, \frac{\sqrt{6}}{\sqrt{n_i+(a^2+1)}}] WU[ni+(a2+1) 6 ,ni+(a2+1) 6 ]

P y t o r c h Pytorch Pytorch H e He He i n i t i a l i z a t i o n initialization initialization也叫做 k a i m i n g kaiming kaiming,调用代码如下:

# tensor表示要初始化的张量
# a表示这层之后使用的rectifier的斜率系数(ReLU的默认值为0
# mode可以为“fan_in”(默认)或“fan_out”。
# “fan_in”保留前向传播时权值方差的量级,“fan_out”保留反向传播时的量级。
torch.nn.init.kaiming_uniform(tensor, a=0, mode='fan_in')

# 举例说明:
w = torch.Tensor(3, 5)
nn.init.kaiming_uniform(w, mode='fan_in')

2、 H e He He i n i t i a l i z a t i o n initialization initialization正态分布初始化

X a v i e r Xavier Xavier正态分布初始化操作一样我们得到 H e He He i n i t i a l i z a t i o n initialization initialization的标准差为:

σ = 2 n i + ( a 2 + 1 ) \sigma = \sqrt{\frac{2}{n_i + (a^2+1)}} σ=ni+(a2+1)2

P y t o r c h Pytorch Pytorch X a v i e r Xavier Xavier正态分布初始化的调用代码如下:

# tensor表示要初始化的张量
# a表示这层之后使用的rectifier的斜率系数(ReLU的默认值为0
# mode可以为“fan_in”(默认)或“fan_out”。
# “fan_in”保留前向传播时权值方差的量级,“fan_out”保留反向传播时的量级。
torch.nn.init.kaiming_normal(tensor, a=0, mode='fan_in')

# 举例说明:
w = torch.Tensor(3, 5)
nn.init.kaiming_normal(w, mode='fan_out')

3、 H e He He i n i t i a l i z a t i o n initialization initialization权重初始化表现效果

如下图 6 6 6所示为采用 H e He He i n i t i a l i z a t i o n initialization initialization方式初始化权重后,隐藏层使用 R e L U ReLU ReLU时,激活函数的输出值的分布情况,从图中可知,针对 R e L U ReLU ReLU激活函数, H e He He i n i t i a l i z a t i o n initialization initialization效果是比 X a v i e r Xavier Xavier i n i t i a l i z a t i o n initialization initialization好很多。
在这里插入图片描述
由此可见, H e He He i n i t i a l i z a t i o n initialization initialization权重初始化方式是非常适用于 R e L U ReLU ReLU激活函数。

预训练模型

目前更多的使用已经针对相似任务已经训练好的模型,称之为预训练模型。在训练开始时就已经有了非常好的初始化参数,只需要将最后的全连接层进行冻结,训练其他部分即可。

总结

1、权重采用初始化为 0 0 0和随机初始化都比较容易出现梯度消失的问题,因此不常用。

2、 X a v i e r Xavier Xavier权重初始化方式主要针对于 t a n H tanH tanH s i g m o i d sigmoid sigmoid激活函数。

3、 H e He He i n i t i a l i z a t i o n initialization initialization权重初始化方式主要针对于 R e L U ReLU ReLU激活函数。

4、如果有相似任务已经训练好的模型,也可以考虑采用预训练模型来作权重初始化。

猜你喜欢

转载自blog.csdn.net/qq_52302919/article/details/131627897