• cs231n--深度学习训练方法


    Training Neural Networks

    Actiation Functions

    20221101101815

    几种常见的激活函数
    20221101101830

    Sigmoid 函数

    20221101101916

    σ ( x ) = 1 1 + e − x \sigma(x) = \frac{1}{1 + e^{-x}} σ(x)=1+ex1

    • 将输入值挤压到 0到1的范围之间
    • 在历史中常用,对神经元的“firing rate” 有良好的解释

    缺点:

    • sigmoid 饱和的时候,梯度消失

    当输入的x过大,或者过小,local gredian 趋近于0,local 梯度与上游传来的梯度相乘,趋近于0,参数几乎无法更新

    为了防止饱和,对于权重矩阵的初始化必须特别留意,如果权重过大,那么大多数神经元将饱和,网络几乎不再更新。

    • sigmoid 函数不是零中心的

    这一情况将影响梯度下降的速度,因为如果输入神经元的数据X总是正数,那么 d σ d W = X T ∗ σ ′ \frac{d\sigma}{dW} = X^T * \sigma' dWdσ=XTσ 总是非负的,因此 w的梯度同号, 这将会导致梯度下降权重更新时出现 公式 字型的下降。该问题相对于上面的神经元饱和问题来说只是个小麻烦,没有那么严重。

    20221101104826

    • exp 计算耗费比较大

    tanh 函数

    20221101104932

    t a n h ( x ) = 2 σ ( 2 x ) − 1 tanh(x) = 2\sigma(2x)-1 tanh(x)=2σ(2x)1

    • 将神经原压缩到[-1,1]之间
    • 是零中心的

    ReLu 函数

    20221101105339

    f ( x ) = m a x ( 0 , x ) f(x) = max(0,x) f(x)=max(0,x)

    • 收敛更快
    • 只有负半轴会饱和
    • 非零中心
    • 训练时ReLu的神经元容易死掉,比较脆弱

    当一个很大的梯度流经过ReLU的神经原的时候,由于提夫下降,可能会导致权重 w都小于0,这是神经元无法被任何数据再次激活,自此经过这个神经元的梯度都将成为0,这个ReLu单元在训练中将死亡

    如果学习率设的比较大,本来大多数大于 0 的 w 更新后都小于 0 了,那么网络中很多神经元就死亡了

    Leaky ReLu

    20221101111114

    • 负区增加了一个斜率,避免死掉的问题

    指数线性单元 ELU

    20221101111416

    20221101111615

    介于 ReLU 和 Leaky ReLU 之间,有负饱和的问题,但是对噪声有较强的鲁棒性。

    Maxout

    20221101112828

    • 有更多的参数

    数据预处理

    Mean Subtraction

    如之前所属如果输入的数据X都是正,会导致 sigmoid 函数更新慢

    20221101113924

    因此可以对数据进行中心化处理。减均值法是数据预处理最常用的形式。它对数据中每个独立特征减去平均值,在每个维度上都将数据的中心都迁移到原点。
    虽然经过这种操作,数据变成零中心的,但是仍然只能第一层解决 Sigmoid 非零均值的问题,后面会有更严重的问题。

    Normalization

    归一化,面都不同维度数值差异较大的问题,使用归一化,使得不同维度的数值范围近似相等

    常用的方式有两种:

    • 第一种是先对数据做零中心化(zero-centered)处理,然后每个维度都除以其标准差,实现代码为 X /= np.std(X, axis=0)
    • 第二种是对每个维度都做归一化,使得每个维度的最大和最小值是 1 和 -1

    在图像处理中,由于像素的数值范围几乎是一致的(都在0-255之间),所以进行这个额外的预处理步骤并不是很必要

    20221101114550

    PCA 可以进行降维处理 和白化

    实际上在卷积神经网络中并不会采用PCA和白化

    一个常见的错误做法是先计算整个数据集图像的平均值然后每张图片都减去平均值,最后将整个数据集分成训练/验证/测试集。正确的做法是先分成训练/验证/测试集,只是从训练集中求图片平均值,然后各个集(训练/验证/测试集)中的图像再减去这个平均值。

    权重初始化

    全零初始化

    这种做法是错误的,会导致每个神经元有相同的输出,这样方向传播求梯度时,就计算出同样的梯度。

    小随机数的初始化

    将权重初始化位很小的数值,以此来打破对称性。

    其思路是:如果神经元刚开始的时候是随机且不相等的,那么它们将计算出不同的更新,并将自身变成整个网络的不同部分。
    W = 0.01 * np.random.randn(D,H)
    randn 函数是基于零均值和标准差的一个高斯分布来生成随机数的

    使用小随机数的初始化,在简单的网络中效果比较好,但是网络结构比较深的情况下,不一定能得到比较好的结果。

    下面一个例子,使用10层,每层500个神经元。

    import numpy as np
    import matplotlib
    matplotlib.use('TkAgg')
    import matplotlib.pyplot as plt
    # 假设一些高斯分布单元
    D = np.random.randn(1000, 500)
    hidden_layer_sizes = [500]*10  # 隐藏层尺寸都是500,10层
    nonlinearities = ['tanh']*len(hidden_layer_sizes)  # 非线性函数都是用tanh函数
    act = {'relu': lambda x: np.maximum(0, x), 'tanh': lambda x: np.tanh(x)}
    Hs = {}
    for i in range(len(hidden_layer_sizes)):
        X = D if i == 0 else Hs[i-1]  # 当前隐藏层的输入
        fan_in = X.shape[1]
        fan_out = hidden_layer_sizes[i]
        W = np.random.randn(fan_in, fan_out) * 0.01  # 权重初始化
        H = np.dot(X, W)  # 得到当前层输出
        H = act[nonlinearities[i]](H)  # 激活函数
        Hs[i] = H  # 保存当前层的结果并作为下层的输入
    # 观察每一层的分布
    print('输入层的均值:%f 方差:%f'% (np.mean(D), np.std(D)))
    layer_means = [np.mean(H) for i,H in Hs.items()]
    layer_stds = [np.std(H) for i,H in Hs.items()]
    for i,H in Hs.items():
        print('隐藏层%d的均值:%f 方差:%f' % (i+1, layer_means[i], layer_stds[i]))
    # 画图
    plt.figure()
    plt.subplot(121)
    plt.plot(list(Hs.keys()), layer_means, 'ob-')
    plt.title('layer mean')
    plt.subplot(122)
    plt.plot(Hs.keys(), layer_stds, 'or-')
    plt.title('layer std')
    # 绘制分布图
    plt.figure()
    for i,H in Hs.items():
        plt.subplot(1, len(Hs), i+1)
        plt.hist(H.ravel(), 30, range=(-1,1))
    plt.show()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    20221101200800

    只有第一层的均值方差比较好,,输出接近高斯分布,后面几层的均值方差基本为 0 ,反向传播时就会计算出非常小的梯度(因权重的梯度就是层的输入,输入接近0,梯度接近0 ),参数基本不会更新。

    如果不用较小的权重,使用 W = np.random.randn(fan_in, fan_out) * 1
    tanh 函数的神经原容易饱和,输出为 -1 或 +1 ,梯度为 0
    方差较大,均值接近于 0
    20221101201224

    Xavier/HE初始化(校准方差)

    W = np.random.randn(fan_in, fan_out) / np.sqrt(fan_in)

    20221101201524

    后几层的输入输出接近高斯分布

    但是使用ReLu 函数这种关系会被罚破,ReLu函数每层会消除一半的神经元,会有越来越多的神经原失活。

    20221101202525

  • 相关阅读:
    pytorch使用LSTMCell层定义LSTM网络结构
    【Vue项目复习笔记】Toast封装
    设备通过国标GB28181/海康Ehome接入EasyCVR,视频无法打开的原因分析及解决方法
    读 | SA : The Hard Parts 之数据所有权
    Cadence Allegro PCB命令行窗口详细说明及常用命令介绍图文教程
    LeetCode(力扣)37. 解数独Python
    Notion AI会员订阅付费
    【无标题】
    华为od机考题目-带空白字符的字符串匹配
    【AHK】 MacOS复制粘贴习惯/MacOS转win键位使用习惯修改建议
  • 原文地址:https://blog.csdn.net/greatcoder/article/details/127657963