【Course 2 改善深度神经网络】Week 1 深度学习的实用层面

Practical aspects of Deep Learning : setting up your ML application

目录

1.train/dev/test sets

2.Bias/Variance 

3.Regularization Reduces Overfitting

3.1 L1、L2 Regularization 

3.1.1 Prior knowledge:L1 Norm and L2 Norm(L1、L2范数)

3.1.2 L1 L2 Regularization

3.2 Why regularization reduces overfitting

3.3 Dropout Regularization

3.4 Other regularization methods

3.4.1数据扩增(data augmentation)

3.4.2 early stopping

4.归一化(Normalize inputs)

5.梯度消失、梯度爆炸及如何避免(Vanishing/exploding gradient)

6.梯度检验(Gradient checking)

7.编程作业


1.train/dev/test sets

应用深度学习是一个反复迭代的过程,需要通过反复多次的循环训练得到最优化参数。决定整个训练过程快慢的关键在于单次循环所花费的时间,单次循环越快,训练过程越快。而设置合适的训练集(Training sets)、验证集(Development sets)、测试集(Test sets)的数量,能有效提高训练效率。基于Idea,先选择初始的参数值,构建神经网络模型结构;然后通过代码Code的形式,实现这个神经网络;最后,通过实验Experiment验证这些参数对应的神经网络的表现性能。根据验证结果,我们对参数进行适当的调整优化,再进行下一次的Idea->Code->Experiment循环。通过很多次的循环,不断调整参数,选定最佳的参数值。

这里写图片描述

Train/Dev/Test sets的设置:

Train sets用来训练你的算法模型;

Test sets用来测试最好算法的实际表现,作为该算法的无偏估计。

Dev sets用来验证不同算法的表现情况,从中选择最好的算法模型。

样本数量较小时的比例分配:

Train sets和Test sets的数量比例为70%和30%。如果有Dev sets,则设置比例为60%、20%、20%,分别对应Train/Dev/Test sets。

样本数量较大时的比例分配:

科学的做法是要将Dev sets和Test sets的比例设置得很低。Train/Dev/Test sets的比例通常可以设置为98%/1%/1%,或者99%/0.5%/0.5%。

问题:训练样本和测试样本分布上不匹配

比如,假设你开发一个识别猫的手机app,可以让用户上传图片。在app识别算法中,训练样本可能来自网络下载,验证和测试样本可能来自不同用户的上传。从网络下载的图片一般像素较高而且比较正规,而用户上传的图片往往像素不稳定,且图片质量不一。因此,训练样本和验证/测试样本可能来自不同的分布。

解决:

尽量保证Dev sets和Test sets来自于同一分布

扩大训练样本的数量,从而让该模型更加强大(即使Train sets和Dev/Test sets不来自同一分布,使用这些技巧也能提高模型性能):将现有的训练样本做一些处理,例如图片的翻转、假如随机噪声等。

2.Bias/Variance 

下图显示了二维平面上high bias,just right,high variance的例子。

【Course 2 改善深度神经网络】Week 1 深度学习的实用层面_第1张图片在输入特征是高维度的情况下,我们可以通过两个数值Train set error和Dev set error来理解bias和variance。一般,Train set error体现了是否出现bias,Dev set error体现了是否出现variance(正确地说,应该是Dev set error与Train set error的相对差值)

Train set error Dev set error Note
1% 11%

high variance

对训练样本识别较好,对验证集识别不太好。该模型对训练样本可能存在过拟合,模型泛化能力不强,导致验证集识别率低。

15% 16%

high bias

该算法模型对训练样本和验证集的识别都不太好。该模型对训练样本存在欠拟合

15% 30%

high bias & high variance

深度学习中最坏的情况

0.5% 1%

low bias & low variance

深度学习中最好的情况

 注:以上的这些假设都是建立在base error是0的基础上,即人类都能正确识别所有猫类图片。base error不同,相应的Train set error和Dev set error会有所变化,但没有相对变化。

传统机器学习算法中,Bias和Variance通常是对立的,减小Bias会增加Variance,减小Variance会增加Bias。而在现在的深度学习中,通过使用更复杂的神经网络和海量的训练样本,一般能够同时有效减小Bias和Variance。这也是深度学习之所以如此强大的原因之一。

目的 方法
减少high bias

增加神经网络的隐藏层个数、神经元个数;

训练时间延长;

选择其它更复杂的NN模型...

减少high variance

增加训练样本数据;

正则化Regularization;

选择其他更复杂的NN模型...

温馨提示:再来看这段视频(@莫烦python),生动地了解一下过拟合。

3.Regularization Reduces Overfitting

3.1 L1、L2 Regularization 

温馨提示:理解这部分最好先看下L1 L2 Regularization @莫烦python

3.1.1 Prior knowledge:L1 Norm and L2 Norm(L1、L2范数)

L1 Norm

Q:L1产生稀疏矩阵的作用?

A:稀疏模型有助于进行特征选择,即L1可用来选择对结果贡献较大的主要特征。

解释说明:

稀疏矩阵指的是很多元素为0、只有少数元素是非零值的矩阵。以线性回归为例,即得到的线性回归模型的大部分系数都是0,这表示只有少数特征对这个模型有贡献,从而实现了特征选择。(如手语翻译项目中,有手、肢体、眼、口等特征值,其中手、肢体的特征值对该模型有主要贡献,那么就可以利用L1产生稀疏矩阵,从而有助于特征选择)

Q:为什么L1可以产生稀疏模型,即L1是怎么让系数等于0的?

A:最优解处某些权重可能为0。

解释说明:

现在我们的目标是求解argmin_{w}(J),换句话说,我们的任务是在L1的约束下求出J_{0}取最小值的解。假设只考虑二维的情况,即只有两个权值w_{1}w_{2},此时的L1正则化公式为L1=|w_{1}|+|w_{2}​​​​​|。对J使用梯度下降法求解,则求解J_{0}的过程可以画出等值线,同时L1正则化的函数也可以在二维平面上画出来。如下图:

【Course 2 改善深度神经网络】Week 1 深度学习的实用层面_第2张图片

J_{0}等值线与L1图形首次相交的地方就是最优解,我们很容易发现L1黑色方形必然首先与等值线相交于方形顶点处。可以直观想象,因为L1函数有很多"突出的角"(二维情况下有四个,多维情况下更多),J_{0}与这些角接触的概率远大于与其它部分接触的概率。而这些点某些权重为0(以上图为例,交点处w_{1}为0),从而会使部分特征等于0。

L2 Norm

Q:为什么L2范数可以防止过拟合呢?

A:二维平面下L2正则化的函数图形是个圆,与方形相比,没有突出的棱角。因此交点在坐标轴的概率很低,即使权重等于0的概率小了许多。由上图可知,L2中得到的两个权值倾向于均为非零的较小数

【Course 2 改善深度神经网络】Week 1 深度学习的实用层面_第3张图片

注:过拟合是指模型参数较大,模型过于复杂,模型抗扰动能力弱。只要测试数据偏移一点点,就会对结果造成很大的影响。因此,要防止过拟合,其中一种方法就是让参数尽可能的小一些。如上述链接中的视频中讲到,当批数据训练时,每次批数据都会得到不同的误差曲线。L2对于这种变化,交点(误差最小的点,又是参数正规化后的最优解)的移动不会很大,但L1下交点的跳动较大,从而侧面反应了L1下的解不稳定。 

Q:为什么L2正则化可以获得值很小的参数?

A:每一次迭代,参数都要乘以一个小于1的因子,从而使其不断减小,因此总的来看,参数是不断减小的。(下面有公式推导)

在所有特征中只有少数特征起重要作用的情况下,选择L1范数比较合适,因为它能自动选择特征。而如果所有特征中,大部分特征都能起作用,而且起的作用很平均,那么使用L2范数也许更合适。

3.1.2 L1 L2 Regularization

相比于扩大训练样本数量,正则化regularization是解决过拟合(high variance)更可行有效的办法。因为通常获得更多训练样本的成本太高,比较困难。

L1 regularization:

J(w,b)=\frac1m\sum_{i=1}^mL(\hat y^{(i)},y^{(i)})+\frac{\lambda}{2m}||w||_1
||w||_1=\sum_{j=1}^{n_x}|w_j|

Logistic regression 中进行 L2 regularization:

J(w,b)=\frac1m\sum_{i=1}^mL(\hat y^{(i)},y^{(i)})+\frac{\lambda}{2m}||w||_2^2
||w||_2^2=\sum_{j=1}^{n_x}w_j^2=w^Tw

注意:为什么只对w进行正则化而不对b进行正则化呢?其实也可以对b进行正则化。但是一般w的维度很大,而b只是一个常数。相比较来说,参数很大程度上由w决定,改变b值对整体模型影响较小。所以,一般为了简便,就忽略对b的正则化了。

深度学习模型中的L2 regularization:

J(w^{[1]},b^{[1]},\cdots,w^{[L]},b^{[L]})=\frac1m\sum_{i=1}^mL(\hat y^{(i)},y^{(i)})+\frac{\lambda}{2m}\sum_{l=1}^L||w^{[l]}||^2

||w^{[l]}||^2=\sum_{i=1}^{n^{[l]}}\sum_{j=1}^{n^{[l-1]}}(w_{ij}^{[l]})^2

||w^{[l]}||^2 被称为Frobenius范数,记作 ||w^{[l]}||_F^2 。一个矩阵的Frobenius范数就是计算所有元素平方和再开方,即

||A||_F=\sqrt {\sum_{i=1}^m\sum_{j=1}^n|a_{ij}|^2}

由于加入了正则化项,梯度下降算法中的dw^{[l]}计算表达式需要做如下修改:

dw^{[l]}=dw^{[l]}_{before}+\frac{\lambda}{m}w^{[l]}

w^{[l]}:=w^{[l]}-\alpha\cdot dw^{[l]}

L2 regularization 也被称做weight decay。这是因为,由于加上了正则项,dw^{[l]}有个增量,在更新w^{[l]}的时候,会多减去这个增量,使得w^{[l]}比没有正则项的值要小一些。不断迭代更新,不断地减小。

 w^{[l]}:=w^{[l]}-\alpha\cdot dw^{[l]} =w^{[l]}-\alpha\cdot(dw^{[l]}_{before}+\frac{\lambda}{m}w^{[l]})\\ =(1-\alpha\frac{\lambda}{m})w^{[l]}-\alpha\cdot dw^{[l]}_{before}(1-\alpha\frac{\lambda}{m})<1

3.2 Why regularization reduces overfitting

下面从两个角度来解释

(一)由上图中W更新的推导公式可得,\lambda增加到足够大,w会接近于0(实际上是不会发生这种情况),而减少许多隐藏单元的影响(直觉上认为大量隐藏单元被完全消除了, 其实不然,实际上是该神经网络的所有隐藏单元依然存在),从而使这个网络变得更简单,简单到越来越接近逻辑回归,可是深度却很大,它会使这个网络从Over Fitting的状态(右图)更接近Under Fitting的状态(左图)。从而会找到一个合适的中间值λ,使网络接近Just Right的状态(中图)。

这里写图片描述

(二)更直观地理解,如果你使用的激活函数是tanh, 那么当\lambda取值很大的时候,w取值很小,经w计算得出的z也很小,z很小意味着g\left (z \right )取值集中于红色部分,相当于tanh函数的线性部分。

【Course 2 改善深度神经网络】Week 1 深度学习的实用层面_第4张图片

g\left (z \right )大致呈线性,那么这个神经元起的作用就相当于是线性回归(linear regression)。如果每个神经元对应的权重都比较小,那么整个神经网络模型相当于是多个linear regression的组合,即可看成一个线性网络(linear network),得到的分类超平面就会比较简单,不会出现过拟合现象。

3.3 Dropout Regularization

温馨提示:吴恩达课程dropout这节看不懂的可以借鉴一下这个教学视频。

Dropout是另一种防止过拟合的方法。

【Course 2 改善深度神经网络】Week 1 深度学习的实用层面_第5张图片

原理:

训练时以p的概率保留神经元,以1-p的概率丢弃神经元及与之相连的边,以此得到每次训练的子网络;

每次单独训练时,每个不完整的神经网络都各不相同,但权值共享。

因为每次单独训练的神经网络不同,所以每次的预测结果都不会依赖于某个特定的神经元,从而防止过拟合。(通俗来说L1、L2正则化通过惩罚权值来防止过拟合,dropout则随机drop神经元而从根本上使神经网络过于依赖)

测试时,所有神经元都保留,但权重由 w 变为 pw 。测试时的结果相当于训练时的期望结果值。

具体做法:

【Course 2 改善深度神经网络】Week 1 深度学习的实用层面_第6张图片

【Course 2 改善深度神经网络】Week 1 深度学习的实用层面_第7张图片实现方法:

常用的方法是Inverted dropout(反向随机失活)

假设对于第L层神经元,设定保留神经元比例概率keep_prob=0.8,即该层有20%的神经元停止工作。dl 为dropout向量,设置dl 为随机vector,其中80%的元素为1,20%的元素为0。在python中可以使用如下语句生成 dropout vector:

dl = np.random.rand(al.shape[0],al.shape[1])

实施dropout的另一个细节:一个拥有三个输入特征的网络,其中一个要选择的参数是keep-prob,它代表每一层上保留单元的概率。所以不同层的keep-prob也可以变化。第一层,矩阵W^{[1]} 是7×3,第二个权重矩阵W^{[2]} 是7×7,第三个权重矩阵W^{[3]} 是3×7,以此类推,是W^{[2]}最大的权重矩阵,因为W^{[2]} 拥有最大参数集,即7×7,为了预防矩阵的过拟合,它的keep-prob值应该相对较低,假设是0.5。对于其它层,过拟合的程度可能不会那么严重,它们的keep-prob值可能高一些,可能是0.7。如果在某一层,我们不必担心其过拟合的问题,那么keep-prob可以为1

总结:如果你担心某些层比其它层更容易发生过拟合,可以把某些层的keep-prob值设置得比其它层更低,缺点是为了使用交叉验证,你要搜索更多的超级参数,另一种方案是在一些层上应用dropout,而有些层不用dropout,应用dropout的层只含有一个超级参数keep-prob。

dropout是一种正则化方法,它有助于预防过拟合,因此除非算法过拟合,不然是不会用dropout的,所以它在其它领域应用得比较少,主要存在于计算机视觉领域,因为我们通常没有足够的数据,所以一直存在过拟合,这就是有些计算机视觉研究人员如此钟情于dropout函数的原因。

 dropout缺点:代价函数J 不再被明确定义,每次迭代,都会随机移除一些节点,如果再三检查梯度下降的性能,实际上是很难进行复查的。定义明确的代价函数J 每次迭代后都会下降,因为我们所优化的代价函数J 实际上并没有明确定义,或者说在某种程度上很难计算,所以我们失去了调试工具来绘制这样的图片。

一种解决办法:先关闭dropout函数,将keep-prob的值设为1,运行代码,确保J函数单调递减。然后打开dropout函数,希望在dropout过程中,代码并未引入bug。

3.4 Other regularization methods

3.4.1数据扩增(data augmentation)

在做图片分类器时,当获取更多数据集代价较高时,可以通过水平翻转图片、随意裁剪图片来扩增数据集。注意,像这样人工合成数据的话,我们须要通过算法验证,图片中的猫经过水平翻转之后依然是原类别。

【Course 2 改善深度神经网络】Week 1 深度学习的实用层面_第8张图片

光学字符识别,可以通过添加数字,随意旋转或轻微地扭曲数字来扩增数据,但它们仍然是数字,把这些数字添加到训练集。这里对字符做了强变形处理(便于清楚理解),所以数字4看起来是波形的,其实不用对数字4做这么夸张的扭曲,只要轻微的变形就好。 

3.4.2 early stopping

【Course 2 改善深度神经网络】Week 1 深度学习的实用层面_第9张图片验证集误差通常会先呈下降趋势,然后在某个节点处开始上升,early stopping 的作用是,神经网络已经在这个迭代过程中表现得很好了,我们在此停止训练吧。

early stopping 代表提早停止训练神经网络,但是它也有一个缺点,分析如下:

机器学习过程的其中2个步骤:

其一选择一个算法来优化代价函数J,该问题的解决工具:如梯度下降、Momentum、RMSprop和Adam等等,在重点优化代价函数时,你只需要留意w 和b,使J(w,b) 的值越小越好,只需要想办法减小这个值,其它的不用关注。

其二是优化代价函数之后,不想发生过拟合,解决方法:如正则化,扩增数据等等。预防过拟合还有其他任务,换句话说就是减少方差,这一步我们用另外一套工具来实现,这个原理有时被称为“正交化”(Orthogonalization)(后面讲)

early stopping 的主要缺点就是不能独立地处理上述这两个问题,因为提早停止梯度下降,也就是停止了优化代价函数,因为现在不再尝试降低代价函数,所以代价函数的值可能不够小,同时你又希望不出现过拟合,但没有采取不同的方式来解决这两个问题,而是用一种方法同时解决两个问题,这样做的结果使考虑的东西变得更复杂。

如果不用early stopping,另一种方法就是L2 正则化,训练神经网络的时间就可能很长。这导致超级参数搜索空间更容易分解,也更容易搜索,但是缺点在于,你必须尝试很多正则化参数\lambda 的值,这也导致搜索大量\lambda 值的计算代价太高。

early stopping的优点是,只运行一次梯度下降,你可以找出w的较小值,中间值和较大值,而无需尝试L2 正则化超级参数\lambda 的很多值。

4.归一化(Normalize inputs)

因为如果输入特征都大致在相同范围内,代价函数更易优化。归一化可以提高神经网络的训练速度,非归一化下,如果使用梯度下降,必须使用一个很小的学习率,而且某个位置要迭代多次才能找到最小值;归一化后的图形如果类似于一个椭球形,可能每个点都可直接找到最小值,而且可以采用较大的步长。

这里写图片描述归一化的2个步骤:

1)零均值化

\mu =\frac{1}{m}\sum_{i=1}^{m}X^{(i)}

X:=X-\mu

2)归一化方差

零均值化后,特征 的方差比特征 的方差要大得多

\sigma ^{2}=\frac{1}{m}\sum_{i=1}^{m}X^{(i)^{2}}

X/=\sigma ^{2}

【Course 2 改善深度神经网络】Week 1 深度学习的实用层面_第10张图片

我们希望不论是训练数据还是测试数据,都是通过相同 定义的相同数据转换,其中 是由训练集数据计算得来的。

5.梯度消失、梯度爆炸及如何避免(Vanishing/exploding gradient)

如果各层权重W^{[i]}都大于1或者都小于1,那么各层激活函数的输出将随着层数L的增加,呈指数型增大或减小。当层数很大时,出现数值爆炸或消失。同样,这种情况也会引起梯度呈现同样的指数型增大或减小的变化。L非常大时,例如L=150,则梯度会非常大或非常小,引起每次更新的步进长度过大或者过小,这让训练过程十分困难。

为改善这种问题,要对神经网络的权重做一些初始化处理,为了让z不会过大或者过小,思路是让w与n有关,且n越大,w应该越小才好。这样能够保证z不会过大。有以下三种初始化权重的方法:

#如果激活函数是tanh,令其方差为1/n
w[l] = np.random.randn(n[l],n[l-1])*np.sqrt(1/n[l-1]) 
#如果激活函数的输入特征被零均值,则是标准方差1,相当于对权重未作处理

#如果激活函数是ReLu,令其方差为2/n——Xavier初始化
w[l] = np.random.randn(n[l],n[l-1])*np.sqrt(2/n[l-1]) 

#Yoshua Bengio提出了另外一种初始化w的方法,令其方差为2/(n[l-1]*n[l])
w[l] = np.random.randn(n[l],n[l-1])*np.sqrt(2/n[l-1]*n[l]) 

我们可以对这些初始化方法中设置某些参数,作为超参数,通过验证集进行验证,得到最优参数,来优化神经网络

6.梯度检验(Gradient checking)

参考:Gradient Checking

目的:

检查验证反向传播过程中梯度下降算法是否正确,验证训练过程是否出现bug。

过程:

1)构造一维向量

分别将W^{[1]},b^{[1]},\cdots,W^{[L]},b^{[L]}这些矩阵构造成一维向量,然后将这些一维向量组合起来构成一个更大的一维向量\theta=(\theta_{1},\theta_{2}...)。这样cost functionJ(W^{[1]},b^{[1]},\cdots,W^{[L]},b^{[L]})就可以表示成J(\theta)

然后将反向传播过程通过梯度下降算法得到的dW^{[1]},db^{[1]},\cdots,dW^{[L]},db^{[L]}按照一样的顺序构造成一个一维向量d\theta

d\theta 的维度与\theta一致。

2)求出近似梯度

利用微分思想,近似求出梯度值,即函数f在点 \theta 处的梯度可以表示成:

g(\theta)=\frac{f(\theta+\varepsilon)-f(\theta-\varepsilon)}{2\varepsilon}其中,\varepsilon >0,且足够小。

这里写图片描述

利用J(\theta)对每个\theta_{i}计算近似梯度,其值与反向传播算法得到的 d\theta_{i} 相比较,检查是否一致。例如对于第i个元素,近似梯度为:

d\theta_{approx}[i]=\frac{J(\theta_1,\theta_2,\cdots,\theta_i+\varepsilon,\cdots)-J(\theta_1,\theta_2,\cdots,\theta_i-\varepsilon,\cdots)}{2\varepsilon}

具体步骤:

 【Course 2 改善深度神经网络】Week 1 深度学习的实用层面_第11张图片

代码实现: 

thetaplus = theta + epsilon                               # Step 1
thetaminus = theta - epsilon                              # Step 2
J_plus = forward_propagation(x, thetaplus)                # Step 3
J_minus = forward_propagation(x, thetaminus)              # Step 4
gradapprox = (J_plus - J_minus) / (2 * epsilon)           # Step 5

3)比较d\theta_{approx} 与 d\theta 的接近程度。

具体步骤:

  • 1'. compute the numerator using np.linalg.norm(...)
  • 2'. compute the denominator. You will need to call np.linalg.norm(...) twice.
  • 3'. divide them.

代码实现:

numerator = np.linalg.norm(grad - gradapprox)                      # Step 1'
denominator = np.linalg.norm(grad) + np.linalg.norm(gradapprox)    # Step 2'
difference = numerator / denominator                               # Step 3'

一般来说,如果欧氏距离越小,例如10^{-7},则表明二者越接近,即反向梯度计算是正确的,没有bug。如果欧氏距离较大,例如10^{-5},则表明梯度计算可能出现问题,需要再次检查是否有bug存在。如果欧氏距离很大,例如10^{-3},甚至更大,则表明二者差别很大,梯度下降计算过程有bug,需要仔细检查。

注:

梯度检查仅作为debug使用,不要在整个训练过程中都进行梯度检查。

如果梯度检查出现错误,找到对应出错的梯度,检查其推导是否出现错误。

注意不要忽略正则化项,计算近似梯度的时候要包括进去。

梯度检查时关闭dropout,检查完毕后再打开dropout。

随机初始化时运行梯度检查,经过一些训练后再进行梯度检查(不常用)。

7.编程作业

你可能感兴趣的:(神经网络,深度学习)