zoukankan      html  css  js  c++  java
  • 13、改善深层神经网路之权重初始化方法

    为什么进行权重初始化???

      在深度学习中,神经网络的权重初始化方法对(weight initialization)对模型的收敛速度和性能有着至关重要的影响。神经网络其实就是对权重参数w的不停迭代更新,以期达到较好的性能。在深度神经网络中,随着层数的增多,我们在梯度下降的过程中,极易出现梯度消失或者梯度爆炸。因此,对权重w的初始化则显得至关重要,一个好的权重初始化虽然不能完全解决梯度消失和梯度爆炸的问题,我们主要讨论四种权重初始化方法:

    • 把w初始化为0
    • 对w随机初始化
    • Xavier initialization
    • He initialization

    一、把w初始化为0

      线性回归、logistics回归,基本上都是把参数初始化为0;

      神经网络中,把w初始化为0是不可以的(这是因为如果把w初始化0,那么每一层的神经元学到的东西都是一样的(输出是一样的),而且在bp的时候,每一层内的神经元也是相同的,因为他们的gradient相同),代码演示如下:

    def initialize_parameters_zeros(layers_dims):
        """
        layer_dims——包含每个层大小的python数组(列表)。
        返回:
        参数——包含参数“W1”、“b1”、…、“WL”、“bL”的python字典:
            W1——形状的权重矩阵(层尺寸[1],层尺寸[0])
            b1——形状的偏置矢量(层尺寸[1],1)
            ...
            WL——形状的权重矩阵(层尺寸[L],层尺寸[L-1])
            bL——形状的偏差向量(层直径[L],1)
        """
        parameters = {}
        np.random.seed(3)
        L = len(layers_dims)  # number of layers in the network
        for l in range(1, L):
            parameters['W' + str(l)] = np.zeros((layers_dims[l], layers_dims[l - 1]))
            parameters['b' + str(l)] = np.zeros((layers_dims[l], 1))
        return parameters

    我们可以看看cost function是如何变化的:

     能够看到代价函数降到0.64(迭代1000次)后,再迭代已经不起什么作用了。

    二、对w随机初始化

      目前常用的就是随机初始化,即W随机初始化。随机初始化的代码如下:

    def initialize_parameters_random(layers_dims):
        """
        layer_dims——包含每个层大小的python数组(列表)。
        返回:
        参数——包含参数“W1”、“b1”、…、“WL”、“bL”的python字典:
            W1——形状的权重矩阵(层尺寸[1],层尺寸[0])
            b1——形状的偏置矢量(层尺寸[1],1)
            ...
            WL——形状的权重矩阵(层尺寸[L],层尺寸[L-1])
            bL——形状的偏差向量(层直径[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
            #乘0.01是因为要把W随机初始化到一个相对较小的值,因为如果X很大的话,W又相对较大,会导致Z非常大,这样如果激活函数是sigmoid,就会导致sigmoid的输出值1或者0,然后会导致一系列问题(比如cost function计算的时候,log里是0,这样会有点麻烦)。
            parameters['b' + str(l)] = np.zeros((layers_dims[l], 1))
        return parameters

      随机初始化后,cost function随着迭代次数的变化示意图为:

     能够看出,cost function的变化是比较正常的。但是随机初始化也有缺点,np.random.randn()其实是一个均值为0,方差为1的高斯分布中采样。当神经网络的层数增多时,会发现越往后面的层的激活函数(使用tanH)的输出值几乎都接近于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()

    三、Xavier initialization

    Xavier initialization是 Glorot 等人为了解决随机初始化的问题提出来的另一种初始化方法,就是尽可能的让输入和输出服从相同的分布,这样就能够避免后面层的激活函数的输出值趋向于0。初始化方法为:

    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后每层的激活函数输出值的分布:

      能够看出,深层的激活函数输出值还是非常漂亮的服从标准高斯分布。虽然Xavier initialization能够很好的 tanH 激活函数,但是对于目前神经网络中最常用的ReLU激活函数,还是无能能力,请看下图:

       当达到5,6层后几乎又开始趋向于0,更深层的话很明显又会趋向于0。

    四、He initialization

      ReLU的初始化方法,一般称作 He initialization。初始化方式为:

    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

      经过He initialization后,当隐藏层使用ReLU时,激活函数的输出值的分布情况:

        现在神经网络中,隐藏层常使用ReLU,权重初始化常用He initialization这种方法

      转自:https://blog.csdn.net/u012328159/article/details/80025785

  • 相关阅读:
    mybatis 源码分析(四)一二级缓存分析
    mybatis 源码分析(三)Executor 详解
    mybatis 源码分析(二)mapper 初始化
    mybatis 源码分析(一)框架结构概览
    Disruptor 详解 二
    Disruptor 详解 一
    JDK源码分析(12)之 ConcurrentHashMap 详解
    并发系列(7)之 ScheduledThreadPoolExecutor 详解
    数据结构系列(6)之 完全二叉堆
    并发系列(6)之 ThreadPoolExecutor 详解
  • 原文地址:https://www.cnblogs.com/hzzhbest/p/15179117.html
Copyright © 2011-2022 走看看