我们的人工神经网络的实现思路

神经网络是当今最强大的学习算法之一。

我们将开始学习一种在给定训练集下为神经网络拟合参数的学习算法。正如我们讨论大多数 学习算法一样,我们准备从拟合神经网络参数的代价函数开始讲起,我们将重点分析神经网络在分类问题中的应用。

Cost Function and Backpropagation

Cost Function

假如,我们有一个如左图所示的神经网络结构,然后假设我们有一个像这样的训练集:m个训练样本 x(i) y(i)

我们用大写字母L来表示 这个神经网络结构的总层数。所以,对于左边的网络结构,我们得到L等于4,然后我们准备用 sl表示第L层的单元的个数,也就是神经元的数量。这其中不包括偏置单元。比如说,我们的s1也就是输入层,是等于3的,s2在这个例子里等于5,然后输出层s4,在左边的这个例子中输出层有4个单元,因此s4=4。

另外,我们将会讨论两种分类问题,第一种是二元分类,在这里,y只能等于0或者1,因此对于这种情况,我们只需要一个输出单元,用于计算hx,它将会是一个实数,表达y=1的概率,跟我们在逻辑回归中学习的一样。

而对于多分类,它有多个输出单元,而根据我们之前的说明,多分类的输出实际上是一个向量,在对应的类别位置上填1,其他位置填0.因此,对于我们这个例子,他是一个四分类。一般来说,我们会使用K来表示面对的分类问题的目标分类数。

现在,我们来为神经网络定义代价函数。

我们在神经网络里使用的代价函数,其实是逻辑回归里使用的代价函数的更一般化形式。

对于逻辑回归而言,我们通常使代价函数J(Θ)最小化,也就是-1/m乘以后面这个代价项,然后再加上这个额外正则化项,这里是一个j从1到n的求和形式,因为我们并不需要把偏置项也正则化。

而对于一个神经网络来说,我们的代价函数是这个式子的一般化形式,这里可能不再是仅有一个逻辑回归输出单元,取而代之的是K个,所以这是我们的代价函数。

神经网络现在输出了一个K维的向量,这里K如果是1,也就退化成了我们熟悉的二分类问题。

对于输出,因为它是一个K维向量,对应我们的K个分类,所以我们采用这样一种标记法,hΘ(x)带下标i来表示第i个输出。 

我们的代价函数J(θ)将成为下面这样的形式-1/m乘以一个类似于我们在逻辑回归里所用的求和项,除了这里,我们求的是k从1到K的所有和,这个求和项主要是K个输出单元的求和,所以如果我有四个输出单元,也就是我的神经网络最后一层,有四个输出单元,那么这个求和项就是,求k等于从1到4的每一个的逻辑回归算法的代价函数。

最后,这里的第二项,这就是类似于我们在逻辑回归里所用的正则化项。

这个求和项看起来,确实非常复杂,它所做的就是把这些项全部相加,也就是对所有i j和l的θji的值都相加,正如我们在逻辑回归里一样。这里要除去那些对应于偏置的项。

所以,逻辑上来理解神经网络的代价函数其实也是很直观的,一共两项:

第一项表达了神经网络对数据的拟合能力;

第二项表达了神经网络的复杂度。

而进一步来看,因为有多分类的情况,相当于有多个逻辑回归模型,因此我们需要把每个模型的代价加在一起,而所谓的代价其实也很简单,它跟逻辑回归并无二致,因为我们的输出节点本身就是逻辑回归,它的输出是表达了预测样本是第i个类别的概率。 第二项虽然更进一步出现了三个求和符号,但也仅仅是为了把所有的模型参数Θ加在一起罢了。所以,如果我们甚至可以不看书或者笔记,直接能手写出这个公式,因为它的逻辑真的很直观。

这就是我们准备应用于神经网络的代价函数。下面,我们开始讲解一个算法来最优化这个代价函数。

Backpropagation Algorithm

我们将主要讨论后向传播算法(BP算法)

后向传播这个术语来源于英文back propagation的翻译,我们也可以称它为BP算法。

这个就是我们写好的代价函数。我们要做的就是,设法找到合适的参数Θ,使得J(Θ)取到最小值。至于怎么找到合适的Θ,我们当然还是借助我们的老朋友——梯度下降算法。因此,为了使用梯度下降算法或者其他某种高级优化算法,比如共轭梯度,我们需要做的就是,写好一个可以通过输入参数θ,然后计算J(θ)的代码,以及这些偏导数项的代码。

记住,这些神经网络里对应的参数,也就是Θ,上标(l),下标ij的参数,这些都是实数,所以这些都是我们需要计算的偏导数项。

为了计算代价函数J(Θ),我们就是用最上面这个公式。比较麻烦的我想大家也能预想,就是这个偏导项,所以,我们后面大部分时间想要做的都是,重点关注,如何计算这些偏导数项。

我知道,因为我们的J(Θ)很复杂,因为hΘ(x)这个函数非常复杂,它是好几层网络定义的一个非常复杂的函数,所以神经网络本身在思考求导这件事情上可能就有一些障碍,但是它是完全可以被理解的,而且它的编程几乎已经是整个机器学习课程中最复杂的了。

我们从只有一个训练样本的情况开始说起。

假设,我们整个训练集只包含一个训练样本,也就是一个实数对。因为只有一个样本,我就不写成x1,y1了,就直接写成(x,y)。 让我们粗看一遍,使用这个一个训练样本来计算的顺序。

首先我们应该使用前向传播方法来计算一下在给定输入的时候,是怎样计算得到输出的。 具体来说,这里的a(1)就是第一层的激活值,也就是输入层在的地方。然后我们来计算z(2),等于Θ(1)乘以a(1),然后a(2)就等于g(z(2)),其中g是一个S型激活函数。这就会计算出第一个隐藏层的激活值,也就是神经网络的第二层。另外,我们还需要增加相应的偏置项。

接下来,我们再用2次前向传播来计算出a(3)和最后的a(4),同样也就是假设函数hΘx的输出。注意,我们这里做的,其实都是已经向量化了,这里面无论是x,z还是a,实际上都是向量,而不是针对单个神经元的。

所以,前向传播很简单,输入乘以对应的边权,然后再调用一次sigmoid函数就可以了。

好了,前向传播已经说清楚了。那么接下来,为了计算导数项,我们将采用一种叫做反向传播的算法。

反向传播算法从直观上说,就是对每一个节点,我们计算这样一项—— δ下标j 上标l,它实际上代表了第l层的第j个节点的误差。

我们还记得a上标l 下标j表示的是第l层第j个单元的激活值。所以,这个δ项,在某种程度上就捕捉到了我们在这个神经节点的激活值的误差。

具体地说,我们用右边这个有四层的神经网络结构做例子,所以这里大写L等于4,对于每一个输出单元,我么们准备计算δ项。第四层的第j个单元的δ就等于这个单元的激活值减去训练样本里的真实值。

所以这一项可以同样写成hΘx下标j。所以δ这一项就是,假设输出和训练集y值之间的差,这里y下标j就是我们训练标签,注意,这里训练标签也应该转化成向量的形式,在对应类别的位置上设置为1。

顺便说一下,如果我们把δ,a和y这三个都看作向量,那么我们可以这样写向量化的实现,也就是δ(4)=a(4)-y。这里,每一个变量,也就是δ(4) a(4)和y都是一个向量,并且向量维数等于输出单元的数目。

所以,现在我们计算出了这个网络的误差项δ(4)

我们下一步就是计算网络中前面几层的误差项δ。这个就是计算δ(3)的公式,δ(3)等于θ(3)的转置乘以δ(4),然后点乘g’(z(3))。点乘就是两个向量的元素间对应相乘。

这里面的g’(z(3))其实是对激活函数g 在输入值为z(3)的时候 所求的 导数,如果我们掌握微积分的话,这个式子我们是可以自己推导出来的。不过这个推到确实有点复杂,所以我们只是从实际角度来看这是什么意思。我们计算这个g’这个导数项,其实是a(3)点乘(1-a(3)),这里的a(3)是激活向量, a(3)是第三层的激活向量。

接下来,应用一个相似的公式,来计算δ(2),同样这里可以利用一个相似的公式,这是在这里,是a(2)。这里我们并没有证明,但是如果我们懂微积分的话,证明是完全可以做到的,那么这个表达式从数学上讲,就等于激活函数g函数的偏导数,这里我用g‘来表示。

最后,就到这里结束了,这里没有δ(1)项,因为它对应输入层,它们是切切实实的训练集数据,所以不会存在误差,所以这个例子中,我们的δ项就只有第2层和第3层。

反向传播这个名字,源于我们从输出层开始计算δ项,然后我们返回到上一层,计算第三层的δ项,接着我们再往前一步来计算δ2,所以说,我们是类似于把输出层的误差,反向传播给了第三层,然后再传到第二层,这就是反向传播的意思。

最后,如果我们直接去推导关于参数Θ的偏导数,那么这个推到过程是出奇的麻烦,出奇的复杂,但是如果我们按照这里讲的几个步骤先计算出δ,就有可能简单直接地完成 复杂的数学证明,如果我们忽略标准化所产生的项,我们可以证明,我们要 求的偏导数项,恰好就等于激活函数和这些δ项。这里我们忽略了λ,或者说标准化项λ等于0。我们后面完善关于正则化的项。

所以,我们通过反向传播计算这些δ项,可以非常快速的计算出所有参数的偏导数项。

现在让我们把所有内容整合在一起。然后说说,如何实现反向传播算法以计算关于这些参数的偏导数。

当我们有一个非常大的训练样本集时,而不是像我们例子里这样的一个训练样本,我们是这样做的,假设我们有m个样本的训练集。

我们要做的第一件事就是,固定这些带下标ij的Δ,这其实是大写的希腊字母δ,我们之前写的那个是小写,这个三角形是大写的Δ。我们将他们统一设置成0。实际上,这些大写Δij会被用来计算偏导数项,也就是jΘ 上标l 下标ij 的偏导数。

所以,正如我们接下来看到的,这些Δ会被作为累加项,慢慢地增加以计算出这些偏导数。

接下来,我们将遍历我们的训练集,我们这样写,写成for i=1 to m,对于第i个循环而言,我们将取训练样本(xi, yi)。

我们要做的第一件事是,设定a(1) 也就是输入层的激活函数。设定它等于xi,xi是我们第i个训练样本的特征向量,接下来我们运用正向传播来计算第二层的激活值,然后是第三层、第四层。一直这样,到最后一层,L层。

接下来,我们将用 我们这个样本的输出值yi 来计算这个输出值所对应的误差项δL,所以δL就是假设输出减去目标输出。

接下来,我们将运用 反向传播算法 来计算δ(L-1), δ(L-2),一直这样直到δ(2),再强调一下,这里没有δ(1),因为我们不需要对输入层考虑误差项。

最后,我们将用这些大写的Δ来累计我们在前面写好的偏导数项。顺便说一下,如果我们再看下这个表达式,我们可以把它写成向量形式,具体地说,如果我们把Δ看作一个矩阵,ij代表矩阵中的位置。那么如果Δ(L)是一个矩阵,我们就可以写成Δ(l)等于Δ(l)加上小写的δ(l+1)乘以a(l)的转置,这就是用向量化的形式,实现了对所有i和j的自动更新值。最后,执行这个for循环体之后,我们跳出这个for循环,然后计算下面这些式子,我们按照如下公式计算大写D,我们对于j=0和j≠0分两种情况讨论。

在j=0的情况下,对应偏差项,所以当j=0的时候,这就是为什么我们没有写额外的标准化项。

最后,尽管严格的证明对于我们来说可能太复杂,不过现在我们可以说明的是,一旦计算出来了这些,这就正好是代价函数对每一个参数的偏导数,所以我们可以把它们用在梯度下降法或者其他一些更高级的优化算法上以寻求适当的参数或者边权来最小化整体代价。

这就是反向传播算法,以及我们如何计算神经网络代价函数的偏导数。这样我们就可以把算法的所有细节拼接在一起,这样当你想运用反向传播算法来计算神经网络的代价函数关于这些参数的偏导数的时候,你就会清晰地知道你要的是什么。

Backpropagation Intuition

前面我们介绍了反向传播算法,对许多人来说,第一次看到它的印象是,这是一个非常复杂的算法,并且这里有很多步骤,人们很难搞清楚是怎么弄出来的,看起来像是一个复杂的黑箱。如果你也是这么觉得,其实很正常。反向传播,很大程度上数学步骤比较复杂,比起线性回归和逻辑回归而言,并不是一个简单的算法。

不过,对于即将要做的编程作业,大家不用担心,我们会有数学的具体步骤,它将帮助我们一步一步完成。所以,我们将能够自主独立实现。在接下来,我们要做的是再一步一步介绍这个算法,让大家更有体会。希望这些机械的步骤能够使得大家更加信服,让你认识到这是一个非常合理的算法。

如果在这一段之后,你还是觉得这个算法非常复杂,其实也没有太大关系。

为了更好地理解反向传播算法,我们先来看看前向传播。

这个神经网络有两个输入层单元,当然不算偏置单元,两个隐层单元 ,有两层,还有一个输出单元。当然,我们都不算偏置单元。

我们稍微修改一下神经元的画法,我特意把每个神经元 画的更扁平一些,这样我们就可以在里面填充一些内容以便更容易地。

当进行前向传播算法地时候,我们可能有一些特别地例子,比如,xi,yi,我们把它输入到这个网络中,所以,xi1、xi2将是我们对输入层的设置。

当我们进入第一个隐层,我们会计算z(2)1和z(2)2,那么这些是我们要用的值,然后我们使用激活函数来计算,它以z值作为输入,产出激活值,这样我们就有了a(2)1, a(2)2。之后我们把这些值赋给z(3)1,然后使用sigmoid函数我们会得到a(3)1。类似地我们一直得到z(4)1,再次计算sigmoid,我们就有了a(4)1,这就是最终的结果。

而反向传播做的很类似,除了这些计算是从右到左。

首先来回顾一下神经网络的代价函数。这是只有一个输出单元时候的代价函数。如果有多个,那就需要增加关于类别的求和逻辑,如果只有一个,用这个函数就行。

我们关注单个样本的前向后向传播,比如我们这里考虑样本(xi, yi)。同时我们现在不考虑正则化,所以λ=0. 所以最后一项去掉。现在再来看这个求和公式,你会发现,这个代价项和我们的训练数据xi, yi相关。所以,单个样本的代价仅仅就是这样子。这个跟我们逻辑回归时很像,我们这里用了log,不过从直觉理解上来说,这其实跟线性回归时的平方误差没什么区别。这其实是我们用于求解整个Θ的最基础的东西。那么简单来说,我们的目标是平均意义上使得这个值最小,它的值衡量了模型对真实数据的拟合能力,那么我们要做的就是尽可能地降低这个cost。

我们来看看反向传播在做什么,特别是反向传播如何计算的Δij。

实际上我们可以将δ(l) j看成第l层第j个单元激活值的代价。

更加正式地说,δ项实际上是这个,它们是关于z(l) j的偏微分。

所以,具体而言,代价函数是关于标注y以及整个网络表达的hΘ(x)这个假设之间的一个函数。那么如果我们在神经网络内部,对z(l)j的值做了一点点修改,那么它会对整个网络的输出造成一些影响,而这会进一步影响代价函数。所以,这些δ项其实就是代价函数关于这些内部中间项的偏导数而已。

所以,它们能够度量我们修改神经网络内部权重的时候对整个代价函数会产生怎样的影响。

现在我们来仔细看看,反向传播究竟是怎么做的。

对于输出层,我们的δ(4)1,它等于y(i)-a(4)1。 所以这是真实的误差,对吧。他是真实值和神经网络预测出来的值之间的差,因此我们就可以这样计算δ(4)1。

下一步,我们将把这个值反向传播,然后不断向前传播以计算每一个隐层节点的δ。

所以反向传播算法大概就是干了这么件事情。

虽然这样解释了,大家仍然可能还是会觉得这是一团浆糊。所以如果确实如此,那么如果你知道求导的链式法则的话,我可以告诉你,其实整个反向传播做的事情就是在做链式法则而已。

实际上,我们的神经网络定义了一个非常复杂的函数hΘ(x),我们这张图里面的z和a实际上也都是函数,而且它们都是嵌套在hΘ(x)中的。因此,对于这个大的嵌套函数,在需要对某个参数Θ(l)ij求偏导的话,其实就是在不断地在整个反向链路上求所有的嵌套它的函数的偏导。而这个过程,如果你去真实地演算的话,那么它就是我们这里写出来的这样的规则。

所以,通过这段解释,希望大家对反向传播有了比较清晰地理解。它本质上并不难懂,但对于初次接触的人来说却是存在一定的理解困难。不过,只要大家多思考整个过程,甚至复习一下微积分中的链式法则,那么对理解整个反向传播几乎就没有任何障碍了。

 

Backpropagation in Practice

Implementation Note: Unrolling Parameters

Gradient Checking

前面我们讨论了如何进行前向传播以及反向传播,从而计算导数。但是,反向传播有很多细节,这些细节有点复杂,稍不留心就会导致一些bug,如果我们用梯度下降来计算,我们会发现,表面上它可以工作。但实际上,J虽然每次迭代都在下降,但是可能,仍然代码中蕴含很多bug。所以,表面上关于Θ的函数J在减小,但是可能最后得到的结果,实际上有很大的误差,这时候我们就会知道,可能存在这一些bug导致了这种不好的算法性能表现。

怎么处理?

其实我们只需要确定我们迭代过程中计算的梯度是没什么问题的就可以了。这个想法被称为梯度检验,英文叫Gradient Checking,它能够帮助我们减少这种错误的概率。它被很多老练的开发人员广泛地使用,因为在实践中它的确很容易帮助开发者降低因为复杂细节导致可能导致的bug。

当然,对于工作中的应用而言,我们通常会使用现成的函数库,而不需要自己从0开始编写所有细节。不过,亲手编写代码实现这些细节,非常有助于大家深刻理解算法本身,特别是你可以清楚地知道它究竟是如何实际工作的。如果你这样做了,你就掌握了本质,那么你在实际应用时就更加地自信,同时也能对可能出现的问题进行有的放矢地行动。总之,我们希望大家能够深刻地理解这些本质逻辑,而不仅仅停留在调用现成的工具包而已。

最后,我们要讲一下,这个梯度检验只是确保我们编写的反向传播算法是正确的而已,可以认为是测试代码,在正式开始运行学习算法工作前,一定要关掉我们的梯度检验,也就是我们讨论的这个数值计算方法。原因在于,这个计算过程,实际上代价很高,复杂度也很高,它并不是一个很好的计算导数的方法,相反,我们前面讨论的反向传播算法则是非常高效的。否则我们也就不会需要反向传播了。

所以,一旦检验证明我们的算法没有错误,就要把梯度检验关掉。所以,如果一定要使用数值方法来计算梯度,那么算法会运行的非常慢。

Random Initialization

现在让我们再来看看一个实现细节。那就是参数的初始化

在之前,不论是线性回归还是逻辑回归,当我们使用梯度下降算法时,我们需要设置初始值,而且我们都是使用的全零初始化。因为在原理上,通过初始值,即使它们都是0,我们也可以一步步地通过梯度下降走到海拔低地地方,也就是求最小值。

但是现在我们处理的是神经网络。比如我们这里的这个网络,如果全部参数都设置成0,那么看到蓝色的权值全都是0。然后红色的权值也是0,然后绿色的边,权值也是0,所以,a(2)1=a(2)2。然后,它们的输出,也就是紫色的连接到输出单元,它们也全是0,可以发现它们的误差值其实也一样,也就是δ(2)1=δ(2)2。所以,如果继续下去,我们可以发现它们满足下述情况:即所有的偏导数,它们都一样。

也就是说,我们会发现,更新的时候,通过计算梯度,更新的结果,这两个参数是一样的。所以,我们会得到非零的值,但这个值大家都是相等的,即使是通过梯度下降算法,结果也是相等。可能有一些非零的结果,比如,红色边权相等,绿色边权也相等,它们虽然都可以改变最终的输出,但是它们的影响完全一致。所以每一次更新,参数对应的结果都是完全一致的。

所以,神经网络实际上进入了很有意思的情况。即使我们的网络如果不仅仅有一个隐层,而是有非常多层,那么这种情况也将是同样的。所有隐层的结果都一样,这是非常冗余的,类似于我们本质上只使用一个特征来做逻辑回归,这就使得我们的神经网络的表现很差,无法达到更有意义的效果。

所以,我们不能把边权或者说参数直接初始化为0.

解决问题的方法就是:参数的随机初始化

具体来说,这个的问题叫做对称现象,所以随机初始化这种技术有时候也被称为打破对称,因为我们进行初始化的目的就是不希望有这种对称。

随机初始化,我们可以指定初始化在一定的范围内,比如[-ε,ε],这样我们的所有参数都随机的被初始化,且在一定的范围内。

那么我们就可以编写这样的代码来进行初始化。我们的rand函数会返回所被要求的维度,但重要的是,它能够返回0~1之间的一个随机数,然后我们将它乘以2倍的ε,这样,我们就得到了0~2ε之间的一个数值,我们再减掉一个ε,这样我们就得到[-ε,ε]之间的数值了。

不过,我们这里面说的ε和梯度检验里面的ε,以及之前编程课中说的判断是否收敛时用的ε都不是一回事。它们在各自的场景用其实均扮演了一种极小值的角色,因为在数学中极小值一般都是用ε这个字符,所以在这些不同的场景中均称它们时ε。这里我们为了避免混淆,我们可以在代码中将它的变量名称为init_epsilon。

 

Putting It Together

我们已经几乎介绍完了神经网络算法。

现在我们结合一下所有的内容,来做一个总体的回顾,看看这些零散的内容,相互之间有怎样的联系,以及神经网络学习算法的总体实现过程。

当我们在训练一个神经网络的时候,我们要做的第一件事,就是搭建网络的大体框架。网络框架的含义是,神经元之间的连接模式,我们可能会从以下几种结构中选择,第一种结构时包含三个输入单元,五个隐藏单元,以及四个输出单元。第二种结构是,三个输入单元作为输入层,两组五个隐藏单元作为隐藏层,四个输出单元的输出层。然后第三种,是3,5,5,5,其中每个隐藏层包含五个神经单元,然后是四个输出单元。这些可能就是我们在面临一个四分类问题时备选的三种网络结构。所以,网络框架的含义就是:有多少层,以及每层有多少个节点,对于更复杂的可能层与层之间都不是全连接的。

那么面对不同的网络结构,我们应该怎么选择呢?

首先,我们知道,我们已经定义了输入单元的数量,一旦我们确定了特征集x,对应的输入单元数目也就确定了,也就是等于特征xi的维度,输入单元数目将会由此确定,如果正在进行多类别的分类问题,那么输出层的单元数量将会由分类问题中所需要区分的类别个数决定,比如二分类我们只需要一个输出单元即可,但是对于一个数字识别应用而言,我们可能就有10个目标分类,而且我们还需要把这些分类重写成向量的形式。

而对于隐层的数量以及隐层内的神经元个数,在传统情况下,默认只使用一个隐层,也就是最左侧的那种,不过随着现在深度神经网络的发展,这个传统情况已经很少了。

因为隐层是对初始特征的高级加工,所以隐层其实神经元数量越多越好,隐层层数也是越多越好,这样可以更好地抽象高级特征。但是越多的隐层或者隐藏神经元,也意味着更大的计算量和更加复杂的优化算法。所以,对于一般的简单应用,我们使用一两个隐层几乎也就够了,如果需要更多,那么很可能就已经进入深度神经网络,也就是现在很热的深度学习的范畴了。

现在我们来具体看看用于训练神经网络的六个步骤。

首先,第一步是构建一个神经网络,然后随机初始化权值,通常我们把权值初始化为很小的值,接近于0,但不是0.

然后我们执行前向传播算法,也就是对于该神经网络的任意一个输入xi,计算出对应的hx值,也就是一个输出值y的向量,接下来我们通过代码计算出代价函数jΘ,然后我们执行反向传播算法,来计算出这些偏导数,或者叫偏微分项,也就是jΘ关于参数Θ的偏微分。

这样我们就能得到该神经网络中每一层中每一个单元对应的所有这些激活值a(l)以及δ项。

然后就是第五步了,我们要做的就是使用梯度检验来比较这些已经计算得到的偏导数项,比较使用反向传播算法计算出来的偏导数值和使用数值方法得到的估计值,以此来确保两种方法得到基本接近的两个值。通过梯度校验,我们能够确保我们的反向传播算法,得到的结构是正确的,但必须要说明的一点是,一旦我们确定我们的反向传播算法实现的没有问题,我们就要去掉梯度检查的代码,因为梯度检查的计算非常慢。

最后,我们就可以使用一个最优化算法,比如我们的老朋友——梯度下降算法来与反向传播算法相结合,这样我们就可以尽量降低代价函数,求得合理可用得参数Θ矩阵了。

到现在,我们已经知道了,如何去计算代价函数,我们知道了如何使用反向传播算法来计算偏导数,那么我们就可以使用某个最优化方法来最小化关于Θ得代价函数jΘ。另外,顺便提一下,对于神经网络代价函数jΘ,它是一个非凸函数,也就是说它并不是凸函数,因此理论上是能够停留在局部最小值得位置上的,实际上梯度下降算法和其他一些高级优化方法理论上也都收敛于局部最小值。

一般来讲,这个问题其实并不是什么要紧的事,尽管我们不能保证这些优化算法一定会得到全局最优值,但通常来讲,像梯度下降这类的算法,在最小化代价函数jΘ的过程中,还是表现的很不错的,通常能够得到一个很小的局部最小值,尽管这可能不一定是全局最优值。

我们可以再回顾最初讲解梯度下降时的图。希望能让大家对梯度下降法在神经网络中的应用产生一个更直观的理解。

这实际上有点类似我们早先时候解释梯度下降时的思路。我们有某个代价函数,并且在我们的神经网络中,有一系列参数值,这里我们只写下了两个参数值,当然实际上,在神经网络里,我们可以有很多的参数值Θ(1), Θ(2)等等。所有的这些都是矩阵,因此我们参数的维度就会很高了,由于绘图的限制,我们不能画出更高维度情况的图像,所以这里我们假设,这个神经网络中只有两个参数值,实际上应该有更多参数。

那么,代价函数jΘ度量的就是这个神经网络对训练数据的拟合情况。

所以,如果去某个参数,比如下面这点,在这个点上jΘ的值非常小,这一点的位置所对应的参数Θ的情况是,对于大部分的训练集数据,我们的假设函数的输出会非常接近于yi,那么如果是这样的话,那么我们的代价函数值就会很小。

而反过来,如果我们取上面,也就是这个点对应的值,那么对于大部分的训练集样本,该神经网络的输出,应该是远离yi的实际值的,也就是我们在训练集观测到的输出值。因此,像这样的点,右边的这个点对应的假设就是,神经网络的输出值在这个训练集上的预测值应该是远离yi的,因此这一点对应着对训练集合拟合的不好的情况。

因此,梯度下降算法的原理是,我们从某个随机的初始点开始,比如这一点,它会不停的往下下降。

那么反向传播算法的目的就是算出,梯度下降的方向,而梯度下降的过程就是沿着这个方向一点点的下降,一直到我们希望得到的点,在这里我们希望找到的就是局部最优点。

所以,当我们在执行反向传播算法并且使用梯度下降或者更高级的优化方法时,这幅图片很好地解释了基本的原理。也就是,试图找到某个最有的参数值,这个值使得我们神经网络的输出值与yi的实际值也就是训练集的标注尽可能的接近。

希望这几段的内容能让大家对零散的神经网络知识如何有机的结合起来 能有一个更加直观的认识。

但是,即便如此,大家可能还是觉得有很多的细节,不能完全明白,为什么这么做,或者说这些如何联系在一起的。没关系,因为神经网络和反向传播算法本身就是非常复杂的算法。

不过没关系,它背后的本质逻辑其实并不复杂,只要多思考几个轮回就基本可以掌握。而更进一步,如果自行编程实现了它,那么相信大家对它的理解就已经算是非常深了。

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值