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