梯度下降

解决下面的最优化问题:
$$
\theta^∗= \underset{ \theta }{\operatorname{arg\ min}} L(\theta) \tag1
$$

  • $L$ :lossfunction(损失函数)
  • $\theta$ :parameters(参数)

这里的parameters是复数,即 $\theta$ 指代一系列参数,比如 $w$ 和 $b$ 。

我们要找一组参数 $\theta$ ,让损失函数越小越好,这个问题可以用梯度下降法解决:

假设 $\theta$ 有里面有两个参数 $\theta_1, \theta_2$
随机选取初始值

$$
\theta^0 = \begin{bmatrix}
\theta_1^0 \
\theta_2^0
\end{bmatrix} \tag2
$$

然后分别计算初始点处,两个参数对 $L$ 的偏微分,然后 $\theta^0$ 减掉 $\eta$ 乘上偏微分的值,得到一组新的参数。同理反复进行这样的计算。黄色部分为简洁的写法,$\triangledown L(\theta)$ 即为梯度。

$\eta$ 叫做Learning rates(学习速率)

上图举例将梯度下降法的计算过程进行可视化。

特征缩放

比如有个函数:

$$y=b+w_1x_1+w_2x_2 \tag{12}$$
两个输入的分布的范围很不一样,建议把他们的范围缩放,使得不同输入的范围是一样的。

为什么要这样做?

上图左边是 $x_1$ 的scale比 $x_2$ 要小很多,所以当 $w_1$ 和 $w_2$ 做同样的变化时,$w_1$ 对 $y$ 的变化影响是比较小的,$x_2$ 对 $y$ 的变化影响是比较大的。

坐标系中是两个参数的error surface(现在考虑左边蓝色),因为 $w_1$ 对 $y$ 的变化影响比较小,所以 $w_1$ 对损失函数的影响比较小,$w_1$ 对损失函数有比较小的微分,所以 $w_1$ 方向上是比较平滑的。同理 $x_2$ 对 $y$ 的影响比较大,所以 $x_2$ 对损失函数的影响比较大,所以在 $x_2$ 方向有比较尖的峡谷。

上图右边是两个参数scaling比较接近,右边的绿色图就比较接近圆形。

对于左边的情况,上面讲过这种狭长的情形不过不用Adagrad的话是比较难处理的,两个方向上需要不同的学习率,同一组学习率会搞不定它。而右边情形更新参数就会变得比较容易。左边的梯度下降并不是向着最低点方向走的,而是顺着等高线切线法线方向走的。但绿色就可以向着圆心(最低点)走,这样做参数更新也是比较有效率。

怎么做缩放?

方法非常多,这里举例一种常见的做法:

上图每一列都是一个例子,里面都有一组特征。

对每一个维度 $i$(绿色框)都计算平均数,记做 $m_i$;还要计算标准差,记做 $\sigma _i$。

然后用第 $r$ 个例子中的第 $i$ 个输入,减掉平均数 $m_i$,然后除以标准差 $\sigma _i$,得到的结果是所有的维数都是 $0$,所有的方差都是 $1$

梯度下降的理论基础

问题

当用梯度下降解决问题:

$$\theta^∗= \underset{ \theta }{\operatorname{arg\ min}} L(\theta) \tag1$$

每次更新参数 $\theta$,都得到一个新的 $\theta$,它都使得损失函数更小。即:

$$L(\theta^0) >L(\theta^1)>L(\theta^2)>···\tag{13}$$

上述结论正确吗?

结论是不正确的。。。

数学理论

比如在 $\theta^0$ 处,可以在一个小范围的圆圈内找到损失函数细小的 $\theta^1$,不断的这样去寻找。

接下来就是如果在小圆圈内快速的找到最小值?

泰勒展开式

定义

若 $h(x)$ 在 $x=x_0$ 点的某个领域内有无限阶导数(即无限可微分,infinitely differentiable),那么在此领域内有:
$$
h(x) = \sum_{k=0}^{\infty }\frac{h^k(x_0)}{k!}(x-x_0)^k\=h(x_0)+{h}’(x_0)(x−x_0)+\frac{h’’(x_0)}{2!}(x−x_0)^2+⋯
$$

当 $x$ 很接近 $x_0$ 时,有 $h(x)≈h(x_0)+{h}’(x_0)(x−x_0)$
式14 就是函数 $h(x)$ 在 $x=x_0$ 点附近关于 $x$ 的幂函数展开式,也叫泰勒展开式。

举例:

图中3条蓝色线是把前3项作图,橙色线是 $sin(x)$。

多变量泰勒展开式

下面是两个变量的泰勒展开式

利用泰勒展开式简化

回到之前如何快速在圆圈内找到最小值。基于泰勒展开式,在 $(a,b)$ 点的红色圆圈范围内,可以将损失函数用泰勒展开式进行简化:

将问题进而简化为下图:

不考虑s的话,可以看出剩下的部分就是两个向量$(\triangle \theta_1,\triangle \theta_2)$ 和 $(u,v)$ 的内积,那怎样让它最小,就是和向量 $(u,v)$ 方向相反的向量

然后将u和v带入。


$$L(\theta)\approx s+u(\theta_1 - a)+v(\theta_2 - b) \tag{14}$$

发现最后的式子就是梯度下降的式子。但这里用这种方法找到这个式子有个前提,泰勒展开式给的损失函数的估算值是要足够精确的,而这需要红色的圈圈足够小(也就是学习率足够小)来保证。所以理论上每次更新参数都想要损失函数减小的话,即保证式1-2 成立的话,就需要学习率足够足够小才可以。

所以实际中,当更新参数的时候,如果学习率没有设好,是有可能式1-2是不成立的,所以导致做梯度下降的时候,损失函数没有越来越小。

式1-2只考虑了泰勒展开式的一次项,如果考虑到二次项(比如牛顿法),在实际中不是特别好,会涉及到二次微分等,多很多的运算,性价比不好。

梯度下降的限制

容易陷入局部极值
还有可能卡在不是极值,但微分值是0的地方
还有可能实际中只是当微分值小于某一个数值就停下来了,但这里只是比较平缓,并不是极值点

Vanishing / Exploding gradients

训练神经网络,尤其是深度神经所面临的一个问题就是梯度消失或梯度爆炸,也就是你训练神经网络的时候,导数或坡度有时会变得非常大,或者非常小,甚至于以指数方式变小,这加大了训练的难度。

这节课,你将会了解梯度消失或梯度爆炸的真正含义,以及如何更明智地选择随机初始化权重,从而避免这个问题。
假设你正在训练这样一个极深的神经网络,为了节约幻灯片上的空间,我画的神经网络每层只有两个隐藏单元,但它可能含有更多,但这个神经网络会有参数$W^{[1]}$,$W^{[2]}$,$W^{[3]}$ 等,直到$W^{[l]}$,为了简单起见,假设我们使用激活函数$g(z)=z$,也就是线性激活函数,我们忽略$b$,假设$b^{[l]}$=0,如果那样的话,输出$y=W^{[l]}W^{[L -1]}W^{[L - 2]}\ldots W^{[3]}W^{[2]}W^{[1]}x$,如果你想考验我的数学水平,$W^{[1]} x = z^{[1]}$,因为$b=0$,所以我想$z^{[1]} =W^{[1]} x$,$a^{[1]} = g(z^{[1]})$,因为我们使用了一个线性激活函数,它等于$z^{[1]}$,所以第一项$W^{[1]} x = a^{[1]}$,通过推理,你会得出$W^{[2]}W^{[1]}x =a^{[2]}$,因为$a^{[2]} = g(z^{[2]})$,还等于$g(W^{[2]}a^{[1]})$,可以用$W^{[1]}x$ 换$a^{[1]}$,所以这一项就等于$a^{[2]}$,这个就是$a^{[3]}$($W^{[3]}W^{[2]}W^{[1]}x$)。

所有这些矩阵数据传递的协议将给出$\hat y$ 不是$y$ 值。

假设每个权重矩阵$W^{[l]} = \begin{bmatrix} 1.5 & 0 \0 & 1.5 \\end{bmatrix}$,从技术上来讲,最后一项有不同维度,可能它就是余下的权重矩阵,$y= W^{[1]}\begin{bmatrix} 1.5 & 0 \ 0 & 1.5 \\end{bmatrix}^{(L -1)}x$,因为我们假设所有矩阵都等于它,它是1.5倍的单位矩阵,最后的计算结果就是$\hat{y}$,$\hat{y}$ 就是等于${1.5}^{(L-1)}x$。如果对于一个深度神经网络来说$L$ 较大,那么$\hat{y}$ 值也会非常大,实际上它呈指数级增长的,它增长的比率是${1.5}^{L}$,因此对于一个深度神经网络,$y$ 值将爆炸式增长。

相反的,如果权重是0.5,$W^{[l]} = \begin{bmatrix} 0.5& 0 \ 0 & 0.5 \ \end{bmatrix}$,它比1小,这项也就变成了${0.5}^{L}$,矩阵$y= W^{[1]}\begin{bmatrix} 0.5 & 0 \ 0 & 0.5 \\end{bmatrix}^{(L - 1)}x$,再次忽略$W^{[L]}$,因此每个矩阵都小于1,假设$x_{1}$ $x_{2}$ 是1,激活函数将变成$\frac{1}{2}$,$\frac{1}{2}$,$\frac{1}{4}$,$\frac{1}{4}$,$\frac{1}{8}$,$\frac{1}{8}$ ,直到最后一项变成$\frac{1}{2^{L}}$,所以作为自定义函数,激活函数的值将以指数级下降,它是与网络层数数量$L$ 关的函数,在深度网络中,激活函数以指数级递减。

我希望你得到的直观理解是,权重$W$ 比1略大一点,或者说只是比单位矩阵大一点,深度神经网络的激活函数将爆炸式增长,如果$W$ 1略小一点,可能是$\begin{bmatrix}0.9 & 0 \ 0 & 0.9 \ \end{bmatrix}$。

在深度神经网络中,激活函数将以指数级递减,虽然我只是讨论了激活函数以与$L$ 关的指数级数增长或下降,它也适用于与层数$L$ 关的导数或梯度函数,也是呈指数级增长或呈指数递减。

对于当前的神经网络,假设$L=150$,最近Microsoft对152层神经网络的研究取得了很大进展,在这样一个深度神经网络中,如果激活函数或梯度函数以与$L$ 关的指数增长或递减,它们的值将会变得极大或极小,从而导致训练难度上升,尤其是梯度指数小于$L$ ,梯度下降算法的步长会非常非常小,梯度下降算法将花费很长时间来学习。

总结一下,我们讲了深度神经网络是如何产生梯度消失或爆炸问题的,实际上,在很长一段时间内,它曾是训练深度神经网络的阻力,虽然有一个不能彻底解决此问题的解决方案,但是已在如何选择初始化权重问题上提供了很多帮助。

Weight Initialization for Deep NetworksVanishing / Exploding gradients

上节课,我们学习了深度神经网络如何产生梯度消失和梯度爆炸问题,最终针对该问题,我们想出了一个不完整的解决方案,虽然不能彻底解决问题,却很有用,有助于我们为神经网络更谨慎地选择随机初始化参数,为了更好地理解它,我们先举一个神经单元初始化地例子,然后再演变到整个深度网络。

我们来看看只有一个神经元的情况,然后才是深度网络。

单个神经元可能有4个输入特征,从$x_{1}$ $x_{4}$,经过$a=g(z)$ 理,最终得到$\hat{y}$,稍后讲深度网络时,这些输入表示为$a^{[l]}$,暂时我们用$x$ 示。

$z = w_{1}x_{1} + w_{2}x_{2} + \ldots +w_{n}x_{n}$,$b=0$,暂时忽略$b$,为了预防$z$ 过大或过小,你可以看到$n$ 大,你希望$w_{i}$ 小,因为$z$ $w_{i}x_{i}$ 和,如果你把很多此类项相加,希望每项值更小,最合理的方法就是设置$w_{i}=\frac{1}{n}$,$n$ 示神经元的输入特征数量,实际上,你要做的就是设置某层权重矩阵$w^{[l]} = np.random.randn( \text{shape})*\text{np.}\text{sqrt}(\frac{1}{n^{[l-1]}})$,$n^{[l - 1]}$ 是我喂给第$l$ 神经单元的数量(即第$l-1$ 神经元数量)。

结果,如果你是用的是Relu激活函数,而不是$\frac{1}{n}$,方差设置为$\frac{2}{n}$,效果会更好。你常常发现,初始化时,尤其是使用Relu激活函数时,$g^{[l]}(z) =Relu(z)$,它取决于你对随机变量的熟悉程度,这是高斯随机变量,然后乘以它的平方根,也就是引用这个方差$\frac{2}{n}$。这里,我用的是$n^{[l - 1]}$,因为本例中,逻辑回归的特征是不变的。但一般情况下$l$ 上的每个神经元都有$n^{[l - 1]}$ 输入。如果激活函数的输入特征被零均值和标准方差化,方差是1,$z$ 会调整到相似范围,这就没解决问题(梯度消失和爆炸问题)。但它确实降低了梯度消失和爆炸问题,因为它给权重矩阵$w$ 置了合理值,你也知道,它不能比1大很多,也不能比1小很多,所以梯度没有爆炸或消失过快。

我提到了其它变体函数,刚刚提到的函数是Relu激活函数,一篇由Herd等人撰写的论文曾介绍过。对于几个其它变体函数,如tanh激活函数,有篇论文提到,常量1比常量2的效率更高,对于tanh函数来说,它是$\sqrt{\frac{1}{n^{[l-1]}}}$,这里平方根的作用与这个公式作用相同($\text{np.}\text{sqrt}(\frac{1}{n^{[l-1]}})$),它适用于tanh激活函数,被称为Xavier初始化。Yoshua Bengio和他的同事还提出另一种方法,你可能在一些论文中看到过,它们使用的是公式$\sqrt{\frac{2}{n^{[l-1]} + n^{\left[l\right]}}}$。其它理论已对此证明,但如果你想用Relu激活函数,也就是最常用的激活函数,我会用这个公式$\text{np.}\text{sqrt}(\frac{2}{n^{[l-1]}})$,如果使用tanh函数,可以用公式$\sqrt{\frac{1}{n^{[l-1]}}}$,有些作者也会使用这个函数。

实际上,我认为所有这些公式只是给你一个起点,它们给出初始化权重矩阵的方差的默认值,如果你想添加方差,方差参数则是另一个你需要调整的超级参数,可以给公式$\text{np.}\text{sqrt}(\frac{2}{n^{[l-1]}})$ 加一个乘数参数,调优作为超级参数激增一份子的乘子参数。有时调优该超级参数效果一般,这并不是我想调优的首要超级参数,但我发现调优过程中产生的问题,虽然调优该参数能起到一定作用,但考虑到相比调优,其它超级参数的重要性,我通常把它的优先级放得比较低。

希望你现在对梯度消失或爆炸问题以及如何为权重初始化合理值已经有了一个直观认识,希望你设置的权重矩阵既不会增长过快,也不会太快下降到0,从而训练出一个权重或梯度不会增长或消失过快的深度网络。我们在训练深度网络时,这也是一个加快训练速度的技巧。

Numerical approximation of gradients

在实施backprop时,有一个测试叫做梯度检验,它的作用是确保backprop正确实施。因为有时候,你虽然写下了这些方程式,却不能100%确定,执行backprop的所有细节都是正确的。为了逐渐实现梯度检验,我们首先说说如何计算梯度的数值逼近,下节课,我们将讨论如何在backprop中执行梯度检验,以确保backprop正确实施。

我们先画出函数$f$,标记为$f\left( \theta \right)$,$f\left( \theta \right)=\theta^{3}$,先看一下$\theta$ 值,假设$\theta=1$,不增大$\theta$ 值,而是在$\theta$ 右侧,设置一个$\theta +\varepsilon$,在$\theta$ 侧,设置$\theta -\varepsilon$。因此$\theta=1$,$\theta +\varepsilon =1.01,\theta -\varepsilon =0.99$,,跟以前一样,$\varepsilon$ 值为0.01,看下这个小三角形,计算高和宽的比值,就是更准确的梯度预估,选择$f$ 数在$\theta -\varepsilon$ 的这个点,用这个较大三角形的高比上宽,技术上的原因我就不详细解释了,较大三角形的高宽比值更接近于$\theta$ 导数,把右上角的三角形下移,好像有了两个三角形,右上角有一个,左下角有一个,我们通过这个绿色大三角形同时考虑了这两个小三角形。所以我们得到的不是一个单边公差而是一个双边公差。

我们写一下数据算式,图中绿色三角形上边的点的值是$f( \theta +\varepsilon )$,下边的点是$f( \theta-\varepsilon)$,这个三角形的高度是$f( \theta +\varepsilon)-f(\theta -\varepsilon)$,这两个宽度都是ε,所以三角形的宽度是$2\varepsilon$,高宽比值为$\frac{f(\theta + \varepsilon ) - (\theta -\varepsilon)}{2\varepsilon}$,它的期望值接近$g( \theta)$,$f( \theta)=\theta^{3}$ 入参数值,$\frac {f\left( \theta + \varepsilon \right) - f(\theta -\varepsilon)}{2\varepsilon} = \frac{{(1.01)}^{3} - {(0.99)}^{3}}{2 \times0.01}$,大家可以暂停视频,用计算器算算结果,结果应该是3.0001,而前面一张幻灯片上面是,当$\theta =1$ ,$g( \theta)=3\theta^{2} =3$,所以这两个$g(\theta)$ 非常接近,逼近误差为0.0001,前一张幻灯片,我们只考虑了单边公差,即从$\theta $ $\theta +\varepsilon$ 间的误差,$g( \theta)$ 值为3.0301,逼近误差是0.03,不是0.0001,所以使用双边误差的方法更逼近导数,其结果接近于3,现在我们更加确信,$g( \theta)$ 能是$f$ 数的正确实现,在梯度检验和反向传播中使用该方法时,最终,它与运行两次单边公差的速度一样,实际上,我认为这种方法还是非常值得使用的,因为它的结果更准确。

这是一些你可能比较熟悉的微积分的理论,如果你不太明白我讲的这些理论也没关系,导数的官方定义是针对值很小的$\varepsilon$,导数的官方定义是$f^{‘}\theta) = \operatorname{}\frac{f( \theta + \varepsilon) -f(\theta -\varepsilon)}{2\varepsilon}$,如果你上过微积分课,应该学过无穷尽的定义,我就不在这里讲了。

对于一个非零的$\varepsilon$,它的逼近误差可以写成$O(\varepsilon^{2})$,ε值非常小,如果$\varepsilon=0.01$,$\varepsilon^{2}=0.0001$,大写符号$O$ 含义是指逼近误差其实是一些常量乘以$\varepsilon^{2}$,但它的确是很准确的逼近误差,所以大写$O$ 常量有时是1。然而,如果我们用另外一个公式逼近误差就是$O(\varepsilon)$,当$\varepsilon$ 于1时,实际上$\varepsilon$ $\varepsilon^{2}$ 很多,所以这个公式近似值远没有左边公式的准确,所以在执行梯度检验时,我们使用双边误差,即$\frac{f\left(\theta + \varepsilon \right) - f(\theta -\varepsilon)}{2\varepsilon}$,而不使用单边公差,因为它不够准确。

如果你不理解上面两条结论,所有公式都在这儿,不用担心,如果你对微积分和数值逼近有所了解,这些信息已经足够多了,重点是要记住,双边误差公式的结果更准确,下节课我们做梯度检验时就会用到这个方法。

今天我们讲了如何使用双边误差来判断别人给你的函数$g( \theta)$,是否正确实现了函数$f$ 偏导,现在我们可以使用这个方法来检验反向传播是否得以正确实施,如果不正确,它可能有bug需要你来解决。

Gradient checking

梯度检验帮我们节省了很多时间,也多次帮我发现backprop实施过程中的bug,接下来,我们看看如何利用它来调试或检验backprop的实施是否正确。

假设你的网络中含有下列参数,$W^{[1]}$ $b^{[1]}$……$W^{[l]}$ $b^{[l]}$,为了执行梯度检验,首先要做的就是,把所有参数转换成一个巨大的向量数据,你要做的就是把矩阵$W$ 换成一个向量,把所有$W$ 阵转换成向量之后,做连接运算,得到一个巨型向量$\theta$,该向量表示为参数$\theta$,代价函数$J$ 所有$W$ $b$ 函数,现在你得到了一个$\theta$ 代价函数$J$(即$J(\theta)$)。接着,你得到与$W$ $b$ 序相同的数据,你同样可以把$dW^{[1]}$ ${db}^{[1]}$……${dW}^{[l]}$ ${db}^{[l]}$ 换成一个新的向量,用它们来初始化大向量$d\theta$,它与$\theta$ 有相同维度。

同样的,把$dW^{[1]}$ 换成矩阵,$db^{[1]}$ 经是一个向量了,直到把${dW}^{[l]}$ 换成矩阵,这样所有的$dW$ 已经是矩阵,注意$dW^{[1]}$ $W^{[1]}$ 有相同维度,$db^{[1]}$ $b^{[1]}$ 有相同维度。经过相同的转换和连接运算操作之后,你可以把所有导数转换成一个大向量$d\theta$,它与$\theta$ 有相同维度,现在的问题是$d\theta$ 代价函数$J$ 梯度或坡度有什么关系?

这就是实施梯度检验的过程,英语里通常简称为“grad check”,首先,我们要清楚$J$ 超参数$\theta$ 一个函数,你也可以将J函数展开为$J(\theta_{1},\theta_{2},\theta_{3},\ldots\ldots)$,不论超级参数向量$\theta$ 维度是多少,为了实施梯度检验,你要做的就是循环执行,从而对每个$i$ 就是对每个$\theta$ 成元素计算$d\theta_{\text{approx}}[i]$ 值,我使用双边误差,也就是

$d\theta_{\text{approx}}\left[i \right] = \frac{J\left( \theta_{1},\theta_{2},\ldots\theta_{i} + \varepsilon,\ldots \right) - J\left( \theta_{1},\theta_{2},\ldots\theta_{i} - \varepsilon,\ldots \right)}{2\varepsilon}$

只对$\theta_{i}$ 加$\varepsilon$,其它项保持不变,因为我们使用的是双边误差,对另一边做同样的操作,只不过是减去$\varepsilon$,$\theta$ 它项全都保持不变。

从上节课中我们了解到这个值($d\theta_{\text{approx}}\left[i \right]$)应该逼近$d\theta\left[i \right]$=$\frac{\partial J}{\partial\theta_{i}}$,$d\theta\left[i \right]$ 代价函数的偏导数,然后你需要对i的每个值都执行这个运算,最后得到两个向量,得到$d\theta$ 逼近值$d\theta_{\text{approx}}$,它与$d\theta$ 有相同维度,它们两个与$\theta$ 有相同维度,你要做的就是验证这些向量是否彼此接近。

具体来说,如何定义两个向量是否真的接近彼此?我一般做下列运算,计算这两个向量的距离,$d\theta_{\text{approx}}\left[i \right] - d\theta[i]$ 欧几里得范数,注意这里(${||d\theta_{\text{approx}} -d\theta||}_{2}$)没有平方,它是误差平方之和,然后求平方根,得到欧式距离,然后用向量长度归一化,使用向量长度的欧几里得范数。分母只是用于预防这些向量太小或太大,分母使得这个方程式变成比率,我们实际执行这个方程式,$\varepsilon$ 能为$10^{-7}$,使用这个取值范围内的$\varepsilon$,如果你发现计算方程式得到的值为$10^{-7}$ 更小,这就很好,这就意味着导数逼近很有可能是正确的,它的值非常小。

如果它的值在$10^{-5}$ 围内,我就要小心了,也许这个值没问题,但我会再次检查这个向量的所有项,确保没有一项误差过大,可能这里有bug

如果左边这个方程式结果是$10^{-3}$,我就会担心是否存在bug,计算结果应该比$10^{- 3}$ 很多,如果比$10^{-3}$ 很多,我就会很担心,担心是否存在bug。这时应该仔细检查所有$\theta$ ,看是否有一个具体的$i$ ,使得$d\theta_{\text{approx}}\left[i \right]$ $ d\theta[i]$ 不相同,并用它来追踪一些求导计算是否正确,经过一些调试,最终结果会是这种非常小的值($10^{-7}$),那么,你的实施可能是正确的。

在实施神经网络时,我经常需要执行forepropbackprop,然后我可能发现这个梯度检验有一个相对较大的值,我会怀疑存在bug,然后开始调试,调试,调试,调试一段时间后,我得到一个很小的梯度检验值,现在我可以很自信的说,神经网络实施是正确的。

现在你已经了解了梯度检验的工作原理,它帮助我在神经网络实施中发现了很多bug,希望它对你也有所帮助。

Gradient Checking Implementation Notes

这节课,分享一些关于如何在神经网络实施梯度检验的实用技巧和注意事项。

首先,不要在训练中使用梯度检验,它只用于调试。我的意思是,计算所有$i$ 的$d\theta_{\text{approx}}\left[i\right]$ 一个非常漫长的计算过程,为了实施梯度下降,你必须使用$W$ $b$ backprop来计算$d\theta$,并使用backprop来计算导数,只要调试的时候,你才会计算它,来确认数值是否接近$d\theta$。完成后,你会关闭梯度检验,梯度检验的每一个迭代过程都不执行它,因为它太慢了。

第二点,如果算法的梯度检验失败,要检查所有项,检查每一项,并试着找出bug,也就是说,如果$d\theta_{\text{approx}}\left[i\right]$ dθ[i]的值相差很大,我们要做的就是查找不同的i值,看看是哪个导致$d\theta_{\text{approx}}\left[i\right]$ $d\theta\left[i\right]$ 值相差这么多。举个例子,如果你发现,相对某些层或某层的$\theta$ $d\theta$ 值相差很大,但是$\text{dw}^{[l]}$ 各项非常接近,注意$\theta$ 各项与$b$ $w$ 各项都是一一对应的,这时,你可能会发现,在计算参数$b$ 导数$db$ 过程中存在bug。反过来也是一样,如果你发现它们的值相差很大,$d\theta_{\text{approx}}\left[i\right]$ 值与$d\theta\left[i\right]$ 值相差很大,你会发现所有这些项目都来自于$dw$ 某层的$dw$,可能帮你定位bug的位置,虽然未必能够帮你准确定位bug的位置,但它可以帮助你估测需要在哪些地方追踪bug

第三点,在实施梯度检验时,如果使用正则化,请注意正则项。如果代价函数$J(\theta) = \frac{1}{m}\sum_{}^{}{L(\hat y^{(i)},y^{(i)})} + \frac{\lambda}{2m}\sum_{}^{}{||W^{[l]}||}^{2}$,这就是代价函数$J$ 定义,$d\theta$ 于与$\theta$ 关的$J$ 数的梯度,包括这个正则项,记住一定要包括这个正则项。

第四点,梯度检验不能与dropout同时使用,因为每次迭代过程中,dropout会随机消除隐藏层单元的不同子集,难以计算dropout在梯度下降上的代价函数$J$。因此dropout可作为优化代价函数$J$ 一种方法,但是代价函数J被定义为对所有指数极大的节点子集求和。而在任何迭代过程中,这些节点都有可能被消除,所以很难计算代价函数$J$。你只是对成本函数做抽样,用dropout,每次随机消除不同的子集,所以很难用梯度检验来双重检验dropout的计算,所以我一般不同时使用梯度检验和dropout。如果你想这样做,可以把dropout中的keepprob设置为1.0,然后打开dropout,并寄希望于dropout的实施是正确的,你还可以做点别的,比如修改节点丢失模式确定梯度检验是正确的。实际上,我一般不这么做,我建议关闭dropout,用梯度检验进行双重检查,在没有dropout的情况下,你的算法至少是正确的,然后打开dropout

最后一点,也是比较微妙的一点,现实中几乎不会出现这种情况。当$w$ $b$ 近0时,梯度下降的实施是正确的,在随机初始化过程中……,但是在运行梯度下降时,$w$ $b$ 得更大。可能只有在$w$ $b$ 近0时,backprop的实施才是正确的。但是当$W$ $b$ 大时,它会变得越来越不准确。你需要做一件事,我不经常这么做,就是在随机初始化过程中,运行梯度检验,然后再训练网络,$w$ $b$ 有一段时间远离0,如果随机初始化值比较小,反复训练网络之后,再重新运行梯度检验。

这就是梯度检验,恭喜大家,这是本周最后一课了。回顾这一周,我们讲了如何配置训练集,验证集和测试集,如何分析偏差和方差,如何处理高偏差或高方差以及高偏差和高方差并存的问题,如何在神经网络中应用不同形式的正则化,如$L2$ 则化和dropout,还有加快神经网络训练速度的技巧,最后是梯度检验。这一周我们学习了很多内容,你可以在本周编程作业中多多练习这些概念。祝你好运,期待下周再见。


BGD(Batch gradient descent)

Theory

假设$f\left(x\right)$ $R^{n}$ 具有一阶连续偏导数的函数。求解
$$
\begin{align*} \ & \min_{x \in R^{n}} f \left( x \right) \end{align*}
$$
无约束最优化问题。$f^{*}$ 示目标函数$f\left(x\right)$ 极小点。

由于$f\left(x\right)$ 有一阶连续偏导数,若第$k$ 迭代值为$x^{\left(k\right)}$,则可将$f\left(x\right)$ $x^{\left(k\right)}$ 近进行一阶泰勒展开
$$
\begin{align*} \ & f\left(x\right) = f\left(x^{\left(k\right)}\right) + g_{k}^{T} \left(x-x^{\left(k\right)}\right)\end{align*}
$$

其中,$g_{k}=g\left( x^{\left(k\right)} \right)=\nabla f \left( x^{\left(k\right)}\right)$ $f\left(x\right)$ $x^{\left(k\right)}$ 梯度。

第$k+1$ 迭代值
$$
\begin{align*} \ & x^{\left( k+1 \right)} \leftarrow x^{\left( k \right)} + \lambda_{k} p_{k} \end{align*}
$$
其中,$p_{k}$ 搜索方向,取负梯度方向$p_{k}= - \nabla f \left( x^{\left(k\right)} \right)$,$\lambda_{k}$ 步长,由一维搜索确定,即$\lambda_{k}$ 得
$$
\begin{align*} \ & f \left( x^{\left(k\right)}+\lambda_{k}p_{k} \right)=\min_{\lambda \geq 0} f \left( x^{\left(k\right)}+\lambda p_{k} \right) \end{align*}
$$
梯度下降算法:
输入:目标函数$f \left( x \right) $,梯度函数$g\left( x^{\left(k\right)} \right)=\nabla f \left( x^{\left(k\right)}\right)$,计算精度$\varepsilon$
输出:$f \left( x \right) $ 极小点$x^{*}$

  1. 取初值$x^{\left(0\right)} \in R^{n}$,置$k=0$

  2. 计算$f \left( x^{\left(k\right)}\right)$

  3. 计算梯度$g_{k}=g\left( x^{\left(k\right)} \right)$,当$| g_{k} | < \varepsilon $ ,停止迭代,令$x^{*}=x^{\left(k\right)}$;否则,令$p_{k}=-g\left(x^{\left(k\right)}\right)$,求$\lambda_{k}$,使

$$
\begin{align*} \ & f \left( x^{\left(k\right)}+\lambda_{k}p_{k} \right)=\min_{\lambda \geq 0} f \left( x^{\left(k\right)}+\lambda p_{k} \right) \end{align*}
$$

  1. 置$x^{\left(k+1\right)}= x^{\left(k\right)}+\lambda_{k}p_{k}$,计算$f \left( x^{\left(k+1\right)} \right)$
    当$| f \left( x^{\left(k+1\right)} \right) - f \left( x^{\left(k\right)} \right) | < \varepsilon $ $| x^{\left(k+1\right)} - x^{\left(k\right)} | < \varepsilon $ ,停止迭代,令$x^{*}=x^{k+1}$

  2. 否则,置$k=k+1$,转3.

Summary

  • BGD(批量梯度下降):更新每一参数都用所有样本更新。
  • 优点:每次迭代都需要把所有样本都送入,这样的好处是每次迭代都顾及了全部的样本,能保证做的是全局最优化。
  • 缺点:由于这种方法是在一次更新中,就对整个数据集计算梯度,所以计算起来非常慢,遇到很大量的数据集也会非常棘手,而且不能投入新数据实时更新模型。