手写感知器的反向传播算法 Part1:梯度传播的理论推导:如何计算梯度?

前言:

感知器作为连接主义学派的最经典的最美妙的一个成果,也成为了万千想要进入人工智能领域的学生所一定绕不开的一个学习项目。很多学校的专业课都会要求选修的学生们手写完成感知器这一算法。用我们助教老师的话来说就是:这是你自己造的第一个轮子。虽然这个轮子可能没有那么圆,也不能让你的车跑的很快,同时现在python的torch包也提供了一个梯度计算工具,但是这毕竟是你自己做的轮子,你一定需要让他能跑起来。

但是这个轮子好造嘛?非常困难。这是因为以下这几个原因:

1.反向传播的算法的核心是数学。

反向传播是计算梯度再加上链式法则。同时这其中的计算梯度还比大家一般学的高等数学中的微积分要求更高些。因为在大多实际运用之中的问题之中,我们基本需要的是对于图片的识别,这也就意味着很多求导针对的不是一个数,而是一个矩阵。矩阵求导的解决方式只有两个:

(1)直接使用网上寻找的公式,比如"The matrix cookbook"中的已知结论

(2)使用代数的方式分别求导,看对于一个矩阵的每一个元素上梯度和求导的结果是什么样的。

所有的论坛上提供的反向传播算法的文章,即使是某些称自己是“手把手教导”的文章也没有做到说清楚为什么梯度是这样。这是作者自己在做的时候面对的问题,也是本文章想要填补的空缺,已提供给初学者一些学习的方式。

2.难以调试:

一般来说,对于感知机,project的要求一般是用感知机分类图片。输入感知机的图片的要求是必须是展开成一个列向量才能进行运算。那么如果一张28*28的图片我们就需要784维度的列向量进行学习。这么大的输入向量,即使只有一层,分成10个类别,那么我们也至少需要10+784*10的参数量。这么多参数量,一旦需要调试根本无法做到完全跟踪。这就导致了debug的难度提升。

3.有很多独立于算法之外的问题:

(1)自己手写的反向传播算法是不能使用pytorch的cuda加速的,所以实验成本极高。

(2)关于超参数的选择,关于网络结构的选择上不知道应该怎么做

(3)处于初学阶段的学生们可能会在很多问题上出现意想不到的问题。

有了上面的这些问题和难点,这个专栏的目的就是希望能够把一些作者自己完成这个任务时百思不得其解的问题和对应的一些解决方式记录下来。希望每一位能够看到这篇文章的孩子能够不用再一个个深夜看着DDL挥舞着镰刀走来,但是只能看着自己的代码手足无措。那么闲言少叙,开始第一部分,从一个纯数学的角度解析反向传播到底干了啥,怎么干的。

Part 1:省流版:

针对于那些只想要一些结论而不想要知道如何计算的读者,作者在这里提供一个省流部分,即直接给出求导的式子:

如图:给出了在第k层的时候状态M_k对于第k层的不同参数矩阵的求导结果。这些梯度的计算过程详细的作者会在后续的第二部分给出。

Part 2:详细的对于梯度的计算和推导:

Part2.1:准备工作:一个简单的两层感知机的模型结构和后续使用的符号简介:

(1)程序图示

作者后续的所有推导都是基于一个简单的单层的感知机,同时作者会先考虑一个回归问题,也就是输出是单个元素的感知机,这样可以先不用知道交叉熵函数的求导结果和方式,便于初学者掌握怎么求导,找到一些本质的规律。感知机的结构是1-3-5-1,每一个数字是每一层的神经元个数。需要说明的是,这里实际上来说神经元一共就只有中间两层,但是为了方便,作者将输入的一元“x”和最后运算结果y_hat也写进了网络结构之中,因为这样画出来的图片和这一组参数是一一对应的。图示如下:

这里的红笔划掉的部分是需要注意的:最后一层是不需要激活函数,否则会导致最后的计算结果一定被映射到[0,1]的范围内,在回归的语境下这就会出现预测受到限制的情况。这一定不是我们所想要的结果。

2.符号说明:

下文中的符号:

1.右上角的T代表着矩阵的转置

2.点乘表示一般的矩阵乘法

3.乘号对应的乘法表示的是列向量对应位置的数字相乘

基于以上的所有的说明,那么下面我们就可以正式开始计算梯度了。

Part2.2:在不考虑链式法则的条件下,对单一参数求导的结果等于多少?

我们先不考虑复杂的链式法则,梯度叠加等等需要更深刻理解的内容。让我们先考虑一下,对于简单的一层中,梯度是怎么计算的。

这其中由于是单层的,所以梯度求导要相对好算一些,这里作者就不手动求导了。虽然这里也涉及到一个矩阵求导:Mi对于wi的求导,但是由于只是A=BW的形式,所以计算起来会比较简单,这个部分留给读者完成。更重要的一点是,这里背结论是完全可行,而且做的到的。这是因为和一元求导十分相似,只要记住加上一个转置即可。

Part2.3:链式法则相关:两个不同的矩阵之间应该用什么样的乘法?

面对梯度的累乘的时候,一个相当自然的问题是:两个不同的矩阵应该使用什么乘法?我们应该用什么乘法将之前的Part2.2中的单个计算结果相乘得到结果?那么面对这个问题,作者首先先给出一个最朴实的做法:代数硬算: 

由上面的复杂计算可以看出,不仅第一个问题得到了回答,即不同的梯度之间的乘法使用的是点乘,而且也对于我们的第二个问题:不同梯度相乘的顺序是什么样给出了一些线索:

Part 2.4:链式法则相关:梯度相乘的顺序如何?

高等代数的一些知识告诉我们,矩阵乘法的顺序将会对于矩阵乘法的结果产生巨大的影响,矩阵的点乘没有可交换性。那么对于矩阵的求导,对于W的求导结果应该乘在之前梯度矩阵结果的什么位置呢?对于z的求导结果的矩阵又应该乘在什么位置?这个问题是需要搞清楚的。

关于这个部分,作者介绍第二种取巧的方式:使用矩阵的维度信息(即行列的值)来判断

结合这次的计算结果和上面的对于w2的计算可以猜测上面的紫色内容是正确的。由此我们就可以得到上面的式子。至此,我们已经得到了一整套计算规则。用这套规则,可以得到下面的部分:

Part2.5:总结:

上面的部分给出了计算的方式和乘法具体顺序,那么下面总结一下应该怎么实践到代码之中:

由此,整个回归部分的反向传播的部分就完成了。

Part3:对于分类任务,对应的推导

1.区别:

为什么这里作者要单独把内容挑出来呢?因为分类最后一层是一个softmax部分,所以这里最后一层需要求一个梯度。但是为什么又跟在前面的内容后面讲呢?这是因为如果把最后一层的函数做改变之后,读者可以发现跟之前的基本没有差别。

2.交叉熵损失函数怎么反向传播呢?

反向传播结果如上,基于这一求导结果之后使用和之前回归部分一样的操作即可进行反向传播。

Part4:总结:

作者在计算梯度反向传播的时候,先使用的方法是一个个拆分出来计算,但是实际上,读者在自己验证的时候,或者是后续计算其他函数进行反向传播的时候,可以尝试直接使用第二种方法,也就是使用维度信息辅助判断。这样可以减少绝大多数计算量。对于这一节,其实是整个实验的铺垫,用我们数学的话来讲更像是一个引理。但是也是绝对重要的。只有搞清楚了到底怎么推导的,以及真的靠自己推导出来了,才能保证在写代码的时候不至于出错。

在Part2.5中,作者其实展示的就是自己在做的时候将数学语言翻译成计算机语言的一个过程和暂时成果。如果想要看到关于计算机中如何实现这一块的部分,敬请关注本人的后续博文。后续作者将在本专栏中细细的讲清楚每一个部分,这样能够帮助那些对这块内容不太了解的孩子理解这最重要的内容。

都看到这里了,不点个赞支持一下本大三的大学牲嘛555555

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值