4 月 15 日,杨铭博士在机器之心线下活动 Interface 上做了一次题为「深度神经网络在图像识别应用中的演化」的演讲。这篇文章对杨铭博士分享的内容进行了整理,同时还附有添加了字幕的视频,希望能为大家学习图像识别提供帮助。
地平线机器人技术 ( Horizon Robotics ) 联合创始人&软件副总裁杨铭博士毕业于清华大学电子工程系并获得工学学士和硕士学位,于美国西北大学电气工程与计算机科学系获得博士学位。杨铭博士是 Facebook 人工智能研究院创始成员之一,曾任 NEC 美国研究院高级研究员,专注于计算机视觉和机器学习领域研究,包括物体跟踪、人脸识别、海量图片检索、及多媒体内容分析。在顶级国际会议 CVPR/ICCV 发表论文 20 余篇。在 Facebook 工作期间负责的深度学习研发项目 DeepFace。多次担任 CVPR/ICCV/NIPS/ACMMM 等顶级国际会议程序委员会成员,T-PAMI/IJCV/T-IP 等顶级国际期刊审稿人,申请获得美国专利 14 项。2015 年,杨铭博士回国加入地平线机器人技术。
下面是添加了字幕的视频,以及演讲内容整理:
大家下午好!我是地平线机器人的杨铭,非常高兴有这样一个机会跟大家交流和分享。首先感谢机器之心的邀请,更加感谢大家在这样一个风和日丽、周六的下午来到这里,听我的分享。
深度神经网络这几年非常火热,取得了很多技术突破。其中最关键的是深度网络的网络结构,网络模型本身具有很强的建模能力,能够完成很多任务,每项任务也都有很好的结果。网络模型本身也经历了一些发展,从 80 年代一直到现在。我想把发展的过程和一些设计的考虑跟大家分享一下。
今天这个分享不只是我一个人的总结,也包括我的同事黄畅博士。黄畅博士也是地平线机器人联合创始人,负责算法方面。之前在清华大学计算机系读博,之后去南加州大学做博士后。我们在硅谷、在 NEC Lab 当过一段时间的同事。后来他去了百度深度学习研究院担任主任架构师,现在负责地平线的算法研发工作。
还有一位合作者是罗恒博士,在蒙特利尔大学做过博士后,后来去了百度深度学习研究院工作,目前在地平线负责图像算法的研发。
简单说一下我的背景。我在清华电子系读的本科和硕士,当时做的是视频编码。2000 年左右的时候,视频编码以及 4G 通信是比较火的项目。我读完硕士之后就去了美国西北大学读博士,那个时候转向了计算机视觉、机器学习。毕业后就去了硅谷,跟黄畅做了同事。后来他们回国,先去了百度,创立了百度深度学习研究院,我去了 Facebook,Facebook 那几年决定加大投入做 AI 相关的研发。
2013 年的 8、9 月份,我们成立了 Facebook AI research,开始叫做 Facebook AI Lab。当年 12 月份的 NIPS 上,Yann LeCun 被 Mark 说服后就加入了我们。之后改名为 Facebook AI Research。在 Facebook,我主要负责的人脸识别后端系统跟算法。2015 年,我回国和余凯、黄畅一块创立了地平线机器人。这一波 AI 浪潮来势凶猛,我们想在这个浪潮之中,顺应历史发展潮流,做一些事情。
这可能是我之前做的比较重要的工作,就是人脸识别。我的感觉是说,深度学习开始在 ImageNet 做的非常好,在人脸识别也表现的非常好。我们之前做的人脸识别工作,DeepFace 是第一次把深度学习在互联网上应用、落地的产品。我们在 2013 年底差不多做完的,2014 年上线。
当时 DeepFace 每天处理 Facebook 上大约 4 亿张人脸识别,现在应该更多了。基本上每一张上传到 Facebook 的人脸会先经过一个人脸检测,再进行后端的比对识别,向用户推荐一下说这是不是人脸。如果我们识别出来了之后,就会打一个名字,如果没有识别准的话,我们可能会列 4、5 个选项。如果说我们比较有把握,Facebook 就会把照片向用户的朋友推荐或者发一些消息,提高用户的活跃度。
这个工作我们只敢说接近人眼的性能,后来很多人它说超过了人的能力,但我觉得还没到完全超过人的能力那个程度,还是有一定的差别。因为计算机非常适合在大规模的情况下做人脸识别,这其中还有一些限制,需要人脸偏正面、偏清晰。但是对于人说,如果是熟悉的亲戚、朋友,甚至你看到一个背影,看到一点点,看到一撇,就可以看出这个人是谁。
整体来讲,在一定规模下的人脸识别,机器肯定超过人的水平,但是遇上非常难和极端的条件,机器可能还是不能达到人的水准。这个工作是深度学习之后,人脸识别领域中应用最多的工作,也被 Science 等很多媒体报道过。
再稍微简单介绍一下地平线机器人。地平线机器人成立于 2015 年 6 月,目前的总部在北京。我们在南京有研发中心,另外在深圳、上海都有办公室。在深圳,我们主要是做人工智能跟硬件相结合,在深圳是非常适合做硬件相关的生产的。我们上个月在上海刚刚成立了一个聚焦于汽车自动驾驶方面研发的分公司,位于上海汽车城,产业很聚集,进行相应测试也非常方便。
主要的员工和同事来自于百度、Facebook。我们硬件团队主要来自于 NOKIA,也有很多同事来自于微软、TI 和英伟达。目前我们还是偏研发的公司,超过 80% 的同事都是在做算法、软件硬件研发的工作。很多人有海外求学的经历,14-15% 是有博士学位的。
目前我们所做的事情主要是希望把深度学习的方法跟硬件相结合,跟嵌入式系统相结合,能够成功落地,影响大家生活。目前的主要目标是希望通过十年、二十年的努力,能够让世界上上千种设备都具有智能的功能,让大家生活更加安全、更加便捷、更加有序,具体来讲我们现在聚焦一下几个业务方向:
第一个,自动驾驶或者智能汽车。这个方向大家也有所了解,这几年非常火热,不断有大新闻曝出来。我们相信这个领域不仅仅可以国家整个社会的运行、整个社会的生活,而且也是人工智能能够发挥很大作用的场景。
第二个,智能家居或者智能生活。2015 年之前,大家听到的智能家居,归结于一个词就是 WIFI,家里的设备能够进行联网控制,我们认为其实这是不够的,还是非常不方便的。大家在外出工作的时候,经常会用手机沟通、打车。但是回家之后如果再掏出手机,点开 APP,再找到几个按纽,对家里的东西进行操控,这是挺不方便,挺不自然的。在家里,人们希望手机可以放在一边,能够更自然地跟家里各种电器、各种设备交互,这是我们的第二个方向,能够在智能家居的场景下,将人工智能镶嵌到设备里面去,给大家提供更便捷的交互方式。
第三个,智能安防或者智能安全。这是跟摄像头相关的,也是一个很好的场景,能够让图像识别技术真正地帮助大家,让这个社会更安全,让这个城市更安全。
这是我们主要做的三个业务方向。总得来说,我们希望把人工智能、深度学习、深度网络这些技术放到嵌入式系统中去,提供一个从软件到硬件,甚至到芯片的全套解决方案,帮助这些产品、设备都具有这种人工智能的功能。
我们公司叫做地平线机器人,但是我们对机器人的定义稍微有点不一样。我们其实并不特别关注那些长得很像人的,有手有脚,能跑能跳的机器人。我们认为只要是一个机器,有感知环境,自主决策的功能,慢慢就发展成机器人。我们业务或者努力方向,更多是把大家生活中的设备变得更聪明,慢慢向机器人的方向发展。这是我们希望做的事情和正在做的事情。
我们从成立之后,也得到了很多世界知名 VC 的支持,包括晨兴资本、红杉资本、也包括李开复老师。去年,我们完成了 A 轮融资。吴亚军老师对我们也很支持,她是中国非常著名的女企业家;还有 YuriMiiner,他是硅谷里非常传奇的俄罗斯大亨,他投资的早期 Facebook 等等公司,基本上属于投了就能中的。
什么是人工智能?
我们大家经常说人工智能。但什么是人工智能,希望大家有一个共识和定义。如果我们查一查百科或者说官方的权威定义,人工智能是学习和设计一种 Intelligent Agents 的学科。这个 Agent 本身能够感知环境,能够采取一些行动,提高自己成功或者是做出一件事的机会。
这个定义本身有几个点可以注意一下。首先是 Intelligent Agent 这个词,这个词语说明能够执行 AI 的载体并不是一个简单的机器或者一个电脑,有可能是一个非常大规模的、非常抽象的,能完成这些功能的设备的集合,甚至可能并不是设备,而只是一些程序。总之,这是一个非常宽泛的词。
另外,它能对环境主动感知,采取行动,实现自己一定的目标。这里包含三个含义,作为一个 AI,首先对物理世界感知(sensing),sensing 之后,相当于把这些获得的信息纳入数字化的世界,在数字化的世界之内对这些信息进行理解、分析、思考。重要的是最后一步,去反馈这个物理世界,做一些控制和行动,反过来影响物理世界,这是整个 AI 系统和人工智能系统所具备的最全面的三个阶段。
如果我们做的工作跟某一个阶段相关,我觉得这也是属于 AI 的研究。这三个环境包括 Sensing 、Thinking、Acting,也包括了很广的概念。比如说 PC 上网,敲键盘打字,是把物理环境的信息输入到了数字世界中,在比如当摄像头、麦克风,还有在汽车中的激光雷达或者是其它的传感器,这些设备把我们物理世界的信号转换到了计算机能够处理的信号。在计算机的处理中,可以对这些数据进行分类、搜索、排序,这些都是理解的过程。再之后,我们对这个世界有一个反馈,包括可以根据搜索的内容,建议一些广告,或者是对于语言的理解之后,比如说要打车哪里,它可以自动给你导航,也包括图像或者人脸识别之后,也许可以让大家找到你的名字,找到你的一些偏好,做一些科学化的设置,包括像无人机、无人车可以根据信号自主避障、寻径,这是反馈到物理世界进行控制。这些都是人工智能研究的方面。
这个不多说了,确实很火,所有大公司还有一些政府都投入了很多的精力。谷歌原来是移动为先的公司,后来说要成为 AI 为先的公司,这个趋势很多公司都看到了。Mobile 文化可能是一个很重要的浪潮了,下一个竞争会升级,升级到智能,比的是谁自动化的控制、自动化数据分析能够更快、更好。
稍微总结一下,为什么人工智能比较重要?从计算的角度可以看到,过去计算机的发展经历了大概两个时代。2000 年-2010 年左右或者更早是 PC 互联网时代。就是我们有电脑、网络,可以上网浏览。这个时代其实催生了比如说像搜索引擎、门户网站,催生了很多很伟大的公司,这是一个时代。
第二个时代是我们正在经历了的移动互联网时代,手机的发展以及 4G 网络通讯的发展。手机我们几乎是离不开的,每天不知道有多少比例的时间花在手机上看消息、去打车、找路、看小说、看电影。
未来会是什么样的时代?大家看到互联网催生了很多公司,比如说高通、苹果这些公司在那个时代做的很好,现在移动互联网的发展已经比较成熟了,机会可能并不像 5 年前那么多了。再往下看,我相信这个时代还没有结束,还会延续很多年。
新的时代也慢慢兴起,就是物联网+智能,IoT。IoT 是指所有的设备,不仅仅都要上网而且也会具有一定的智能,让这个世界更紧密地联系起来。从这个角度来讲,这会是今后 5 年到 10 年会有大的发展。
总得来说,从大的发展来看,计算机的角度有三个因素,计算、连接、智能。连接和计算现在有很大的发展,我们觉得下一步时代就是关于智能,也是关于软件方面智能的发展。
什么是深度学习?
大家都提深度学习,什么是深度学习?有一个非常简单的定义。我们有一些没有经过处理的原始数据,可能是语音、文字、图像,也可能是一些传感器得到了没有经过处理的数据。而深度学习本身的任务就是对这些原始数据进行数字化的表达,表达完成之后就可以做很多事情。做什么事情?这就跟应用相关了。
深度学习的主要定义或者是要做的事情就是端到端的学习,能够把原始数据转化为某种程度上的表征的方法,只要不是最简单的数模转换,其实都可以放到数据的框架里面来。
深度学习的历史沿革
这里还是要简单回顾一下历史,最早起源于 1957 年的 Mark I perception。从数学上来讲是一个很简单的形式,就是你有若干个输入,每一个信号输入乘上一些权重,然后经过一个函数输出,这个函数也是线性函数。这是神经网络或者是深度学习最最简单的起源了。比较有意思的是,这个数据模型当时是通过硬件的方式提出来的,用物理的连线去联接这些信号进行输出的。但是为什么它算是神经网络的起源?因为这些联线的权重不是固定设好的,如果固定设好的,那就是电路系统,这些权重通过数据自动调节改进来确定的,所以它就是 learning machine 的雏形。
当年的纽约时报就报道说这是计算机能够很快学习、走路、谈话、理解、写字,甚至繁殖的前兆吧。我们经过了60 年的发展,现在大概在 See 和 Write 左右。
当时大家对这个东西感到很兴奋,觉得这个东西潜力很大。但是这个感知机还是线性的,经过实验发现,它对一些基本的函数都没有办法建模或者描述,比如说异或 SOR。所以之后十年神经网络迎来了一个低谷期,大家觉得用途可能不是很大。1980 年,Fukushima 提出了神经网络多层的结构,但是并没有提出如何学习这个结构。1980 年包括 Yann LeCun 等,大概有三、四个人,他们都提出了类似反向传播的方式,能够把这个神经网络学出来,这就是一个非常重大的进展里程碑了。
之后,80 年代到 90 年代有一个非常快速的发展时期,大家的期望值也很高,希望可以做很多的事情,但是由于种种的限制,其实没有办法做很复杂的功能,只能做到简单的图像识别,简单的手写 OCR,之后发展趋势又掉下来了。在学术界,大概有差不多 7、8 年的时间,神经网络相关的研究基本上是很难发表的。大家都不在乎,认为神经网络不就是这样子嘛!
神经网络的再度兴起始于 2006 年,G.Hinton 提出深度神经网络。不过他当时不敢提深度神经网络这个名字。这种结构可以通过一层一层来学习,来得到一个比较好的结果。之前的网络太深,大家是学不了的。这种网络结构给大家的启发是并不需要逐层地学习,通过端到端的学习也可以实现,而且学到一定深度之后,建模能力也是比较强的。
自那之后,深度神经网络的优越性能就不断爆发。语音识别是第一个被突破的领域。IBM、微软以及谷歌等等几个公司发表了一些文章,有了很大的突破,因为之前基于 HMM(隐马尔科夫)的识别大概有 10 年、15 年没有本质性的改进了。再之后 Jeff Dean 在谷歌率先实现了大规模的深度学习网络的基础架构,当时是基于一万个 CPU,比较重要的结果就是自动学习识别出是猫脸还是狗脸。谷歌做这个事情是有示范作用的。
再之后大家就很清晰了,2012 年 ImageNet 中,微软将识别率降了 10 个百分点,这是很大的突破。之后,大家将这个技术应用到人脸识别和图像识别中。到 2014 年、2015 年时 RNN 或者带有一定记忆的程度网络开始流行,对于序列学习,以及生成文字上都有很大的提高。再之后应用到自动驾驶。
2016 年的 AlphaGO,基本上算是横空出世,一下子就把 AI 从学术界推到了公众领域中,做了一个很好的科普。2016 年、2017 年其实还在迅速的发展,包括 2016 年之前就有的对抗生成网络,2017 年谷歌刚刚公布了用 TPU 芯片方式做成网络的结构。他们应该是 2015 年就做出来了,估计这个 TPU 不是他们第一代的产品,估计是把第一代的架构公布了,现在已经做第二代。
总之从 2006 年开始,深度学习进入波澜壮阔的快速发展时期。我们希望 2020 年以后或者是神经网络不光运行在云端,用上百台的 GPU 跟大家下围棋,而是希望真正运用到设备端,来影响大家的生活。这是一些简单的历史,大家可以看到 ANN、CNN、RNN、LSTM 等等,它们基本上都属于神经网络,神经网络本身属于深度学习,深度学习属于 AI,这是一个大体的范畴。
在我们讲这些神经网络结构之前,先简单介绍一下架构,让大家有一个统一的认识。这是最简单的神经网络,只要超过两层三层以上,都算是深的网络。
这种一般叫做 Multi-layer Perceptron(MLP,多层感知机)。有一些输入层,输入层是某种数据,最终会得到一个输出,输出可以是一个数,也可能是一个矢量,是一个二维的或者是 tensor,你希望学到神经网络达到一定目的,实现你模拟所达到那个目的的函数,比如一个函数 F 从输入到输出。这个网络本身有很多的隐层,每一层有很多的节点,节点都是线性的,互相相联的,就是一个简单的 MLP。有这个结构之后,我们需要定义这个输入,然后定义这个输出,再定义一个 Loss Function(损失函数),来评价神经网络测算出来的结果跟你希望的结果是不是一致的。有了输出、输入、评价这三个过程,就实现了机器学习。
在这个学习的过程中,大量的数据放到输入层,给这个网络随机分配一些初始的非常小的数来算,算出来之后结果肯定不对。也没有理由是对的,有了这个不对的结果之后,可以反向根据这个结果与期望之间的差异,对每一个节点的参数求导。求导了之后沿着这个梯队方向,稍微修改一点点,希望能让这个结果有一点点变化,其实这个变化是没有保证的。但是只要反复按照这个方式运行,给它一个结果去前向计算,得到一个输出,跟你的希望结果去比较,计算这个误差,通过误差反过来调整这个参数以及权重,反复运行,之后就可以实现一个比较好的函数的拟和效果,拟和出你想实现的目标。
概念上说,这个每一步现在都已经发展出很多算法,你用一个数据点去算\去修改网络,可能是很不稳定的,因为你这个点的 lable 可能是错的。这时候你可能需要一个 minibatch 的方法,把一批数据结果平均一下,根据它们的方向去修改。修改的过程中,修改力度(learning rate)可以调整。开始的时候,拿不准的就学得快一慢,慢慢有把握了,就学得慢一点。
后来有一些比较新的方法,可以在这个过程中做出一些规划,让这个数值不要太大,数值上比较稳定,能快速地收敛。
这个网络的结构以及学习方法在上世纪八九十年代就有了,当时它有一些问题导致大家觉得它可能不是那么有用。包括 over-fitting(过拟合),意思是在数据不是很多的情况下,网络参数很多。这种情况,虽然可以学到一个非常好的结果,但是来了一个新的结果未必能够正确处理,这就是 Over-fitting。还有就是数据结果可能会有一些标注的错误,你不能保证你所有的标注都是 100% 正确的。另外,网络结构本身是一个黑盒子,它做什么事情,大家很难理解。
现在有了很多改进。首先 Over-fitting 不再是问题了,因为数据足够多。比如说人脸识别,如果有世界上所有的人脸来做训练,就已经没有必要 Over-fitting 了,因为你已经没有更新的数据了。如果数据足够多的话,Over-fitting 这个事情并不是那么重要。
第二,大量数据的处理需要很高的性能,大家发现用 GPU 这种新架构,并行去练,可以处理很多数据,比 CPU 效率高很多,这确实能够推动神经网络发展的一个很重要的关键因素。
刚才提到的训练中的很多新改进,包括 dropout、batchnormalization 等都对处理更多数据,快速收敛有所改进等,这些是算法上的提高。
但有一件事没有本质性的改变,这个网络结构还是属于 black magic。但是本质上还是实验出来。实验出来得到一些比较好的结构、功能,然后再反过来给大家解释一下,它总是会有一些道理。
所以今天我可能稍微回顾一下各种网络结构和它设定的原则和思考。应该指出的是,确实还没有放置四海皆可用的结构或者一个绝对正确的设计原则。有一些思考,但是这些思考是不是全面和正确,现在还不好说。这也是一个领域,大家可以继续探索研究的。
为什么深度学习现在能够获得这么大的关注,跟其他的方法是有一些区别,随着数据的,增加别的方法的性能在某一个点上不会再提升了,某种意义上饱和了,但是深度学习目前为止还没有明显地发现这种情况,增速会减慢,但不会停止。这是深度学习最吸引人的地方。对于各大公司来说,如果数据足够多,能带来性能提升,这就是非常好的事情。
网络结构越深越好?
从网络结构本身发展来看,第一个关键的问题还在深度。但是不是越深就越好?我觉得从物理上看,不应该越深越好,但是目前情况还是网络越深,性能越好。我在这里打一个问号,但是这个趋势发展还是很好的。
第二,深度学习很强大,它的模型或者说网络结构很深,参数很多,其实运算复杂度以及存储复杂度很高了。我们能否把模型的规模精简,这也是一个发展的方向。
另外这两年大家重视的是,有没有可能把这些适合于 GPU 运行的神经网络能够用硬件加速?能够进行更快的计算?能不能用嵌入式系统运算?这也是我们现在的努力的方向。
这里有几个里程碑式的工作,包括 80 年代 Yann LeCun 等人做的 LeNet5,2012 年 AlexNet 能突破性地把图像识别的错误率降了 10%。再之后谷歌 GoogLeNet 能够把网络结构的复杂程度突破大家的想象。在那之前,大家还是按照 LeCun 的方式去做。微软的 Residual Net 也是一个很好的工作,可以让网络结构变得更深,效果也更好。
通过最初的工作,大家看到 CNN 或神经网络大概的工作过程。刚才说那种多层的线性的神经网络,每一层都有很多节点,每一个节点都会连接到下一层的一个节点中去那么这就是用来处理一维数据的最简单方法。
LeNet-5
卷积神经网络有两个角度的改进。第一个是下一层的节点并不是连接上一层的所有节点,它只连接一个区域的几个节点。比如说如果你第 1 层有 10 个节点,第 2 层有 10 个节点,那么第 2 层一个节点连接一个小区域,一个局部的小区域,比如 3 个节点。在图像中就意味着你可能只是连接图像中一个小区域,一个小 patch。
第二个改进是连接这个小区域中,你的这个小区域跟连接的下个小区域的所有的连接的 weight 是一样的,这个叫做 weight sharing(权重共享)。或者说你有一个线性的卷积核(convolutional kernel)。这个卷积核,比如说 3×3 的卷积核,有 9 个数,这 9 个数拍在这个空间上去算一个卷积,平均一下再拍到另一个空间,也算一个卷积。这几个卷积中的卷积核本身是一样的。所以从原来最开始那个 MLP 向下发展到 CNN,定义出了一个卷积的概念。就是这两点不同。
第一,下一个节点,就是第二层节点只连接上一层的局部的几个输入。第二,这几个局部输入位置在空间上是共享的、固定的。你有一个输入之后可能会有几个卷积核。如果你有一个卷积,一个 filter,然后通过扫描方式,或者放一个点,乘加一次就算出一个数来,就会得到这边的一个点。你有一个卷积函数的话,就可以得到这边的一个区域,叫 feature map。如果你有六个卷积的话就是 6 ×28×28,那就是你做了 6 个卷积把输入图像从 32×32 变成了 28×28,那是第一层的卷积操作。然后你需要一些降采样。
当时 LeCun 为了计算量比较小,立刻就降采样了。降采样之后还是 6 个 feature map。之后他在 C3 层定义了 10 个 feature map。这 10 个 feature map,每一个卷积核在这 6 个卷积核的 6 个 feature map 上,上一层的 6 个 feature map 上也进行卷积。空间上不断地移动。卷积了之后把结果线性组合一下。线性组合本身的所有参数都是学习到的。线性组合得到下一个层的 feature map。你有 10 个,那么就重复 10 次这个过程,就把这 6 个 feature map 变成了 10 个。
事实上,LeCun 在处理这个工作的时候是处理不了这么多的。就是说 6 个 feature map 对应 10 个 feature map,他其实是随机选了一下。可能只有一个 C3 层的一个 feature map 是对应于 6 个,其他几个是对应之前的 3 个或 4 个。
当时 LeCun 的文章解释说是为了破坏对称性,就说不要完全对称。
但我觉得主要还是计算量的原因。最后类似地你可以再把规模降小一点,进行降采样,然后做一些全连接。全连接就是指每个输入跟下一层每个输出全连接在一起,这不是一种卷积形式。
当时这个结构有大概是 6 万个参数,能识别手写体的数字或者是邮编。LeCun 他们把这做完之后还真的实现产品化了。当时它发展到可以处理美国 1/3 的邮件的手写体识别,这应该是八九十年代最巅峰的工作了。
到了 2012 年的 AlexNet,结构本身没有本质性的提高,但是规模大了很多。
AlexNet
LeNet-5 是 6 万个参数,那么 AlexNet 是 6000 万个参数。
分成上下两层,输入的是 24×24 的图像,之后第一层是 11×11 卷积,也是一个 11×11 的卷积的滤波器,放到图像上去,开始平移,乘加,平移一次,算出一个点,算出来之后做一次采样。
采样是指你有几个点,你挑一个点使用。这个采样叫 pooling。比如你有 4 个点,取 1 个最大的,那就叫 Max pooling。如果说有 4 个点,平均一下就是一个值,那就是 average pooling。只要能够把多个点变成一个点,那么这种某种方式就叫 pooling。
做完 Max Pooling 之后,继续卷积,去做 Pooling。
本质上结构跟原来是一样的,只是大了很多,以至于当时的 GPU,用一块是训练不了的,所以同时用两块去训练。当时一个 GPU 的内存可能是 3G。训练的时候开始对输入进行一些归一化,要加一些 dropout,就是随机的在训练过程中把一些节点设置为 0。
在神经网络中,很多连接、很多节点,每个节点可能都会输出一个值,做一个 Activation,输给下一层。那么本来是说每个节点都会对最终结果有贡献,那么 dropout 就是在这过程中随机性把 50% 或者 40% 的节点的输出置为 0,让它没有贡献,那这样你训练得到的分类结果,就不能依赖于所有节点都正常工作,或者所有的信息都能收集到。这种情况下,如果还要得到一个好结果,那么你在测试的时候,就不会非常依赖于这些数据要跟之前的数据很像,或者是见过的数据,这样的话你就能处理一些未知的数据。这是当时就是 AlexNet 的改进,但是本质网络结构本身还是相当。
VGG
这之后一个有名的工作是牛津大学做出来的 VGG。他们其实是把 AlexNet 这种网络结构推到了极致。
一个主要的一个变化是基本上主要采取最简单的 3×3 的卷积。他们觉得 3×3 的卷积就可以完成任务了,此时的层数是到了 19 层,参数又多了很多,之前可能是八九层。基本上来说,VGG 某种意义上就是把 CNN 推到了极致。
Network in network
2014 年的一个比较重要的工作是颜水成他们在新加坡做的 Network in Network。
之前的网络是一层一层去卷积,还是比较规则的。而颜水成做的工作是设计一些小的网络。大的网络是由一些小的网络来组成的。小的网络,比如 11×11 的卷积,在卷积之后加了一些 MLP,多层的 Perceptron,就是说每个输入层跟输出层都是全连接的、线性的网络连接。
另外一种意义上讲,可以把它看成一种叫 1×1 的卷积。1×1 的卷积就是指它在空域上就是一个点,所以它就没有把周围的空间信息做聚合了。但是它在不同的 feature map 之间做了一个线性组合。比如说你有 96 个 feature map,那么你可以把 96 个 feature map 在某一个点上进行组合,再生成下一层的 feature map 一个点。采取比较少的 1×1 的卷积,你就可以把这种 96 个 feature map 的个数变小。你也可以考虑把它变多,比如你用这层是 96 个,下层用 128。但比较有意义的一个作用是,在这种结果下变小了之后,再进行下一级的一个小的 In Network。
我觉得这个工作一个重要的价值在于把大家的思维给稍微解放了一点。原来纯粹就是不断地去加层数,加 feature map 个数、滤波器的个数,像 VGG 那样可能也已经差不多到头了。VGG 的参数已经非常多非常重了。现在我们加一些小的网络,在小的网络中间,我可以把一些维数,再降低一点,降低了之后,我们可以再加点网络,就可以使网络变得更深。变深之后确实是还是有些提高的。
GoogLeNet
受 Network In Network 的启发,2015 年,谷歌某种意义上讲就 go crazy 了,他们当时做的应该是有 30 多层网络,很复杂。但其实基本上是分成两个部分。一部分是开始这一部分,还是比较传统的卷积,然后 pooling 的方式,之后就是累加了很多这种 Inception model。
Inception model 是什么样的呢?就是你有一个 Previous layer ,就是上一层,那么你做一个 1×1 的卷积,就相当于把很多 feature map 给平均了一下,或者线性组合了一下。
这个过程可以减少 feature map,再做一些个 3×3 跟 5×5,做一些 pooling,再把这些个卷积层、卷积的 feature map 的结果拼在一起,作为下次的输出。它能把这个单元作为一个独立单元放在后面,后面都是类似结构单元。
每个单元其实蛮复杂的,这个复杂的一个小单元,从设计上讲,借鉴了刚才那个 Network in Network 的思路,放了一些 1×1 的卷积,必须把这 feature map 减小,否则都用 3×3、5×5,那么其实还是会很大的,会很难训练的。
一个小单元内部考虑了 1×1 考虑 3×3,或者 5×5,实际上是说捕捉到了不同 scale 大小的图像信息。有的分类问题可能需要要看非常 local,或者非常小的图像的结构,而有的分类问题需要看到大一点,那么它的一个小单元其实是包括了不同的信息,1×1、3×3、5×5。但是如果直接这么用,可能会出现 feature map 太多,参数太多,学得比较困难,所以先用 1×1 卷积把它稍微降一点,把 feature map 层数降一点,组成这么一个单元,在这个单元拼到后面,拼出 30 多层来。
层数越深,性能是会提高的,但是训练的难度会增加。当时为了能够快速地训练,去收敛,不会把训练给训崩了,就加了几个分支,在那个分支上,把正确图像分类的信息也加上去。先训练一些个小的网络,再不断加深,做了几个分支。这是当时所需要的,后面一些改进可能,也就不需要这些分支了。不需要这些个分支,也可以训练出来比较深的网络,那时候是 30 几层。
这是第一个是 GoogLeNet 是他们的第一个版本。之后他们又推出了几个版本。在这个过程中他们对网络结构做了一些思考和总结。
第一,在网络结构过程中有很多层,你尽量避免在早期的时候触碰瓶颈,或者说 information bottleneck。比如说你有你有 10 层网络,第 1 层有很多卷积,第 2 层就放 1 个卷积核,就 1 个 feature map。甚至再极端一点,那个点就一个输出,也就是说一层之后,到第二层就只有一个数。那么你可以想象,后面无论加多少层,结果都不会好,因为信息都被浓缩到了一个数之后,就不可能再把它发散出来。
所以他的第一个想法就是说,你尽量避免在比较早的时候有一些信息的瓶颈,导致信息传递不出去。其实这也是一个比较直观的想法,因为我们现在需要多层的网络,是希望它通过训练之后,到最后一层抽象出比较好的一个表达,去做分类、检测或识别,而不是在开始的时候,信息就没有了,后面就更不可能得到了。
举个例子。比如说是图像是一个小 patch,就是 35×35,其实不一定是图像,就是一个二维的数据,35×35 的,你有 320 个 feature map,那么到第二层,把它限制成 17×17,然后有 320 feature map,之后后面一级,把它升成 17×17,有 640 个 feature map,那么这 640 个 feature map 就很有可能学不到特别多的信息了,因为你已经把它缩到 320 了。所以这是他这个图的意思是,如果中间加了一个瓶颈,后面学到东西可能就不会那么多。
这个怎么改变。如果不想有瓶颈限制,那么第二子集也还是 35×35×640。信息是增加了,没有瓶颈,再缩减下去,变成 17×17×640,所以最后输出都是 17×17。左边有瓶颈,右边没瓶颈。虽然没有瓶颈,但是 35×35×640 是一个非常大的 tensor,有很多参数要学,比左边那个 17×17×320 图多了八倍。
所以说如果是简单地为了没有瓶颈加很多 feature,可能解决这个问题了,但是代价就是要学很多参数。你的数据要求很多,其实很慢。
怎么去解决?首先左边这一个结构是用 1×1 的去降维,这样缩小 feature map 的个数,再统统去做卷积,另外就是说我可以把它拆成两个并行的小网络,左边是 17×17×320,右边是 17×17×320,然后把它们拼在一起,结果还是 17×17×640 个 feature map。但是中间那两个小网络是并行的,它们的参数是相加的关系,能够容纳信息的量也比原来的 17×17×320,翻了两倍。通过这种方式同时保证了参数不是特别多,也没有信息瓶颈。这是他们当时关于设计网络结构的思考。
第二个是思考是,做一个 3×3 的卷积或者 5×5 的卷积,实际上是把图像中 spatial 的信息聚合到一起了。这种聚合其实是可以用低维的卷积核来实现的。这就回到了 3×3 的卷积有什么特殊的这个问题上。
其实没什么特殊的。那为什么用 3×3,不用 5×5 、7×7 的卷积?这个时候有一个解释是说,用 5×5 、7×7 的卷积是可以的,但是这些卷积本身其实可以,用 3×3 的卷积来表示,因为卷积本身其实是线性的。你用两个 3×3 去做,是可以等价于一个 5×5。
与其用一个 5×5,不如用两个 3×3 的两级。好处是每一级的计算量减小了,每级最后作为卷积之后,还会有一个 activation function,还能加入一些非线性的信息和变换。所以与其用比较大的卷积核去做网络,还不如用多层、多个小的卷积核去等价它,这样节省了参数,又增加了网络的非线性。整个神经网络它能够学习,能够去能建模很多东西很多内容,是因为它参数很多,同时也因为整个网络是非线性的函数而不是一个线性函数。
到这个时候大家对 VGG 用 3×3 的 kernel,有一个更好的解释,用小的 kernel,用多级,其实比用较大的卷积核有好处。进一步推一下,3×3 其实还可以进一步去等价于一个 1×3 和一个 3×1,就是一个水平的一个卷积,再加一个竖直卷积,用进一步拆分的卷积去聚合空间上的信息。所以他们在设计这个网络的时候,就用了一个在 17×17 的那一级上,用 1×7 跟 7×1 的卷积,这样一来,聚合了比较多的信息,但是一个 1×7 再加上一个 7×1,是 14 个量级的参数,比直接一个 7×7,参数小很多,但是层数就深了很多。
所以这也是后来我们为什么可以进一步看到,网络越来越深的一个理由. 用更深的网络、更少的参数去近似一些比较大的 kernel 很有可能是有好处的。
第三个总结是指导原则。在高层的一些网络的最后几层中,一个点代表着最开始输入图像当中的一大块区域。如果说原始图像中哪些区域可以影响到最后的一个点,那么在最后几层的一个点,是有一大片区域可以影响的。这个区域,某种意义上来说,是这个点的 receptive field,意思是它能够去影响的区域。那么在最后几层的时候,你就不应该去用一些很大的卷积核,尽量用一些小的卷积核,他写的是:
Higher dimensional representations are easier to process locally.
所以你最好有些小卷积核,可以总结很多空间上的信息。他们当时在最后几级 8×8 的规则上面是用这种很小的卷积核。
总体来看,第一代的 GoogLeNet 中,他们估计也没有搞清楚为什么要这么设计,之后就做了很多实验,总结出一些设计的指导思路。
最后一个总结是,要平衡网络的宽度跟深度,你当然可以搞得非常深,非常窄或者是非常宽。但是基本上应该有一个大体的平衡。
ResNet
下面一个是微软 MSRA 的非常好的工作:Residual Network。他们当时发现用一个神经网络去模拟一个函数,虽然说无论多复杂的函数,我们都可以模拟,但是发现层数很深之后,性能提升就会变慢。这并不是由于 Over Fitting 引起的,而是由于训练中可能有些数值的问题引起的。微软的一个很好的想法是,与其去模拟一个函数,还可以模拟函数跟原始数据的差。我们不去模拟输出 y=F(x) 的 F (x),模拟这个 F(x)-x,模拟残差。
这个是一个很好的想法,反应到网络结构上去,就是这边可能还有一些常规的卷积,有一些矩阵操作。那么有一条通路,竖向本身直接到最后,去跟模拟的结果做一个加法,之后再有一个 activation function,一般都用 ReLU,就是说负的地方是零,正的地方是线性,通过一个非线性函数去输出。通过这种方式,你在右边分支,这个小的网络结构模拟的就是输出-x,是残差。所以这叫 Residual Network。通过这种方式,你就可以进一步的把网络加深,他们都尝试了。有一个版本是 101 层,还有一个版本是 152 层,这是微软做出的很好的工作。
Inception V4
后来,谷歌的人觉得,我们要说明我们的 Inception 网络结构一样可以做得很深,一样可以做到很好。这就有了 Inception V4。
整体结构是这样的,第一步输入图像,有一个叫 STEM。开始的几层是比较常规的,做一些 3×3 的卷积。之后涉及到 Inception A B C。让 A 在 35×35 的 grid(网格)上去做卷积,B 是在 17×17,后面那个 C 是在那个 8×8 的 grid 上做卷积,然后再设计出这个结构。这些结构就符合他们之前说的那几个设计的思想。就是尽量用 1×7、7×1 的这些卷积,去把大的卷积核拆开。第二层是用 1×7、7×1 的卷积。在 8×8 最后那几层,要尽量用小的卷积核,这样也把网络结构变得非常深。
他们做了一些实验,跟 Residual Network 去比,认为加入 Residual Network 一个连线直接把输入信号传下去,是会有帮助的,但是也不是必须的。这个结论本身不好评价。只是说他们至少在 ImageNet 任务上,错误率只有 3.5%-3.6% 左右。但是是不是用了 Inception Network 就可以提高呢?我觉得这还是没有结论的。
稍微总结一下。至少在 ImageNet 上,设计神经网络时要考虑以下因素。一个是性能,就是准确度怎么样;一个是网络模型的大小,就是有多少参数;一个是运算量,就是有多少个 operation。下面的图就把刚才提到的所有网络结构做了一个很好的总结。
可以看到,至少到目前为止,Inception V4 设计得很复杂,用了那几个原则去指导去设计,性能确实是略高一点,参数至少比 AlexNet、ResNet 还少一些,计算量也是相当。所以设计复杂的结构还是能够获得一些收益的。
全卷积网络
还有一个比较重要的工作是全卷积网络(Fully Convolutional Network),它可以做比较合理的分割。这种网络结构本身是正常的,但是最后输出到一个跟输入是相当大小的 pixel-wise prediction。它就可以去对每个 pixel 做一个 lable,就是给一个分类,比较适合做分割。我觉得这个工作比较好,虽然网络结构并不是特别特殊,但是我还是把它列在这里。
以上这一系列网络结构的发展都是在 CNN 框架下。基本上是你给我一个输入,我就算出了一个输出,你再给我一个输入,我又算出了一个输出。这两个输入跟输出,跟结果之间是没有关系,没有任何记忆的。所以在这个范围内,我们可以看到,从 AlexNet9 层,到 GoogLeNet 30 层,到后来现在 ResNet100 多层,到 Inception。
从 RNN 到 LSTM 和 GRU
与 CNN 相对的另一种思路是把网络中加入一些记忆的单元,某种意义上讲,也是使网络深了很多。
我们可以看到原来的一个神经元,就是说你有一个输入 X,你有一个输出,这个过程本身是无状态,无记忆的。第一个想法就是,我们是不是可以加入记忆,或者加入一些状态。每个神经元本身有一个状态,那么你的输出就不止决定于当前时刻的输入,还决定于本身实际上存的数据,两个数决定出一个输出。如果你做这方面的改进之后,本身有个状态,状态本身 X 乘上一个 W,跟你输入 X 乘上一个 U,最后经过 V 输出 O。这个结构本身也可以等价的看成一个很深的网络,从时间上讲它是一个很深的网络。Xt-1 是 t-1 时刻的输入,有个状态 St-1,那么下一个时刻就相当于,St-1 跟 St 决定输出,同时也决定状态 St,再决定下一个时刻。如果你考虑神经元有了状态跟记忆之后,从逻辑上讲或者概念上讲神经网络本身就等效于一个非常非常深的网络。
所以这是另外一个角度把网络变得 deeper 的一个方面。这种方式被称为 Recurrent Neural Network——RNN,后面有一些发展,一个就是 LSTM——长短时间记忆,还有一个简化版就是 gated recurrent network。
概念上简单地来说,我们加了一个状态,那么每个神经网络神经元就记住了一个数,那么这个数会对多长时间的预测有影响呢?是可以记住一个时间单位,还是十个时间单位还是一百个时间单位?从道理上讲,其实没有限制,你可以记录很多时间单位,但实际上其实是很难控制的。这里的一个改进就是 LSTM,它把长时间的记忆跟短时间记忆比较显式地在网络结构中描述出来。
这是 LSTM 网络。看上去蛮复杂的,它有三个门,或者说三个小的神经网络单元,来决定什么信息去记忆到这个神经元里去,什么信息去输出,什么信息去更新自己的状态。这个 Xt 就是指 t 时刻的输入,Ht 是 t 时刻的输出,还有一个 Ct 是这个 cell 或者结构本身记录的信息的内容。
首先,你有一个输入,就是上一个时刻的输出跟现在时刻的输入来决定你有多少信息会继续保留在这个单元,叫 forgetting gate,在这里是 Ft。下一个需要的是上一时刻的输出和现在时刻输入来决定当前的内容,就是 Ct。C 是 cell 本身的内容,意思是有多少信息是继续保留。所以通过那个 [Ht-1,Xt],算出来一个 It 那个 Sigma 就是 whatever 一个函数了,一个 activation function。Wt 是某种意义上你会学到一个 weight,一个矩阵。重要是 Ht-1 跟 Xt 决定了一个 it,it 去决定 Ct。也就是说什么信息能继续保留下来。ft 是指需要多少记忆去忘记,它和 Ct 这一时刻,这二者会做一个线性组合去决定 Ct,决定继续保留在这个时刻这个单元里的信息内容。最后还有一个 Ot,就是输出的 gate,就是说决定一下 Ht-1 跟 Xt,去学习一些参数,去决定哪些作为下一个时刻输出。
虽然看上去是很复杂的,但是总的来说,从概念上讲,就是上一时刻的输出,跟现在当前时刻的外界的输入,去决定哪些信息是继续保留的,哪些信息是需要遗忘的,哪些信息是需要输出的。那么这个建模能力就比较强,可以说是很全面很综合了。更重要的是,这些函数本身都是可以根据你的输入数据学出来的,也就是说,对于每一个这样的单元,哪些是记性型记忆,哪些记忆型输出 哪些是保留都是可以学出来的。
其实后面会有很多变种,比如说你可以看到这些所有的信息输入的函数都是 ht-1 的一个 It,就是说只由上一时刻的输出,跟当前时刻输入决定。那么你可能也考虑到当前那个状态 Ct,那就是一系列 RNN 变种了。
一个比较有意义的变种是它可以把这个 RNN 进一步简化,而且它的性能可能接近的就是 gated recurrent network、gated recurrent unit。就相当于把刚才有三个这种控制的门,forgetting gate、input、output。把它合并成两个,变成 zt 跟 rt,其中一个还是控制输出。另外一个就是说,原来是 ft 跟那个 rt 两个数字去控制哪些信息继续保留,那么现在要合并成一个 zt。就是说我只考虑这一个因素。你哪些信息保留,1-Zt 跟那个 Zt 平均一下。我觉得目前看来这是比较 promising(有前途)的一个改进了。它进一步简化了,而且建模能力还是相当的。
这一系列工作为的是如何让 network 更深,而且是在时间运用角度上更深。
Fixed point neural network
前面两块内容基本上介绍了一下神经网络结构如何变得更深或者网络结构的发展。下面再简单介绍一下另一个方向,让网络变小,或者是参数量变得更简单或者参数量变少。简单的意义是讲原来那些参数都是,比如说 floating point,32 位的 floating point,或者是 16 位的 floating point。那么下一步的工作是我们能不能把这些参数用一些 8 位的定点,或甚至一些二值化(Binary)的+1 和-1 这些数来表示。这些工作可以让网络变得更轻量级,所需的存储更小。
所以这一个工作是把这个网络定点化,第一步主要是把这些参数进行量化,这一系列的工作我觉得到极致了,就是可以 binary——二值化的网络。如果你把网络结构每个参数、每个权重都二值化,这样就非常非理想,适合用硬件去实现,而且效率就会高很多。
这里有一个简单的比较。之前如果是浮点运算的话,那每个卷积其实就是乘加运算,就是一个核往那一放,对应位置相乘,乘完之后累加,得出一个数。如果是二值化的网络,就变成了一种 XNOR 的操作,加上 bit count 相乘,就是做一些反的亦或,然后去累加,其实就是去数到底有多少个 0,多少个 1,是奇数个 1,还是偶数个 1,决定出结果。这个操作不仅简化了而且也更适合硬件来实现。
一个比较好的一个工作是它如何去训练这样的一个二值化的网络。二值化网络在训练过程中的梯度还是用浮点来表示的,否则你没办法去计算梯度,去更新这些 weight 了。在反向传播的时候仍然要用浮点去表示,但网络在正向去算的时候,就强迫它们每个节点、每个 activation 输出都是二值化的,可以通过进行限制一下范围或者做一个直接的量化来变成二值。所以正向的是二值,反向的时候可以用浮点操作,去更新这些参数。
有一些比较新的工作证明至少目前在一些小的集合上,比如 Cifar 10,它的性能跟浮点是很接近的。它的存储空间可以想象一下,如果从 32 位浮点直接变成二值,大约是能够简化 32 倍了。
所这也是现在神经网络结构发展一个很重要的方向,用网络结构表示精度,去简化,能够更适合硬件的使用。
下面有一些比较具体的操作,能保证训练成功。因为表示的精度变差后,还要训练出来一个比较稳定的性能比较好的网络结构是需要一些 trick 的。
这些技巧跟网络结构本身没有关系。实际上深度神经网络结构本身有改进之后,它对很多工作都是有帮助的。我没有谈具体的分类、检测或者分割但是,实际在很多任务上,任务本身的 formulation 是没有变的。
什么变了呢?变的是这种最复杂的需要建模那个部分替换成神经网络,这边就举一个简单的例子,强化学习。
强化学习
强化学习,Reinforcement Learning 是现在相当火的一个概念。强化学习、监督学习、非监督学习都属于机器学习。监督学习(supervised learning)的每个数据都有一个标注的结果后,你学到一个集合函数。无监督学习(unsupervised learning)没有标注,就要学出一个函数来去拟合。强化学习(reinforcement learning)不是给定了标注之后再学习,而是一步一步在一种 online 的状态下去学习,这种学习你告诉它好坏,它每次去做一点改进。所以 Reinforcement Learning 跟 Deep Learning 之间不属于隶属的关系,而是不同的 learning Paradigm——学习范式。
Reinforcement Learning 存在很多年了,最近我们看到它在围棋,或者一些自动控制的任务中,都有很大的改进。改进的本身是指最核心的一些部分现在用了深度神经网络去做近似。
所以 Reinforcement Learning 这个概念本身就是说我是一个 agent,是能够去自主做决策的实体。我用一个大脑来表示,它可以感知周围的状态、环境,它会挑选一些它能选择的 action 去影响环境。影响环境之后,环境的状态会改变,同时给出反馈,一个 reward,也会更新自己的状态。这个过程是一步一步的:给一个 action,得到一个反馈改变了环境,改变了自己,再不断地去改进——希望我的 reward 能够最大化。这就是强化学习的过程。
Agent 在学习如何最大化自己的利益时,有两个很重要的函数。一个是如何去选择采取 action 的方法,到底是用什么策略去选择采取什么行动,这个一般叫策略函数(policy function)。另外一个是能够去选择这些方法的原因。它自己对这个 action 能带来的这种反馈,会有一个评估,这个评估叫 value function(价值函数)。
这些概念其实都是早就有了。现在 policy function 和 value function 本身就是比较复杂的函数。用深度神经网络去模拟深度的 DNN,让 DNN 去模拟去近似。最著名的应用是在 AlphaGo 里了,我就不多讲了。它将 policy network 和 value network 都用 CNN 去表示、去近似。
这里就把它作为一个例子,说明这些深度神经网络本身的结构在不断发展,它的建模能力不断提高。提高之后,它就可以用来近似任何任意的比较复杂的函数。如果具有近似复杂函数的能力,那么对很多任务就有很大的帮助,包括增强学习、图像识别、语音控制。比如在今后的无人车控制中,可能会用这种强化学习的方式去不断地改进、去选择自己的路径。但是对于路径本身,其实没办法用一个很简单的一个函数去规定好每次获得什么输入之后要去做什么样的改变什么规划什么路径。
这个肯定是很复杂的函数。这些函数可以用之前所介绍的那些神经网络中比较好的一些来做。也就是说,你有一个很好的神经网络结构之后,你就可以潜在地用它去做一个非常复杂的非线性函数的模拟,然后可以完成很多任务,这个在很多应用中都会有帮助。
OK,这基本上就是我今天想分享的内容。
点击阅读原文,报名参与机器之心 GMIS 2017 ↓↓↓