深度学习模型训练的过程本质是对weight(即参数W)进行更新,这须要每一个参数有相应的初始值。
有人可能会说:“参数初始化有什么难点?直接将全部weight初始化为0或者初始化为随机数!” 对一些简单的机器学习模型,或当optimization function是convex function时,这些简单的方法确实有效。
然而对于深度学习而言,非线性函数被疯狂叠加,这即是一个非凸函数,如何选择参数初始值便成为一个值得探讨的问题。
研究的目的是:选择更适合的初始化方法,使得目标函数更容易被优化。html
若是全部参数都被初始化为0,那么全部神经元的输出将是相同的,反向传播时每一层内全部的神经元的梯度也是相同的,这显然是一个不可行的方案。node
pre-training是早期训练神经网络的有效初始化方法。第一步,将神经网络的每一层取出来,构建auto-encoder作训练,使得输入层和输出层保持一致。在这个过程当中参数获得更新,造成初始值;第二步,将每一层放回神经网络中,使用训练数据fine-tuning网络。
随着数据量的增长以及activation function的发展,这种方案已不多采用,你们直接奔着训练的主题去了。如今咱们每每是拿任务A(imagenet竞赛)中训练好的模型(可称为pre-training model),将其放在任务B上作fine-tuning。网络
随机初始化,是最容易想到的方案。可是一旦随机分布选择不当,会致使网络优化陷入困境。app
data = tf.constant(np.random.randn(2000, 800)) layer_sizes = [800 - 50 * i for i in range(0,10)] num_layers = len(layer_sizes) fcs = [] # To store fully connected layers' output for i in range(0, num_layers - 1): X = data if i == 0 else fcs[i - 1] node_in = layer_sizes[i] node_out = layer_sizes[i + 1] W = tf.Variable(np.random.randn(node_in, node_out)) * 0.01 fc = tf.matmul(X, W) fc = tf.nn.tanh(fc) fcs.append(fc)
这里咱们建立了一个10层的神经网络,非线性变换为tanh,每一层的参数都是随机正态分布,均值为0,标准差为0.01。每一层输出值分布的直方图:dom
随着层数的增长,网络输出迅速向0靠拢。在反向传播中,根据链式法则,梯度等于当前输入x(上一层的输出)乘之后一层的梯度,x趋向于0,意味着梯度将很小,参数更新缓慢。机器学习
调整初始化策略,增长方差:函数
W = tf.Variable(np.random.randn(node_in, node_out))
均值仍然为0,标准差如今变为1,此时每一层输出值分布的直方图:
学习
此时,全部值会集中到-1或1附近,神经元饱和saturated了,也就是说tanh在-1和1附近的gradient都接近0,参数亦难更新。优化
泽维尔初始化的基本思想是:保持输入和输出的方差一致。注意:Xavier推到过程是基于线性函数的,可是它在非线性的神经元中依然表现不错。code
W = tf.Variable(np.random.randn(node_in, node_out)) / np.sqrt(node_in)
输出值在不少层以后依然保持着良好的分布,这颇有利于咱们优化神经网络!以前谈到Xavier是在线性函数上推导得出,这说明它对非线性函数并不具备普适性,因此这个例子仅仅说明它对tanh颇有效,那么对于目前最经常使用的ReLU神经元呢?
W = tf.Variable(np.random.randn(node_in, node_out)) / np.sqrt(node_in) ... fc = tf.nn.relu(fc)
前面看起来还不错,可是后面的趋势倒是愈来愈接近0。幸运的是,He initialization能够用来解决ReLU初始化的问题。
He initialization的思想是:在ReLU网络中,假定每一层有一半的神经元被激活,另外一半为0,因此,要保持variance不变,只须要在Xavier的基础上再除以2。
W = tf.Variable(np.random.randn(node_in,node_out)) / np.sqrt(node_in/2) ... fc = tf.nn.relu(fc)
效果获得了很大改善。
BN是一种巧妙又粗暴的方法,能够来削弱bad initialization的影响。在网络传播中,咱们想要的是在非线性activation以前,输出值应该有较好的分布(如高斯分布),以便于反向传播时计算梯度。BN的作法就是将输出值强制作一次高斯归一化和线性变换。BN的知识能够参考LRN和Batch Norm
随机初始化,有Batch Normalization:
W = tf.Variable(np.random.randn(node_in, node_out)) * 0.01 ... fc = tf.contrib.layers.batch_norm(fc, center=True, scale=True, is_training=True) fc = tf.nn.relu(fc)
很容易看到,Batch Normalization的效果很是好。
Xavier initialization是由Xavier Glorot et al.在2010年提出,He initialization是由Kaiming He et al.在2015年提出,Batch Normalization是由Sergey Ioffe et al.在2015年提出。