Introduction
Introduction
来自中科院计算所博士师兄的建议
作者简介:刘昕,中科视拓CEO,工学博士,毕业于中国科学院计算技术研究所,师从山世光研究员。主要从事计算机视觉技术和深度学习技术的研究与工业化应用。
编程语言与DL框架的选择
当然,作为开发者,想要去实现一个模型,绕不开的问题便是:
应该选择什么语言?应该选择什么框架?
对于开发人员而言,语言的选择其实不是问题。但作为入门,最为理所当然的建议则是Python,原因也非常简单:Python最好学。
对于机器学习的学习,使用Python就意味着你不必分心去学习那些复杂的数据类型约束以及转化、指针、内存管理或垃圾收集之类的“高级”(一般同时也代表着复杂)的特性,将精力集中在自己的目标上。当然,一些Python特有的方法(如lambda、yield或reduce)以及工具(如NumPy、pandas),还是需要多多使用,尽快熟练。
而框架方面,从使用者的维度去划分,当前数量非常之多的机器学习框架,则可大体上分为两大阵营。
学术友好型: Theano、Torch与Caffe
学术研究时,弄出来一个新模型、新算法、新函数是常有的事,做出新的突破也是学术研究最基本的要求。所以,这些框架通常都便于定制模型,也可深入修改内部实现。很多新成果都会在发表论文的同时,提供这些框架上的实现代码以供参考。它们在性能方面也比较出色。
其代价就是,要么是使用了困难(Caffe:C++)或小众(Torch:Lua)的开发语言,要么是有一些古怪的缺点(Theano:编译超级慢)。
而且,这些框架似乎都没怎么考虑过“怎么提供服务”的问题。想要部署到服务器上?Caffe已算是最简单的了,但仍要经历漫长而痛苦的摸索历程。
工业友好型: Tensorflow、MXNet与Caffe
工业上往往更注重“把一个东西做出来,并且让它运行得良好”。所以这些框架首先就需要支持并行训练。其中Tensorflow和MXNet支持多机多卡、单机多卡、多机单卡并行,Caffe则支持单机多卡,虽然性能还不是特别理想。
在我们的测试中,Tensorflow的双卡并行只能达到单卡的1.5倍左右性能,卡越多,这个比例越低。Caffe要好一些,但参数同步和梯度计算无论如何也都需要时间,所以没有哪个框架能在没有性能损失的情况下实现扩展。而多机情况下,性能损失更大,很多时候都让人感到无法接受。
相对来说,只有Tensorflow提供了比较好的部署机制(Serving),并且有直接部署到移动端的方案。而MXNet和Caffe则是直接编译的方式,虽然也能实现,但是说实话,依然很麻烦。
至于缺点,除Caffe之外,其他两种框架对于学术界动态的跟踪都不太紧,Tensorflow到现在都没有PReLU的官方实现,前不久才刚推出一系列检测(Detection)的模型。MXNet这一点上要积极些,可是受限于较小的开发者社区,很多成果都只能等待大神们的contribution,或是自行实现。
这样看来,难道最好的框架是Caffe?既能兼顾学术和实现,又能兼备灵活性和性能兼备……说实话,我的确是这么认为的。但前提是你懂C++,如果出身不是C++开发人员,相信我,这门语言也不比机器学习容易多少。
所以,对于大多数有志于投身于机器学习开发(而非研究)的同学们来说,我推荐首选Tensorflow作为你的第一个开发框架。除了上述的优点之外,最主要的因素是它人气高。遇到任何问题,你都可以找到一群志同道合的伙伴们去咨询,或是一起研究。对于初学者而言,其重要程度不言而喻。
实战上手的数据
上过课程、学好语言、装好框架之后,自然就要通过亲手编程,来把自己的模型实现出来。
但在深度学习领域,没有数据的模型就是无源之水,毫无价值。而目前流行的监督学习,要求必须有足够的带标注数据来作为训练数据。那么,从哪里能得到这样的数据以进行学习呢?答案就是公开数据集。
例如,在学习论文时,如果它提出了一个性能优异的模型或者方法,通常会附有在几个公开的标准数据集上的成绩,这些标准数据集就是可以去下载来学习和使用的资源。另外,诸如Kaggle和天池之类的机器学习竞赛,其比赛项目中也会提供很多数据集供学习和测试。这些就是学习阶段的主要数据来源。
以CV领域为例,常见的公开数据集就包括以下这些。
MNIST
不论选择哪本教材、哪个框架,在刚刚接触机器学习的时候,一定会接触到MNIST。它是由Yann LeCun所建立的手写数字库,每条数据是固定的784个字节,由28x28个灰度像素组成,大概长成这样:
目标是对输入进行10-分类,从而输出每个手写数字所表示的真实数字。
因为它体积小(10M左右)、数据多(6万张训练图片)、适用范围广(NN/CNN/SVM/KNN都可以拿来跑跑)而闻名天下,其地位相当于机器学习界的Hello World。在LeCun的MNIST官方网站上(yann.lecun.com/exdb/mnist/),还贴有各种模型跑这个数据集的最好成绩,当前的最好得分是CNN的,约为99.7%。
由于该数据集非常之小,所以即便是在CPU上,也可以几秒钟就跑完NN的训练,或是几分钟跑完一个简单的CNN模型。
CIFAR
而打算从图像方面入手的同学,CIFAR数据库(官网:www.cs.toronto.edu/~kriz/cifar.html)则是一个更好的入门选项。
该数据库分为2个版本,CIFAR-10和CIFAR-100。顾名思义,CIFAR-10有10个分类,每个分类有5000张训练图片和1000张测试图片,每张图片是32x32像素的3通道位图,如图2所示。
而CIFAR-100则有100个分类,每个分类变成500张训练图片与100张测试图片,但图片的大小并没有什么变化。
之所以它比MNIST更适合作为图片处理的入门,是因为它尽管分辨率较低,但却是三通道、真实拍摄的照片。其中有些图片的背景还略微复杂,更贴近我们真实的图片处理场景。相对而言,MNIST的灰度输入和干净背景就显得过于简单,况且99.7%的准确率也确实难有提升的空间。
ImageNet和MS COCO
至于ImageNet(www.image-net.org/)和COCO(http://mscoco.org/),则是两个工业级别的图像数据集。通常提到它们时,ImageNet指的是ILSVRC2012的训练集,而COCO则是COCO-2014训练集。
ImageNet有大量的图片(一百多万张,分成1000个分类)和标注。
COCO虽然图片数量少一些(8万多张,80个分类),但每张图片都有轮廓标记,并且附带分类标注和5句描述话语(英文)。其图片大致如图4。
所以当我们进入实际工作的阶段,就要根据具体的需要从中选择适合自己的数据集,以作为benchmark或是pretrain数据集。
实战阶段的学习用机配置
接下来,我们就需要一台机器来把框架搭建起来,以编写和运行我们的helloAI。然而,我在很多地方都看到小伙伴们在问
(1)我需要什么样的配置能学机器学习?
(2)我需要买块GTX1080/TITAN/Tesla吗?
(3)我应该装几块显卡?一块?两块?还是四块?
而答案也往往倾向于:
“必须得有GPU啊,至少1080,没有四路Titan你都不好意思跟人打招呼!”
其实,并不完全是这样。
如果仅仅是入门和学习,CPU或GPU完全不影响你对代码和框架的学习。运行MNIST或CIFAR之类的玩具数据集,它们的差距并不大。以我的机器为例,运行自带的CIFAR demo,i7 CPU和GTX 1080 Ti的速度分别是770 pics/s和2200 pics/s。GPU大概有不到三倍的性能优势。所以,差距其实也没多大。
这里还有一个小窍门,就是想用CPU版本的Tensorflow,最好不要用pip下载的方式,而是自行编译。因为在开发机上编译时,它会自动打开所有支持的加速指令集(SSE4.1/SSE4.2/AVX/AVX2/FMA),从而使CPU的运算大大加快。根据我们的测试,在打开全部加速指令集的情况下,训练速度大概会有30%的提升,而预测的速度大概能提升一倍。
当然,如果真想用一个复杂模型去处理实际的生产问题,模型的复杂度和数据量都不是CIFAR这样的玩具数据集可以比拟的。如果用我们的一个生产模型来运行CIFAR数据集,其他参数和条件完全相同,它在i5/i7/960/GTX1080/GTX1080Ti下的速度分别是:19/25/140/460/620(单位pics/s,越大越好)。这里就能看出差距了,1080Ti大概是i7 CPU的25倍。而在模型上线使用(inference)时,GPU也会有10-20倍的性能优势。模型越复杂,GPU的优势越明显。
综合来看,如果仅仅是入门时期的学习,我建议先不用专门购买带GPU的机器;而是先用你现有的机器,使用CPU版本,去学习框架和一些基础。等到你对基础已经掌握得比较扎实,那么自然就会形成跑一些更复杂的模型和更“真实”的数据的想法,这时候再考虑买一块GPU,以缩短训练时间。
在选GPU时,我听过一些朋友们推荐GTX1070×2这样的选择。理论上讲,1070的性能大概能达到1080的75%,而价格只有1080的一半,从各个方面看,似乎都是双1070更有优势。然而不要忘记,双卡的性能是不可能达到单卡的2倍的,在目前的Tensorflow上,大概只能达到1.5倍上下,算下来其实和1080单卡差不多。而双显卡的主板、电源与机箱散热都需要做更多的考虑,从性价比上来看,未必真的划算。
不过,如果显卡预算刚好卡在5000-6000的档位,双1070也有它的优势。比如,可以学习使用多显卡并行计算的用法,在不着急的时候可以用两块显卡同时跑两个不同的任务,合并起来就相当于有了16G的显存等等。考虑到这些因素,双1070的确是最适合入门学习的选择——如果买不起双1080/双TITAN的话(笑)。
如果你有打算用笔记本来作为主力学习用机,我的建议是:最好不要,除非你使用Linux的经验很丰富,或是不打算用GPU加速。很多笔记本在安装Liunx后会出现驱动方面的问题,而且使用GPU加速时的高热量也会非常影响系统的稳定性。如果没有很丰富的经验,经常会在一个小问题上卡掉几个小时宝贵的学习时间。
深度学习高手该怎样炼成?
深度学习本质上是深层的人工神经网络,它不是一项孤立的技术,而是数学、统计机器学习、计算机科学和人工神经网络等多个领域的综合。深度学习的理解,离不开本科数学中最为基础的数学分析(高等数学)、线性代数、概率论和凸优化;深度学习技术的掌握,更离不开以编程为核心的动手实践。没有扎实的数学和计算机基础做支撑,深度学习的技术突破只能是空中楼阁。
所以,想在深度学习技术上有所成就的初学者,就有必要了解这些基础知识之于深度学习的意义。除此之外,我们的专业路径还会从结构与优化的理论维度来介绍深度学习的上手,并基于深度学习框架的实践浅析一下进阶路径。
最后,本文还将分享深度学习的实践经验和获取深度学习前沿信息的经验。
数学基础
如果你能够顺畅地读懂深度学习论文中的数学公式,可以独立地推导新方法,则表明你已经具备了必要的数学基础。
掌握数学分析、线性代数、概率论和凸优化四门数学课程包含的数学知识,熟知机器学习的基本理论和方法,是入门深度学习技术的前提。因为无论是理解深度网络中各个层的运算和梯度推导,还是进行问题的形式化或是推导损失函数,都离不开扎实的数学与机器学习基础。
(1)数学分析:在工科专业所开设的高等数学课程中,主要学习的内容为微积分。对于一般的深度学习研究和应用来说,需要重点温习函数与极限、导数(特别是复合函数求导)、微分、积分、幂级数展开、微分方程等基础知识。在深度学习的优化过程中,求解函数的一阶导数是最为基础的工作。当提到微分中值定理、Taylor公式和拉格朗日乘子的时候,你不应该只是感到与它们似曾相识。这里推荐同济大学第五版的《高等数学》教材。
(2)线性代数:深度学习中的运算常常被表示成向量和矩阵运算。线性代数正是这样一门以向量和矩阵作为研究对象的数学分支。需要重点温习的包括向量、线性空间、线性方程组、矩阵、矩阵运算及其性质、向量微积分。当提到Jacobian矩阵和Hessian矩阵的时候,你需要知道确切的数学形式;当给出一个矩阵形式的损失函数时,你可以很轻松的求解梯度。这里推荐同济大学第六版的《线性代数》教材。
(3)概率论:概率论是研究随机现象数量规律的数学分支,随机变量在深度学习中有很多应用,无论是随机梯度下降、参数初始化方法(如Xavier),还是Dropout正则化算法,都离不开概率论的理论支撑。除了掌握随机现象的基本概念(如随机试验、样本空间、概率、条件概率等)、随机变量及其分布之外,还需要对大数定律及中心极限定理、参数估计、假设检验等内容有所了解,进一步还可以深入学习一点随机过程、马尔可夫随机链的内容。这里推荐浙江大学版的《概率论与数理统计》。
(4)凸优化:结合以上三门基础的数学课程,凸优化可以说是一门应用课程。但对于深度学习而言,由于常用的深度学习优化方法往往只利用了一阶的梯度信息进行随机梯度下降,因而从业者事实上并不需要多少“高深”的凸优化知识。理解凸集、凸函数、凸优化的基本概念,掌握对偶问题的一般概念,掌握常见的无约束优化方法如梯度下降方法、随机梯度下降方法、Newton方法,了解一点等式约束优化和不等式约束优化方法,即可满足理解深度学习中优化方法的理论要求。这里推荐一本教材,Stephen Boyd的《Convex Optimization》。
(5)机器学习:归根结底,深度学习只是机器学习方法的一种,而统计机器学习则是机器学习领域事实上的方法论。以监督学习为例,需要你掌握线性模型的回归与分类、支持向量机与核方法、随机森林方法等具有代表性的机器学习技术,并了解模型选择与模型推理、模型正则化技术、模型集成、Bootstrap方法、概率图模型等。深入一步的话,还需要了解半监督学习、无监督学习和强化学习等专门技术。这里推荐一本经典教材《The elements of Statistical Learning》
计算机基础
深度学习要在实战中论英雄,因此具备GPU服务器的硬件选型知识,熟练操作Linux系统和进行Shell编程,熟悉C++和Python语言,是成长为深度学习实战高手的必备条件。当前有一种提法叫“全栈深度学习工程师”,这也反映出了深度学习对于从业者实战能力的要求程度:既需要具备较强的数学与机器学习理论基础,又需要精通计算机编程与必要的体系结构知识。
(1)编程语言:在深度学习中,使用最多的两门编程语言分别是C++和Python。迄今为止,C++语言依旧是实现高性能系统的首选,目前使用最广泛的几个深度学习框架,包括Tensorflow、Caffe、MXNet,其底层均无一例外地使用C++编写。而上层的脚本语言一般为Python,用于数据预处理、定义网络模型、执行训练过程、数据可视化等。当前,也有Lua、R、Scala、Julia等语言的扩展包出现于MXNet社区,呈现百花齐放的趋势。这里推荐两本教材,一本是《C++ Primer第五版》,另外一本是《Python核心编程第二版》。()(2)Linux操作系统:深度学习系统通常运行在开源的Linux系统上,目前深度学习社区较为常用的Linux发行版主要是Ubuntu。对于Linux操作系统,主要需要掌握的是Linux文件系统、基本命令行操作和Shell编程,同时还需熟练掌握一种文本编辑器,比如VIM。基本操作务必要做到熟练,当需要批量替换一个文件中的某个字符串,或者在两台机器之间用SCP命令拷贝文件时,你不需要急急忙忙去打开搜索引擎。这里推荐一本工具书《鸟哥的Linux私房菜》。
(3)CUDA编程:深度学习离不开GPU并行计算,而CUDA是一个很重要的工具。CUDA开发套件是NVidia提供的一套GPU编程套件,实践当中应用的比较多的是CUDA-BLAS库。这里推荐NVidia的官方在线文档http://docs.nvidia.com/cuda/。
(4)其他计算机基础知识:掌握深度学习技术不能只满足于使用Python调用几个主流深度学习框架,从源码着手去理解深度学习算法的底层实现是进阶的必由之路。这个时候,掌握数据结构与算法(尤其是图算法)知识、分布式计算(理解常用的分布式计算模型),和必要的GPU和服务器的硬件知识(比如当我说起CPU的PCI-E通道数和GPU之间的数据交换瓶颈时,你能心领神会),你一定能如虎添翼。
深度学习入门
接下来分别从理论和实践两个角度来介绍一下深度学习的入门。
(1)深度学习理论入门:我们可以用一张图(图1)来回顾深度学习中的关键理论和方法。从MCP神经元模型开始,首先需要掌握卷积层、Pooling层等基础结构单元,Sigmoid等激活函数,Softmax等损失函数,以及感知机、MLP等经典网络结构。接下来,掌握网络训练方法,包括BP、Mini-batch SGD和LR Policy。最后还需要了解深度网络训练中的两个至关重要的理论问题:梯度消失和梯度溢出。
以卷积神经网络为例,我们用图2来展示入门需要掌握的知识。起点是Hubel和Wiesel的对猫的视觉皮层的研究,再到日本学者福岛邦彦神经认知机模型(已经出现了卷积结构),但是第一个CNN模型诞生于1989年,1998年诞生了后来被大家熟知的LeNet。随着ReLU和Dropout的提出,以及GPU和大数据所带来的历史机遇,CNN在2012年迎来了历史性的突破——诞生了AlexNet网络结构。2012年之后,CNN的演化路径可以总结为四条:1. 更深的网络;2. 增强卷积模的功能以及上诉两种思路的融合ResNet和各种变种;3. 从分类到检测,最新的进展为ICCV 2017的Best Paper Mask R-CNN;4. 增加新的功能模块。
(2)深度学习实践入门:掌握一个开源深度学习框架的使用,并进一步的研读代码,是实际掌握深度学习技术的必经之路。当前使用最为广泛的深度学习框架包括Tensorflow、Caffe、MXNet和PyTorch等。框架的学习没有捷径,按照官网的文档step by step配置及操作,参与GitHub社区的讨论,遇到不能解答的问题及时Google是快速实践入门的好方法。
初步掌握框架之后,进一步的提升需要依靠于具体的研究问题,一个短平快的策略是先刷所在领域权威的Benchmark。例如人脸识别领域的LFW和MegaFace,图像识别领域与物体检测领域的ImageNet、Microsoft COCO,图像分割领域的Pascal VOC等。通过复现或改进别人的方法,亲手操练数据的准备、模型的训练以及调参,能在所在领域的Benchmark上达到当前最好的结果,实践入门的环节就算初步完成了。
后续的进阶,就需要在实战中不断地去探索和提升了。例如:熟练的处理大规模的训练数据,精通精度和速度的平衡,掌握调参技巧、快速复现或改进他人的工作,能够实现新的方法等等。
深度学习实战经验
在这里,分享四个方面的深度学习实战经验。
1. 充足的数据。大量且有标注的数据,依旧在本质上主宰着深度学习模型的精度,每一个深度学习从业者都需要认识到数据极端重要。获取数据的方式主要有三种:开放数据(以学术界开放为主,如ImageNet和LFW)、第三方数据公司的付费数据和结合自身业务产生的数据。
2. 熟练的编程实现能力。深度学习算法的实现离不开熟练的编程能力,熟练使用Python进行编程是基础。如果进一步的修改底层实现或增加新的算法,则可能需要修改底层代码,此时熟练的C++编程能力就变得不可或缺。一个明显的现象是,曾经只需要掌握Matlab就可以笑傲江湖的计算机视觉研究者,如今也纷纷需要开始补课学习Python和C++了。
3. 充裕的GPU资源。深度学习的模型训练依赖于充裕的GPU资源,通过多机多卡的模型并行,可以有效的提高模型收敛速度,从而更快的完成算法验证和调参。一个专业从事深度学习的公司或实验室,拥有数十块到数百块的GPU资源已经是普遍现象。
4. 创新的方法。以深度学习领域权威的ImageNet竞赛为例,从2012年深度学习技术在竞赛中夺魁到最后一届2017竞赛,方法创新始终是深度学习进步的核心动力。如果只是满足于多增加一点数据,把网络加深或调几个SGD的参数,是难以做出真正一流的成果的。
根据笔者的切身经历,方法创新确实能带来难以置信的结果。一次参加阿里巴巴组织的天池图像检索比赛,笔者提出的一点创新——使用标签有噪声数据的新型损失函数,结果竟极大地提高了深度模型的精度,还拿到了当年的冠军。
深度学习前沿
前沿信息的来源
实战中的技术进阶,必需要了解深度学习的最新进展。换句话说,就是刷论文:除了定期刷Arxiv,刷代表性工作的Google Scholar的引用,关注ICCV、CVPR和ECCV等顶级会议之外,知乎的深度学习专栏和Reddit上时不时会有最新论文的讨论(或者精彩的吐槽)。
一些高质量的公众号(深度学习大讲堂),同时,关注学术界大佬LeCun和Bengio等人的Facebook/Quora主页,关注微博大号“爱可可爱生活”等人,也常有惊喜的发现。
建议关注的重点
(1)新的网络结构。在以SGD为代表的深度学习优化方法没有根本性突破的情况下,修改网络结构是可以较快提升网络模型精度的方法。2015年以来,以ResNet的各种改进为代表的各类新型网络结构如雨后春笋般涌现,其中代表性的有DenseNet、SENet、ShuffuleNet等。
(2)新的优化方法。纵观从1943年MCP模型到2017年间的人工神经网络发展史,优化方法始终是进步的灵魂。以误差反向传导(BP)和随机梯度下降(SGD)为代表的优化技术的突破,或是Sigmoid/ReLU之后全新一代激活函数的提出,都非常值得期待。笔者认为,近期的工作如《Learning gradient descent by gradient descent》以及SWISH激活函数,都很值得关注。但能否取得根本性的突破,也即完全替代当前的优化方法或ReLU激活函数,尚不可预测。
(3)新的学习技术。深度强化学习和生成对抗网络(GAN)。最近几周刷屏的Alpha Zero再一次展示了深度强化学习的强大威力,完全不依赖于人类经验,在围棋项目上通过深度强化学习“左右互搏”所练就的棋力,已经远超过上一代秒杀一众人类高手的AlghaGo Master。同样的,生成对抗网络及其各类变种也在不停地预告一个学习算法自我生成数据的时代的序幕。笔者所在的公司也正尝试将深度强化学习和GAN相结合,用于跨模态的训练数据的增广。
(4)新的数据集。数据集是深度学习算法的练兵场,因此数据集的演化是深度学习技术进步的缩影。以人脸识别为例,后LFW时代,MegaFace和Microsoft Celeb-1M数据集已接棒大规模人脸识别和数据标签噪声条件下的人脸识别。后ImageNet时代,Visual Genome正试图建立一个包含了对象、属性、关系描述、问答对在内的视觉基因组。
最后,也是最初
在目前这个阶段,业内还处于算法红利期,新的算法、新的模型层出不穷,仅仅在CV领域,每天就有二三十篇paper被发布到arXiv上,每年的顶会顶刊收录的成果都在大幅度刷新上一年甚至上一个月的记录。
打好基础之后,跟踪论文并复现、学习和思考,这样的任务将成为你现阶段的一项日常作业,如果你已经进入或是决定进入这个行业的话。因为稍有懈怠,便要面临着被时代抛弃、跟不上节奏的情况。所以,到这一步,对于有些人来说是一个结束,而对另一些人来说,则才刚刚是开始。
这个时候,我们可以回过头来重新问问自己前面那几个问题:
(1)“我真的已经想清楚,要踏足这个行业吗?”
(2)“我能够付出比其他人更多的辛苦汗水,在这条路上坚定地走下去吗?”
(3)“在遭受了痛苦甚至打击之后,我对机器学习的热爱,仍然能够维持我继续前进吗?”
这条路,我在走,很多人在走,那么,你来吗?