转型AI|非科班却拿下阿里云栖一等奖,他经历的坑足够你学100天
作者 | 智亮
编辑 | 胡永波
深度学习正在从实验室下沉到技术一线。“年薪百万”的人才需求背后,是各用人团队找不出可用之才的窘境,同时也说明广大有志于AI的人才没能迅速掌握深度学习。背后的原因,恐怕是深度学习的实用性太过超前,创造出深度学习的这批大牛还没来得及培养接班梯队便已扑向技术一线,而立足于一线工作技术人才在学习过程中往往又要重新去趟坑。
如何处理这一环节上的反复,是当前AI人才培养难题上的一大关键。11 月份《程序员》杂志的“AI工程师职业指南”特地请来AI各领域技术一线的专家,希望他们能把成功经验和学习方法详细而走心地分享给有志于此的技术人才,让大家在做规划时,可以用上更为合理的学习路径。
其中,智亮老师的一篇《实战路径:程序员的机器学习进阶方法》,是根据他痛苦的转型经历来告诉大家——一个非科班出身的程序员是如何一步一步踏上深度学习这条不归路,并开发出一款荣获阿里云栖大会API Solution一等奖的植物识别App。
在这过程中,如何选择入门课程?如何选择深度学习框架及编程语言?如何上手数据?如何配置一台能运行深度学习的电脑并跑出你的第一个模型?以下为智亮的正文分享,你可以清晰地看到他趟过的每一个坑,希望借他的肩,让你勇敢前行。
▽▽▽
在计算机行业,关于从业人员的素质,一直都有一个朴素的认识——科班出身好过非科班,学历高的好过学历低的。大部分时候,这个看法是对的。在学校学习,有老师指点,有同学讨论,有考试压迫,有项目练手。即便不大用心的学生,几年耳濡目染下来,毕业后作为半个专业人士,还是没什么问题的。
不过,量子物理告诉我们,这个世界的本质要看概率。所以,科班出身的同学,在技术上好过非科班出身的同学,这是大概率事件;相反,非机器学习专业,甚至非计算机专业的同学,在这个领域做的比本专业同学更好,则就是小概率事件了。但小概率事件并非“不可能事件”,国内很多做机器学习公司的CTO,都不是机器学习专业的科班出身,却能够抓住这里的“小概率”,让自己华丽地转身并实现弯道超车。
他们是怎么做到的?
如果在上学的时候,我们没能嗅到机器学习领域的机会,而是选择其他领域来学习和工作……如今却打算半路出家、改行机器学习,应该怎么做,才能做到跟这些人一样好?或者,至少是足够好?
我自己痛苦转型的经历,说出来可以供大家参考一下。
我也是非科班出身,但因为工作,一直需要接触计算机视觉的一些传统算法。后来,看到ImageNet竞赛的结果,我意识到了深度学习在视觉领域的巨大优势,遂决定开始转型深度学习和神经网络,走上了这条学习的不归路(笑)。
想要转型,跟上学的时候不同,因为手头正在做的工作意味着,自己需要从没有时间的情况下挤出时间,需要把别人睡觉、打游戏的时间用来学习,而所学的又是一种颇为艰深晦涩的学问。
转型,其实很容易,需要做到的只有一件事:学习。
转型,其实很困难,因为必须做到一件事:坚持学习。
最难的不是下定决心,而是贯彻到底。所以,在开始之前,不妨先问问自己这样几个问题:
“我真的已经想清楚,要踏足这个行业吗?”
“我能够付出比其他人更多的辛苦汗水,在这条路上坚定地走下去吗?”
“在遭受了痛苦甚至打击之后,我对机器学习的热爱,仍然能够维持我继续前进吗?”
根据我掌握的数据,100个程序员里大概有30个考虑过转型,而真正付诸行动的不过10个。一个月以后仍然在坚持的仅有5个,最终能完成第一个阶段学习的,最多两三个而已。
真的这么困难吗?是的。特别是你要白天上班,晚上才能学习,独学而无友,有问题又只能自己查。而要系统地入门,又不是咬牙一天两天就能学出来,恐怕得坚持几个月才能get到点。
我个人的经历是这样:一开始接触时,每周一、三、五固定3天时间,每晚花两个小时去学习、看视频、翻书,周六周日则用来完成课程附带的编程作业,大概也是每天两小时左右。在这种强度下坚持了三个月,我才算是完成了入门的第一步。
也许有的人效率更高一些,也许有的人步子更慢一些,但快和慢不是关键,即使学习最慢的人,也要比一开始放弃学习的人走得更远。
所以,其实真正重要的,不是“我该学什么”,或者“我该怎么学”;而是“我是不是真的有足够的决心”,以及“我是不是能坚持到底”。
上手的课程
定好决心后,我们就能看看:在学机器学习的时候,我们到底在学什么?
几乎所有人都知道人工智能这个概念;有一部分人知道“机器学习”这个概念;其中一小部分人能清楚描述“深度学习”、“机器学习”和“神经网络”的关系; 很少一部分人能够正确说明“卷积”、“池化”、“CTC”这些名词的正确含义与计算/实现的方法;非常少的人能清楚地理解损失函数和反向传播的数学表达;极少极少的人能够阐述网络的一个修改(比如把卷积核改小)对precision/recall会产生什么影响;几乎没有人能描述上述影响到底是什么原理。
这就是目前“程序员”这个群体,对于机器学习的了解程度。
我个人的经验,适用于“很少一部分人”之外的那“很大一部分人”,也就是说,他们最多知道深度学习是什么意思,神经网络又是什么概念,却并未真正系统地学习接触过这个领域。
而我们的目标,则定位成为“非常少的人”,也就是能够理解损失函数/反向传播这些较为基础、较为底层的知识,使得自己能够设计新的算法或网络,或至少能辅助大牛去实现他们所设想的算法和神经网络。
要实现这个小目标,我们就必须掌握最基础的知识,就好像学写汉字时,不练横竖撇捺折是不现实的。
但是,作为“不明真相的广大群众”,从哪里入手好呢? 线性代数?概率论?那是最糟糕的选择!它们只会让你入门之前就彻底丧失信心,其漫长而陡峭的学习曲线还会让你误以为这是一个不友好的领域。事实上,只有成为“很少一部分人”(能够正确说明“卷积”,“池化”,“CTC”这些名词的正确含义和计算/实现方法)之后,你才真正需要去复习它们。
在这之前,你所要用到的数学知识,只有以下这三点:
1. 懂得矩阵运算的基本计算方法,能够手动计算[3×4]×[4×3]的矩阵,并明白为什么会得到一个[3×3]的矩阵。
2. 懂得导数的基本含义,明白为什么可以利用导数来计算梯度,并实现迭代优化。
3. 能够计算基本的先验及后验概率。
只要大学考试不是完全靠抄答案,稍微翻翻书,你就能把这点知识找回来,可能半天都用不上。
然后就可以入门了,对于所有零基础的同学,我都建议从吴恩达的机器学习课程开始: Machine Learning - Stanford University | Coursera
吴恩达的英语又慢又清晰,课程字幕的翻译又到位,课程设置与课中测验及时而又合理,重点清晰、作业方便,再加上吴恩达教授深入浅出的讲解,讲解过程中不时的鼓励和调侃,都能让你更为积极地投入到机器学习的学习之中,让你扎实而快速地掌握机器学习的必备基础知识。
这门在线课程,相当于斯坦福大学CS229的简化版,涵盖内容包括机器学习最基础的知识、概念及其实现,以及最常用的算法(例如PCA、SVM)和模型(全连接神经网络)。学习这门课程,重要的是基础的概念与实现。作为一名具备编程基础的开发人员,在这个阶段要将自身理论同实践相结合的优势发挥出来,充分利用它所提供的编程作业,尽可能多地实践,从理论和代码两个角度去理解课程中的知识点。
学习完成后,你能了解到机器学习的一些基本名词和概念,并具备一定的算法层面的编码能力。打好理论和实践的基础,你就可以进行下一阶段的学习了,其中有两大的方向:夯实基础和选择领域。
夯实基础的意思,就是这门课的完成,并不代表自己学会了机器学习,只不过是从门外汉进了一步,一只脚踏进了门,但其实也仅仅是一些基本的了解。这个时候,你也许会觉得自己有很多的奇思妙想,却难以评估这些想法的价值和正确的可能性,这就是基础不够的缘故。
所以,在继续学习深度神经网络之前,建议结合自己所学到的知识,回头去看一遍CS229,将传统算法整体熟悉一遍,尽可能把所有的基本概念都掌握扎实。
而选择领域,则是由于任务目标的不同,深度学习领域已在大体上分成了计算机视觉(CV)、自然语言处理(NLP)以及其他一些子领域,例如语音和更为特殊的强化学习等。在每个领域下,都有大量的研究者在投入精力钻研,发表论文和成果。考虑到个人精力的限度,建议选择一到两个方向作为主攻,跟上学术界主流的进展,其他子领域有基础的了解即可,必要时作为参考即可。
在完成了相应领域的学习后,下一步要做的就是尝试阅读最新的经典论文并试图复现它们了。
编程语言与深度学习框架的选择
当然,作为开发者,想要去实现一个模型,绕不开的问题便是:
应该选择什么语言?应该选择什么框架?
对于开发人员而言,语言的选择其实不是问题。但作为入门,最为理所当然的建议则是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%的准确率也确实难有提升的空间。
Tensorflow给出了CIFAR的例程:
https://www.tensorflow.org/tutorials/deep_cnn
并附有代码:
https://github.com/tensorflow/models/tree/fb96b71aec356e054678978875d6007ccc068e7a/tutorials/image/cifar10
ImageNet和MS COCO
至于ImageNet(www.image-net.org/)和COCO(http://mscoco.org/),则是两个工业级别的图像数据集。通常提到它们时,ImageNet指的是ILSVRC2012的训练集,而COCO则是COCO-2014训练集。
ImageNet有大量的图片(一百多万张,分成1000个分类)和标注,大部分都是图3这样的。
COCO虽然图片数量少一些(8万多张,80个分类),但每张图片都有轮廓标记,并且附带分类标注和5句描述话语(英文)。其图片大致如图4。
所以当我们进入实际工作的阶段,就要根据具体的需要从中选择适合自己的数据集,以作为benchmark或是pretrain数据集。
实战阶段的学习用机配置
接下来,我们就需要一台机器来把框架搭建起来,以编写和运行我们的helloAI。然而,我在很多地方都看到小伙伴们在问:
我需要什么样的配置能学机器学习?
我需要买块GTX1080/TITAN/Tesla吗?
我应该装几块显卡?一块?两块?还是四块?
而答案也往往倾向于:
“必须得有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加速时的高热量也会非常影响系统的稳定性。如果没有很丰富的经验,经常会在一个小问题上卡掉几个小时宝贵的学习时间。
然后,要不要来试试第一个模型?
在Tenforflow安装完成后,我们可以用这种方式来最快地把第一个CIFAR demo跑起来:
OK,只需几分钟来下载数据,我们就能看到我们的第一个“图像识别模型”正在训练了。
训练过程中我们可以看到log中在不断地输出loss信息,但除了想要跟踪loss之外,我们还希望看到当前训练模型的识别准确率到底如何,这就不是cifar10_train.py这个脚本能够提供的了。我们还需要执行
这个脚本会不断地验证最近的检查点的识别准确率。
如果使用GPU的话,就会发现训练脚本运行起来之后,所有的显存都已被这个进程占满;再启动验证脚本的话,就会报错一大堆的内存不足(OOM),这是Tensorflow的机制决定的,它会默认占据所有显卡的所有显存,而不管自己是否真能用到那么多。
解决这个问题的办法也很简单。
首先,我们可以指定Tensorflow使用哪几块显卡进行训练。要做到这一点,可以在执行较本前,用命令行指定环境变量:
其中的“0,2”就是希望使用的GPU编号,从0开始,用逗号分隔开。
或者在代码中创建一个GPUOption,设置visible_device_list=‘0,2’,也能起到同样的效果。
然后,我们还可以限制Tensorflow所用的显存,使其动态增长而非一启动就占满。方法和上面的类似,在代码中创建一个GPUOption,并设置allow_growth=True即可。
官方的CIFAR例程大概能达到86%的准确率,这个成绩在现在来说可以算是比较差的,最新模型的准确率通常都在97%左右,即便不经仔细调参而随意训练也能轻松达到93%左右。大家可以尝试修改cifar10.py中定义的模型,以得到更好的效果。
最后,也是最初
在经历过如此漫长、痛苦但也充满乐趣的学习和实践之后,你应该可以算是机器学习的一个业内人士了。但这并不意味这条道路已经走到了尽头,恰恰相反,在完成这一切之后,你才刚刚踏出了机器学习从业生涯的第一步。
在目前这个阶段,业内还处于算法红利期,新的算法、新的模型层出不穷,仅仅在CV领域,每天就有二三十篇paper被发布到arXiv上,每年的顶会顶刊收录的成果都在大幅度刷新上一年甚至上一个月的记录。
打好基础之后,跟踪论文并复现、学习和思考,这样的任务将成为你现阶段的一项日常作业,如果你已经进入或是决定进入这个行业的话。因为稍有懈怠,便要面临着被时代抛弃、跟不上节奏的情况。所以,到这一步,对于有些人来说是一个结束,而对另一些人来说,则才刚刚是开始。
这个时候,我们可以回过头来重新问问自己前面那几个问题:
“我真的已经想清楚,要踏足这个行业吗?”
“我能够付出比其他人更多的辛苦汗水,在这条路上坚定地走下去吗?”
“在遭受了痛苦甚至打击之后,我对机器学习的热爱,仍然能够维持我继续前进吗?”
这条路,我在走,很多人在走,那么,你来吗?
△△△
正文到此就结束了,这里,我想说一点题外话。
我是AI科技大本营的技术主笔波波,一直很喜欢智亮老师的分享,非常走心,他从一位非科班的技术一路走到今天,也拿过阿里云栖大会的一等奖,他太知道其中的不易与艰辛了。跟智亮老师几经约稿,其在百忙之中终于抽空成文,将宝贵经验倾囊相授,实属不易。