推荐《Python神经网络编程》这本入门书。豆瓣评分9.2。
如果你可以进行加、减、乘、除运算,那么你就可以制作自己的神经网络。我们使用的最困难运算是梯度演算(gradient calculus),但是,我们会对这一概念加以说明,使尽可能多的读者能够理解这个概念。
在这本书中,我们将扬帆起航,制作神经网络,识别手写数字。
我们将从非常简单的预测神经元开始,然后逐步改进它们,直到达到它们的极限。顺着这条路,我们将做一些短暂的停留,学习一些数学概念。我们需要这些数学概念来理解神经网络如何学习和预测问题的解。
我们将浏览一些数学思想,如函数、简单的线性分类器、迭代细化、矩阵乘法、梯度演算、通过梯度下降进行优化,甚至是几何旋转。但是,所有这些数学概念将会以一种非常优雅清晰的方式进行解释,并且除了简单的中学数学知识以外,读者完全不需要任何前提知识或专业技术。
一旦我们成功制作了第一个神经网络,我们将带着这种思想,在各个方面使用这种思想。例如,我们无需诉诸额外的训练数据,就可以使用图像处理来改善机器学习。我们将一窥神经网络的思想,看看它是否揭示了任何深刻的见解——很多书籍并没有向你展示神经网络的工作机制。
当我们循序渐进制作神经网络时,我们还将学习一种非常简单、有用和流行的编程语言Python。同样,你不需要有任何先前的编程经验。
本书揭示神经网络背后的概念,并介绍如何通过Python实现神经网络。全书分为3章和两个附录。第1章介绍了神经网络中所用到的数学思想。第2章介绍使用Python实现神经网络,识别手写数字,并测试神经网络的性能。第3章带领读者进一步了解简单的神经网络,观察已受训练的神经网络内部,尝试进一步改善神经网络的性能,并加深对相关知识的理解。附录分别介绍了所需的微积分知识和树莓派知识。
本书适合想要从事神经网络研究和探索的读者学习参考,也适合对人工智能、机器学习和深度学习等相关领域感兴趣的读者阅读。
《Python神经网络编程》数学知识:微积分简介
首先,让我们从一个非常简单的场景开始。
想象一下,汽车以30英里每小时的速度匀速前进。不快也不慢,就是时速30英里。
下表中显示了汽车在各个时间点的速度,每半分钟测量一次。
时间/分 | 速度(英里/小时) |
---|---|
0 | 30 |
0.5 | 30 |
1.0 | 30 |
1.5 | 30 |
2.0 | 30 |
2.5 | 30 |
3.0 | 30 |
下图可视化了在这几个时间点的速度。
可以看到,速度并不随时间而改变,因此这是一条水平直线。这条直线不向上倾斜(加速),也不向下倾斜(减速),汽车就保持在30英里每小时。
速度的数学表达式,我们称之为s:
现在,如果有人询问速度如何随时间变化,我们会说速度不随时间变化。变化率为0。换句话说,速度不取决于时间,相关性为0。
我们刚刚就完成了微积分计算!
微积分探讨的是,建立关系以表示一种事物如何随着其他事物的变化而变化。此处,我们思考的是速度如何随时间变化而变化。
我们有一个数学方式来表达这种关系。
这些是什么符号?可以将这个符号的意思视为“当时间改变时,速度如何变化”或“s如何与t相关”。
因此,这个表达式说的是速度不随时间变化,这是数学家使用的一种简洁的方式。或者换一种说法,随着时间的推移,速度不受影响。速度对时间的依赖性为0。这就是表达式中0所表示的意思。它们完全是不相关的。
事实上,当你再次观察速度的表达式s=30时,你可以发现这种不相关性。在这个表示式中,一点都没提到时间。也就是说,在这个表达式中,没有隐藏的时间t。因此,我们不需要做任何复杂的微积分来计算出∂s / ∂t = 0,只要简单地观察表达式就可以得出这个结论。数学家称之为“观察法”。
如∂s / ∂t的表达式,解释了变化率,称为导数。就我们的目的而言,我们不需要知道这点,然而你可能会在其他地方遇到这个词。
现在,如果我们踩下油门,让我们看看会发生什么。这真是太令人兴奋了!
试想一下,相同的汽车以30英里每小时的速度前进。我们轻轻踩下油门,车子加速。我们一直踩住油门,观察仪表盘上的标度,每30秒记录一次速度。
在30秒后,汽车以35英里每小时的速度前进。在1分钟后,汽车以40英里每小时的速度前进。在90秒后,汽车以45英里每小时的速度前进。在2分钟后,汽车的速度达到了50英里每小时。汽车的加速度为每分10英里每小时。
下表总结了相同的信息。
时间/分 | 速度(英里/小时) |
---|---|
0.0 | 30 |
0.5 | 35 |
1.0 | 40 |
1.5 | 45 |
2.0 | 50 |
2.5 | 55 |
3.0 | 60 |
让我们再次将其可视化。
你可以看到,汽车的速度以恒定速率从30英里每小时一路攀升到60英里每小时。由于每半分的速度增量是相同的,因此速度随时间变化的图像是一条直线,可以看到这一速率。
什么是速度的表达式?在时间0,速度为30。在此之后,速度每分钟增加10英里每小时。因此,速度的表示式如下所示。
或者使用符号表示如下:
在这里,可以看到常数30。而且还可以看到(10×t),这意味着每分钟增加10英里每小时。你很快就会意识到,10是我们所绘制直线的斜率。请记住,直线的一般形式为y = ax + b,其中a是斜率或梯度。
那么,速度随时间变化的表达式是什么样的呢?嗯,我们已经讨论到这个问题了,速度每分钟增加10英里每小时。
这个表达式说的是,由于∂s / ∂t不为0,速度和时间之间的确存在着相关性。
请记住,直线y = ax + b的斜率是a,我们通过“观察法”,可以知道s = 30 +10t的斜率为10。
做得好!我们已经讨论了微积分的许多基础知识,这些知识一点也不难。现在,让我们加大油门!
想象一下,我从静止起动了汽车,用力踩下油门,不松开油门。由于我们一开始没有移动,因此起动速度为0。
试想一下,我们非常用力地踩下油门,汽车不以恒定的速率增加速度。相反,汽车更快地提高速度。这意味着,它每分钟不是提高10英里每小时,而是随着踩下油门时间增加,汽车加速度本身也增加了。
对于这个例子,想象一下,我们每分钟测量一次速度,如下表所列。
时间/分 | 速度(英里/小时) |
---|---|
0 | 0 |
1 | 1 |
2 | 4 |
3 | 9 |
4 | 16 |
5 | 25 |
6 | 36 |
7 | 49 |
8 | 64 |
如果你仔细观察可以发现,我选择让速度为时间(分钟)的平方。即,在时间为2分钟时,速度为22 = 4;在时间为3分钟时,速度为32=9;在时间为4分钟时,速度为42 = 16;依此类推。
现在,这个表达式也很容易写出来了。
虽然我知道示例的汽车速度是有意为之的,但是这非常好地阐述我们如何进行微积分计算。
让我们将这个表达式可视化,这样,我们就可以感觉到,速度如何随时间的变化而变化。
可以看到速度的变化越来越快。当前,这幅图已经不是一条直线了。可以想象一下,速度爆炸式地快速增加到非常大的数字。在20分钟时,速度将达到400英里每小时;在100分钟时,速度将达到10000英里每小时!
一个有趣的问题是——相对于时间,速度的变化率是什么样的?也就是说,速度如何随时间的变化而变化?
这与在特定时间点实际速度是多少的问题不一样。我们已经有了表达式s = t2,因此已经知道这个值了。
我们要问的是——在任何时间点,速度的变化率是多少?在这个示例中,这句话的意思是图线向何处弯曲?
如果回想一下前面的两个例子,可以发现,变化率是速度关于时间的曲线的斜率。当汽车以恒定30英里每小时的速度前进时,速度并未改变,因此变化率为0。当汽车稳步加快时,速度的变化率是每分钟10英里每小时。在任何时间点,每分钟10英里每小时都是正确的。在时间2分钟的时候,变化率为每分钟10英里每小时。在4分钟时,在100分钟时,这都是正确的。
在曲线图中,我们可以应用相同的思路吗?当然可以——但是,此处,让我们慢慢理解这一点。
让我们仔细看看,在时间等于3分钟时,发生了什么。
在3分钟时,速度为9英里每小时。我们知道,在3分钟后速度将变得更快。让我们将这与6分钟时发生的事情相比。在第6分钟,速度为36英里每小时。在6分钟后,速度会变得更快。
但是,我们也知道,在6分钟后的那一瞬间,速度增加的速率比3分钟后的那一瞬间大。这是发生在3分钟和6分钟处事情的真正区别。
让我们将这种对比可视化,如下图所示。
可以看到,在6分钟处的斜率比在3分钟处的斜率要大。斜率就是我们希望得到的变化率。这是一个重要的体会,让我们再说一遍。在曲线任何点处的变化率,就是曲线在该点的斜率。
但是,如何测量曲线的斜率呢?对于直线而言,测量斜率非常容易,对于曲线而言,可以画出称为切线的直线,切线要尽可能与曲线中某一点处的斜率相同,这样就可以根据切线的斜率估计出曲线在这一点的斜率。事实上,在其他测量方法出现之前,这就是人们测量曲线斜率的方式。
为了让读者体会一下这种做法,我们就试试这个粗略的方法。下图显示了速度曲线图,在6分钟时,我们得到了与速度曲线仅有一个交点的切线。
从中学数学中我们知道,要计算出斜率或梯度,需要将斜面的高度除以宽度。在上图中,高度(速度)为Δs,宽度(时间)为Δt。符号Δ称为“增量”,也就是一个微小的变化。因此Δt就是t的一个小变化。
斜率为Δs/Δt。对于斜面,可以选择任何尺寸的三角形,用尺子测量高度和宽度。根据我的测量结果,恰好得到了一个Δs为9.6、Δt为0.8的三角形。因此,所得的斜率如下:
我们得到了一个重要的结果!在6分钟时,速度变化率为每分钟12.0英里每小时。
你应该明白,靠着一把尺子,尽其所能,甚至尝试用手画切线,结果也不会特别准确。因此,让我们把事情变得稍微复杂一点。
仔细观察下图,这幅图中有一条新的标记直线。这条直线与曲线相交于两点上,因此不是一条切线。但是,这条直线看起来以某种方式围绕着时间点3分钟这个中心。
事实上,这条直线与时间点3分钟有联系。我们所选择的时间点是,我们所感兴趣的时间点t = 3分钟的上下几分。此处,我们选择了在t = 3分钟时间点的上下2分钟处,也就是,t = 1分钟和t = 5分钟。
使用数学符号表示,我们可以说Δx为2分钟。我们选择的时间点为 x-Δx和x+Δx。请记住,符号Δ只是意味着一个“小小的改变”,因此Δx是在x坐标上的小小改变。
为什么这样做呢?读者很快就会明白了,我们先吊吊读者的胃口。
如果观察在时间点x-Δx 和x+Δx处的速度,在这两点之间画一条直线,那么就会得到一条直线,其斜率大致与中间点x切线的斜率相同。再次观察上图,看看那条直线。当然,这条直线与在x处切线的真正斜率不是完全相同,但是我们会修正这一点的。
让我们计算出这条直线的梯度(斜率)。与之前使用的方法一样,我们将斜面的高度除以宽度得到梯度。下图更清晰显示了斜面的高度和宽度。
高度是在x-Δx和x +Δx两点处速度的差,也即是在1分钟和5分钟时两个速度之间的差。我们知道,在这两点处,速度分别为12 = 1和52 = 25英里每小时,因此速度的差值为24。宽度非常容易计算,就是x-Δx 和 x+Δx之间的距离,也就是1和5之间的距离,即4。因此,我们得到:
直线的梯度与在t = 3分处切线的梯度近似,为每分钟6英里每小时。
让我们暂停一下,回顾一下已经完成的事情。首先,我们试图使用手绘切线,计算出曲线的斜率。这种方法永远不会准确,由于我们是人类,会厌倦、无聊和犯错误,因此不能一再使用这种方法。下一种方法不需要手绘切线,而是要按照某种方法创建一条不同的直线,这条直线的斜率与正确的斜率大致相同。第二种方法可以使用计算机自动完成,由于不需要人的工作,因而可以多次进行,并且速度非常快。
这已经很不错了,但是还是不够好!
第二种方法只得到一个近似值。如何改进这个值,使其变得准确呢?我们的目标是按照精确数学的方式,计算出事情如何改变,得到梯度值。
这是发生神奇事情的地方!数学家已经发展了一种非常轻巧犀利的工具,并且从这个工具中获得了许多乐趣。
如果将宽度变小,会发生什么情况?用另一种方式来表达,也就是,如果让Δx变小,会发生什么情况?下图详细说明了当Δx逐渐变小时,所得到的若干逼近线或坡度线。
我们已经绘制出了Δx = 2.0、Δx = 1.0、Δx = 0.5 和Δx = 0.1的直线。你可以看到,直线越来越接近我们所感兴趣的点,3分钟处的点。你可以想象一下,当我们不断减小Δx的值,直线将越来越接近3分钟处的真正切线。
当Δx变得无限小时,直线无限接近真实的切线。这真是太酷啦!
通过让偏差变得越来越小,改进近似值,逼近解,这种想法简直太强大了。数学家曲径通幽,求解出难以正面求解的问题。这有点像从侧面悄悄逼近,而不是从正面进攻。
我们前面说过,微积分探讨的是以精确的数学方式,理解事物如何变化。让我们来看看,我们是否能够将这种逐步缩小Δx的想法应用到定义这些事物的数学表达式中——如汽车速度曲线。
我们知道速度是时间的函数,即s = t2。我们希望知道作为时间的函数,速度是如何变化的。当绘制关于t的曲线时,我们已经看到这是s的斜率。
变化率∂s / ∂t等于我们所构造直线的高度除以宽度,但是,其中Δx无限小。
高度是什么?正如我们先前看到的,这是(t + Δx)2-(t -Δx)2。也就是根据公式s = t2,其中t为所感兴趣的点上下偏移Δx,算出对应的s,相减得到。
宽度是什么?正如我们先前所看到的,简单说来,这只是(t + Δx)和(t - Δx)之间的距离,也就是2Δx。
我们就快到达目标了,
让我们展开并简化表达式
实际上,我们很幸运,代数本身已经简化得非常灵巧了。
我们已经到达目标了!在数学上,精确的变化率为∂s / ∂t = 2t。这意味着,对于任何时间t,我们知道速度的变化率为∂s / ∂t = 2t。
在t = 3分钟处,我们有∂s / ∂t = 2t = 6。在使用近似方法之前,我们事实上确认过这个值。在t = 6分钟处,∂s / ∂t = 2t = 12,这非常准确地符合了我们之前发现的值。
在t= 100分钟处,这个值是多少呢?∂s / ∂t = 2t = 每分钟200英里每小时。这意味着,在100分钟后,汽车的加速度达到每分钟200英里每小时。
让我们花点时间,思考一下,刚才做的事情有多么的重要,多么的酷炫!我们得到了一个数学表达式,这个表达式允许我们精确地知道,在任何一个时间点汽车速度的变化率。根据先前的讨论,我们可以发现变化率确实随着时间而定。
我们很幸运,代数简化得很精巧,但是简单的s = t2并没有给我们一个尝试的机会,让我们能够有目的地缩小Δx。因此,试一试另一个示例,在这个示例中,汽车的速度有点复杂。
现在,高度是什么呢?这是在t+Δx处和t-Δx处所计算得到的s的差。
即,高度为(t +Δx)2+ 2(t +Δx)-(t -Δx)2 - 2(t -Δx)。
宽度是什么?这就是(t +Δx)和(t -Δx)之间的距离,依然为2Δx。
展开并简化表达式
这是一个重要的结果!可悲的是,代数再次将其简化得有一点太过容易了。这里有一个稍后将谈到的模式,因此,我们不费吹灰之力就得到了结果。
让我们尝试另一个示例,这个示例不会太过复杂。我们将汽车的速度设置为时间的三次方。
展开并简化表达式
现在,事情变得更有趣了!我们得到了一个结果,这个结果中包含了Δx,而在之前,表达式中的Δx都互相抵消了。
那么,请记住,只有Δx越来越小,变得无限小时,梯度值才正确。
这是最酷炫的地方!当Δx越来越小的时候,在表达式∂s / ∂t = 3t2 + Δx2 中的Δx会发生什么事情呢?它消失了!如果这听起来令你吃惊,那么请将Δx想象为非常小非常小的一个值。你可以尝试想到一个较小的一个值,然后是一个更小的值……你可以一直这样找下去,使得Δx越来越接近于0。因此,就让我们直接将它当为0,避免这所有的麻烦。
这就得到了一直在寻找的数学上的精确答案:
这是一个奇妙的结果,这次,我们使用强大的数学工具来进行微积分,并且这一点都不困难。
我们使用deltas值(如Δx),将deltas值越变越小时,观察发生的事情,计算导数,而乐在其中的是我们可以直接计算导数而无需进行所有这些工作。
看看计算得到的导数,是否能够观察到任何模式:
可以看到,t的函数的导数,除了t的幂减少了1,其余是相同的。因此t4变为了t3,t7成为t6,以此类推。这相当容易!t就是t1,因此,t的导数为t0即为1。
由于常数,如3,4,5(常数变量,我们可能称之为a,b,c),都没有变化率,因此常数就简单地消失了。这就是称它们为常量的原因。
但是,等等,请注意,t2成为2t而不是t,t3成为3t2不是t2。这里还有一步,在幂指数减小之前,幂指数被用作了乘数。因此,在2t5的幂指数减1之前,幂指数5要作为乘数,从而5 × 2t4 = 10t4。
下面总结了在进行微积分运算时,使用的这种幂规则。
让我们在更多的例子中尝试,实践这一新技术。
因此,这条规则允许进行大量的微分运算,对于大多数用途而言,这就是我们所需的微分。这条规则只适用于多项式,也就是使用各种变量的幂次方组成的表达式,如y = ax3+ bx2 + cx + d,但是不包括sinx或cosx这样的式子。由于使用幂规则进行微积分运算有着大量的用途,因此这不算是一个很大的缺陷。
然而,对于神经网络而言,我们确实需要一个额外的工具,我们将在下一节中讨论这个工具。
想象一下,一个函数
其中y本身也是函数
如果我们愿意,我们也可以写为f =(x 3 + x)2。
f如何随着y的改变而改变?也就是,∂f / ∂y是什么?只要应用刚刚得到的幂规则,乘上幂指数,幂指数减1,那么这个计算就很容易了,可以得到∂f / ∂y= 2y。
还有一个有趣的问题——f如何随着x的变化而变化呢?可以展开表达式f =(x3 + x)2,然后应用相同的规则。不能不加思索地硬套规则,将(x3 + x)2变为2(x3 + x)。
如果像以前一样,采用逐渐减小的delta方式,通过漫长艰难的道路,解出了这个表达式,我们会意外发现这里存在着另一组模式。让我们直接跳到答案吧。
这个模式是这样的:
这是一个非常重要的结果,我们称之为链式法则。
可以看到,这个模式允许我们逐层计算出导数,就像剥洋葱,将复合的层一层一层解开。为了计算∂f / ∂x,我们可能发现,先计算出∂f / ∂y,然后再计算出∂y / ∂x,这会比较容易一些。如果这些都比较容易,那么我们就可以对看起来不可能的表达式进行微积分运算。链式法则允许我们打破问题,将问题分割为较小、较容易的问题。
再次观察这个示例,应用链式法则:
现在,计算得到了比较简单的项。第一项是(∂f / ∂y)= 2y,第二项是(∂y / ∂x)= 3x2 + 1。然后,使用链式法则,将这些项结合起来,我们得到:
我们知道,y = x3 + x,因此,得到了只有x的表达式:
这真是见证神奇的一刻!
你可能会质疑为什么这样做,为什么不能首先根据x展开f,然后应用简单的幂规则,对所得到的多项式进行微积分运算。当然能这样做,但是如果这样的话,就不能详细说明链式法则,而链式法则可以解决许多比较困难的问题。
让我们来看看最后一个例子,这个示例演示了如何处理多个独立变量。
如果得到一个函数
其中x、y和z是彼此无关的变量。我们说的无关是什么意思呢?我们的意思是,x、y和z可以为任意值,并且无需关心其他变量的取值——它们彼此之间不互相影响。这不同于前一个示例y=x3 + x,在这种情况下,y与x相关。
∂f / ∂x是多少?让我们看看这个长表达式的每项。第一项是2xy,因此导数为2y。为什么这么简单呢?由于y与x无关,因此非常简单。当我们说∂f / ∂x,我们说的是,当x变化时,f如何变化。如果y与x无关,那么可以将其视为常数。即y也可能是如2、3、10的另一个数。
让我们继续,下一项是3x2z。可以应用幂规则,得到2×3xz或6xz。由于x与z无关,因此我们将z视为如2、4或者100这样无聊的常数。z的变化不会影响到x。
最后一项是4z,这项中不存在x。由于我们将其视为如2或4的普通常数,因此这项完全消失了。
最后的答案是
在最后一个示例中,重要的一点是你要有信心,忽略已知的无关变量。这使得对相当复杂的表达式进行微积分运算变得非常简单。在观察神经网络的时候,我们非常需要这种深刻的见解。
你可以进行微积分运算了!
如果走到了这一步,那么你真是太棒了!
你真正理解了微积分的真谛,明白了如何使用逼进,一步一步地改善,直到最终引入了微积分。在其他困难的问题上,如果难以使用正常的方法求解,那么你可以尝试使用这些方法求解。
我们学习了幂规则和链式法则这两种技术,从而能够进行大量的微积分运算,包括理解神经网络的工作机制和原理。
享受你的新力量吧!
延伸阅读
人工智能算法(卷3):深度学习和神经网络
本书将演示各种现实世界任务中的神经网络,如图像识别和数据科学。我们研究了当前的神经网络技术,包括ReLU激活、随机梯度下降、交叉熵、正则化、Dropout及可视化等。
本书适合作为人工智能入门读者以及对人工智能算法感兴趣的读者阅读参考。