浅谈深度学习初始化参数(weight initialization)

在这里插入图片描述

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

初始化为0的可行性?

我们在线性回归logistics回归的时候,基本上都是把参数初始化为0,我们的模型也能够很好的工作。然后在神经网络中,把w初始化为0是不可以的。这是因为如果把w初始化0,那么每一层的神经元学到的东西都是一样的(输出是一样的),而且在bp的时候,每一层内的神经元也是相同的,因为他们的gradient相同。造成的结果就是神经网络学不到有效的知识。

随机初始化

随机初始化是很多人目前经常使用的方法,然而这是有弊端的,一旦随机分布选择不当,就会导致网络优化陷入困境。

随机初始化 python 代码

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 = {} # weight bias dict
    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.1
        parameters['b' + str(l)] = np.zeros((layers_dims[l], 1))
    return parameters

我们创建10层的神经网络用于实验,非线性变换为tanh,每一层的参数都是随机正态分布均值为0标准差为0.01。下图给出了每一层输出值分布的直方图。
在这里插入图片描述

随着层数的增加,我们看到输出值迅速向0靠拢,在后几层中,几乎所有的输出值都很接近0!神经网络的back propagation算法,根据链式法则gradient等于当前函数的gradient 乘以后一层的gradient,这意味着输出值[公式]是计算gradient中的乘法因子,直接导致gradient很小,使得参数难以被更新

np.random.randn(layers_dims[l], layers_dims[l - 1])

均值仍然为0标准差现在变为1,下图是每一层输出值分布的直方图:
在这里插入图片描述

几乎所有的值集中在-11附近,神经元饱和!注意到tanh-11附近的gradient都接近0,这同样导致了gradient太小,参数难以更新

Xavier initialization

Xavier initialization可以解决上面的问题!其初始化方式也并不复杂。基本思想保持输入和输出的方差一致,这样就避免了所有输出值都趋向于0。注意,为了问题的简便,其推导过程是基于线性函数的,但是它在一些非线性神经元中也很有效。具体推导可以见这篇博客-Xavier initialization 理解与实现

Xavier initialization python 代码

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

在这里插入图片描述

输出值在很多层之后依然保持着良好的分布,这很有利于我们优化神经网络!之前谈到Xavier initialization是在线性函数上推导得出,这说明它对非线性函数并不具有普适性,所以这个例子仅仅说明它对tanh很有效,那么对于目前最常用的ReLU神经元呢?

在这里插入图片描述

前面看起来还不错,后面的趋势却是越来越接近0。幸运的是,He initialization可以用来解决ReLU初始化的问题

He initialization

He initialization思想是:在ReLU网络中,假定每一层有一半的神经元被激活,另一半为0,所以,要保持variance不变,只需要在Xavier的基础上再除以2

He initialization python 代码

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(2 / layers_dims[l - 1])
        parameters['b' + str(l)] = np.zeros((layers_dims[l], 1))
    return parameters

在这里插入图片描述

看起来效果非常好,推荐在ReLU网络中使用!

Batch Normalization Layer

Batch Normalization是一种巧妙而粗暴的方法来削弱bad initialization的影响,其基本思想是:If you want it, just make it!

我们想要的是在非线性activation之,输出值应该有比较好的分布(例如高斯分布),以便于back propagation时计算gradient,更新weight。Batch Normalization将输出值强行做一次Gaussian Normalization和线性变换

在这里插入图片描述

Batch Normalization中所有的操作都是平滑可导,这使得back propagation可以有效运行并学到相应的参数 γ \gamma γ β \beta β。需要注意的一点是Batch Normalization在training和testing时行为有所差别。Training时 μ B \mu_B μB σ B \sigma_B σB由当前batch计算得出;在Testing时 μ B \mu_B μB σ B \sigma_B σB应使用Training时保存的均值或类似的经过处理的值,而不是由当前batch计算

随机初始化,无 Batch Normalization
在这里插入图片描述

随机初始化,有Batch Normalization
在这里插入图片描述

很容易看到,Batch Normalization的效果非常好,推荐使用!

参考资料

Xavier initialization是由Xavier Glorot et al.2010年提出,He initialization是由Kaiming He et al.在2015年提出,Batch Normalization是由Sergey Ioffe et al.2015年提出。

  • 7
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TransientYear

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值