这里与一元函数有几点不同:
- 首先,二元函数描述的是一个自变量和两个因变量之间的关系,也就是说函数的定义域是一个二维平面,我们要找的极值点就在这个二维平面上。
- 其次,由于是在二维平面上寻找极值点,我们每一步可以选择的方向不再局限于一维时的向左或向右,而是瞬间变成了无穷多个方向。因此,枚举试探法彻底宣告失效。还好我们有更智能的梯度下降法。
- 一元梯度定义式里的导数现在已经换成了多元函数的偏导数。
好了,现在算法开始:
起始点坐标(-5,-5), 学习率step = 0.5 #在我们的例子里,梯度的计算式为2xi + 2yj。i和j分别是指向x轴正向和y轴正向的单位向量 求点(-5,-5)处的梯度为-10i-10j,负梯度为10i+10j,写成坐标形式就是(10,10) 在点(-5,-5)处沿此梯度走一步 根据公式 向量坐标 = 终点坐标 - 起点坐标,得终点坐标 = 起点坐标 + 向量坐标 这里,终点坐标是(x新, y新),起点坐标是(x旧, y旧) = (-5, -5) 向量坐标是负梯度坐标 = (10,10),再考虑学习率step,就可以得到 (x新, y新) = (-5,-5) + 0.5 * (10, 10) = (0, 0) 求(0, 0)处的梯度为零向量,说明到达极值点
将上述过程抽象,我们就得到了梯度下降算法的全部逻辑:
我们要找函数的极小值点(使函数取值尽可能小的那一组自变量),因为,梯度的方向是函数值增长速度最快的方向,所以,沿着梯度的反方向函数值下降最快。
因此,只要沿着梯度的反方向一步步逼近就有可能找到那一组使函数取值尽可能小的自变量。
如何沿着梯度的反方向一步步逼近呢?
我们随机指定一个起点坐标(一组自变量取值),然后沿着梯度的方向求出未知的终点坐标,梯度是一个向量,本身也具有坐标
通过上面的迭代公式,无论是多少元的函数,它的一个个自变量们都会比较快的接近极值点(或者其近似)。这样我们就可以找到一组自变量值,使得函数值尽可能的小。
1.2.3 小结
- 梯度的计算公式为
- 梯度是一个向量,它总指向当前函数值增长最快的方向,而它的模长则是这个最快的增长率(导数)的值。
- 梯度下降法是一种通过数值计算求解函数极值点的方法
- 其过程概括来说就是顺着梯度的反方向一步步逼近可能的极值点
- 使用梯度下降法的理由在于求极值点的其他方法(如传统法、枚举试探法)不具有可计算性,无法编程实现
- 梯度下降法可以很方便的向多元函数推广,利于编写程序
- 记住在这个过程中,我们要找的是极值点(使函数取极值的那一组自变量),而不是具体的极值
- 梯度下降法的劣势在于不一定能找到全局最优解
二、人工神经网络(ANN)
如果是第一次听到人工神经网络这个名词,不免会觉得比较高大上,好像我们已经可以模仿神秘的神经系统了。其实它只是一个数学模型而已。当然ANN的效果是令人眼前一亮的,好像计算机一下子真的有了人的能力,可以识人、识物。
但其实稍加抽象便能发现,这个东西无非就是个分类器,它的输入是一张图片,或者确切的说就是一堆代表像素点的数值,而输出则是一个类别。
所以说白了,所谓的人工神经网络其实就是一个超大规模的函数。
这就好比飞机和鸟儿的关系。让飞机飞起来靠的不是依葫芦画瓢造一个人工鸟,而是靠流体力学中的原理建立数学模型,然后计算得出飞机的尺寸、造型,并设计相应的发动机。
2.1 神经元的数学模型
盗一张老师ppt里的图说明问题,可以看出ANN中的每一个节点(也就是所谓的神经元)就是这样一个简单的线性函数模型。
当然通过激活函数我们可以制造一点非线性的因素,以提高模型的表达能力。这样的话下面的神经元就代表这样一个函数
其中,,这里w1, w2, w3, b都是参数,x1, x2, x3是函数的输入,也就是因变量。
常用的激活函数在这里(仍然盗用老师的ppt,捂脸逃~)
以上就是所谓的人工神经元或者叫人造神经元,很多很多这样的神经元按一定规则相连就构成了ANN,所以我才说ANN就是一个超大规模的函数而已。
是不是和你想象中的高大上的神经元大相径庭,但是我们现在所谓的人工智能其实就是这样的数学模型而已。无论是简单的图像分类器还是战胜人类的AlphaGo,都是靠这样的数学计算算出来结果的,而不是靠什么化腐朽为神奇的力量。
2.2 ANN是如何炼成的?
知道了ANN的本质,现在就让我们看看得到一个ANN需要怎么做?这里,请留意我们会遇到不同功能的函数,千万不要搞混了。
既然ANN是一个超大规模的函数,那么首先我们做的就是搭建起这个函数的架构,也就是设计人工神经网络的架构。 这时这个函数就有一堆参数待定了。 接下来我们准备一堆训练数据训练ANN,也就是把上面提到的待定参数都给他确定了。 模型完成,可以使用。
显然,最关键的是第三步——确定未知参数。
这里首先解释训练数据,我们知道ANN是一个分类器也是一个函数,这个函数读取一些输入值,经过复杂的计算后得到输出值,这些输出值可以被解释为类别。而训练数据就是输入值和最后的输出值都已知的一组数据,换句话说就是已知一组函数的自变量和因变量的对应关系。
再说的明白点,我们的任务就是,已知函数的架构、函数的一组输入值和输出值,但不知道函数的一些参数,现在要推出这些未知参数。我把这里我们要求出的这个函数称之为目标函数。于是,一言以蔽之,我们的任务就是求出目标函数的未知参数。
为了完成这个任务,我们引出另一个重要的概念——损失函数。
2.2.1 损失函数
在这里,我们玩一点小心机。注意了,这里很关键!!!
既然我们已知目标函数的一组输入和输出,而未知其参数,那么我们不妨将计就计将这些未知参数直接视为因变量,而将目标函数的输入直接代入进去,这样我们不就得到了一个自变量是目标函数的所有未知参数且函数整体完全已知的函数了吗?
这时,如果能找到一组合适的未知参数,这个函数应该能输出和已知输入对应的输出完全一致的值。
于是我们可以通过作差比较定义损失函数了
上图给出了损失函数的两种形式(除此之外还有交叉熵损失函数等其他类型),一般需要根据不同的任务类型选取适当的损失函数。为了便于初学者理解,后文将以第二种均方误差的形式做讲解。这里之所以出现了求和符号,是因为ANN的输出端可能对应了不止一个函数,这些函数可以分别表示把一张图片分成不同类别的概率。后面我们引入一个直观的例子,一看便知。
这里一定要注意,损失函数看起来虽然还有目标函数的影子,但实际已经完全不同了。我们列表比较一下
举个例子看看函数变异的过程吧。设原函数为,这是一个关于的二元函数,其中a, b, c均是常数,也可以叫待定参数。现在我们给出一组具体的函数输入值比如,令把它们代入函数,并且将a, b, c视为变量,则函数变成了关于a, b, c的三元函数,记作。
综上,求目标函数的过程,就变成了寻找损失函数极小值点的过程,而寻找极小值点不正可以用上面介绍的梯度下降法实现吗?
2.2.2 一个实例:关于链式求导和误差反向传播(BP)
行文至此,有关ANN的重要概念,我们还剩下链式求导和误差反向传播(BP)没有提及,让我们用一个实例融会贯通一下。
考虑下面这个简单的ANN:
这个ANN只有4个神经元,分别是。它输出两个目标函数,均是输入变量的函数,分别由神经元输出。可以记为
这里给加上帽子,表示这两个函数(即目标函数)的函数值是预测值,区别于训练数据给出的实际标签值。而均是目标函数的待定参数,这里我们假定神经元均采用sigmoid激活函数,即,而神经元不采用激活函数。
现在定义损失函数为
注意接下来我们会将具体的一组输入变量带进去,这样损失函数就被视作以为自变量的多元函数(具体的自变量变化过程参见上文描述)。其中,是中间变量,它们均是以为自变量的多元函数。
现在只要给出一个包含输入输出数据的训练样例,损失函数就成为不含未知参数的完全确定的函数。而我们要做的就是找到这个损失函数的极小值。
按照梯度下降算法的推导,此时我们只要按照下面的步骤就可以找出这个极小值:
- 随机指定一组初始参数
- 计算Loss函数关于各个参数的偏导数,注意这一步要代入参数的具体数值,也就是说这一步得到的是一个数
- 按照梯度下降的公式更新各个参数值直到满足一定条件为止
其中2、3里的内容是需要反复迭代的。
现在,我们以其中的几个参数为例,看看在调整过程中会遇到什么新问题。
先试试调整吧,这时我们需要求出损失函数对自变量的偏导数值(注意是数值,不是表达式),为此写出它的依赖关系:
这里,Loss函数依赖于变量,但与无关。回想多元函数求偏导数的规则,我们对求导时,应将视为常数。
而依赖于变量,因此这里应按照复合函数求导法则,即传说中的链式求导法则,先让Loss函数对变量求导,再令对求导,即:
其实从神经网络的图中可以很清楚的看出求导链。
这里有几个要点:
- 首先,式子的每一项均加下标w,表示要将具体的一组代入式子,得到一个数值
- 其次,当g(u)表示sigmoid函数时,对其求导的结果就是
- 函数对变量求偏导时,虽然也是函数,但它是关于自变量的函数,与无关,因此视为常数。这样,对求偏导的结果就是
- 等式右端最后得出的三项,在给出一个训练样例,并指定初始参数后,是可以独立计算出结果的
求出损失函数对的偏导数值,我们就可以按照梯度下降算法推导的公式,调整这个参数了!
现在,再来看看靠前的参数是怎么调整的,我们以和为例
还是老规矩,对照神经网络图,先写出它的依赖关系:
可以看出和,分别是函数和的变量,而函数均与和有关,所以Loss函数需要对均求偏导。
依然按照链式求导法则对求偏导,有:
对求偏导,有:
注意红框圈出来的部分是不是有些眼熟?
事实上,这一部分已经在调整后层参数的时候计算过了(请回看计算时的计算公式)。因此在编程时,可以让程序保存中间结果,这里直接拿来用。
现在纵观整个过程,我们惊奇的发现,对于ANN,当我们需要使用它时,是从最前面给出输入,然后一步步往后计算得出这个庞大复杂函数的输出的;而当我们需要训练它时,则是从最后面的参数开始,一步步向前求导,调整各个参数的。并且计算前面的参数时一般都会用到之前计算过的中间结果。
这样,ANN调整参数的过程就可以看作是一个误差反向传播(BP)的过程。
之所以会这样反向传播,是因为神经网络中靠后的参数依赖的中间变量少、复合层数少,而靠前的参数则经过层层复合,求导链会拉的很长。
2.2.3 最后的一点小问题
以上我们将求偏导的过程整个过了一遍,而求偏导只是梯度下降算法的一环。
程序跑起来之后,我们会对每一个训练样例,一遍遍的求偏导,直到基本上找到极小值点。
也就是说,按照梯度下降算法,每一个训练样例都会最终给出一组参数值。
一个训练集中显然会有多个训练样例,因此最终会得到好多组各不相同的参数值。
而ANN的训练目标是确定一组参数值,得到一个有一定效果的很复杂的函数,
怎么解决?
对每一个参数,我们可以将不同训练样例得出的不同值求一个平均。也可以构建一个更大的损失函数,即将每一个训练样例生成的损失函数求和,然后用梯度下降算法找到这个累计损失函数的极小值点。
这样,我们就能通过训练,最终确定ANN这个大函数的所有待定参数,然后用它来做一些神奇的事情。