其实我本来是不打算学这个算法的。虽然这个算法很基础,但是跟数学太紧密了,满屏的公式让我有种欲哭无泪的感觉。可是,每次看到深度学习一些新技术的时候,这个算法(或者其变体)总要跳出来干扰我的理解。就跟隔壁老王一样,你不摸清楚他的来龙去脉,总感觉心里不踏实。
我能怎么办?我也很绝望啊!在饱受其困扰之后,我决定一探究竟,自己实现以下该算法,顺便学习以下python以及NumPy。这代码一写,好家伙,我发现之前对epoch和mini_batch的理解都是有偏差的。果然还是要实践才能发现我只是错误的以为我以为我懂了。
[注:已经了解基础概念的,希望看证明或者详细介绍backpropagation的,不需要看本篇水文,直接跳到下一篇]
要讲Backpropagation,得从基础的神经网络说起(前一篇有讲到神经网络和深度学习等这些词是嘛意思)。神经网络有许多种形式,比较基础的一种称之为feedforward神经网络(另外还有recurrent神经网络,这里不涉及)。它是啥意思呢,盗一张图说明一下:
简单点说,就是前一层的输出,作为后一层的输入,后一层的输出(或者中间值)并不对前一层造成影响。
图中,每个圆圈,代表一个神经元。每一根箭头,代表一个权重(weight, w),它表示输出神经元与接收神经元之间联系的强弱。每个圆圈(除了第一层的)会有一个偏差(bias, b)对应,表示一个修正,是一个与前一层神经元无关的常数。
如果认为前一层的输出是x的话, 后一层跟前一层关联的输入就是
这玩意用矩阵的方式表示,就是wx(这里w和x都是矩阵, 对于图中第一层和第二层而言,w是
4*6
的矩阵,x是6*1
的矩阵,为啥我要说这么细,因为这样子对初学者来说才直观)。但这里我们还需要加入一个常量起到偏移作用, 所以输入就是z=wx+b
(注意,这里都是矩阵)。但是这样还没完,单纯这样的变化,并不能让神经元的表达能力逆天,所以发明这些的人,又给神经元再套了一个函数,称之为激活函数(Activation Function),它为神经元的输出加入非线性特性,增强了神经网络对训练数据的学习能力。所以,神经元的输出就变成了:
这里的a就是上文中的x。把这个公式不断地应用到下一层,就可以计算出整个神经网络的输出。
深度学习的过程,说白了,就是先随机
(当然并不是完全随机,里面藏着一些猫腻)生成每一层的w和b,然后用一些方法不断对它们进行修正。凭什么修正呢?数据!你得预先准备好一堆数据,每个数据的意思就是给定一个输入(x), 应该得到什么输出(d)。因为有了输入之后,一定可以根据上面的公式和已有的w和b(我们已经随机好了初始值), 算出一个最终输出(y),算的过程就是上面这个公式一层一层迭代过去。这个输出(y)跟真正的输出(d)不一样。学习过程就是不断调整w和b, 让d和y之间的差距尽量小。
这里又有一个地方要注意了,图中最后一层只有一个神经元,但是实际上最后一层可以有多个神经元的,因此y是一个矩阵。相应的d也是一个矩阵。那怎么定义差距呢?下面两个公式说明了一种定义方式:
这个看起来很直观吧,就跟几何上的“距离”类似。不过再次强调一下,这只是损失函数的一种形式(搞机器学习的学者们还发明了一堆奇形怪状的损失函数,脑洞之大,我只能说在下心服口服)。
本来只想写backpropagation的,因为网上很多推导不全,或者讲得不够直白。但没想到只是介绍最最基础的东西, 就这么多了, 那剩余的部分,待下回分解吧。