吴恩达深度学习笔记(1)——超参数调试与优化

深度学习的实用层面

训练集/开发集/测试集

  • 在机器学习中,通常是训练集:测试集=7:3或者训练集:开发集:测试集=6:2:2
  • 在大数据时代,开发集和测试集的容量可以有所减小(对于超百万级别的数据,训练集可以占到99.5%)
  • 确保开发集和测试集的数据与训练集来自同一分布

偏差和方差

  • 高偏差:欠拟合(例如训练集误差15%,开发集误差16%)
  • 高方差:过拟合(例如训练集误差1%,开发集误差11%)

训练神经网络的基本方法

  • 高偏差(训练集性能不佳)-> 尝试规模更大的神经网络/花费更多时间训练算法/更先进的优化算法
  • 高方差(开发集性能不佳)-> 尝试获取更多的数据/正则化/其他神经网络模型

$L_2$正则化

$$J(W,b)=\frac{1}{m}\sum^m_{i=1}\mathcal{L}(\hat{y}^{(i)},y^{(i)})+\frac{\lambda}{2m}||W||^2_2$$

  • 欧几里得范数:

$$||W||2^2=\sum{j=1}^{n_x}W_j^2=W^TW$$

  • 弗罗贝尼乌斯范数(Frobenius Norm):

$$||W^{[l]}||^2_F=\sum^{n^{[l-1]}}{i=1}\sum^{n^{[l]}}{j=1}(W_{ij}^{[l]})^2$$

  • 正则化参数$\lambda$设置较大,权重矩阵接近于0,消除或者减少许多隐藏单元的影响,简化神经网络,从而减少过拟合

Dropout正则化

  • 反向随机失活:随机删除神经网络中的一些单元,简化神经网络,从而减少过拟合
  • Dropout在计算机视觉中使用比较频繁

其他正则化方法

  • 通过翻转、随机剪裁图片、轻微变形等方法增大数据集
  • Early Stopping:随着迭代次数的增加,训练集性能提升同时开发集性能下降,因此在迭代过程中提早停止训练网络

归一化输入

  • 零均值化
  • 归一化方差

梯度消失和梯度爆炸

  • 深层网络反向传播对激活函数(例如sigmoidtanh)求导,梯度更新以指数衰减或递增,造成梯度消失和梯度爆炸

梯度检验

  • 用于开发反向传播的求导是否正确
  • 梯度检验不用于训练,只用于debug
  • 梯度检验不能忽略正则项
  • 梯度检验不能和Dropout混用
  • 随机初始化时运用一次梯度检验,反复训练之后再次运用梯度检验

优化

Mini-Batch梯度下降

  • 把一个包含大量样本的训练集拆分成数个小样本(Mini-Batch)的训练集,从而提高训练的效率
  • 当Mini-Batch的大小等于m时,称为Batch梯度下降,缺点是每次迭代的时间过长
  • 当Mini-Batch的大小等于1时,称为随机梯度下降,缺点是失去向量化带来的算法加速,计算效率低下
  • 视情况选择合适的Mini-Batch的大小
  • 若训练集样本少于2000,直接使用Batch梯度下降
  • 典型的Mini-Batch设置为64~512(常为2的次方)

指数加权平均

$$v^t=\beta v^{t-1}+(1-\beta)\theta^t$$

Momentum梯度下降

$$V_{dW} = \beta v_{dW} + (1-\beta)d_W$$
$$V_{db} = \beta v_{db} + (1-\beta)d_b$$
$$W = W - \alpha v_{dW}, b = b - \alpha v_{db}$$

  • $\beta$一般取$0.9$

RMSprop

$$S_{dW} = \beta S_{dW} + (1-\beta)dW^2$$
$$S_{db} = \beta S_{db} + (1-\beta)db^2$$
$$W = W - \alpha \frac{dW}{\sqrt{S_{dW}+\epsilon}}$$
$$b = b - \alpha \frac{db}{\sqrt{S_{db}+\epsilon}}$$

Adam优化算法

  • 结合了Momentum和RMSprop再修正其偏差
  • Momentum

$$V_{dW}=\beta_1V_{dW}+(1-\beta_1)dW$$
$$V_{db}=\beta_1V_{db}+(1-\beta_1)db$$

  • RMSprop

$$S_{dW}=\beta_2S_{dW}+(1-\beta_2)dW^2$$
$$S_{db}=\beta_2S_{db} + (1-\beta_2)db^2$$

  • 偏差修正

$$V^{corrected}{dW} = \frac{V{dW}}{1-\beta_1^t}, V^{corrected}{db} = \frac{V{db}}{1-\beta_1^t}$$
$$S^{corrected}{dW} = \frac{S{dW}}{1-\beta_2^t}, S^{corrected}{db} = \frac{S{db}}{1-\beta_2^t}$$
$$W = W - \alpha \frac{V^{corrected}{dW}}{\sqrt{S^{corrected}{dW}}+\epsilon}$$
$$b = b - \alpha \frac{V^{corrected}{db}}{\sqrt{S^{corrected}{db}}+\epsilon}$$

  • $\beta_1$一般取$0.9$,$\beta_2$一般取$0.999$,$\epsilon$一般取$10^{-8}$

学习率衰减

  • 线性衰减:$\alpha = \frac{1}{1 + \text{decay-rate} * \text{epoch-num}} \alpha_0$
  • 其他方法:指数衰减、平方根衰减、离散下降、手动衰减等

局部最优

  • 高维空间中更有可能遇到鞍点而不是局部最优点

超参数调试、Batch正则化和程序框架

调试处理

  • 超参数:学习率$\alpha$, $\beta$(Mometum), $\beta_1$ / $\beta_2$ / $\epsilon$(Adam),神经网络层数,隐含层的神经元数,学习率衰减率,mini-Batch的大小等
  • 最重要的超参数:学习率$\alpha$
  • 次重要:$\beta$(Mometum)、mini-Batch的大小、隐含层的神经元数
  • 再次重要:网络层数、学习率衰减率
  • Adam的参数基本采用常用设置

为超参数选择合适的范围

  • 用对数标尺搜索超参数比随机均匀取值更合理
  • 例如:$\alpha=10^r,r\in[-4,0]$

Batch Normalization

  • 归一化也适用于隐含层的$z^{(1)}$~$z^{(m)}$

$$\mu=\frac{1}{m}\sum_i{z^{(i)}}$$
$$\sigma^2=\frac{1}{m}\sum_i({z^{(i)}-\mu})^2$$
$$z_{norm}^{(i)}=\frac{z^{(i)}-\mu}{(\sqrt{\sigma^2+\epsilon}}$$
$$\tilde{z}^{(i)}=\gamma z_{norm}^{(i)}+\beta$$

  • 其中$\gamma$和$\beta$是模型的学习参数
  • BN减少了隐含层变量的分布变化数量,同时有轻微的正则化效果
  • 通常用指数加权平均来调整每个mini-batch训练集中的$\mu$和$\sigma$

Softmax回归

  • Softmax将逻辑回归推广到C类,输出$X$属于各分类的概率
  • $t=e^{z^{[l]}}$,$z^{[l]}$是输出层的元素构成的向量

$$a^{[l]}=\frac{e^{z^{[l]}}}{\sum_{j=1}^nt_i}$$
$$a^{[l]}i=\frac{t_i}{\sum{j=1}^n t_i}$$

深度学习框架

  • Caffe/Caffe2
  • CNTK
  • DL4J
  • Keras
  • Lasagne
  • mxnet
  • PaddlePaddle
  • TensorFlow
  • Theano
  • Torch
  • 选择框架的标准:易于编程;运行速度;持续开源

TensorFlow

  • 示例
    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
    import numpy as np
    import tensorflow as tf

    # 假设代价函数是J = w**2 - 10*w + 25,w是我们要优化的变量
    w = tf.Variable(0, dtype=tf.float32)
    # cost = tf.add(tf.add(w**2, tf.mutiply(-10., w)), 25)
    cost = w**2 - 10*w + 25
    # 学习率0.01
    train = tf.train.GradientDescentOptimizer(0.01).minimize(cost)

    init = tf.global_variables_initializer()
    session = tf.Session()

    # 输出w初始化的值0.0
    session.run(init)
    print(session.run(w))

    # 输出一步梯度下降后w的值0.1
    session.run(train)
    print(session.run(w))

    # 迭代1000次,w接近于最优值5
    for i in range(1000):
    session.run(train)
    print(session.run(w))
  • placeholder()函数
    1
    2
    3
    4
    5
    6
    7
    8
    # placeholder()告诉tensorFlow稍后要为x输入变量
    x = tf.placeholder(tf.float32, [3, 1])

    cost = x[0][0]*w**2 + x[1][0]*w + x[2][0]

    coefficients = np.array([[1.], [-10.], [25.]])

    session.run(train, feed_dict=[x:coefficients])