程序员想搞机器学习?看看Nodejs之父这一年摸爬滚打的心路历程

做者 | Ryan Dahl
html

编译 | AI100 
算法

tinyclouds.org/residency/
编程


去年,在我研究TensorFlow出了一番成果后,我开始申请Google Brain的首届见习项目(Google Brain Residency Program),最后竟然成功了。受邀参加该项目的共有24人,每一个人都有着不一样的机器学习背景。服务器

咱们24我的,须要在Google位于山景城的深度学习研究实验室工做一年,天天跟Google的科学家和工程师们一块儿,共同来作TensorFlow的前沿研究。想一想就把我给兴奋坏了。网络

现在,这个为期一年的项目已经结束了,确实收获满满。我也但愿把学到的一些东西,结合个人心得,总结一下,分享出来,但愿能为在机器学习的道路上耕耘的伙伴儿提供一些帮助。架构

先说说我起初拟定的目标吧。个人目标是修正老电影或电视剧的画面并发

想象一下,画面粗糙的90年代电视剧,或是60年代黑白电影,要是能被修正为色彩华丽的4K画面,观看体验会有多棒!框架

而这事看上去彻底可行:咱们很轻松就能把4K视频转换成尽是颗粒感的、低分辨率的、甚至是只有黑白两色的视频,只要训练出某个监督模型来反转这个过程就能够了。并且,可用的训练数据无穷无尽。咳咳,这个想法简直太强悍了!机器学习

带着这样的目标,我再一次(上一次是为Node.js项目)从纽约布鲁克林搬到旧金山湾区,以更好地实现这项深度学习技术。几天后,个人平常生活就变成了跟Google的深度学习专家进行讨论、在Google庞大的软件库内浏览代码,blablabla...异步

接下来我要开始大谈这些日子以来,我所作的不少技术细节。固然,若是不想看,能够直接跳到总结部分。

超分辨率的像素递归

众所周知,FBI在《犯罪现场调查》(CSI)中所用的缩放技术是不可能实现的。没人能任意放大照片。然而,在你放大照片图像时把相关像素所构成的合理图形呈现出来,这仍是有可能作到的。可以平滑地提高图像分辨率,将是我实现目标的第一步。

该问题在本文中用 超分辨率 一词来描述,好久之前人们就在尝试解决它了。

据此,咱们认识到简单使用ConvNet没法完全解决该问题:它只是把你输入的低分辨率图像的像素间距(L2)最小化来输出高分辨率图像。这类损失函数所学到的,是输出全部可能结果的平均值——所输出的图像看上去就比较模糊了。咱们想要的模型是这样的:对于给定的低分辨率图像,它能从全部可能的强化结果中选出那张特定的、效果最好的高分辨率图像。若是是“强化”一张关于树的模糊照片,咱们会但愿它能给出枝、叶在位置上的一些细节,即使它们的位置并不是是枝、叶在树上的实际位置。

某种条件型的GAN(生成式对抗网络)看上去颇有但愿,但构建起来较难,通过几回失败的尝试后,咱们换成了另外一种新型的生产式模型:PixelCNN,它也比较有戏。(等咱们启动以后,用GAN解决来超分辨率问题的SRGAN就发布了,它生成的结果很是好。)

PixelCNN是一种奇怪的反直觉模型。它将图像生成问题重写成每次选择一个像素序列。像LSTM(长短时记忆网络)这样的门控制递归网络在序列生成方面是很是成功的,它一般会用在单词或字符上。PixelCNN巧妙地构建出一个卷积神经网络(CNN),它能基于先前的像素的几率分布来精确生成像素。这是RNN和CNN的混合功能。

示意图由 van den Oord 等人所绘

意外的是,PixelCNN所生成的图像看起来很是天然。不像艰难平衡两种目标的对抗网络,该模型的目标只有一个,于是面对超参数的变化,它有更好的稳健性。也就是说,它更易于优化。

解决超分辨率问题的首次尝试,我野心过大,选用了ImageNet来训练PixelCNN。(跟CIFAR-十、CelebA或LSUN相比,ImageNet是个较难的数据集,不少生成式模型研究都在用它。)但很显然,按像素来序列生成图像的过程极其缓慢。输出图像的尺寸大于64x64时,耗时将超过数小时!然而,在我把图像的尺寸限制到小尺寸,并使用脸部或卧室类的小型数据集后,得出的结果就开始使人激动了。

图1:用名人脸部图像数据集训练出来的超分辨率像素递归模型所生成的高分辨率图像。左侧为测试数据集所用的8x8低分辨率输入图像。中间为PixelCNN模型所输出的32x32高分辨率图像,右侧是原始的32x32分辨率图像。咱们的模型优先整合脸部特征,然后去合成较为逼真的头发与皮肤方面的细节。

因为在Google能够获取到无穷的计算资源,如何扩大训练的规模便成为该项目的另外一个目标——由于即使采用这些小型的数据集,在单个CPU上完成训练也要花上数周的时间。

异步随机梯度降低算法(Asynchronous SGD)是最理想的分布式训练方法。使用这种方法,你用N台机器独立来训练同以个模型,但每一个时间步长都要共享一次权重参数。权重参数被托管在一台单独的“参数服务器”上,该服务器在每一个时间步长内都进行远程过程调用(RPC),以得到最新数值并发送梯度更新。若是数据管道足够好,你就能够线性增长模型每秒内的训练步数,方法是增长机器——由于机器之间互不依赖。然而,当机器增长时,因为老机器更新了权重,新机器的权重会逐步过时或“落伍”。在分类网络中,这里的问题不大,把训练的规模扩增到几十台机器不难。但PixelCNN却对过期的梯度极其敏感,在它的异步随机梯度降低算法内增长机器几乎没有任何收益。

另外一个方法,是用同步随机梯度降低算法(Synchronous SGD)。使用这一方法,机器在每一个时间步长内都进行同步,且每台机器的梯度都会被平均。它与随机梯度降低算法在数学上是相同的。更多的机器会增大批尺寸。但同步随机梯度降低算法(Sync SGD)容许各机器使用更小、更快的批尺寸,从而来增长每秒的步数(steps/sec)。

然而,同步随机梯度降低算法也有它本身的问题。首先,它须要大量的机器常常进行同步,这必然致使停机时间的增长。其次,除非将每台机器的批尺寸设为1,不然它没法经过增长机器来增长每秒训练的步数。最终,我发现简单的设置是用一台机器安装8个GPU来使用同步随机梯度降低算法——但完成训练仍需花上数天的时间。

采用大规模计算的另外一个办法,是进行规模更大的超参数搜索。如何来肯定所用的批尺寸?把它们全都试一遍。在找到论文中所用的配置前,我尝试过数百种配置。

如何定量评估结果,则是另一个难题。如何才能证实咱们的图像比基准模型好?衡量超分辨率质量的典型方法,是对比强化图像与原始图像的对应像素点之间的距离(峰值信噪比,PSNR)。虽然说本模型输出的脸部图像在质量上明显更好,但在像素对比上,平均看来它们还不如基准模型所输出的模糊图像。咱们尝试用PixelCNN自己的类似度测量来证实咱们的样本比基准版本有着更高的几率值,但一样失败了。最后,咱们把这项任务众包给人类评估员——询问他们哪些图像看上去更真实。这倒奏效了。

具体的结果请查看这篇论文:超分辨率的像素递归

https://arxiv.org/abs/1702.00783

PixColor: 关于着色的尝试

PixColor输出的双色模式

Slim的创造者Sergio Guadarrama一直在尝试给图像着色。他跟我说过一个试验:用份量接口(该接口中图像的灰度、颜色相互分离)获取一张224×224×3的图像,将其颜色通道降至28×28×2的超低分辨率,而后用双线性插值法再把颜色通道放大,所得图像与颜色分辨率很高的原始图像相比几乎没有差异。

图3:你须要的只是一些颜色。顶行是原始彩色图像。中间行是下降采样率后的真实色度图像,尺寸缩小至28像素。底行是双线性提升中间行的采样率并结合原始灰度图像的结果。

这代表,把问题变成仅预测低分辨率颜色,咱们就能够简化着色问题。我本来已准备好完全放弃PixelCNN了,由于它显然没法放大小图像,但用来生成28×28×2的图像仍是很可行的。经过将颜色数值简化为32个数字而非256,咱们进一步简化了着色问题。

Sergio构建了一个“改进的”网络,它可以清理低分辨率颜色的输出,并将溢出边界的颜色推回至正确位置——使用前馈式图像对图像卷积神经网络进行训练,损失仅为L2。咱们还用一个预训练好的ResNet做为条件网络,用以消解额外的损耗项需求,毕竟在超分辨率项目中咱们已经用过这样的损耗项。

使用这些方法后,不管是众包评估仍是用颜色直方图相交评估,咱们都能得出ImageNet上最好的结果。事实证实,通过正确训练的PixelCNN能够很好地模拟图像统计数据,不发生任何模式崩溃。

图7:实验室颜色空间中的颜色通道的边缘统计数据。左:每种方法的直方图以蓝色显示,ImageNet的测试数据集直方图以黑色显示。右图:颜色通道的直方图相交。

因为模型为每一个灰度输入的可能着色声明了一个几率分布,咱们能够对该分布进行屡次取样,以获取同一输入的不一样着色。下图用结构类似度(SSIM) 很好地展现了分布的多样性:

图8:为证实咱们的模型可生成不一样的样本,咱们用多尺度SSIM对比了同一输入的两种输出。上图显示了ImageNet测试数据集的SSIM距离直方图。图中在多个SSIM间距上分别显示了每对图像。SSIM值为1表示两张图像彻底相同。

该模型离远未完美。ImageNet尽管庞大,但不能表明全部的图像。而该模型在处理非ImageNet图像时并不理想。咱们发现,真实的黑白照片(不一样于彩色转化为灰度的黑白照)会得出不一样的统计数据,并能出现不少彩色照片中所没有的物体。好比,Model T汽车的彩色照片很少,ImageNet图像集中可能一张都没有。采用更大的数据集和更好的数据扩增,也许能简化这些问题。

想了解图像质量的话,能够来看看这些图:

  • 处于咱们模型处理中间阶段的一小组很是难处理的图像

http://tinyclouds.org/residency/step1326412_t100/index.html

  • 用于咱们模型的ImageNet随机测试数据集图像

http://tinyclouds.org/residency/rld_28px3_t100_500_center_crop_224/

做为对比,下面是用其余算法来处理同一ImageNet测试数据集的结果:

  • 给图像着色!

http://tinyclouds.org/residency/ltbc_500_center_crop_224/index.html

  • 彩色图像着色

http://tinyclouds.org/residency/cic_500_center_crop_224/index.html

  • 自动着色的学习表示

http://tinyclouds.org/residency/lrac_500_center_crop_224/index.html

最后,完整的细节都在咱们的论文中: PixColor: Pixel Recursive Colorization

https://arxiv.org/abs/1705.07208

失败与未报告的实验

这一年期间,我曾短暂着迷过许多业余的小项目,尽管它们都失败了……接下来我会简单来描述其中的几个:

大数的素因数分解

素因数分解一贯都是个大难题。但即使是现在,咱们仍在不断发现有关素数分解的新问题。若是为深度神经网络提供足够的实例,它能不能找出一些新东西?Mohammad和我尝试过两种方法。他修改了Google机器翻译的seq2seq神经模型,该模型把一个半素大数的整数序列做为输入,并将其素因素预测为输出。我则使用一个较为简单的模型,它将定长整数做为输入,并用几个全链接层来预测输入的分类:素数或合数。这两种方法都只学到了最为明显的规律(若是尾数为0,那它就不是素数!),咱们只能抛弃这个想法。

Adversarial Dreaming

受Michael Gygli的项目启发,我想探究一下鉴别器可否充当它本身的生成器。为此,我构建出一个简单的二元分类卷积神经网络来判断输入的真假。为了生成图像,你须要给出噪点并让它使用梯度来更新输入(有时被称为deep dreaming),令该网络把“真实”类别最大化。该模型经过交替生成“假”实例来进行训练,然后跟典型的GAN鉴别器同样,经过升级权重来区分真假实例。

个人想法是,鉴于更少的架构决策,该网络相比通常的GAN可能更容易训练。事实上,它用MNIST确实能够工做。下图中每一栏都在展现:不一样的噪音图像被逐渐推向红色MNIST数值的情形。

但我无法让它在CIFAR-10数据集上工做,而且它的实际意义也极为有限。这遗憾了,我相信 "Adversarial Dreaming" 会是一个很酷的论文题目。

使用PixelCNN来训练生成器

PixelCNN生成样本的时间过长,这让我很沮丧。因而,我就想试试能不能用一个预训练的PixelCNN训练出前馈式图像对图像卷积神经网络(8x8至32x32尺寸的LSUN卧室图片集)。我所设置的训练方法是:在前馈式网络的输出上进行自动回归。在PixelCNN下更新权重以便将几率最大化。它用这样的线条生成了很是奇怪的图像:

对异步随机梯度降低算法的修改探索

如前文所述,不少模型都不适用于异步随机梯度降低算法。最近,一篇名为DCASGD论文提出了一种解决过期梯度问题的可能方法:在机器开始步进去应用它们权重的前,在权空间(weight space)使用差分向量。这种方法可大大减小每个人的训练时间。不幸的是,我没能在TensorFlow上重复他们的结果,也没法实现我所想出的几个相似想法。这里可能有Bug。(若是想获取个人实现方法,请经过内部渠道联系我)

想法和总结

聊了这么多的技术,我大体作些总结,也算是比较深的心得体会吧。

做为软件工程师,我在机器学习方面并无什么经验。但基于过去一年对深度学习的研究,我来分享一下在该领域的整体见解,及其同范围更广的软件领域之间的关系。

我坚信,机器学习将改变全部行业,并最终改善每一个人的生活,许多行业都会因机器学习所提供的智能预测而受益。

对于我,我在这个项目中,最初的目标是,在不久的未来,全部人均可以看到查理·卓别林这类老电影的4K版。

不过,我确实发现,这一模型的构建、训练和调试都至关困难。固然,大部分的困难是因为我缺少经验,这也代表有效训练这些模型是须要至关丰富的经验的。

个人工做集中在机器学习最为容易的分支上:监督式学习。但即使有着完美的标注,模型开发仍十分困难。彷佛,预测的维度越大,构建模型所花的时间就越长(例如:花大把的时间进行编程、调试和训练)。

所以,我推荐全部人在开始时都尽量简化和限制你的预测

举一个咱们在着色实验中的例子:咱们在开始时试图让模型预测整个的RGB图像,而非只预测颜色通道。咱们认为,神经网络很容易就能处理好灰度图(intensity image)并输出出来,由于咱们使用的是跳跃链接(skip connection)。只预测颜色通道依然能改进性能。

若是我以主观、本能的方式使用“工做”来描述软件:图像分类工做起来彷佛很稳健。生成式模型几乎不多能工做,人们也不太了解这种模型。GAN能输出很好地图像,可是构建起来几乎是不可能的——个人经验是,对架构做出任何小改动都有可能使它没法工做。我据说强化学习更加困难。但因经验不足,我对递归神经网络不予置评。

可是,随机梯度降低算法工做起来是太过于稳定,即便是严重的数学错误也不会让它完全失败,仅稍微有损于性能。

由于训练模型常常须要花费数日,这是一个很是缓慢的 修改—运行 循环。

测试文化还没有彻底兴起。训练模型时咱们须要更好的评断方法,网络的多个组成部分须要维持特定的均值和变量,不能过分摆动或者留在范围内。机器学习漏洞使系统的heisenbugs能特别轻松地经过测试。

并行化能带来的好处颇有限。增长计算机数后,大规模的超参数搜索会变得更加容易,可是理想状况下,咱们会设计不用仔细调试也能正常工做的模型。(实际上,我怀疑超参数搜索能力有限的研究人员将不得不设计出更好的模型,所以他们设计出的模型更加稳定)。

不幸的是,对于不少模型而言,异步随机梯度降低算法并无什么用处——更加精确的梯度一般用处不大。这就是为何 DCASGD 的研究方向很重要的缘由。

从软件维护的角度看,关于如何组织机器学习项目你们都鲜有共识。

就像是Rail出现以前的网站:一群随机PHP脚本,商业逻辑和标记符号乱混一气。在TensorFlow项目中,数据管道、数学和超参数/配置管理无组织地混为一团。我认为咱们还未发现精美的结构/组织。(或者说是还未从新发现,就像DHH从新发现并普及 MVC那样。)个人项目结构一直在进步,可是我不会认为它是精美的。

框架会继续快速进化。我开始使用的是Caffe,不得不称赞TensorFlow带来的好处。如今,PyTorch 和 Chainer之类的项目使用动态计算图形取悦客户。漫长的修改—行循环是开发更好模型的主要阻碍——我怀疑能优先实现快速启动和快速评估的框架最终会取得成功。尽管拥有TensorBoard和iPython之类的有用工具,可是检查模型在训练期间的活动仍然很难。

论文中的信噪比很低。可是须要改进的空间还很大。人们一般不会坦率认可他们模型的失败之处,由于学术会议更看重的是准确度而不是透明度。我但愿学术会议能接受提交博客文章,并要求开源实现)。Distill 在这方面的努力值得称赞。

对机器学习而言,这是一个使人激动的时代。各个层面上有大量工做须要完成:从理论端到框架端,还有不少值得改进的空间。它几乎和因特网的诞生同样使人激动。加入这场技术革命吧!

这是你的机器学习系统吗?

是啊!将数据倒到这一大堆线性代数中,而后在另一端收集答案。

若是答案是错误的呢?

只管搅动这堆线性代数,直到结果开始看起来正确为止。

相关文章
相关标签/搜索