吴恩达深度学习笔记(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
:随着迭代次数的增加,训练集性能提升同时开发集性能下降,因此在迭代过程中提早停止训练网络
归一化输入
- 零均值化
- 归一化方差
梯度消失和梯度爆炸
- 深层网络反向传播对激活函数(例如
sigmoid
和tanh
)求导,梯度更新以指数衰减或递增,造成梯度消失和梯度爆炸
梯度检验
- 用于开发反向传播的求导是否正确
- 梯度检验不用于训练,只用于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
25import 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])