你好,游客 登录
背景:
阅读新闻

深度学习入门系列,用白话文的方式让你看得懂学的快

[日期:2017-08-01] 来源:推酷  作者: [字体: ]

一年多前,吴军博士写了一本畅销书《智能时代》[1]。书里提到,在人工智能领域,有一个流派叫“鸟飞派”,亦称之为“模仿派”。说的是,当人们要学习飞翔的时候,最先想到的是模仿鸟一样去飞翔。

很多年前,印度诗人泰戈尔出了本《飞鸟集》,里面有个名句:“天空没有留下翅膀的痕迹,但我已经飞过”。有人对此解读为,“人世间,很多事情虽然做过了,却不为人所知,但那又如何?重要的是,我已做过,并从中获得了许多。”

两千多年前,司马迁在《史记•滑稽列传》写到:“此鸟不飞则已,一飞冲天;不鸣则已,一鸣惊人。”说的是当年楚庄王在“势不眷我”时,选择了“蛰伏”。蛰伏,只是一个储势过程,迟早有一天,蓄势待发,“发”则达天。

这三者的情感交集,让我联想到出了本章的主人公杰弗里•辛顿(Geoffrey Hinton)教授,在学术界里,他就是这样的一个“励志”人物!

1986年,辛顿教授和他的小伙伴们重新设计了BP算法,以“人工神经网络”模仿大脑工作机理,“吻”醒了沉睡多年的“人工智能”公主,一时风光无限。

但“好花不常开,好景不常在”。当风光不再时,辛顿和他的研究方向,逐渐被世人所淡忘。

这被“淡忘”的冷板凳一坐,就是30年。

但在这30年里,辛顿又如“飞鸟”一般,即使“飞过无痕”,也从不放弃。从哪里跌倒,就从哪里爬起。实在不行,即使换个马甲,也要重过一生。

玉汝于成,功不唐捐。

终于,在2006年,辛顿等人提出了“深度信念网(Deep Belief Nets,DBN)”(这实际上就是多层神经网络的马甲)[2]。这个“深度信念网”后期被称为“深度学习”。终于,辛顿再次闪耀于人工智能世界,随后被封为“深度学习教父”。

但细心的读者可发现,即使辛顿等人提出了“深度信念网”,在随后的小10年里,这个概念亦是不温不火地发展着(如图1所示)。直到后期(2012年以后),随着大数据和大计算(GPU、云计算等)的兴起,深度学习才开始大行其道,一时间甚嚣尘上。

(图7-1 深度学习的谷歌趋势图)

回顾起杰弗里•辛顿过往40多年的学术生涯,可谓是顾跌宕起伏,但最终修得正果。倘若细细说起,这“牛逼”,还得从1986年吹起。

7.1 1986年的那篇神作

1986年10月,杰弗里•辛顿还在卡内基梅隆大学任职。他和在加州大学圣迭戈分校的认知心理学家大卫·鲁梅尔哈特(David Rumelhart)等人,在著名学术期刊《自然》上联合发表题为:“通过反向传播算法的学习表征(Learning Representations by Back-propagating errors)”的论文[3]。该文首次系统简洁地阐述反向传播算法(BP)在神经网络模型上的应用,该算法把网络权值纠错的运算量,从原来的与神经元数目的平方成正比,下降到只和神经元数目本身成正比。

与此同时,当时的大背景是,在八十年代末,Intel x86系列的微处理器和内存技术的发展,让计算机的运行速度和数据访存速度也比二十年前高了几个数量级。这一下(运算量下降)一上(计算速度上升),加之多层神经网络可通过设置隐含层 (hidden layer),极大增强了数据特征的表征能力,从而轻易解决感知机无法实现的异或门 (XOR gate)难题,这些“天时地利人和”的大好环境,极大缓解了当年明斯基对神经网络的责难。

于是,人工神经网络的研究,渐渐得以复苏。

(图7-2 1986年杰弗里•辛顿的那篇神作)

值得一提的是,在文献[3]中,杰弗里•辛顿并不是第一作者,鲁梅尔哈特才是,而辛顿仅仅“屈居”第二(如图7-2所示)。但为什么我们提起BP算法时,总是说起辛顿呢?其实原因也很简单,主要有二:第一、鲁梅尔哈特毕竟并非计算机科学领域之内的人士,我们计算机科学家,总不能找一个脑科学家去“拜码头”吧;第二、辛顿是这篇论文的通信作者,通常而言,通信作者才是论文思路的核心提供者,这样一来,即使作者排名第二,也没有埋没掉辛顿教授的贡献。

同在1986年,鲁梅尔哈特也和自己的小伙伴们合作发表了一篇题为“并行分布式处理:来自认知微结构的探索”的论文[4]。仅仅从论文题目的前半部分来看,我们很可能误解这是一个有关“高性能计算”的文章,但从标题的后半部分可以得知,这是鲁梅尔哈特等人对人类大脑研究的最新认知。鲁梅尔哈特对大脑工作机理的深入观察,极大地启发了辛顿。辛顿灵光一现,觉得可以把这个想法迁移到“人工神经网络”当中。于是,就有了他们神来一笔的合作。

我们知道,1986年,辛顿和鲁梅尔哈特能在大名鼎鼎的《自然》期刊上发表论文,自然不是泛泛而谈,它一定是解决了什么大问题。下面我们就聊聊这个话题。

7.2 多层感知机网络遇到的大问题

由于历史的惯性,在第六讲中提到的多层前馈网络,有时也被称为多层感知机(Multilayer Perceptron,MLP)。但这个提法导致概念多少有些混淆。这是因为,在多层前馈网络中,神经元的内部构造已悄然发生变化,即激活函数从简单粗暴的“阶跃函数”变成了比较平滑的挤压函数Sigmoid(如图7-3所示)。

激活函数为什么要换成Sigmoid呢?其实原因并不复杂,这是因为感知机的激活函数是阶跃函数,不利于函数求导,进而求损失函数的极小值。我们知道,当分类对象是线性可分,且学习率(learning rate)η足够小时,由感知机还不堪胜任,由其构建的网络,还可以训练达到收敛。但分类对象不是线性可分时,感知机就有点“黔驴技穷”了。因此,通常感知机并不能推广到一般前馈网络中。

(图 7-3 变更激活函数的前馈多层神经网络)

按照我们前面章节的说法,所谓的机器学习,简单来说,就是找到一个好用的函数(function),从而较好地实现某个特定的功能(function)。一言蔽之,函数就是功能。而对于某个特定的前馈神经网络,给定网络参数(连接权值与阈值),其实就是定义了一个具备数据采集(输入层)、加工处理(隐含层),然后输出结果(输出层)的函数。

如果仅仅给定一个网络结构,其实它定义的是一个函数集合。因为不同的网络参数(连接权值与阈值),实现的功能“大相径庭”。功能不同,自然函数也是不同的!

针对前馈神经网络,我们需要实现的目的很简单,就是想让损失函数达到最小值,因为只有这样,实际输出和预期输出的差值才最小。那么,如何从众多网络参数(神经元之间的链接权值和阈值)中选择最佳的参数呢?

最简单粗暴的方法,当然就是枚举所有可能值了!

(图7-4 暴力调参不可取)

但这中暴力策略,对稍微复杂一点的网络就不可取了!例如,用于语音识别的神经网络,假设网络结构有7层,每一层有1000个神经元,那么仅一层之间的全连接权值,就达到1000×1000=106个,一旦层次多了,那权值数量就海了去了!(如图7-4所示)。故此,这种暴力调参找最优参数,既不优雅,也不高效,故实不可取!

7.3到底什么是梯度?

为了克服多层感知机存在的问题,人们设计了一种名为delta(Δ)法则(delta rule)的启发式方法,该方法可以让目标收敛到最佳解的近似值[5]。

delta法则的核心思想在于,使用梯度下降(gradient descent)的方法找极值。具体说来,就是在假设空间中搜索可能的权值向量,并以“最佳”的姿态,来拟合训练集合中的样本。那么,何谓最佳拟合呢?当然就是让前文提到的损失函数达到最小值!

我们知道,求某个函数的极值,难免就要用到“导数”等概念。既然我们把这个系列文章定位为入门层次,那不妨就再讲细致一点。什么是导数呢?所谓导数,就是用来分析函数“变化率”的一种度量。针对函数中的某个特定点x0,该点的导数就是x0点的“瞬间斜率”,也即切线斜率,见公式(7.1)。

如果这个斜率越大,就表明其上升趋势越强劲。当这个斜率为0时,就达到了这个函数的“强弩之末”,即达到了极值点。而前文提到的损失函数,如果要达到损失最小,就难免用到导数“反向指导”如何快速抵达极小值。

在单变量的实值函数中,梯度就可以简单地理解为只是导数,或者说对于一个线性函数而言,梯度就是线的斜率。但对于多维变量的函数,它的梯度概念就不那么容易理解了。下面我们来谈谈这个概念。

在向量微积分中,标量场的梯度其实是一个向量场(vector filled)。对于特定函数的某个特定点,它的梯度就表示从该点出发,该函数值增长最为迅猛的方向(direction of greatest increase of a function)[6]。假设一个标量函数f的梯度记为:f或gradf,这里的表示向量微分算子。那么,在一个三维直角坐标系,该函数的梯度就可以表示为公式(7.2):

求这个梯度值,难免要用到“偏导”的概念。说到“偏导”,这里顺便“轻拍”一下国内的翻译。“偏导”的英文本意是“partial derivatives(局部导数)”,书本上常翻译为“偏导”,可能会把读者的思路引导“偏”了。

那什么是“局部导数”呢?对于多维变量函数而言,当求某个变量的导数(相比于全部变量,这里只求一个变量,即为“局部”),就是把其它变量视为常量,然后整个函数求其导数。之后,这个过程对每个变量都“临幸”一遍,放在向量场中,就得到了这个函数的梯度了。举例来说,对于3变量函数f=x2+3xy+y2+z3,它的梯度可以这样求得:

(1) 把y,z视为常量,得x的“局部导数”:

(2) 然后把xx,z视为常量,得y的“局部导数”:

(3) 最后把xx,y视为常量,得z的“局部导数”:

于是,函数f的梯度可表示为:

针对某个特定点,如点A(1, 2, 3),带入对应的值即可得到该点的梯度:

这时,梯度可理解为,站在向量点A(1, 2, 3),如果想让函数f的值增长得最快,那么它的下一个前进的方向,就是朝着向量点B(8,7,27)方向进发(如图7-3所示)。很显然,梯度最明显的应用,就是快速找到多维变量函数的极(大/小)值。

(图7-5 梯度概念的示意图)

在这里需要说明的是,我们用“局部导数”的翻译,仅仅是用来加深大家对“偏导”的理解,并不是想纠正大家已经约定俗成的叫法。所以为了简单起见,在后文我们还是将“局部导数”称呼为“偏导”。

7.4 到底什么是梯度下降?

上面我们提到了梯度的概念,下面我们说说在求损失函数极小值过程中,常常提到的“梯度递减”的概念。

我们先给出一个形象的案例。爬过山的人,可能会有这样的体会,爬坡愈平缓(相当于斜率较小),抵达山峰(函数峰值)的过程就越缓慢,而如果不考虑爬山的重力阻力(对于计算机而言不存在这样的阻力),山坡越陡峭(相当于斜率越大),顺着这样的山坡爬山,就越能快速抵达山峰(对于函数而言,就是愈加快速收敛到极值点)。

(图7-6 梯度递减求极小值)

如果我们把山峰“乾坤大挪移”,把爬山峰变成找谷底(即求极小值),这时找斜率最陡峭的坡而攀爬山峰的方法,并没有本质变化,不过是方向相反而已。如果把登山过程中求某点的斜率称为“梯度(gradient)”,而找谷底的方法,就可以把它称之为“梯度递减(gradient descent)”,示意图如图7-6所示。

依据“梯度递减”作为指导,走一步,算一步,一直遵循“最陡峭”的方向,探索着前进,这个过程,是不是有点像邓公的名句“摸着石头过河”?

这个“梯度递减”体现出来的指导意义,就是“机器学习”中的“学习”内涵,即使在大名鼎鼎的“AlphaGo”中,“学习”这是这么玩的!你是不是有点失望?这机器学习也太不高大上了!

但别忘了,在第一讲中,我们就已经讲到“学习”的本质,在于性能的提升。利用“梯度递减”的方法,的确在很大程度上,提升了机器的性能,所以,它就是“学习”!

当然,从图7-3中,我们也很容易看到“梯度递减”的问题所在,那就是它很容易收敛到局部最小值。正如攀登高峰,我们会感叹“一山还比一山高”,探寻谷底时,我们也可能发现,“一谷还比一谷低”。但是“只缘身在此山中”,当前的眼界让我们像“蚂蚁寻路”一样,很难让我们有全局观,因为我们都没有“上帝视角”。

7.5 重温神经网络的损失函数

针对前馈神经网络的设计,输入和输出层设计比较直观。比如说,假如我们尝试判断一张手写数字图片上面是否写着数字“2”。很自然地,我们可以把图片像素的灰度值作为网络的输入。如果图片的维度是16×16,那么我们输入层神经元就可以设计为256个(也就是说,输入层是一个包括256个灰度值向量),每个神经元接受的输入值,就是规格化的灰度值。

而输出层的设计也很简单,就是需要包含10神经元,输出是数字“0~9”的分类概率(也就是说,输出层是一个包括10个概率值的向量)。择其大者而判之,如图7-7所示,如果判定为“2”的概率(比如说80%)远远大于其他数字,那么整个神经网络的最终判定,就是手写图片中的数字是“2”,而非其它数字。

相比于神经网络输入、输出层设计的简单直观,它的隐含层设计,可就没有那么简单了。说好听点,它是一门艺术,依赖于“工匠”的打磨。说不好听点,它就是一个体力活,需要不断地“试错”。

但通过不断地“折腾”,研究人员还真是掌握了一些针对隐层的启发式设计规则(如下文即将提到的BP算法),以此降低训练网络所花的开销,并尽量提升网络的性能。

那么,怎样才算是提升神经网络性能呢?这就需要用到前面我们前面提到的损失函数了。在第六章我们提到,所谓“损失函数”,就是一个刻画实际输出值和期望输出值之间“落差”的函数。

为了达到理想状态,我们当然希望这种“落差”最小,也就是说,我们希望快速配置好网络参数,从而让这个损失函数达到极小值。这时,神经网络的性能也就接近最优!

关于求损失函数极小值,台湾大学李弘毅博士给出了一个通俗易懂的例子,下面我们来说说。对于识别手写数字的神经网络,训练数据都是一些“0,1 2, …, 9”等数字图像,如图7-8所示。

(图7-8 识别手写数字的神经网络)

由于人们手写数字的风格不同,图像的残缺程度不同,输出的结果有时并不能“十全十美”,于是我们就用损失函数来衡量二者的误差。前面我们提到,常用的损失函数是:

机器学习的任务,在很大程度上,找一个模型,拟合(fitting)或者说“适配”给定的训练数据,然后再用这个模型预测新数据。这个模型的表现形式,具体说来,就是设计一个好用的函数,用以揭示这些训练样本随自变量的变化关系。揭示拟合好坏的程度,就要用到损失函数。“损失”越小,说明拟合的效果就越好。

(图7-9 用梯度递减,更新网络权值)

在我们训练神经网络时,损失函数说白了,就是有关“权值参数”的函数。为了求损失函数的极小值,就不可避免地需要计算损失函数中每一个权值参数的偏导数,这时前文中提到的“梯度递减”方法就派上用场了。训练线性单元的梯度递减算法示意图如图7-9所示,图中的参数η就是“学习率”,它决定了梯度递减搜索的步长,这个步长“过犹不及”。如果值太小,则收敛慢,如果值太大,则容易越过极值,导致网络震荡,难以收敛。

图7-9仅仅给出一个权值变量wiwi的梯度示意图,而实际上,神经网络中的参数是非常多的,因此针对损失函数LL的权值向量的梯度w⃗ w→可以记作:

在这里,∇L(w⃗ )本身就是一个向量,它的多个维度分别由损失函数LL对多个权值参数wi求偏导所得。当梯度被解释为权值空间的一个向量时,它就确定了L对陡峭上升的方向。

如果需要根据图7-9所示的公式来更新权值,我们需要一个更加实用的办法,在每一步重复计算。幸运的是,这个过程并不复杂,通过简易的数学推导,我们可以得到每个权值分量wi更加简明的计算公式:

其中,xid表示训练集合第dd个样例的输入分量xixi,ydyd表示第dd样例的期望输出值,y′d表示第d样例的实际输出值,这二者的差值就是“损失(loss)”,也称之为误差(error)。有了公式(7.5)做支撑,图7-9所示的算法就可行之有“章法”了。

有了前面的知识铺垫,我们终于可以在下一章谈谈误差反向传播(Back Propagation,BP)算法了。

7.6 小结

在本章中,我们主要讲解了梯度的概念。所谓梯度,就是该函数值增长最为迅猛的方向,然后我们介绍了梯度下降法则。

在下一章中,我们将用最为通俗易懂的图文并茂的方式,给你详细解释误差反向传播(BP)算法。BP算法不仅仅是作为经典留在我们的记忆里,而且,它还“历久弥新”活在当下。要知道,深度信念网(也就是深度学习)之所以性能奇佳,不仅仅是因为它有一个“无监督”的逐层预训练(unsupervised layer-wise training),除此之外,预训练之后的“微调(fine-tuning)”,还是需要“有监督”的BP算法作为支撑。

由此可见,BP算法影响之深,以至于“深度学习”都离不开它!

“世上没有白走的路,每一步都算数”。希望你能持续关注。

7.7 请你思考

通过本章的学习,请你思考如下问题:

(1)在前馈神经网络中,隐含层设计多少层、每一层有多少神经元比较合适呢?我们可以设定一种自动确定网络结构的方法吗?

(2)神经网络具有强大的特征表征能力,但“成也萧何,败也萧何”,BP算法常常遭遇“过拟合(overfitting)”,它可能会把噪音当做有效信号,你知道有什么策略来避免过拟合吗?

【参考文献】

[1] 吴军. 智能时代. 中信出版集团. 2016.8

[2] Hinton G E, Osindero S, Teh Y W. A fast learning algorithm for deep belief nets[J]. Neural computation, 2006, 18(7): 1527-1554.

[3] Williams D, Hinton G. Learning representations by back-propagating errors[J]. Nature, 1986, 323(6088): 533-538.

[4] Rumelhart D E, McClelland J L, PDP Research Group. Parallel Distributed Processing, Volume 1 Explorations in the Microstructure of Cognition: Foundations[J]. 1986.

[5] Tom Mitchell著.曾华军等译. 机器学习. 机器工业出版社. 2007.4

[6] Better Explained. Vector Calculus: Understanding the Gradient

文章作者:张玉宏,著有《品味大数据》一书。审校:我是主题曲哥哥。

---------------------华丽的分割线---------------------

BP算法双向传,链式求导最缠绵(深度学习入门系列之八)

8.1 BP神经网络极简史

在神经网络(甚至深度学习)参数训练中,BP(Back Propagation)算法非常重要,它都占据举足轻重的地位。在提及BP算法时,我们常将它与杰弗里•辛顿(Geoffrey Hinton)的名字联系在一起。但实际上,辛顿还真不是第一个提出BP算法的人,就像爱迪生不是第一个发明电灯的人一样。但人们记住的,永远都是那个让电灯“飞入平常百姓家”的功勋人物爱迪生,而不是它的第一发明人美国人亨利·戈培尔(Henry Goebel)。

如果说辛顿就是BP算法的“爱迪生”,那谁是BP算法的“戈培尔”呢?他就是保罗·沃伯斯(Paul Werbos)。1974年,沃伯斯在哈佛大学博士毕业。在他的博士论文里,首次提出了通过误差的反向传播来训练人工神经网络[1]。事实上,这位沃伯斯不光是BP算法的开创者,他还是循环神经网络(Recurrent Neural Network,RNN)的早期开拓者之一。在后期的系列入门文章中,我们还会详细介绍RNN,这里暂且不表。

说到BP算法,我们通常强调的是反向传播,但其实呢,它是一个典型的双向算法。更确切来说,它的工作流程是分两大步走:(1)正向传播输入信号,输出分类信息(对于有监督学习而言,基本上都可归属于分类算法);(2)反向传播误差信息,调整全网权值(通过微调网络参数,让下一轮的输出更加准确)。

下面我们分别举例,说明这两个流程。为了简化问题描述,我们使用如图8-1所示的最朴素三层神经网络。在这个网络中,假设输入层的信号向量是[-1, 1],输出层的目标向量为[1, 0],“学习率”η为0.1,权值是随机给的,这里为了演示方便,分别给予或“1”或“-1”的值。下面我们就详细看看BP算法是如何运作的?

(图8-1 简易的三层神经网络)

8.2.1正向传播信息

正向传播信息,简单说来,就是把信号通过激活函数的加工,一层一层的向前“蔓延”,直到抵达输出层。在这里,假设神经元内部的激活函数为Sigmod(

)。之所以选用这个激活函数,主要因为它的求导形式非常简洁而优美:

事实上,类似于感知机,每一个神经元的功能都可细分两大部分:(1)汇集各路链接带来的加权信息;(2)加权信息在激活函数的“加工”下,神经元给出相应的输出,如图8-2所示。

(图8-2 单个神经元的两部分功能)

于是,在正向传播过程中,对于f1(e)f1(e)神经元的更新如图8-3所示,其计算过程如下所示:

(图8-3 神经元信息前向更新神经元1的f1(e))

接着,在同一层更新f2(e)f2(e)的值,过程和计算步骤类似于f1(e)f1(e),如图8-4所示:

(图8-4 神经元信息前向更新神经元2的f2(e))

接下来,信息正向传播到下一层(即输出层),更新神经元3的f3(e)f3(e)(即输出y1y1的值),如图8-5所示。

(图8-5 神经元信息前向更新神经元3的f3(e))

然后,类似地,计算同在输出层求神经元f4(e)(即输出y2)的值,如图8-6所示。

(图8-6神经元信息前向更新f4(e))

到此,在第一轮信号前向传播中,实际输出向量已计算得到y′=[0.65,0.59]T,但我们预期输出的向量(即教师信号)是y=[1,0]T,这二者之间是存在“误差”的。于是,重点来了,下面我们就用“误差”信息反向传播,来逐层调整网络参数。为了提高权值更新效率,这里就要用到下文即将提到的“反向模式微分法则(chain rule)”。

8.2.2 求导中的链式法则

(砰!砰!砰!敲黑板!请注意:如下部分是BP算法最为精妙之处,值得细细品味!)

在前面信号正向传播的示例中,为了方便读者理解,我们把所有的权值都暂时给予了确定之值。而实际上,这些值都是可以调整的,也就是说其实它们都是变量,除掉图8-1中的所有确定的权值,把其视为变量,得就到更为一般化的神经网络示意图8-7。

(图8-7 带权重变量的神经网络)

这里为了简化理解,我们暂时假设神经元没有激活函数(或称激活函数为y=x),于是对于隐含层神经元,它的输出可分别表示为:

然后,对于输出层神经元有:

于是,损失函数L可表示为公式(8.2):

这里YY为预期输出值向量(由y1,y2,...,yi,...等元素构成),实际输出向量为fi(w11,w12,...,wij,...,wmn)。对于有监督学习而言,在特定训练集合下,输入元素xi和预期输出yiyi都可视为常量。由此可以看到,损失函数LL,在本质上,就是一个单纯与权值wij相关的函数(即使把原本的激活函数作用加上去,除了使得损失函数的形式表现得更加复杂外,并不影响这个结论)。

于是,损失函数L梯度向量可表示为公式(8.3):

其中,这里的eij是正交单位向量。为了求出这个梯度,需要求出损失函数LL对每一个权值wij的偏导数。

BP算法之所以经典,部分原因在于,它是求解这类“层层累进”的复合函数偏导数的利器。为啥这么说呢?下面,我们就列举一个更为简化但不失一般性的例子来说明这个观点(以下案例参考了Chris Olah的博客文章[3])。

假设有如下一个三层但仅仅包括a、b、c、d和e等5个神经元的网络,在传递过程中,c、d和e神经元对输入信号做了简单的加工,如图8-8所示。

(图8-8 简易的神经网络)

假设变量aa影响cc,此时我们想弄清楚a是如何影响c的。于是我们考虑这么一个问题,如果a变化一点点,那么c是如何变化的呢?我们把这种影响关系定义为变量c相对于变量a的偏导数,记做∂c/∂a。

利用高等数学的知识,我们很容易求得,对于直接相连的神经元(如a对c,或b对d),可利用“加法规则”或“乘法规则”直接求出。例如,利用加法规则,∂c/∂a可表示为:

而对于表达式为乘法的求偏导规则为:

那么,对于间接相连的神经元,比如aa=对e,如果我们也想知道a变化一点点时e变化多少,怎么办呢?也就是说,偏导数∂e/∂a该如何求呢?这时,我们就需要用到链式法则了。

这里假设a=2,b=1。如果aa的变化速率是1,那么c的变化速率也是1(因为∂c/∂a=1)。类似地,如果c的变化速率为1,那么e的变化速率为2(因为∂e/∂c=d=2)。所以相对于a变化1,e的变化为1×2=2。这个过程就是我们常说的“链式法则”,其更为形式化的表达为(如图8-9所示):

(图8-9 链式法则示意图)

a对e的“影响”属于单路径的影响,还比较容易求得,但这并不是我们关注的重点。因为在神经网络中,神经元对神经元的连接,阡陌纵横,其影响也是通过多条路径“交织”在一起的。在图8-9中,我们研究一下b对e的影响,就能比较好理解这一工作机理。显然,b对e的影响,也可表达为一个偏导关系:

从图8-9可以看出,b对e影响,其实是“兵分两路”:(1)b通过影响c,然后通过c影响e;(2)b通过影响d,然后通过d影响e。这就是多维变量(这里“多”仅为2)链式法则的“路径加和”原则。

这个原则,看起来简单明了,但其实蕴藏着巨大代价。因为当网络结构庞大时,这样的“路径加和”原则,很容易产生组合爆炸问题。例如,在如图8-10所示的有向图中,如果X到Y有三条路径(即X分别以α、β和χ的比率影响Y),Y到Z也有三条路径(Y分别以δ、ε和ξ的比率影响Z)。

(图8-10 路径加和规则演示)

于是,很容易根据路径加和原则得到X对Z的偏导数:

上面用到的求偏导数方法,可称之为“前向模式微分(forward-mode differentiation)”,如图8-11-(a)所示。当网络结构简单时,即使X到Z的每一个路径都被“临幸(遍历)”一遍,总共才有 3×3=9条路径,但一旦网络结构的复杂度上去了,这种“前向模式微分”,就会让求偏导数的次数和神经元个数的平方成正比。这个计算量,就很可能是成为机器“难以承受的计算之重”。

有道是“东方不亮西方亮”。为了避免这种海量求导模式,数学家们另辟蹊径,提出了一种称之为“反向模式微分(reverse-mode differentiation)”。取代公式(8.4)的那种简易的表达方式,我们用公式(8.5)的表达方式来求X对Z的偏导:

或许你会不屑一顾,这又是在搞什么鬼?把公式(8.4)恒等变换为公式(8.5)又有什么用呢?

(图8-11 前向与反向微分方法对比)

你可别急,这背后大有玄机,且听我慢慢道来。

前文提到的前向模式微分方法,其实就是我们在高数课堂上学习的求导方式。在这种求导模式中,强调的是某一个输入(比如X)对某一个节点(如神经元)的影响。因此,在求导过程中,偏导数的分子部分,总是根据不同的节点总是不断变化,而分母则锁定为偏导变量“∂X”,保持定不变(见图8-11-(a))。

相比而言,反向模式微分方法则有很大不同。首先在求导方向上,它是从输出端(output)到输入端进行逐层求导。其次,在求导方法上,它不再是对每一条“路径”加权相乘然后求和,而是针对节点采纳“合并同类路径”和“分阶段求解”的策略。

拿8-11-(b)的例子来说,先求Y节点对Z节点的"总影响"(反向第一层):

然后,再求节点X对节点Z的总影响(反向第二层):

特别需要注意的是,∂Z/∂Y∂已经在第一层求导得到。在第二层仅仅需要求得∂Y/∂X,而∂Y/∂X∂ 容易求得(α+β+χ),然后二者相乘即可得到所求。这样一来,就大大减轻了第二层的求导负担。在求导形式上,偏导数的分子部分(节点)不变,而分母部分总是随着节点不同而变化,即[∂Z/∂]。

这样说来说去,好像还是不太明白!下面我们还是用图8-9所示的原始例子,对比二者的求导过程,一遍走下来,有了感性认识,你就能明白其中的差异。为了进一步方便读者理解,我们将图8-9重新绘制为图8-12的样子。

(图8-12 前向模式微分方法)

以求变量b偏导数的流程为例,我们先用前向模式微分法,来说明这种方法的求导过程。根据加法规则,对于求偏导值∂e/∂b的步骤可以分两步走:(1)求得所有输入(包括a和b)到终点e的每条路径上的偏导值乘积;(2)对所有条路径的导数值进行加和操作。

从8-12所示的图中,对于两个输入a和b,它们共有3条路径抵达终点e(分别计为①、②和③)。

对于第①条路径而言,输入a对e的影响为:

对于第②条路径而言,输入b对e的影响为:

对于第③条路径而言,输入b对e的影响为:

所以在整体上,输入a和b从三条路径上对e施加的“总影响”为:0+2+3=5.

或许读者已经注意到了,有些路径已经被冗余遍历了,比如在图8-12所示中,a→c→e(第①条路)和b→c→e(第②条路)就都走了路径c→e。

这些局部性的冗余也就罢了,更为“恶劣”的是,对于求∂e/∂a,上述三条路径,它们同样还得“一个都不能少”地跑一遍,如果求得的变量多了,这到底得有多少冗余啊!

可能你会疑问,对于∂e/∂b(∂e/∂a),第①(③)条路径明明可以不走的嘛?这种明智,是对人的观察而言的,而且是对于简单网络而言的。因为,如果网络及其复杂,人们可能就没有这么“慧眼识珠”,识别其中的路径冗余。

此外,对于计算机而言,有些时候,局部操作的“优化”,相对于整体操作的“规范化”,顶多算得上“奇淫巧技”,其优势可谓是“荡然无存”。有过大规模并行编程经验的读者,可能对这个观点会有更深的认知。

然而,同样是利用链式法则,反向模式微分方法就能非常机智地避开了这种冗余(下面即将讲到的BP算法,正是由于这么干,才有其优势的)。在这种方法中,它能做到对每一条路径只“临幸”一次,这是何等的节俭!下面我们来看看它是如何工作的。

(图8-13反向模式微分方法)

相比于“前向模式微分法”是以输入(如图8-13-(a)所示的a和b)为锚点,正向遍历每一条可能的路径。反向模式微分法是以节点(或说神经元,如图8-13-(a)所示的e、c和d)为锚点,逐层分阶段求导,然后汇集每一个节点的外部路径(合并同类路径)。

如图8-13-(b)所示,在反向求导的第1层,对于节点c有:

类似的,对于节点d有:

在阶段性的求解完毕第一层的导数之后,下面开始求解第二层神经元变量的偏导。如图8-13-(c)所示,在反向第2层,对于节点a有如图8-14-(Ⅰ)所示的求导模式。

(图8-14反向模式微分方法的推演)

特别需要注意的是,8-14-(Ⅰ)所示的表达式“∂e/∂c×∂c/∂a”中左部“∂e/∂c”,已经在第1层求解过了,并“存储”在神经元cc中。此时,采用“拿来主义”,拿来就能用!这就是反向模式微分的精华所在!

类似地,在反向求导第2层,对于节点bb,由于它汇集“两路兵马”的影响,所以需要合并同类路径,有如图8-14-(Ⅱ)所示结果。

这样一来,如图8-13反向模式微分方法,每个路径仅仅遍历一次,就可以求得所有输出(如e节点)对输入(如a或b节点)的偏导,干净利落,没有任何冗余!

在第七章中,我们曾提到,“BP算法把网络权值纠错的运算量,从原来的与神经元数目的平方成正比,下降到只和神经元数目本身成正比。”其功劳,正是得益于这个反向模式微分方法节省的计算冗余

8.2.3 误差反向传播

有了前面“链式求导”的知识铺垫,下面我们就来细细讲解误差反向传播的过程。鉴于我们的系列文章是写给初学者(实践者)看的,下面我们尽量省略了其中较为复杂的推导公式,对该部分感兴趣的读者可参阅卡内基梅隆大学Tom Mitchell教授的经典著作《机器学习》[3](对公式不感冒的读者,第一遍阅读可以直接跳过公式,直达图文解释部分)。

误差反向传播通过梯度下降算法,迭代处理训练集合中的样例,一次处理一个样例。对于样例d,如果它的预期输出(即教师信号)和实际输出有“误差”,BP算法抓住这个误差信号Ld,以“梯度递减”的模式修改权值。也就是说,对于每个训练样例d,权值wji的校正幅度为Δwji(需要说明的是,wji和wij其实都是同一个权值,wji表示的是神经元j的第i个输入相关的权值,这里之所以把下标“j”置于“i”之前,仅仅表示这是一个反向更新过程而已):

在这里,Ld表示的是训练集合中样例d的误差,分解到输出层的所有输出向量,Ld可表示为:

其中:

yj表示的是第j个神经单元的预期输出值。

y′j表示的j个神经单元的实际输出值。

outputsoutputs的范围是网络最后一层的神经元集合。

下面我们推导出∂Ld/∂wji的一个表达式,以便在公式(8.7)中使用梯度下降规则。首先,我们注意到,权值wji仅仅能通过netj影响其他相连的神经元。因此利用链式法则有:

在这里,netj=∑iwjixji,也就是神经元jj输入的加权和。xji表示的神经j的第i个输入。需要注意的是,这里的xji是个统称,实际上,在反向传播过程中,在经历输出层、隐含层和输入层时,它的标记可能有所不同。

由于在输出层和隐含层的神经元对“纠偏”工作,承担的“责任”是不同的,至少是形式不同,所以需要我们分别给出推导。

(1)在输出层,对第i个神经元而言,省略部分推导过程,公式(8.8)的左侧第一项为:

为了方便表达,我们用该神经元的纠偏“责任(responsibility)”δ(1)描述这个偏导,即:

(2)对隐含层神经元j的梯度法则(省略了部分推导过程),有:

其中:

fj表示神经单元j的计算输出。

netj表示的是神经单元j的加权之和。

Downstream(j)表示的是在网络中神经单元jj的直接下游单元集合。

隐含层神经元的纠差职责,是通过计算前一步输出神经元的“责任”来实现的。

这里说的每层神经元“责任”,或者更为确切来说是“纠偏责任”,其实就是在8.2.2节讲到的“分阶段求解”策略。

在明确了各个神经元“纠偏”的职责之后,下面就可以依据类似于感知机学习,通过如下加法法则更新权值:

对于输出层神经元有:

对于隐含层神经元有:

在这里,η∈(0,1)表示学习率。在实际操作过程中,为了防止错过极值,η通常取小于0.1的值。hj为神经元j的输出。xjk表示的是神经单元j的第k个输入。

上面的公式依然比较抽象,难以理解。下面我们还是以前面的神经网络拓扑结构为例,用实际运算过程给予详细说明,以期望给与读者感性认识。

在这里,我们把每个神经元根据误差调参的“责任”记为δ,那么,根据公式(8.9)和(8.10),神经元3的“责任”可表示为:

(图8-15 误差反向传播计算神经元3的“责任”)

(图8-16 误差反向传播计算神经元4的责任)

在反向更新完毕输出层的权值后,下面。我们开始反向更新隐含层的网络权值,示意图如图8-17所示。

(图8-17 误差反向传播计算神经元1的责任)

如果我们把反向传播误差的“职责(即δj)”,也看做一种特殊信息的话,那么在隐藏层的每个神经元都会有一个加权和影响,记为Δj,实际上,这里的Δj,就是公式(8.11)的加权求和Downstream(j)(其实也就是8.2.2所提及的“合并同类路径”)。

对于隐含层神经1,则有:

在计算出计算神经元1承担的“责任”之后,我们就可以更新与神经元1相连的两个输入变量权值:

类似的流程(示意图如图8-18所示),可以求得神经元2的累计加权影响有:

(图8-18误差反向传播计算神经元2的责任)

同样,计算出计算神经元2承担的“责任”之后,我们就可以更新与神经元2相连的两个输入变量权值:

从上面的推导过程,我们可以看到,经过一轮的误差逆传播,神经网络的权值前后确有不同。但由于学习率(即步长)较小(为0.1),所以前后的权值变化并不大(括号内的数值为原始权值),如图8-19所示。

(图8-19 一轮BP算法之后前后的权值对比)

如此一来,整个网络的权值就全部得以更新。接下来,网络就可接受下一个训练样例,接着往下训练了,直到输出层的误差小于预设的容忍度。

BP算法,在很多场所的确非常有用。例如,1989年,Yann Lecun(又一位当下的深度学习大牛)等人就用BP算法,在手写邮政编码识别上有着非常成功的应用[5],训练好的系统,手写数字错误率只有5%。Lecun借此还申请了美国专利,开了公司,发了一笔小财。

在发表BP算法之后的30年,2006年,辛顿等人在发表的有关“深度信念网”的经典论文中指出[8],深度信念网(DBN)的组成元件就是受限玻尔兹曼机 (Restricted Boltzmann Machines, RBM)。而DBN的构建其实分两步走的:(1)单独“无监督”地训练每一层RBM网络,以确保特征向量在映射到不同特征空间时,能够尽可能多地保留特征信息;(2)在DBN的最后一层,设置BP网络,用以接收RBM的输出特征向量作为它的输入特征向量,然后“有监督”地训练实体关系分类器,对网络权值实施微调(Fine-Tune)。

现在你看到了,BP算法的影响力,一直渗透到“深度学习”骨子里!这就是为什么在讲深度学习时,我们绕不过BP算法的原因。

8.4 小结

在本章中,我们详细解释了反向传播(BP)算法,通过学习我们知道,BP算法其实并不仅仅是个反向算法,而是一个双向算法。也就是说,它其实是分两大步走:(1)正向传播信号,输出分类信息;(2)反向传播误差,调整网络权值。如果没有达到预期目的,重走回头路(1)和(2)。

BP算法很成功。但我们也要看到BP算法的不足,比如说会存在“梯度扩散(Gradient Diffusion)”现象,其根源在于对于非凸函数,梯度一旦消失,就没有指导意义,导致它可能限于局部最优。而且“梯度扩散”现象会随着网络层数增加而愈发严重,也就是说,随着梯度的逐层消减,导致它对调整网络权值的调整效益,作用越来越小,故此BP算法多用于浅层网络结构(通常小于等于3),这就限制了BP算法的数据表征能力,从而也就限制了BP的性能上限。

再比如说,虽然相比于原生态的BP算法,虽然它降低了网络参数的训练量,但其网络参数的训练代价还是不小,耗时非常“可观”。就拿LeCun的识别手写邮编的案例说事,其训练耗时就达3天之久。

再后来,与LeCun同在一个贝尔实验室的同事Vladimir Vapnik(弗拉基米尔·万普尼克),提出并发扬光大了支持向量机 (Support Vector Machine) 算法。

SVM作为一种分类算法,对于线性分类,自然不在话下。在数据样本线性不可分时,它使用了所谓“核机制(kernel trick)”,将线性不可分的样本,映射到高维特征空间 (high-dimensional feature space),从而使其线性可分。自上世纪九十年代初开始,SVM逐渐大显神威,在图像和语音识别等领域,获得了广泛而成功的应用。

在手写邮政编码的识别问题上,LeCun利用BP算法,把错误率整到5%左右,而SVM在1998年就把错误率降到低至0.8%。这远超越同期的传统神经网络算法。

就这样,万普尼克又把神经网络研究送到了一个新的低潮!

在下一章中,我们将来聊聊“卷积神经网络”,这可是深度学习发展过程中的一个重要里程碑,希望你能关注。

8.5 请你思考

通过本章的学习,请你思考如下问题:

(1)正是由于神经网络具有强大的表示能力,“成也萧何,败也萧何”,BP算法常常遭遇“过拟合(overfitting)”,它可能会把噪音当做有效信号,你知道有什么策略来避免过拟合吗?

(2)利用梯度递减策略,BP算法常停止于局部最优解,而非全局最优解,这好比“只因身在此山中”,却不知“人外有人,山外有山”,你知道有什么方法可以改善这一状况吗?

(3)在BP算法流程中,我们看到的是反反复复的权值调整,而杰弗里•辛顿在文献[4]中提到的特征表示(representation),体现在什么地方?

【参考文献】

[1] Paul J. Werbos. Beyond Regression: New Tools for Prediction and Analysis in the Behavioral Sciences. PhD thesis, Harvard University, 1974

[2] Christopher Olah. Calculus on Computational Graphs: Backpropagation

[3]Tom Mitchell著.曾华军等译. 机器学习. 机器工业出版社. 2007.4

[4] Williams D, Hinton G. Learning representations by back-propagating errors[J]. Nature, 1986, 323(6088): 533-538.

[5] LeCun Y, Boser B, Denker J S, et al. Backpropagation applied to handwritten zip code recognition[J]. Neural computation, 1989, 1(4): 541-551.

[6]周志华. 机器学习. 清华大学出版社. 2016.1

[7] Mirosav Kubat著. 王勇等译. 机器学习导论. 机械工业出版社. 2016.11

[8] Hinton G E, Osindero S, Teh Y W. A fast learning algorithm for deep belief nets[J]. Neural computation, 2006, 18(7): 1527-1554.

文章作者:张玉宏,著有《品味大数据》一书。审校:我是主题曲哥哥。

收藏 推荐 打印 | 录入:admin | 阅读:
相关新闻      
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数
点评:
       
评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款