Deeplearning.ai吴恩达笔记之优化深度神经网络1

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35564813/article/details/86476775

Setting up your Machine Learning Application

Train/Dev/Test sets

对于一个需要解决的问题的样本数据,在建立模型的过程中,我们会将问题的data划分为以下几个部分:

  • 训练集(train set):用训练集对算法或模型进行训练过程;

  • 验证集(development set):利用验证集或者又称为简单交叉验证集(hold-out cross validation set)进行交叉验证,选择出最好的模型;

  • 测试集(test set):最后利用测试集对模型进行测试,获取模型运行的无偏估计。

数据量小

在数据量比较小的时候,如100、1000、10000的数据量石,可以将数据划分如下:

  • 无验证集时:70%/30%
  • 有验证集时:60%/20%/20%

数据量小时,以上的比例是非常合理的。

数据量大

但是在如今的大数据时代,对于一个问题,我们拥有的data的数量可能是百万级别的,所以验证集和测试集所占的比重会趋向于变得更小。

验证集的目的是为了验证不同的算法哪种更加有效,所以验证集只要足够大能够验证大约2-10种算法哪种更好就足够了,不需要使用20%的数据作为验证集。如百万数据中抽取1万的数据作为验证集就可以了。

测试集的主要目的是评估模型的效果,如在单个分类器中,往往在百万级别的数据中,我们选择其中10000条数据足以评估单个模型的效果。

100万数据量:98% / 1% / 1%;
超百万数据量:99.5% / 0.25% / 0.25%(或者99.5% / 0.4% / 0.1%)

Notation

  • 建议开发集要和测试集来自于同一个分布,即使Train sets和Dev/Test sets不来自同一分布,也可以使得机器学习算法变得更快;
  • 如果不需要用无偏估计来评估模型的性能,则可以不需要测试集。

Bias/Variance

对于下图中两个类别分类边界的分割:

在这里插入图片描述

从图中我们可以看出,在欠拟合(underfitting)的情况下,出现高偏差(high bias)的情况;在过拟合(overfitting)的情况下,出现高方差(high variance)的情况。

在bias-variance tradeoff 的角度来讲,我们利用训练集对模型进行训练就是为了使得模型在train集上使 bias 最小化,避免出现underfitting的情况;

但是如果模型设置的太复杂,虽然在train集上 bias 的值非常小,模型甚至可以将所有的数据点正确分类,但是当将训练好的模型应用在dev 集上的时候,却出现了较高的错误率。这是因为模型设置的太复杂,使得模型出现overfitting的情况,在dev 集上出现高 variance 的现象。

所以对于bias和variance的权衡问题,对于模型来说是一个十分重要的问题。

例子:

几种不同的情况:

在这里插入图片描述

以上为在人眼判别误差在0%的情况下,该最优误差通常也称为“贝叶斯误差”,如果“贝叶斯误差”大约为15%,那么图中第二种情况就是一种比较好的情况。

High bias and high variance的情况

上图中第三种bias和variance的情况出现的可能如下:

在这里插入图片描述

没有找到边界线,但却在部分数据点上出现了过拟合,则会导致这种高偏差和高方差的情况。

虽然在这里二维的情况下可能看起来较为奇怪,出现的可能性比较低;但是在高维的情况下,出现这种情况就成为可能。

Basic Recipe for Machine Learning

在训练机器学习模型的过程中,解决High bias 和High variance 的过程:

在这里插入图片描述

  1. 是否存在High bias?

    • 增加网络结构,如增加隐藏层数目;
    • 训练更长时间;
    • 寻找合适的网络架构,使用更大的NN结构;
  2. 是否存在High variance?

  • 获取更多的数据;
  • 正则化( regularization);
  • 寻找合适的网络结构;

Notation

  1. 解决high bias和high variance的方法是不同的。实际应用中通过Train set error和Dev set error判断是否出现了high bias或者high variance,然后再选择针对性的方法解决问题。

  2. Bias和Variance的折中tradeoff。传统机器学习算法中,Bias和Variance通常是对立的,减小Bias会增加Variance,减小Variance会增加Bias。而在现在的深度学习中,通过使用更复杂的神经网络和海量的训练样本,一般能够同时有效减小Bias和Variance。

Regularizing your neural network

Regularization

利用正则化来解决High variance 的问题,正则化是在 Cost function 中加入一项正则化项,惩罚模型的复杂度。

Logistic regression

加入正则化项的代价函数:
J ( w , b ) = 1 m i = 1 m l ( y ^ ( i ) , y ( i ) ) + λ 2 m w 2 J(w,b)=\frac{1}{m}\sum_{i=1}^ml(ŷ^{(i)},y^{(i)})+\frac{λ}{2m}||w||^2
上式为逻辑回归的L2正则化。

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

L2正则化: λ 2 m w 2 2 = λ 2 m j = 1 n x w j 2 = λ 2 m w T w \frac{λ}{2m}||w|^2_2=\frac{λ}{2m}\sum_{j=1}^{nx}w^2_j=\frac{λ}{2m}w^Tw
L1正则化: λ 2 m w 1 = λ 2 m j = 1 n x w j \frac{λ}{2m}||w||_1=\frac{λ}{2m}\sum_{j=1}^{nx}|w_j|
其中λ为正则化因子。

与L2 regularization相比,L1 regularization得到的w更加稀疏,即很多w为零值。其优点是节约存储空间,因为大部分w为0。然而,实际上L1 regularization在解决high variance方面比L2 regularization并不更具优势。而且,L1的在微分求导方面比较复杂。所以,一般L2 regularization更加常用。

注意:lambda在python中属于保留字,所以在编程的时候,用“lambd”代表这里的正则化因子λ。

Neural network

加入正则化项的代价函数:

J ( w [ 1 ] , b [ 1 ] , , w [ L ] , b [ L ] ) = 1 m i = 1 m l ( y ^ ( i ) , y ( i ) ) + λ 2 m l = 1 L w [ l ] F 2 J(w^{[1]},b^{[1]},⋯,w^{[L]},b^{[L]})=\frac{1}{m}\sum_{i=1}^ml(ŷ ^{(i)},y^{(i)})+\frac{λ}{2m}\sum_{l=1}^L||w^{[l]}||^2_F

其中 w [ l ] F 2 = i = 1 n [ l 1 ] j = 1 n [ l ] ( w i j [ l ] ) 2 ||w^{[l]}||^2_F=\sum_{i=1}^{n^{[l−1}]}\sum_{j=1}^{n^{[l]}}(w^{[l]}_{ij})^2 ,因为w的大小为 ( n [ l 1 ] , n [ l ] ) (n^{[l−1]},n^{[l]}) ,该矩阵范数被称为“Frobenius norm”

####Weight decay

在加入正则化项后,梯度变为:
d W [ l ] = ( f o r m _ b a c k p r o p ) + λ m W [ l ] dW^{[l]}=(form\_backprop)+\frac{λ}{m}W^{[l]}
则梯度更新公式变为:
W [ l ] : = W [ l ] α d W [ l ] W^{[l]}:=W^{[l]}−\alpha dW^{[l]}
代入可得:
W [ l ] : = W [ l ] α [ ( f o r m _ b a c k p r o p ) + λ m W [ l ] ] W^{[l]}:=W^{[l]}−\alpha[(form\_backprop)+\frac{λ}{m}W^{[l]}]
= W [ l ] α λ m W [ l ] α ( f o r m _ b a c k p r o p ) =W^{[l]}−\alpha\frac{λ}{m}W^{[l]}−\alpha(form\_backprop)
= ( 1 α λ m ) W [ l ] α ( f o r m _ b a c k p r o p ) =(1−\frac{\alphaλ}{m})W^{[l]}−\alpha(form\_backprop)
其中, ( 1 α λ m ) (1−\frac{αλ}{m}) 为一个<1的项,会给原来的 W [ l ] W^{[l]} 一个衰减的参数,所以L2范数正则化也被称为“权重衰减(Weight decay)”。

Why regularization reduces overfitting?

为什么正则化能够有效避免high variance,防止过拟合呢?下面我们通过几个例子说明。

还是之前那张图,从左到右,分别表示了欠拟合,刚好拟合,过拟合三种情况。

在这里插入图片描述

假如我们选择了非常复杂的神经网络模型,如上图左上角所示。在未使用正则化的情况下,我们得到的分类超平面可能是类似上图右侧的过拟合。但是,如果使用L2 regularization,当λ很大时, w [ l ] 0 w^{[l]}≈0 w [ l ] w^{[l]} 近似为零,意味着该神经网络模型中的某些神经元实际的作用很小,可以忽略。从效果上来看,其实是将某些神经元给忽略掉了。这样原本过于复杂的神经网络模型就变得不那么复杂了,而变得非常简单化了。如下图所示,整个简化的神经网络模型变成了一个逻辑回归模型。问题就从high variance变成了high bias了。

在这里插入图片描述

还有另外一个直观的例子来解释为什么正则化能够避免发生过拟合。

假设神经元中使用的激活函数为g(z)=tanh(z),在加入正则化项后:

在这里插入图片描述

当λ增大,导致 W [ l ] W^{[l]} 减小, Z [ l ] = W [ l ] a [ l 1 ] + b [ l ] Z^{[l]}=W^{[l]}a^{[l−1]}+b^{[l]} 便会减小,由上图可知,在z较小的区域里,tanh(z)函数近似线性,所以每层的函数就近似线性函数,那么整个神经网络模型相当于是多个linear regression的组合,即可看成一个linear network。得到的分类超平面就会比较简单,不会出现过拟合现象。

Dropout Regularization

Dropout(随机失活)就是在神经网络的Dropout层,为每个神经元结点设置一个随机消除的概率,对于保留下来的神经元,我们得到一个节点较少,规模较小的网络进行训练。

在这里插入图片描述

实现Dropout的方法:反向随机失活(Inverted dropout)

首先假设对 layer 3 进行dropout:

keep_prob = 0.8  # 设置神经元保留概率
d3 = np.random.rand(a3.shape[0], a3.shape[1]) < keep_prob
a3 = np.multiply(a3, d3)
a3 /= keep_prob

这里解释下为什么要有最后一步:a3 /= keep_prob

依照例子中的keep_prob = 0.8 ,那么就有大约20%的神经元被删除了,也就是说a3中有20%的元素被归零了,在下一层的计算中有 Z [ 4 ] = W [ 4 ] a [ 3 ] + b [ 4 ] Z^{[4]}=W^{[4]}⋅a^{[3]}+b^{[4]} ,所以为了不影响 Z [ 4 ] Z^{[4]} 的期望值,所以需要把 a [ 3 ] a^{[3]} 除以一个keep_prob。

Inverted dropout通过对“a3 /= keep_prob”,则保证无论keep_prob设置为多少,都不会对 Z [ 4 ] Z^{[4]} 的期望值产生影响。

Notation

在测试阶段不要用dropout,因为那样会使得预测结果变得随机。

Understanding Dropout

另外一种对于Dropout的理解。

这里我们以单个神经元入手,单个神经元的工作就是接收输入,并产生一些有意义的输出,但是加入了Dropout以后,输入的特征都是有可能会被随机清除的,所以该神经元不会再特别依赖于任何一个输入特征,也就是说不会给任何一个输入设置太大的权重。

所以通过传播过程,dropout将产生和L2范数相同的收缩权重的效果。

在使用dropout的时候,有几点需要注意:

  1. 不同隐藏层的dropout系数keep_prob可以不同。一般来说,神经元越多的隐藏层,keep_prob可以设置得小一些.,例如0.5;神经元越少的隐藏层,keep_prob可以设置的大一些,例如0.8,甚至是1。
  2. 不建议对输入层进行dropout,如果输入层维度很大,例如图片,那么可以设置dropout,但keep_prob应设置的大一些,例如0.8,0.9。总体来说,就是越容易出现overfitting的隐藏层,其keep_prob就设置的相对小一些。
  3. dropout是一种regularization技巧,用来防止过拟合的,最好只在需要regularization的时候使用dropout。

使用dropout的缺点:

  1. 在交叉验证 (网格) 搜索时,会有更多的超参数 (运行会更费时) 。
  2. 代价函数的定义不够明确,很难确定代价函数是否已经定义的足够好,因为每次迭代都会随机消除一些神经元结点,所以我们无法绘制出每次迭代J(W,b)下降的图。因此就不能用绘图的方法去调试错误了,通常这个时候我会关闭dropout,把留存率设为1 ,然后再运行代码并确保代价函数J 是单调递减的,最后再打开dropout并期待使用dropout的时候没有引入别的错误。

Other regularization methods

  • 数据扩增(data augmentation):通过图片的一些变换,得到更多的训练集和验证集

    在这里插入图片描述

  • Early stopping:在交叉验证集的误差上升之前的点停止迭代,避免过拟合。这种方法的缺点是无法同时解决bias和variance之间的最优。

    在这里插入图片描述

通常来说,机器学习训练模型有两个目标:一是优化cost function,尽量减小J;二是防止过拟合。这两个目标彼此对立的,即减小J的同时可能会造成过拟合,反之亦然。我们把这二者之间的关系称为正交化orthogonalization。

Notation

与early stopping相比,L2 regularization可以实现“分而治之”的效果:迭代训练足够多,减小J,而且也能有效防止过拟合。而L2 regularization的缺点之一是最优的正则化参数λ的选择比较复杂。对这一点来说,early stopping比较简单。总的来说,L2 regularization更加常用一些。

Setting up your optimization problem

Normalizing inputs

在训练神经网络时,标准化输入可以提高训练的速度。标准化输入就是对训练数据集进行归一化的操作,即将原始数据减去其均值μ后,再除以其标准差 σ σ

  • 计算每个特征所有样本数据的均值: μ = 1 m i = 1 m x ( i ) μ=\frac{1}{m}\sum_{i=1}^mx^{(i)}
  • 方差: σ 2 = 1 m i = 1 m ( x ( i ) ) 2 σ^2=\frac{1}{m}\sum_{i=1}^m(x^{(i)})^2
  • x : = x μ σ x:=\frac{x−μ}{σ}
    以二维平面为例,下图展示了其归一化过程:(normalization应该除以标准差,而不是方差)

在这里插入图片描述

值得注意的是,由于训练集进行了标准化处理,那么对于测试集或在实际应用时,应该使用同样的μ和 σ 2 σ^2 对其进行标准化处理。这样保证了训练集合测试集的标准化操作一致。

之所以要对输入进行标准化操作,主要是为了让所有输入归一化同样的尺度上,方便进行梯度下降算法时能够更快更准确地找到全局最优解。假如输入特征是二维的,且x1的范围是[1,1000],x2的范围是[0,1]。如果不进行标准化处理,x1与x2之间分布极不平衡,训练得到的w1和w2也会在数量级上差别很大。这样导致的结果是cost function与w和b的关系可能是一个非常细长的椭圆形碗。对其进行梯度下降算法时,由于w1和w2数值差异很大,只能选择很小的学习因子α,来避免J发生振荡。一旦α较大,必然发生振荡,J不再单调下降。如下左图所示。

然而,如果进行了标准化操作,x1与x2分布均匀,w1和w2数值差别不大,得到的cost function与w和b的关系是类似圆形碗。对其进行梯度下降算法时,α可以选择相对大一些,且J一般不会发生振荡,保证了J是单调下降的。如下右图所示。

在这里插入图片描述

Vanishing/Exploding gradients

在神经网络尤其是深度神经网络中存在可能存在这样一个问题:梯度消失和梯度爆炸。意思是当训练一个层数非常多的神经网络时,计算得到的梯度可能非常小或非常大,甚至是指数级别的减小或增大。这样会让训练过程变得非常困难。

如下图所示,以两个输入为例:

在这里插入图片描述

首先我们假定 g ( z ) = z , b ( l ) = 0 g(z)=z,b^{(l)}=0 ,所以对于目标输出有:

​ ŷ = W [ L ] W [ L 1 ] W [ 2 ] W [ 1 ] X W^{[L]}W^{[L−1]}⋯W^{[2]}W^{[1]}X

  • W ( l ) W^{(l)} 的值大于1的情况:

    如: W ( l ) = [ 1.5 0 0 1.5 ] W^{(l)}=\begin{bmatrix} ​ 1.5 &amp; 0 \\ ​ 0 &amp; 1.5 ​ \end{bmatrix} ,那么最终,
    ŷ= W ( L ) [ 1.5 0 0 1.5 ] L 1 X W^{(L)}\begin{bmatrix} ​ 1.5 &amp; 0 \\ ​ 0 &amp; 1.5 ​ \end{bmatrix}^{L-1}X ,激活函数的值将以指数级递增

  • W ( l ) W^{(l)} 的值小于1的情况:

    如: W ( l ) = [ 0.5 0 0 0.5 ] W^{(l)}=\begin{bmatrix} ​ 0.5 &amp; 0 \\ ​ 0 &amp; 0.5 ​ \end{bmatrix} ,那么最终,
    ŷ= W ( L ) [ 0.5 0 0 0.5 ] L 1 X W^{(L)}\begin{bmatrix} ​ 0.5 &amp; 0 \\ ​ 0 &amp; 0.5 ​ \end{bmatrix}^{L-1}X ,激活函数的值将以指数级递减

上面的情况对于导数也是同样的道理,所以在计算梯度时,根据情况的不同,梯度函数会以指数级递增或者递减,导致训练导数难度上升,梯度下降算法的步长会变得非常非常小,需要训练的时间将会非常长。

在梯度函数上出现的以指数级递增或者递减的情况就分别称为梯度爆炸或者梯度消失。

Weight Initialization for Deep Networks

以一个单个神经元为例子:

在这里插入图片描述

这里忽略了常数项b。为了让z不会过大或者过小,思路是让w与n有关,且n越大,w应该越小才好。这样能够保证z不会过大。

  1. 激活函数是tanh,在初始化w时,令其方差为 1 n \frac{1}{n} ,这里称为Xavier initialization,相应的python伪代码为:

    w[l] = np.random.randn(n[l],n[l-1])*np.sqrt(1/n[l-1])

    这么做是因为,如果激活函数的输入x近似设置成均值为0,标准差1的情况,输出z也会调整到相似的范围内。虽然没有解决梯度消失和爆炸的问题,但其在一定程度上确实减缓了梯度消失和爆炸的速度。

  2. 激活函数是ReLU,权重w的初始化一般令其方差为 2 n \frac{2}{n}

    w[l] = np.random.randn(n[l],n[l-1])*np.sqrt(2/n[l-1])

  3. 除此之外,Yoshua Bengio提出了另外一种初始化w的方法,令其方差为 2 n [ l 1 ] n [ l ] \frac{2}{n^{[l−1]}*n^{[l]}}

    w[l] = np.random.randn(n[l],n[l-1])*np.sqrt(2/n[l-1]*n[l])

至于选择哪种初始化方法因人而异,可以根据不同的激活函数选择不同方法。另外,我们可以对这些初始化方法中设置某些参数,作为超参数,通过验证集进行验证,得到最优参数,来优化神经网络。

###Numerical approximation of gradients

在这里插入图片描述

由图可以看出,双边误差逼近的误差是0.0001,先比单边逼近的误差0.03,其精度要高了很多。

涉及的公式:

  • 双边导数:

    f ( θ ) = f ( θ + ϵ ) f ( θ ϵ ) 2 ϵ f&#x27;(\theta)=\frac{f(\theta+\epsilon)-f(\theta-\epsilon)}{2\epsilon}

    误差: O ( ϵ 2 ) O(\epsilon^2)

  • 单边导数:

    f ( θ ) = f ( θ + ϵ ) f ( θ ) ϵ f&#x27;(\theta)=\frac{f(\theta+\epsilon)-f(\theta)}{\epsilon}

    误差: O ( ϵ ) O(\epsilon)

Gradient checking

参数连接

在这里插入图片描述

梯度检验

利用J(θ)对每个 θ i θ_i 计算近似梯度,其值与反向传播算法得到的 d θ i dθ_i 相比较,检查是否一致。例如,对于第i个元素,近似梯度为:
d θ a p p r o x [ i ] = J ( θ 1 , θ 2 , , θ i + ε , ) J ( θ 1 , θ 2 , , θ i ε , ) 2 ε dθ_{approx}[i]=\frac{J(θ_1,θ_2,⋯,θ_i+ε,⋯)−J(θ_1,θ_2,⋯,θ_i−ε,⋯)}{2ε}
计算完所有 θ i θ_i 的近似梯度后,可以计算 d θ a p p r o x dθ_{approx} 与dθ的欧氏(Euclidean)距离来比较二者的相似度。公式如下:

d θ a p p r o x d θ 2 d θ a p p r o x 2 + d θ 2 \frac{||dθapprox−dθ||_2}{||dθ_{approx}||_2+||dθ||_2}

其中,“ 2 ||⋅||_2 ”表示欧几里得范数,它是误差平方之和,然后求平方根,得到的欧氏距离。

一般来说,如果欧氏距离越小,例如 1 0 7 10^{−7} ,甚至更小,则表明 d θ a p p r o x dθ_{approx} 与dθ越接近,即反向梯度计算是正确的,没有bugs。如果欧氏距离较大,例如 1 0 5 10^{−5} ,则表明梯度计算可能出现问题,需要再次检查是否有bugs存在。如果欧氏距离很大,例如 1 0 3 10^{−3} ,甚至更大,则表明 d θ a p p r o x dθ_{approx} 与dθ差别很大,梯度下降计算过程有bugs,需要仔细检查。

Gradient Checking Implementation Notes

在进行梯度检查的过程中有几点需要注意的地方:

  • 不要在整个训练过程中都进行梯度检查,仅仅作为debug使用。
  • 如果梯度检查出现错误,找到对应出错的梯度,检查其推导是否出现错误。
  • 注意不要忽略正则化项,计算近似梯度的时候要包括进去。
  • 梯度检查时关闭dropout,检查完毕后再打开dropout。
  • 随机初始化时运行梯度检查,经过一些训练后再进行梯度检查(不常用)。

猜你喜欢

转载自blog.csdn.net/qq_35564813/article/details/86476775