吴恩达深度学习deeplearning.ai学习笔记(二)1.9 1.10 1.11 1.12 1.13 1.14

1.9 归一化输入方法

假设一个数据集只有两个输入特征x_1,x_2,并且数据集的散点图如下:

归一化输入需要两个步骤:

(1)零均值化(zero\ out/subtract\ out\ the\ mean)

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

x:=x-\mu\ \ \ \ \ (2)

移动训练集直到它完成零均值化,效果如下:

(2)归一化方差(Normalize\ variance)

注意到图中x_1的方差要比x_2的方差大得多,我们要做的是给\sigma赋值:

\sigma^{2} =\frac{1}{m}\sum_{i=1}^{m}x^{(i)} \ast \ast 2\ \ \ \ \ (3)

这里\ast \ast 2的意思是指平方,之所以这么写,是因为x^{(i)},\sigma^2都是向量,这里:

x^{(i)}=\begin{bmatrix} x_1^{(i)}\\ x_2^{(i)} \end{bmatrix}

\sigma^2=\begin{bmatrix} \sigma_1^2\\ \sigma_2^2 \end{bmatrix}=\begin{bmatrix} \frac{1}{m}\sum_{i=1}^{m}x_1^{(i)}\ast \ast2\\ \frac{1}{m}\sum_{i=1}^{m}x_2^{(i)}\ast \ast2 \end{bmatrix}

它的每个特征都有方差;并且注意到前面已经做了0均值化,方差原本的定义是\frac{1}{m}\sum_{i=1}^{m}(x_i-\mu)^2,但均值\mu已经归零,所以\frac{1}{m}\sum_{i=1}^{m}x_i^2就是方差了;

接下来要将所有数都除以\sigma^2,图像将变得比较均衡,此时x_1,x_2的方差都等于1:

x/=\sigma\ \ \ \ \ (4)

提示:

如果你用它来调整训练数据,那么也应该用相同的\mu,\sigma^2来归一化测试集,你不希望训练集和测试集的归一化有所不同,均值和方差本来就是模型的参数之一,所以更换输入并不需要改变它们,无论\mu,\sigma^2的值是什么,终归是要用它们按x:=x-\mux/=\sigma两个式子去计算,所以你要用同样的方法按这四个式子去调整测试集,不能再训练集和测试集上分别预估\mu,\sigma^2;我们希望不论是训练数据还是测试数据都是通过相同的\mu,\sigma^2定义的相同数据转换,其中\mu,\sigma^2是由训练集数据计算得到的;

为什么我们想要归一化输入特征?

如果使用非归一化的输入特征,代价函数将会变得细长狭窄,假设w,b都是一维的:

而如果特征值x_1,x_2在不同的范围,例如x_1的取值范围是1~1000,x_2是0~1,结果是参数w_1,w_2的范围或比率将会非常不同,导致代价函数像狭长的碗;如果你能画出部分参数的轮廓,它会是一个狭长的函数:

而归一化以后成本函数平均起来更对称:

说到底,如果在狭长的成本函数上运行梯度下降法,你将被迫选择一个很小的学习率,如图中位置梯度下降法可能需要很多迭代过程,但如果成本函数是一个更圆的球形轮廓,那么不论从哪个位置开始,梯度下降法都能更加直接地找到最小值,可以使用较大的学习率即较大的梯度下降步长;

当然w是一个高维向量,用二维图不能很好描绘,也许代价函数是高度非线性非凸的,但总的来说,代价函数更圆一些就会更容易优化,前提是特征都要在相似范围内;例如,x_1\in (-1,1),x_2\in(0,1),x_3\in (1,2),这些是相似范围,但x_1\in(1,1000),x_2\in (0,1)这样不是相似范围,对优化算法相当不利

总结:

零均值化、归一化为标准方差(即1)、确保特征都在相似范围内,通常就可以帮助学习算法运行得更快;

1.10 梯度消失和梯度爆炸

训练神经网络有时导数或梯度会变得非常大或非常小,指数级的,加大了训练难度;

假设我们在训练一个很深的神经网络,为了简化假设每层都只有两个单元,并设:

g^{[l]}(z)=z,b^{[l]}=0,l=1,2,\cdots,L

z^{[1]}=w^{[1]}x,a^{[1]}=z^{[1]}

z^{[2]}=w^{[2]}a^{[1]},a^{[2]}=z^{[2]}

\cdots

z^{[L]}=w^{[L]}a^{[L-1]},a^{[L]}=z^{[L]}

\therefore \hat{y}=a^{[L]}=w^{[L]}a^{[L-1]}=\cdots=w^{[L]}w^{[L-1]}\cdots w^{[2]}w^{[1]}x

if\ w^{[1]}=w^{[2]}=\cdots=w^{[L-1]}=\begin{bmatrix} 1.5 &0 \\ 0 &1.5 \end{bmatrix}=1.5E

then\ \hat{y}=(1.5)^{L-1}w^{[L]}x

一个深度神经网络的L一般很大,从而会使激活函数值逐层呈指数级爆炸增长,\hat{y}最终很大;

if\ w^{[1]}=w^{[2]}=\cdots=w^{[L-1]}=\begin{bmatrix} 1.5 &0 \\ 0 &1.5 \end{bmatrix}=0.5E

then\ \hat{y}=(0.5)^{L-1}w^{[L]}x

此时,会使激活函数值逐层呈指数级减小到接近于0,\hat{y}最终很小;

直观理解就是w^{[l]}只要比单位矩阵大一些,深度神经网络的激活函数就将爆炸性增长;w^{[l]}只要比单位矩阵小一些,深度神经网络的激活函数就将指数级递减到0;

不仅仅是激活函数值a^{[L]},而且对和层数L相关的导数也是呈指数增长或递减;

当前的深度神经网络能达到150层以上,在这种深度神经网络中如果作为L的激活函数或梯度函数以指数级上升或下降,它们的值会变得极大,导致训练难度上升,尤其是梯度和层数相差指数级时,梯度下降法的步长会变得很小,梯度下降法将花费很多时间来学习;

1.11 神经网络的权重初始化

这是一个解决梯度爆炸和消失并不完整和系统的方法,从一个例子看起:

例1:单个神经单元权重初始化

z=w_1x_1+w_2x_2+\cdots+w_nx_n

先忽略参数b,为了防止z过大或者过小,当n越大时,希望的是w_i,i=1,2,\cdots,n能够越小,因为z是由nw_ix_i相加而得的,n越大时,自然希望每一项w_ix_i能够小一些,也就是希望w_i能够小一些;比较合理的方法是设置w_i=\frac{1}{n}

Var(w_i)=\frac{1}{n}

而对于多层神经网络,对于第l层而言有n^{[l-1]}个输入,也可以设置w^{[l]}为:

w^{[l]}=np.random.randn(shape)\ast np.sqrt(\frac{1}{n^{[l-1]}})

这里的shape应该指的就是w^{[l]}的维度即(n^{[l]},n^{[l-1]}),而np.random.randn指令在这是指生成一个指定维度的矩阵,矩阵中的元素是从标准正态分布(均值为0,标准差为1)中随机抽取的,而n^{[l-1]}指的是第l-1层的单元数,np.sqrt指对括号中的数开根号,所以结果就是将一个矩阵和一个数相乘,数乘进矩阵会影响矩阵的每一个元素;

而如果使用的是ReLu激活函数,那么方差设置为2/n会更好:

Var(w_i)=\frac{2}{n}

w^{[l]}=np.random.randn(shape)\ast np.sqrt(\frac{2}{n^{[l-1]}})

这其实叫“He/MSRA 初始化”的正态分布初始化:

所以如果激活函数的输入特征被零均值化、归一化方差,z也会调整到相似范围,这样虽然没有彻底解决,但也确实减少了梯度下降和爆炸的问题,它通过给权重矩阵w设置了合理的值,不能比E大很多,也不能比E小很多,所以梯度并没有消失或爆炸得太快;

其他变体函数:

对于使用tanh激活函数的情况,初始化为以下两种更好,叫“Xavier初始化”:

w^{[l]}=np.random.randn(shape)\ast np.sqrt(\frac{1}{n^{[l-1]}})

w^{[l]}=np.random.randn(shape)\ast np.sqrt(\frac{2}{n^{[l-1]}+n^{[l]}})

这些公式只是给出一个起点,一个初始化权重矩阵的默认值,如果你愿意调整,实际上可以把方差参数当作一个超参数进行调整,也许是在\frac{1}{n^{[l-1]}}中加入一个乘数参数作为超参数,但实际上这个超参数一般不知首先想调优的超参数,并不如其他超参数那么重要。

1.12 梯度的数值逼近

在实施backprop时有一个测试叫梯度检验,它的作用是保证backprop能够正常实施,有时你写下这些方程式,但无法100%确定执行backprop的所有细节都是正确的;为了逐渐实现梯度检验,首先说说如何对计算梯度做数值逼近,下一节再讨论如何在back prop中执行梯度检验;

这是一个和微积分有关的有趣例子,假设我们要求一条曲线在\theta =1处的导数,导数在微积分里的直观意义是什么呢?是切线斜率。但还有另一种理解方式,那就是如图所示,\theta =1处的导数严格意义讲就差不多等于\varepsilon \rightarrow 0时小绿三角的斜边的斜率,也差不多等于大绿三角斜边的斜率,注意三角形除了直角边顶点外的顶点都在曲线上,对应着\theta- \varepsilon , \theta,\theta+ \varepsilon;而绿三角形斜边的斜率就等于三角形的高宽比;

技术上,大绿三角形在利用高宽比计算导数时比小绿三角更加准确,大概是因为大三角考虑了左下方的小三角,得到了一个双边公差,这比小绿三角的双边公差更加精准;

我们可以验证一下,假设f(\theta)=\theta^3\varepsilon =0.01,则大三角形的高宽比是:

\frac{f(\theta +\varepsilon)-f(\theta -\varepsilon)}{2\varepsilon }=\frac{1.01^3-0.99^3}{2\times 0.01}=3.0001

小三角形的高宽比是3.0301,实际上\theta =1处的导数为3,所以用大三角计算出来的误差更小;

准确的数学定义中:

{f}'(\theta)=\lim_{x\rightarrow 0}\frac{f(\theta +\varepsilon)-f(\theta -\varepsilon)}{2\varepsilon }

如果直接让{f}'(\theta)=\frac{f(\theta +\varepsilon)-f(\theta -\varepsilon)}{2\varepsilon },那么得到的误差将是o(\varepsilon ^2);而如果采用单边误差,让{f}'(\theta)=\frac{f(\theta +\varepsilon)-f(\theta)}{\varepsilon },那么得到的逼近误差将是o(\varepsilon ),会比o(\varepsilon ^2)大得多;

1.13 梯度检验(Grad\ Check)

梯度检验帮忙节省了很多时间,也帮忙发现了很多backprop中的bug;

如何利用它来调试或检验backprop实施是否正确呢?

神经网络中有w^{[1]},b^{[1]},w^{[2]},b^{[2]},\cdots,w^{[L]},b^{[L]}这些参数,为了执行梯度检验,首先要做的是:

把所有参数转换为一个巨大的向量

实际中就是将每一个w矩阵转换为向量然后所有(包括b)的向量进行连接运算(concatenate),变成一个巨型向量\Theta;于是成本函数就是:

J(w^{[1]},b^{[1]},w^{[2]},b^{[2]},\cdots,w^{[L]},b^{[L]})=J(\Theta)=J(\theta_1,\theta_2,\cdots)

然后得到和w,b有同样顺序的dw^{[1]},db^{[1]},dw^{[2]},db^{[2]},\cdots,dw^{[L]},db^{[L]},一样将他们整合成一个巨型向量d\Theta,它和\Theta有同样的维度;

那么d\Theta与成本函数J的梯度有什么关系?

不论\Theta维度是多少,总能展开成J(\Theta)=J(\theta_1,\theta_2,\cdots),为了实施梯度检验,所要做的就是循环执行以下代码:

for\ each\ 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 }

实际上,d\Theta_{approx}[i]应该会逼近d\Theta[i]=\frac{\partial J}{\partial \theta_i};这个for loop要求对每个i都执行这个运算,最终将所有d\Theta_{approx}[i]按顺序排列组成d\Theta_{approx},和d\Theta具有相同维度;

如何衡量两个向量之间是否彼此接近?

一般做以下运算来检查d\Theta_{approx}d\Theta的接近程度:

\frac{​{\parallel d\Theta_{approx}-d\Theta \parallel }_2 }{​{\parallel d\Theta_{approx} \parallel }_2+{\parallel d\Theta \parallel }_2}=\left\{\begin{matrix} 10^{-7},great!\\ 10^{-5},careful!\ check\ if\ there\ is\ a\ bug\\ 10^{-3},sorry!\ check\ the\ bug! \end{matrix}\right.

注意这里是欧式距离,即这个向量的所有元素的平方求和再开根号,类似于\sqrt{\theta_1^2+\theta_2^2+\cdots+\theta_n^2},分母则是用向量长度做归一化,只是用于预防这些向量过大或者过小;这里的10^{-7}等是沿用了前面设定的\varepsilon =0.01,误差合理的值应该是o(\varepsilon ^2)=o(10^{-4}),也就是要比10^{-4}更高阶更小的无穷小量;

检查bug时应该仔细查看是否有某个id\Theta_{approx}[i]d\Theta[i]大不相同,如果有利用它去追踪一些求导的计算是否正确,调试,直到式子降到比如10^{-7}

在实施神经网络中经常要执行foreprop和backprop,然后可能发现这个梯度检验有一个较大的值,合理怀疑有bug存在,调试,调试……debug,debug……直到一段时间后得到一个很小的梯度检验值,就可以自信地说神经网络正确地执行了。

1.14 关于梯度检验实现的注记

(1)不要在训练中使用梯度检验,它只用于调试;

计算所有i值的d\Theta_{approx}[i]是一个非常漫长的过程,为了实施梯度下降,你必须使用backprop来计算d\Theta并使用backprop来计算导数,只有调试时才会计算d\Theta_{approx}[i],完成后,你会关闭梯度检验,梯度下降的每一个迭代过程都不会执行梯度检验,因为实在太慢了;

(2)如果算法的梯度检验失败,要检查所有项,检查每一项试图找出bug;

即如果d\Theta_{approx}d\Theta相去甚远,应该检查不同的i值看看是哪个导致了这样;比如你发现\Thetad\Theta里,某些层l中,db^{[l]}的值相差很大,但dw^{[l]}的各项却非常接近,记住\Theta的每项和w,b的每一项是一一对应的,这是你可能会发现在计算b^{[l]}的导数db^{[l]}时存在bug;同理,也有可能bug会出现在dw^{[l]}中,虽然未必能精确帮你定位bug的位置,但它确实可以帮你估计需要在哪些地方追踪bug;

(3)在实施梯度检验时,如果使用正则化一定要加注意正则项;

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

(4)梯度检验不能和dropout一起使用;

因为每次迭代过程中dropout都会随机消除隐层单元的不同子集,难以计算dropout在梯度下降上的成本函数;dropout可以作为优化成本函数的一个方法,但成本函数被定义为对所有指数极大的节点子集求和,如果使用dropout,在迭代过程中这些节点都有可能被随机消除,很难计算成本函数,仅仅是对成本函数做抽样;所以很难用梯度检验来双重检验dropout的计算;

因此一般在进行梯度检验时不使用dropout或要使用也要将keep-prob设为1以后再打开dropout,希望它实施正确;在梯度检验完成以后再打开dropout;

(5)(很少出现)在随机初始化过程中运行梯度检验,再训练网络,反复训练后再重新进行梯度检验;

现实中几乎不会出现这种情况,就是当w,b都接近于0时,可能在随机初始化过程后不久时间内,梯度下降的实施是正确的,但是在运行梯度下降时w,b变得更大,当w,b变得越来越大时梯度下降变得越来越不准确;

如果出现这种情况,你需要做的是考虑在随机初始化后立即进行梯度检验。随后,在训练过程中可以定期或不定期地再次进行梯度检验,以确保梯度下降的持续正确性。

  • 13
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值