DeepLearning.ai 笔记(二)

本笔记是课程《Improving Deep Neural Networks: Hyperparameter tuning, Regularization and Optimization》的第一周学习笔记,主要内容是数据集划分,偏差和方差,解决过拟合问题的正则化方法(包括L2正则化和dropout),Data augmentation和early stopping,加速训练的方法像归一化输入,Xavier初始化权值方法,以及确保反向传播的梯度检验。


数据集划分

数据集一般分为训练数据(trainingdata)、验证数据(development data)和测试数据(test data)。

传统机器学习算法的分割方式一般为60%、20%、20%。

大数据时代不需要特别多的验证数据和测试数据,如果有100万数据,那么可能训练数据有98万,验证数据和测试数据各1万,还可能更少各5000。

验证数据的作用是选择更好的算法,可以理解为确定超参数,测试数据用来无偏估计算法的性能。如果不需要无偏估计算法性能,有时候也可以不需要测试数据,直接用验证数据来当测试数据用,这种情况下有的人也把它称为测试数据,最合适的叫法是训练-验证集

验证集和测试集的分布要相同,即来源要相同,它们两者和训练集有时为了更快捷的获得数据可以分布不同。


偏差&方差

偏差(bias)和方差(variance),训练集损失一般用来衡量偏差,验证集损失一般用来衡量方差。基础损失(base error)一般表示一个可以达到的最低损失,比如人眼观测的损失。


举个例子:假如有个判断是否为猫的图片的数据集,人眼错误率为0。

训练集损失低(1%),验证集损失高(15%),过拟合,高方差。

训练集损失高(15%),验证集损失高(16%),两者相差不多且明显高于基础损失(0),欠拟合,高偏差。

训练集损失高(15%),验证集损失更高(30%),且明显高于基础损失(0),高偏差,高方差。

训练集损失低(0.5%),验证集损失低(1%),且和基础损失(0)差不多,低偏差,低方差。


在训练一个网络时,首先要做的是观察偏差,先把偏差降到最低。如果偏差过高,那么使用更大规模的神经网络,一般这种做法是有用的。也可以训练更长时间,这方法有时候有用。

一旦偏差降低到可接受程度,再看方差,通过查看验证集损失。若方差高,可以使用更多的数据,一般是有用的。如果不能得到更多数据,可以使用正则化的方法。当然也可以更换神经网络,通过找到合适的神经网络实现一箭双雕的目的。

重复以上过程直到实现低方差和低偏差。


在机器学习初期,通常方差和偏差互相影响。而在深度学习时期,通常使用一个更大规模的网络配合正则化,可以在不影响方差的基础上降低偏差。而增加更多的的数据量,可以在不影响偏差的基础上降低方差。


降低方差&减小过拟合

正则化

正则化方法分为多种,用的比较多的是L2正则化和dropout。


L2正则化

使用L2正则化的交叉熵损失:
$$
J{regularized} = \small \underbrace{-\frac{1}{m} \sum\limits{i = 1}^{m} \large{(}\small y^{(i)}\log\left(a^{L}\right) + (1-y^{(i)})\log\left(1- a^{L}\right) \large{)} }_\text{cross-entropy cost} + \underbrace{\frac{1}{m} \frac{\lambda}{2} \sum\limits_l\sum\limits_k\sum\limits_j W{k,j}^{[l]2} }_\text{L2 regularization cost}
$$
正则化用于减少方差,一般用L2正则化而不用L1,因为L1正则化倾向于把W变得很稀疏,会有很多0。L2正则化在代价函数后面加上$\frac{\lambda}{2m} ||W||^2$,因为lambda是python的保留字,所以我们用lambd表示正则化系数,这是个超参数。在训练时,在dW项后面加一个$\frac{\lambda}{m}W$,即正则化项总是倾向于使得W减少,相当于乘了一个小于1的权重衰减系数(weightdecay)。
$$
\frac{d}{dW} ( \frac{1}{2}\frac{\lambda}{m} W^2) = \frac{\lambda}{m} W
$$
关于正则化为什么有用,其中一种说法是,当使用正则化时,整个网络会被迫使得一部分参数项变小,进而使得原本复杂的网络变的简单,相当于变相的把复杂的神经网络简单化,也就减小了过拟合的程度。


总结:

  1. 代价函数要添加正则化项
  2. 反向传播梯度dW要添加额外的项$\frac{\lambda}{m}W$
  3. 正则化使得参数更倾向于取较小的值


Dropout

dropout本身是一种正则化方法,可以理解为,神经网络不会把高权值放在任何一个神经元节点上,因为每一个节点都有可能失活,于是它会倾向于利用每一个神经元把它们权值压缩的很小,某种意义上和L2正则化相似。

如果某一层输出为a,则:

1
2
3
d= np.random.rand(a.shape[0], a.shape[1]) < keep_prob
a =np.multiply(a, d)
a = a / keep_prob #为了不影响a的期望值,添加这一步,使得测试阶段不需要调整数值范围。

我们只需要在训练阶段使用dropout,在测试阶段不需要使用。

我们可以在参数矩阵W较大的层上使用较小的keep_prob,一般不对输入层使用dropout,一般只在计算机视觉领域使用dropout,因为通常没有足够的数据,dropout仅仅用于解决过拟合问题。

dropout缺点是代价函数J不再被明确定义。梯度下降不容易复查,通常我们会关闭dropout,确保J单调递减,再打开dropout。


实现代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#正向传播:
# Step 1: initialize matrix D1 = np.random.rand(..., ...)
D1 =np.random.rand(A1.shape[0],A1.shape[1])
# Step 2: convert entries of D1 to 0 or 1 (using keep_prob as the threshold)
D1 = D1 < keep_prob
# Step 3: shut down some neurons of A1
A1 = A1 * D1
# Step 4: scalethe value of neurons that haven't been shut down
A1 = A1 / keep_prob
#反向传播
# Step 1: Apply mask D1 to shutdown the same neurons as during the forward propagation
dA1 = dA1 * D1
# Step 2: Scale the value ofneurons that haven't been shut down
dA1 = dA1 / keep_prob


总结:

  1. dropout是一种正则化方法
  2. 只能在训练过程中使用dropout,不能在测试时使用
  3. 在前向传播和反向传播中都使用dropout
  4. 在dropout时,因为dropout过程会使得输出值变为原本的keep_prob倍,固把输出A除以keep_prob的值,可以使得激活函数的输出得到期盼的值。


总结

不同的正则化方法得到的实验结果:

model train accuracy test accuracy
3-layer NN without regularization 95% 91.5%
3-layer NN with L2-regularization 94% 93%
3-layer NN with dropout 93% 95%

正则化方法会降低训练准确率,但是会有利于测试集准确率。

结论:

  1. 正则化有利于避免过拟合
  2. 正则化会使得参数倾向于更小的值
  3. L2正则化和Dropout是两种很有效的正则化方法。


Data augmentation

解决过拟合问题,如果不能增加数据量,还可以对图片水平翻转,随机旋转,随机裁剪放大后的图片,称为data augmentation。


Early stopping

另一个解决过拟合的方法是early stopping。验证集误差不再下降则停止训练。它和L2正则化可以二选一。L2正则化需要更大的计算代价,需要找最优的正则化系数。early stopping缺点是不能独立的解决训练数据最优化和防止过拟合两个问题,我们一般倾向于用独立的方法解决单一问题,所以一般不用early stopping。


加速训练

归一化输入数据

其中一个加速训练的方法是归一化输入。第一步零均值化,第二步归一化方差。如果用某均值和方差来归一化训练集,那么应该用同样的均值和方差来归一化测试集。我们在两个数据集上要使用同样的数据转换。

归一化的目的是使得输入数据的各个维度的特征具有相似的范围,这样更有利于梯度下降算法的实施,我们也就可以用相对来说更大的学习率,训练速度就会变的更快。比如如果x1范围是[0, 1000],x2范围是[0, 1],优化起来就会变的特别慢。

Xavier初始化权值

梯度消失和梯度爆炸,梯度值将伴随着层数呈指数增加或衰减,目前的解决方法之一是使用Xavier方法初始化权值,这也是加快训练速度的技巧之一。

Xavier初始化指的是当激活函数为relu时,W = np.random.randn(…) * np.sqrt(2/n[l-1]),使得W的方差变为2/n,这样最终的输出a依然是可以接受的方差。如果激活函数是tanh,则为W = np.random.randn(…) *np.sqrt(1/n[l-1]),把W方差变为1/n。


参数初始化时需要注意的点:

  1. 不同的初始化方式导致不同的结果,较差的方法会导致梯度爆炸或梯度消失,
  2. 随机初始化用来打破对称性,使得不同的隐层神经元学到不同的东西。
  3. 不要把权值初始化太大,会减慢训练速度。
  4. He初始化方法对于ReLU网络效果最好,即W = np.random.randn(...) * np.sqrt(2/layers_dims[l-1])
Model Train accuracy Problem/Comment
3-layer NN with zeros initialization 50% fails to break symmetry
3-layer NN with large random initialization 83% too large weights
3-layer NN with He initialization 99% recommended method


梯度检验

梯度检验用于检查反向传播是否正确实施,做梯度检验时,使用双边误差比单边误差更准确。不要再训练过程中使用梯度检验,它只用来debug。

梯度检验时,把所有的参数矩阵W转换成一个一维向量,然后把所有的转换后的W一维向量以及一维的b参数连接成一个大的一维向量$\theta$。对于dW和db做同样的对应处理,得到$d\theta$。然后对$J(\theta)$进行双边误差计算(公式4),得到$d{\theta}approx$,然后计算$d{\theta}approx$和$d\theta$的距离(公式5) 。

$$
\frac{\partial J}{\partial \theta} = \lim_{\varepsilon \to 0} \frac{J(\theta + \varepsilon) - J(\theta - \varepsilon)}{2 \varepsilon}
$$

$$
difference = \frac {| grad - gradapprox |_2}{| grad |_2 + | gradapprox |_2 }
$$

梯度检验时要加上正则化项,但梯度检验不能和dropout同时使用,进行梯度检验时要关掉dropout。


总结:

  1. 如果$\epsilon=1e-7$,则最后的difference应小于等于1e-7,这样说明梯度下降没问题。
  2. 梯度检查速度很慢,因此不要在训练过程中执行梯度检查,只需要在验证梯度下降是否正确时使用。
  3. 梯度检查不能再dropout时使用,应先关闭dropout,使用梯度检查确保梯度下降正确,再使用dropout进行训练。