深度学习中的weight initialization对模型收敛速度和模型质量有重要影响!php
import numpy as np
W = np.random.randn(node_in, node_out) / np.sqrt(node_in / 2)
import tensorflow as tf
# put this before nonlinear transformation
layer = tf.contrib.layers.batch_norm(layer, center=True, scale=True,
is_training=True)
实验代码请参见个人Github。html
深度学习模型训练的过程本质是对weight(即参数 W)进行更新,这须要每一个参数有相应的初始值。有人可能会说:“参数初始化有什么难点?直接将全部weight初始化为0或者初始化为随机数!” 对一些简单的机器学习模型,或当optimization function是convex function时,这些简单的方法确实有效。然而对于深度学习而言,非线性函数被疯狂叠加,产生如本文题图所示的non-convex function,如何选择参数初始值便成为一个值得探讨的问题 --- 其本质是初始参数的选择应使得objective function便于被优化。事实上,在学术界这也是一个被actively研究的领域。node
TLDR里已经涵盖了本文的核心要点,下面在正文中,咱们来深刻了解一下来龙去脉。python
答案是不可行。 这是一道送分题 哈哈!为何将全部W初始化为0是错误的呢?是由于若是全部的参数都是0,那么全部神经元的输出都将是相同的,那在back propagation的时候同一层内全部神经元的行为也是相同的 --- gradient相同,weight update也相同。这显然是一个不可接受的结果。git
pre-training是早期训练神经网络的有效初始化方法,一个便于理解的例子是先使用greedy layerwise auto-encoder作unsupervised pre-training,而后再作fine-tuning。具体过程能够参见UFLDL的一个tutorial,由于这不是本文重点,就在这里简略的说一下:(1)pre-training阶段,将神经网络中的每一层取出,构造一个auto-encoder作训练,使得输入层和输出层保持一致。在这一过程当中,参数得以更新,造成初始值(2)fine-tuning阶段,将pre-train过的每一层放回神经网络,利用pre-train阶段获得的参数初始值和训练数据对模型进行总体调整。在这一过程当中,参数进一步被更新,造成最终模型。github
随着数据量的增长以及activation function (参见个人另外一篇文章) 的发展,pre-training的概念已经渐渐发生变化。目前,从零开始训练神经网络时咱们也不多采用auto-encoder进行pre-training,而是直奔主题作模型训练。不想从零开始训练神经网络时,咱们每每选择一个已经训练好的在任务A上的模型(称为pre-trained model),将其放在任务B上作模型调整(称为fine-tuning)。算法
随机初始化是不少人目前常用的方法,然而这是有弊端的,一旦随机分布选择不当,就会致使网络优化陷入困境。下面举几个例子。网络
核心代码见下方,完整代码请参见个人Github。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靠拢,在后几层中,几乎全部的输出值都很接近0!回忆优化神经网络的back propagation算法,根据链式法则,gradient等于当前函数的gradient乘之后一层的gradient,这意味着输出值
是计算gradient中的乘法因子,直接致使gradient很小,使得参数难以被更新!
让咱们将初始值调大一些:
W = tf.Variable(np.random.randn(node_in, node_out))
均值仍然为0,标准差如今变为1,下图是每一层输出值分布的直方图:
几乎全部的值集中在-1或1附近,神经元saturated了!注意到tanh在-1和1附近的gradient都接近0,这一样致使了gradient过小,参数难以被更新。
Xavier initialization能够解决上面的问题!其初始化方式也并不复杂。Xavier初始化的基本思想是保持输入和输出的方差一致,这样就避免了全部输出值都趋向于0。注意,为了问题的简便,Xavier初始化的推导过程是基于线性函数的,可是它在一些非线性神经元中也颇有效。让咱们试一下:
W = tf.Variable(np.random.randn(node_in, node_out)) / np.sqrt(node_in)
Woohoo!输出值在不少层以后依然保持着良好的分布,这颇有利于咱们优化神经网络!以前谈到Xavier initialization是在线性函数上推导得出,这说明它对非线性函数并不具备普适性,因此这个例子仅仅说明它对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)
看起来效果很是好,推荐在ReLU网络中使用!
Batch Normalization是一种巧妙而粗暴的方法来削弱bad initialization的影响,其基本思想是:If you want it, just make it!
咱们想要的是在非线性activation以前,输出值应该有比较好的分布(例如高斯分布),以便于back propagation时计算gradient,更新weight。Batch Normalization将输出值强行作一次Gaussian Normalization和线性变换:
Batch Normalization中全部的操做都是平滑可导,这使得back propagation能够有效运行并学到相应的参数,
。须要注意的一点是Batch Normalization在training和testing时行为有所差异。Training时
和
由当前batch计算得出;在Testing时
和
应使用Training时保存的均值或相似的通过处理的值,而不是由当前batch计算。
随机初始化,无Batch Normalization:
W = tf.Variable(np.random.randn(node_in, node_out)) * 0.01
......
fc = tf.nn.relu(fc)
随机初始化,有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年提出。
另有知乎网友在评论中提到了一些其余相关工做:https://arxiv.org/abs/1511.06422, https://arxiv.org/pdf/1702.08591.pdf
原文: https://www.leiphone.com/news/201703/3qMp45aQtbxTdzmK.html