为什么要初始化权重

训练神经网络需要指定权重的初始值,而一个好的初始化方法将有助于网络学习。

好的初始化可以加快梯度下降、模型收敛;减小梯度下降收敛过程中训练和泛化出现误差的几率;

在一个多层的神经网络的正向传播和反向传播中,可知经常会出现连乘的计算,假设激活函数为线性函数,则 y=WnWn1W2W1xy = W_n W_{n-1}···W_2W_1x ,当权重 W 小于 1 时,由于连乘可知结果很容易出现指数级减小;当权重 W 大于 1 时,由于连乘可知结果很容易出现指数级爆炸式增长;

梯度消失和梯度爆炸问题都是因为网络太深,网络权值更新不稳定造成的,本质上是因为梯度反向传播中的连乘效应。

通过选择好的初始化权重一般可以有效减小这种问题的出现。

初始化权重方法

零初始化(不推荐)

通常,将所有权重初始化为零会导致网络无法打破对称性

当所有初始值相同时,例如将每个权重初始化为0,然后进行反向传播时,所有权重将具有相同的梯度,因此也将具有相同的更新。这就是所谓的对称性。这意味着所有节点都将学习相同的东西,而我们不希望这样做,因为我们希望网络学习不同种类的功能。

若权重通过随机初始化实现的,此后梯度将有所不同,并且每个节点将变得与其他节点更加不同,从而可以进行多种特征提取。这就是所谓的破坏对称性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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 = {}
L = len(layers_dims)
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

随机初始化(不推荐)

随机分布选择不当会导致网络优化陷入困境。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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)
parameters = {}
L = len(layers_dims)

for l in range(1, L):
parameters['W' + str(l)] = np.random.randn(layers_dims[l], layers_dims[l - 1]) * 10
parameters['b' + str(l)] = np.zeros((layers_dims[l], 1))

return parameters

Xavier初始化

早期的参数初始化普遍是将数据和参数normalize为高斯分布(均值0,方差1),但随着神经网络深度的增加,这个方法并不能解决梯度消失的问题。

Xavier初始化的作者,Xavier Glorot,发现:激活值的方差是逐层递减的,这导致反向传播中的梯度也逐层递减。要解决梯度消失,就要避免激活值方差的衰减,即每一层输出的方差应该尽量相等。

Xavier初始化的基本思想是,若对于一层网络的 输出和输出可以保持正态分布且方差相近,这样就可以避免输出趋向于0,从而避免梯度消失情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def initialize_parameters_Xavier(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)
"""
# He初始化
np.random.seed(3)
parameters = {}
L = len(layers_dims)

for l in range(1, L):
parameters['W' + str(l)] = np.random.randn(layers_dims[l], layers_dims[l - 1]) * np.sqrt(
2./ layers_dims[l - 1])
parameters['b' + str(l)] = np.zeros((layers_dims[l], 1))

return parameters

He初始化

Xavier 在 tanh 中表现的很好,但在 Relu 激活函数中表现的很差,He是针对于Relu的初始化方法。

He 初始化和 xavier 一样都是为了防止梯度弥散而使用的初始化方式。He初始化的出现是因为xavier 存在一个不成立的假设, xavier 在推导中假设激活函数都是线性的,而在深度学习中常用的ReLu 等都是非线性的激活函数。

He 初始化本质上是高斯分布初始化,与上述高斯分布初始化有所不同,其是个满足均值为 0,方差为 2/n 的高斯分布。

由于ReLU 函数一半的Z值(负值)变为零,实际上移除了大约一半的方差。所以我们需要加倍权重的方差以补偿这一点。补偿的方法,只需要对 Xavier 初始化进行一项微小的调整——将权重的方差乘以2。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def initialize_parameters_he(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)
"""
# He初始化
np.random.seed(3)
parameters = {}
L = len(layers_dims)

for l in range(1, L):
parameters['W' + str(l)] = np.random.randn(layers_dims[l], layers_dims[l - 1]) * np.sqrt(
2./ layers_dims[l - 1])
parameters['b' + str(l)] = np.zeros((layers_dims[l], 1))

return parameters

1511.06422.pdf (arxiv.org)

1702.08591.pdf (arxiv.org)

啃一啃神经网络——权重初始化 - 知乎 (zhihu.com)

(47条消息) 深度学习之参数初始化(二)——Kaiming初始化_凯明初始化公式_Vic时代的博客-CSDN博客

深度学习——Xavier初始化方法_shuzfan-DevPress官方社区 (csdn.net)

Deep Learning基础–参数优化方法 - 蓝鲸王子 - 博客园 (cnblogs.com)