zoukankan      html  css  js  c++  java
  • 进一步聊聊weight initialization

    深度学习模型训练的过程本质是对weight(即参数W)进行更新,这需要每个参数有相应的初始值。
    有人可能会说:“参数初始化有什么难点?直接将所有weight初始化为0或者初始化为随机数!” 对一些简单的机器学习模型,或当optimization function是convex function时,这些简单的方法确实有效。
    然而对于深度学习而言,非线性函数被疯狂叠加,这便是一个非凸函数,如何选择参数初始值便成为一个值得探讨的问题。
    研究的目的是:选择更适合的初始化方法,使得目标函数更容易被优化。

    初始化为0

    如果所有参数都被初始化为0,那么所有神经元的输出将是相同的,反向传播时每一层内所有的神经元的梯度也是相同的,这显然是一个不可行的方案。

    预训练

    pre-training是早期训练神经网络的有效初始化方法。第一步,将神经网络的每一层取出来,构建auto-encoder做训练,使得输入层和输出层保持一致。在这个过程中参数得到更新,形成初始值;第二步,将每一层放回神经网络中,使用训练数据fine-tuning网络。
    随着数据量的增加以及activation function的发展,这种方案已很少采用,大家直接奔着训练的主题去了。现在我们往往是拿任务A(imagenet竞赛)中训练好的模型(可称为pre-training model),将其放在任务B上做fine-tuning。

    random initialization

    随机初始化,是最容易想到的方案。但是一旦随机分布选择不当,会导致网络优化陷入困境。

    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。每一层输出值分布的直方图:

    随着层数的增加,网络输出迅速向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 initialization

    泽维尔初始化的基本思想是:保持输入和输出的方差一致。注意:Xavier推到过程是基于线性函数的,但是它在非线性的神经元中依然表现不错。

    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

    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)
    

    效果得到了很大改善。

    Batch Normalization Layer

    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年提出。

  • 相关阅读:
    关于屏幕点亮和熄灭你所需要知道的
    关于handler的使用和理解
    关于Android Task的学习
    Android触摸屏幕事件总结
    Android工作问题总结
    Android生命周期总结
    Android中如何在子线程更新UI
    Eclipse中启动tomcat无效,而手动启动可以访问的原因
    使用Spring进行文件加载进内存
    spring集成quartz定时器的使用
  • 原文地址:https://www.cnblogs.com/houkai/p/10160685.html
Copyright © 2011-2022 走看看