数学拥有无穷的力量。它既帮助游戏开发工程师建模物理世界,也帮助量化金融分析师赚取利润,还帮助音频处理工程师制作音乐。在数据科学和机器学习领域,数学知识更是不可或缺的。
有人热爱数学,将它比作诗歌,为之着迷一生;有人很难领会数学的妙处,受困于“数学焦虑症”。本书正是为了帮助程序员消除这种焦虑,用自己熟悉的工具,即代码,重新发现数学之美。
本书以图文结合的方式帮助你用Python代码解决程序设计中的数学问题。通过边学边练,你会发现线性代数和微积分的重要概念跃然纸上、印在脑中。
来源 | 《程序员数学:用Python学透线性代数和微积分》
作者 | 保罗·奥兰德(Paul Orland)
译者 | 百度KFive
本节将介绍如何将神经网络看作数学函数,以及如何根据其结构来预测它的行为。
对于图像分类问题,我们的神经网络有64个输入值和10个输出值,并且需要数百次运算才能完成评估。因此,本节使用具有三个输入和两个输出的简单神经网络。这样就可以描绘出整个网络的样子,并贯穿评估的每个步骤。一旦了解了这一点,就可以很容易地用Python实现适用于任意规模神经网络的评估步骤。
01
组织神经元和连接
神经网络模型是神经元的集合,其中一个给定神经元的激活值取决于其连接的其他神经元的激活值。在数学上,激活一个神经元是该神经元所连接的神经元激活值的函数。神经网络的行为取决于用到的神经元数量,连接到哪些神经元,以及连接神经元的函数。在本章中,我们聚焦于一种最简单有用的神经网络——多层感知机(multilayer perceptron,MLP)。
多层感知机由几列神经元组成,称为层,从左到右排列。每个神经元的激活值都是上一层(即贴近其左侧的层)激活值的函数。最左侧的层不依赖于其他神经元,它的激活值取决于训练数据。图16-8提供了一个四层MLP的示意图。
图16-8 多层感知机的示意图,由多层神经元组成
在图16-8中,每个圆圈代表一个神经元,圆圈之间的线条表示神经元相连。一个神经元的激活值只取决于上一层神经元的激活值,它同时也影响下一层每个神经元的激活值。我随意设定了每一层中神经元的数量。在这个特定的示意图中,这些层分别由3个、4个、3个和2个神经元组成。
因为有12个神经元,所以有12个激活值。通常,神经元的数量可能会更多(我们将会用90个神经元进行数字分类),无法为每个神经元指定不同字母形式的变量名称。因此,我们用字母来表示所有的激活值,并用上标和下标对它们进行索引。上标表示层,下标则用于定位层内的神经元。例如,
代表第二层第二个神经元的激活值。
02
神经网络数据流
要将神经网络作为数学函数进行评估,有三个基本步骤,我将使用激活值来描述。本节先从概念上进行讲解,然后介绍公式。请记住,神经网络只是一个函数,它接收一个输入向量并产生一个输出向量。中间的步骤只是从给定的输入获取输出的方法。下面是流程的第1步。
第1步:将输入层的激活值设置为输入向量的条目
输入层是第一层或最左侧一层的另一个叫法。图16-8中的网络输入层有三个神经元,所以这个神经网络可以将三维向量作为输入。如果输入向量是(0.3, 0.9, 0.5),那么可以通过设置、
和
来执行第一步。这填充了网络中12个神经元中的3个(见图16-9)。
图16-9 将输入层的激活值设置为输入向量的条目
第一层的每个激活值都是针对第零层激活值的函数。现在我们有足够的信息来计算它们了,这就是第2步。
第2-1步:使用针对输入层中所有激活值的函数计算下一层中的每个激活值
这一步是计算的关键,等我把所有的步骤概念性地介绍完了,再回过头来讲。现在要知道的重要事情是,下一层中的每个激活值通常由上一层激活值的一个不同函数给出。假设我们要计算。这个激活值是
、
和
的某个函数,可简单写成
。例如,假设我们计算
得到答案0.6。那么在本次计算中,
的值就变成了0.6(见图16-10)。
图16-10 使用针对输入层激活值的函数计算第一层的一个激活值
下面计算第一层的下一个激活值,它也是针对输入层激活值
、
和
的函数,但在一般情况下是一个不同的函数,比如
。即使具有相同的输入,但因为函数不同,我们很可能会得到一个不同的结果。比如,
,那么这就是
的值(见图16-11)。
图16-11 使用针对输入层激活值的另一个函数计算第一层的另一个激活值
之所以使用和
,是因为它们是简单的占位函数名称。就输入层而言,
和
还有两个不同的函数。这里就不再继续命名这些函数了,因为我们很快就会用完所有字母。重要的一点是,每个激活值都有一个针对上一层激活值的专用函数。计算完第一层的所有激活值后,我们将填充好12个激活值中的7个。这些数仍然是虚构的,但结果可能如图16-12所示。
图16-12 多层感知机计算后的两层激活值
从这里开始重复这个过程,直到计算出网络中每个神经元的激活值,这也属于第2步。
第2-2步:重复此过程,根据上一层的激活值计算后续各层的激活值
首先使用针对第一层激活值(、
、
和
)的函数计算
。然后继续计算
和
,这两个激活值由各自的函数给出。最后,我们用两个不同的第二层激活值函数分别计算
和
。此时,网络中每个神经元都有一个激活值(见图16-13)。
图16-13 计算了所有激活值的MLP示例
至此,所有的计算就都完成了。我们计算了中间层(称为隐藏层)和最后一层(称为输出层)的激活值。现在需要做的就是读取输出层的激活值以获取结果,这就是第3步。
第3步:返回一个向量,其条目是输出层的激活值
在本例中,向量是(0.2, 0.9),因此将我们的神经网络当作输入向量为(0.3, 0.9, 0.5)、输出向量为(0.2, 0.9)的函数进行评估。
这就是全部的内容!我唯一没有讲到的是如何计算单个激活值,而这正是神经网络的独特之处。除了输入层的神经元,每个神经元都有自己的函数,而定义这些函数的参数就是我们将要调整的数,以使神经网络满足我们的需求。
03
计算激活值
好消息是,为了计算下一层的激活值,我们将为上一层的激活值使用一种形式熟悉的函数:logistic函数。棘手的是,我们的神经网络除输入层之外有9个神经元,所以需要跟踪9个不同的函数。此外,还有几个常数用来决定每个logistic函数的行为。我们的大部分工作将是追踪这些常数。
在本节的MLP示例中,激活值依赖于输入层中的三个激活值:、
和
。计算
的函数是具有这些输入(包括一个常数)并被传入sigmoid函数的线性函数。这里有四个自由参数,暂时把它们命名为
、
、
和
(见图16-14)。
图16-14 根据输入层激活值来计算的函数的一般形式
我们需要调整变量、B、
和
,使
对输入做出适当的响应。在第15章中,我们认为logistic函数会接收几个数并对它们做出是或否的决定,即答案为“是”的确定性(取值在0和1之间)。从这个意义上说,可以把网络中间的神经元看作把整个分类问题分解成了更小的“是或否”分类器。
对于网络中的每个连接,都有一个常数表示输入神经元激活值对输出神经元激活值的影响程度。在这种情况下,常数表示
对
的影响程度,而
和
分别表示
和
对
的影响程度。这些常数称为神经网络的权重,在本章使用的神经网络通用图中,每条线段都有一个权重。
常数的作用是增大或减小
的值,不会影响连接且与输入层的激活值无关。它被恰当地命名为神经元的偏置(bias),因为它衡量的是在没有任何输入的情况下做出决定的倾向性。偏置这个词有时会带有负面的含义,但它在任何决策过程中都是重要的组成部分,并且有助于避免做出异常的决定。
尽管看起来会很乱,但我们需要对这些权重和偏置建立索引,而不是将它们命名为、
、
和
。将权重写成
的形式,其中
是连接右侧的层,
是
层中目标神经元的索引,
是
层中前一个神经元的索引。例如,第零层第一个神经元对第一层第一个神经元的权重
表示为
。连接第三层第二个神经元与上一层第一个神经元的权重为
(见图16-15)。
图16-15 与权重和
相对应的连接
偏置对应的是神经元,而不是神经元对,所以每个神经元有一个偏置:
为第层第j个神经元的偏置。根据这些命名约定,我们可以将
的公式写为:
或者将的公式写为:
如你所见,通过计算激活值来评估MLP并不困难,但如果变量的数量过多,则该过程将变得繁琐且容易出错。幸运的是,我们可以使用第5章介绍的矩阵表示法来简化这个过程,使其更容易实现。
04
用矩阵表示法计算激活值
虽然很麻烦,但是我们可以通过一个具体的例子推导出整个网络层激活值的公式,然后看看如何用矩阵表示法来简化它,并给出一个可复用的公式。第二层中的三个激活值公式如下所示。
事实证明,给sigmoid函数接收到的这一长串表达式起个名字会很有用。让我们通过、
和
来分别表示,简化为:
和
这些值的公式更好,因为它们都是上一层激活值的线性组合,再加上一个常数。这意味着我们可以把它们写成矩阵向量的形式。
将这三个方程写为向量。
然后把偏置提出来形成一个向量和。
这只是一个三维向量加法。尽管中间的大向量看起来像一个较大的矩阵,但它只是一个包含三个和值的列向量。然而,这个大向量可以展开成矩阵乘法,如下所示。
将应用于所得向量的每一个条目,可以获得第二层的激活值。虽然这只是一种符号上的简化,但从心理学上讲,提取
和
并置入各自的矩阵非常有用。这些数定义了神经网络本身,而不仅仅是评估过程中每一步的激活值
。
为了深入理解,可以将评估神经网络与评估函数进行比较。
是输入变量,
和
是定义函数的常数;可能的线性函数空间是由
和
定义的。数值
,即使被重新命名为
,也只是
计算中的一个增量步骤。以此类推,一旦你决定了MLP中每层的神经元数量,每层的权重矩阵和偏置向量其实就是定义神经网络的数据。记住这一点,我们就可以用Python实现MLP了。
推荐阅读
《程序员数学 用Python学透线性代数和微积分》
作者:保罗·奥兰德(Paul Orland)
译者:百度KFive
代码和数学是相知相惜的好伙伴,它们基于共同的理性思维,数学公式的推导可以自然地在编写代码的过程中展开。
500余幅图片,本书以图文结合的方式帮助你用Python代码解决程序设计中的数学问题。
300余个练习,通过边学边练,你会发现线性代数和微积分的重要概念跃然纸上、印在脑中。
《普林斯顿微积分读本(修订版)》
《普林斯顿数学分析读本》
《普林斯顿概率论读本》
作者:[美] 史蒂文·J. 米勒、拉菲·格林贝格、史蒂文·J. 米勒
译者:李馨
风靡美国普林斯顿大学的数学课程读本,教你怎样在数学考试中获得高分,用大量例子和代码全面探讨数学问题提供课程视频和讲义。被誉为“普林斯顿读本”三剑客。
《线性代数应该这样学(第3版)》
作者:【美】阿克斯勒(Sheldon Axler)
译者:杜现昆 刘大艳 马晶
斯坦福大学等全球 40 多个国家、300 余所高校采用的数学教材,公认的阐述线性代数经典佳作。从向量空间和线性映射出发描述线性算子,包含 561 道习题和大量示例,提升熟练运用线性代数知识的能力。
《程序员的数学》(系列全四册)