深度学习的参数分为超参(hyper parameters)和普通参数。超参是模型开始训练前,人工指定的参数,比如网络层数、每层的神经元数、学习速率以及正则项系数等。神经网络的权重初始化(weight initialization)对模型的收敛速度和性能有着至关重要的影响。神经网络的学习是对权重参数W的不停迭代更新,以期达到较好的性能,随着网络层数的增多,在BP(back propagation)过程中,极易出现梯度消失或者爆炸。一个好的权重初始化虽然不能完全解决梯度消失或爆炸的问题,但是对于处理这两个问题是有很大帮助的,并且十分有利于模型性能和收敛速度。
把W初始化为0
在线性回归、logistics回归的时候,把参数初始化为0,模型也能很好的工作。但是在神经网络中,把W初始化为0是不可以的,因为神经网络单点激活的过程可抽象为Y= H(W*X)+ b,当W=0时 公式变为 Y = H(0) + b,每一层神经元学到的东西都是一样的(输出是一样的),而且在bp的时候,每一层内的神经元也是相同的,因为他们的gradient相同。
对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
————————————————
版权声明:本文为CSDN博主「天泽28」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u012328159/article/details/80025785
乘0.01是因为要把W随机初始化到一个相对较小的值,Y=H(W*X)+b,例如H为sigmoid激活函数,X很大,W也相对较大会导致输出的值是1或0,会导致一系列的问题。随机初始化后,cost function随着迭代次数的变化示意图为:
![c5fe60f4366c0b87bcfe7b9107dbc3d1.png](https://i-blog.csdnimg.cn/blog_migrate/dc9346990a48d00de1dad7f22f50f54f.png)
能够看出,cost function的变化比较正常的。但是随机初始化也有缺点,np.random.randn()其实是一个均值为0,方差为1的高斯分布采样。当神经元的层数增多时,会发现月往后面层的激活函数(activation function)例如使用tanh的输出值几乎都接近0。激活函数输出值接近于0会导致梯度非常接近于0,会导致梯度消失。
import numpy as np
import matplotlib.pyplot as plt
def initialize_parameters(layer_dims):
"""
:param layer_dims: list,每一层单元的个数(维度)
:return:dictionary,存储参数w1,w2,...,wL,b1,...,bL
"""
np.random.seed(3)
L = len(layer_dims)#the number of layers in the network
parameters = {}
for l in range(1,L):
parameters["W" + str(l)] = np.random.randn(layer_dims[l],layer_dims[l-1])*0.01
parameters["b" + str(l)] = np.zeros((layer_dims[l],1))
return parameters
def forward_propagation():
data = np.random.randn(1000, 100000)
# layer_sizes = [100 - 10 * i for i in range(0,5)]
layer_sizes = [1000,800,500,300,200,100,10]
num_layers = len(layer_sizes)
parameters = initialize_parameters(layer_sizes)
A = data
for l in range(1,num_layers):
A_pre = A
W = parameters["W" + str(l)]
b = parameters["b" + str(l)]
z = np.dot(W,A_pre) + b #计算z = wx + b
A = np.tanh(z)
#画图
plt.subplot(2,3,l)
plt.hist(A.flatten(),facecolor='g')
plt.xlim([-1,1])
plt.yticks([])
plt.show()
————————————————
版权声明:本文为CSDN博主「天泽28」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u012328159/article/details/80025785
结果如下图所示:
![8ec72a4430a9d7c4f47d915b7c561b64.png](https://i-blog.csdnimg.cn/blog_migrate/03d947f8e59b099f4af4b56117774fda.png)
W值使用xavier初始化
xavier initialization是Glorot等人为了解决随机初始化的问题提出来的另一种初始化方法,思想就是尽可能的让输入和输出服从相同的分布,即保持输入和输出的方差一致。即将随机初始化的值乘以缩放因子:
np.random.randn(layers_dims[l], layers_dims[l - 1]) * np.sqrt(1. / layers_dims[l - 1])
1、caffer下的xavier实现
caffe中,网络参数初始化通过从一个0均值和特定方差的分布(一般为正态分布或均匀分布)中获得:
2、Glorot & Bengio vaxier实现
在 Glorot & Bengio’s 的文章(Understanding the difficulty of training deep feedforward neural networks)中,推荐的却是如下形式:
3、简单推导
n个成分构成的输入向量X,经过一个随机矩阵为W的线性神经元,得到输出
已知
推导如下,由独立变量积的方差计算公式(Product of independent variables)可知,
又已对输入向量去均值,输入和权值矩阵均值均为 0,则:
所以进一步有:
因此为使得,输出 yy 与输入 xx 具有相同的均值和方差,权值矩阵的方差则要求:
这里的 nn 指的是输入样本的维数,这即是 caffe 中关于 xavier 的实现。
Glorot & Bengio’s 论文中,在基础上,还需考虑反向传播时的情形,反向传播是正向传播的逆过程,此时的输入是前向传播的输出,则有:
综合以下两点要求,则可得到满足以上两点要求的权值矩阵的方差为:
初始化方法为:
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)
"""
np.random.seed(3)
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]) * np.sqrt(1 / layers_dims[l - 1])
parameters['b' + str(l)] = np.zeros((layers_dims[l], 1))
return parameters
————————————————
版权声明:本文为CSDN博主「天泽28」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u012328159/article/details/80025785
来看下xavier initialization后每层的激活函数输出值的分布:
![8efe69ceec0aa93517ebe5354c27af78.png](https://i-blog.csdnimg.cn/blog_migrate/b8cc0fcddf5d8e7be339425e27ae5360.png)
能够看出,深层的激活函数输出值服从标准高斯分布。但是xavier initialization对于目前常用的ReLU激活函数,还是无能为力,请看下图:
![95d8d2a834abbf2473f8d70b6354962d.png](https://i-blog.csdnimg.cn/blog_migrate/02178c69567f2e7d2b4e1f16f3a9503a.png)
当达到5、6层后几乎又开始趋向于0,更深层更趋向于0.
W值使用he initialization初始化
He初始化可以解决上面在ReLU激活函数是Xavier效果不好的问题。其思想是:在ReLU网络中,假定每一层有一半的神经元被激活,另一半为0,要保持方差不变,只需要在Xavier的基础上再除以2。即缩放因子变为:
np.random.randn(layers_dims[l], layers_dims[l - 1]) * np.sqrt(2. / layers_dims[l - 1])
其分布如下图,可见效果很好。
![e52256550b48842d0b0942f617bfba4b.png](https://i-blog.csdnimg.cn/blog_migrate/7c93c0890863e9f33e67310fcfb59c42.png)
He初始化在ReLU的输出概率分布
![51678d95a21368d6e0b531971a45a2c1.png](https://i-blog.csdnimg.cn/blog_migrate/e5877c2b1e71e8baeefcc7045d43036e.png)
Batch Normalization Layer
合理的参数初始化是为了避免梯度消失,有效的反向传播,需要进入激活函数的数值有一个合理的分布,以便于反向传播是计算梯度。其思想是在线性变化和非线性激活函数之间,将数值做一次高斯归一化和线性变化。
![ffb9a131fec2aa184d4d89d28ddbff2f.png](https://i-blog.csdnimg.cn/blog_migrate/3568f23b7f0498a2ba30d8a989e7a72a.jpeg)
Batch Normalization中所有的操作都是平滑可导,因此可以有效的学习到参数
如图表示使用随机初始化的参数,ReLU作为激活函数,未使用Batch Normalization时,每层激活函数的输出分布:
![1ecb1c3c6d2ff98561caf171493b9da8.png](https://i-blog.csdnimg.cn/blog_migrate/c55ec0f12d9d7edbff2c3a546d8a456a.png)
下图为使用Batch Normalization时,每层激活函数的输出分布:
![e52256550b48842d0b0942f617bfba4b.png](https://i-blog.csdnimg.cn/blog_migrate/7c93c0890863e9f33e67310fcfb59c42.png)
可见,使用batch Normalization 非常有效。
#参考资料
- Glorot X, Bengio Y. Understanding the difficulty of training deep feedforward neural networks[C]//Proceedings of the Thirteenth International Conference on Artificial Intelligence and Statistics. 2010: 249-256.
- He K, Zhang X, Ren S, et al. Delving deep into rectifiers: Surpassing human-level performance on imagenet classification[C]//Proceedings of the IEEE international conference on computer vision. 2015: 1026-1034.
- Ioffe S, Szegedy C. Batch normalization: accelerating deep network training by reducing internal covariate shift (2015)[J]. arXiv preprint arXiv:1502.03167, 1735-1780.
- Coursera, deep-neural-network