PyTorch 和 TensorFlow 到底哪个更好?看看研究者们怎么说

1,268 阅读16分钟
原文链接: zhuanlan.zhihu.com

Theano、TensorFlow、Torch、MXNet 再到近日比较热门的 PyTorch 等等,深度学习框架之间的比较一直以来都是非常受人关注的热点话题。机器之心也曾发表过多篇相关的介绍和对比文章,如《主流深度学习框架对比:看你最适合哪一款?》《五大主流深度学习框架比较分析:MXNET 是最好选择》《对比深度学习十大框架:TensorFlow 最流行但并不是最好》《从 TensorFlow 到 Theano:横向对比七大深度学习框架》


不过你知道用户实际用起来的感觉怎么样吗?近日,Reddit 用户 cjmcmurtrie 发了一个主题为「PyTorch vs. TensorFlow」的讨论帖,想要了解这两大流行的框架之间各自有什么优势。


原帖地址:[D] So... Pytorch vs Tensorflow: what's the verdict on how they compare? What are their individual strong points? • r/MachineLearning


帖子一楼写道:


我还没有从 Torch7 迁移到 TensorFlow。我玩过 TensorFlow,但我发现 Torch7 更加直观(也许是我玩得不够?)。我也尝试了一点 PyTorch,所以我决定先看看效果。


使用了几周 PyTorch 之后,我认为我现在还不必迁移到 TensorFlow,至少在我感兴趣的项目上还不需要。用 PyTorch 写自定义模块真是简单至极。而且其动态图构建(dynamic graph construction)给我之前需要熬夜实现(或等待列表上)的东西带来了很多新想法。我认为对机器学习开发者来说,PyTorch 是一个了不起的工具集。我也知道 TensorFlow 的社区资源要强大得多,但如果要开发全新的项目(而不是为已有的架构重新写代码或阅读教程),社区也不一定能有很大的帮助。


这个 Reddit 帖子发出后得到了很多机器学习研究者和开发者的关注,他们纷纷跟贴谈论自己的想法和经验(不只是关于 PyTorch 和 TensorFlow,讨论中还涉及到更多工具)。机器之心在这里选择其中一些我们认为有价值的评论,希望能够给你的学习和研究带来帮助。以下按赞成数量排序。


ajmooch的回复:


我一直在做一个 TensorFlow 的项目,所以我可以公正地在 Theano+Lasagne, PyTorch 和 Tensorflow 三者之间做一个比较。但对于前两者,我可以给出一些漫漫的看法。


背景:大概在一年前我开始接触 Theano+Lasagne,并在我的两篇论文中使用了它。我上周改换到 PyTorch,并重新建了两个我以前用 Theano 实现的关键项目。


API:Theano 的图形构建和编译工作方式让我学习起来很费劲,但一旦我找到了它的窍门,一切都迎刃而解(这也许会花费两个月,但是我仍旧在学习 Python 和基本的神经网络方面的东西,所以对这一速度的参考价值持保留态度)。Lasagne 的 API,对我来说,就像是优雅的凯瑟琳女皇骑着逆戟鲸展开了战斗,也就是说我爱死它了。如果我提前知道我有多想要一个 Theano 的程式库去工作,我一定会写一个程式库,这大大地减轻了繁重的劳动。


PyTorch 的 API,另一方面来说感觉有些粗糙,但对它有一些限定词,这个稍后再谈。如果你只是做一些标准的任务(实现 ResNet 或者 VGG)我认为你不会有问题,但我一直都有一些分歧因为我所做的一切都有些奇怪。举个例子,在我当前的项目中,因为 strided 张量索引(tensor indexing)还未实现,我必须使用几个 hacky 解决方法,虽然当前的索引技术非常灵活,比起直接使用 numpy 风格的索引,它们少了很多直观性。中心的限定条件是,它们确实只是释放 friggin 的框架,当然并不是一切都实现,还有一些待解决的问题。Theano 发展时间长且已经成熟,我并没有观察到它或者 Lasagne 在这个过程中遇到过困难。


除此之外,对于 PyTorch 我最大的「抱怨」基本上是在神经网络 API 方面「事情并未按照我让他们组合的方式进行放置」。具体来说,我非常喜欢 Lasagne 的「层次(layers)」范式—但是一点点批判性的思维就会让你得出这个结论,这个范式尤其不适合动态图框架。我完全习惯于考虑并且优化我关于静态图形定义的思考过程,所以转换 API 方法是一个小的痛点。这非常重要-我花了很长时间思考「好吧,既然我不能使用自己的标准流控制写出一个常规的程序一样,写出这个图的 Theano,那么我该如何定义它呢,」这让我在思维的道路上变得越来越强大。


然而,动态图需要一个与「定义+运行」基本不同的 API,虽然我个人认为它并不直观,就在上周其单独执行定义的方法,正如 CJ 所说,打开了我的思路并给了我几十个项目的想法,这在以前是不可能的。我还想象,如果你在任何你想的地方使用 RNNs 做任何事情,比如,在没有消耗计算的前提下实现动态计算,接口的命令性质将会使它更容易这样做。


速度:所以我没有做广泛的基准测试,但是我惊讶的发现,PyTorch 是可以立即使用的,在我当前的项目的单 GPU 的训练时间比 theano+lasagne 快 100%。我已经在 Geforce gtx 980 和 Titan X 上测试了它,并实现了已经确认相同且在合理的误差范围内的网络。100% 逐字地在 CIFAR100 上从(在最简单的情况下)5 分/历元到 2.5 分/历元,并且在某些情况下降到 2 分钟/历元(即,快两倍)


这是相同的模板代码,使用了相同的数据提取程序(我不得不讽刺地说「fetcher」没有思考「去死吧,FETCHER(DIE, FETCHER!)」),除了实际的代码,训练和运行网络,一切都相同。


这让我感到惊讶,因为我的印象是,Theano 的广泛和积极的内存优化(在这种情况下,当你开始训练,只需花费几分钟进行编译)意味着它在单 GPU 下的速度非常快。我不知道什么导致了速度的提升,或者,因为他们同样都使用了 cuDNN 的最新版本(我仔细地检查了一遍以确保的确是这样),所以这一切的收获一定在天空的某一个地方,但我并不知道会在哪里。


相关地,使用 Theano 工作时,我从来没有能够得到多 GPU 或者半精度浮点数。我花了好几天的时间试图让 libgpuarray 工作,并使用 platoon 试图进行修复,但每次我都会精疲力尽(想象一下即使我可以得到编译的资源也不会如此困难,这已经是一个痛点了)。然而,立即使用的 PyTorch 的数据并行性(单节点,4 GPU)和半精度(用于卷积的 pseudo-FP16,这意味它不会变快但是会使用更少的内存)问题就解决了。当时就是这样。


开发团队交互:我与两个框架的核心开发团队一直交流的非常愉快。对于 Lasagne 和 Theano,我遇到了一些困难,很多奇怪的问题。很多次,他们总是快速且简洁地帮我弄清楚什么错了(我通常不明白)。PyTorch 团队同样有帮助—我一直在提出我遇到的错误或问题,并得到及时的反映,通常会在当天修复,或者得到解决方法或得到问题跟踪。我并没有在 Keras 或者 Tensorflow 上工作,但是我看过他们的「问题」日志和一些用户组,只是因为大量的用户,这些框架看起来并不会得到这种个人的关注 - 就像是我去 Cal Poly(加州理工州立大学)一样,在这个地方,教授/学生的比例很高,你很少看到一个班中有超过 20 个学生,然而在 Berkeley 你能看到 1000 人的演讲厅。这并非批评 Cal 的孩子或者暗示 berkeley 盲目扩招,但如果你是一个像我一样开发非标准神经网络的人(我并不是在说 Chuck Tingle weird),然而从一个实际构建框架的人那里得到快速的反馈,这是非常宝贵的能力。


Misc:我担心一个特别的问题(为什么我打算几年拾起 TensorFlow 并将它作为主要框架),Theano 和 PyTorch 都没有为部署设计,开发团队它看上去并没有把重心放在 PyTorch 上(虽然在这方面,我可能看错了,我模糊的记得我在论坛的帖子上看到过这个)。我想要练习将一些东西放置在网站或者 droid app 上(主要是为了娱乐,但我一直都非常专注于研究并认为这是一个真正有用的技能,可以实际获得我在设备上所做的东西),我不确定其他的框架能很好地支持这种方式。


相关地,PyTorch 的分布式框架仍然是实验性的,最近我听说 TensorFlow 在设计时就考虑到了分布式,所以如果你需要运行真正的大规模项目,TensorFlow 多半是最好的。


TL;DR:我并不是试图推荐哪个框架比较好;我至死都爱 Lasagne(可能更多),但我已经发现动态图的灵活性和其快速地、难以理解的增益的速度。我在上个星期安装了 PyTorch 并且只用了非常少的时间就上手了,我想我不太可能回头了。我并不是很了解 TensorFlow。但能从 PyTorch 开发者那里得到及时反馈对我来说是很重要的一点,因为我正在做一些看来有点奇怪的研究,但在未来我也可能为一些项目重新使用 TensorFlow。这个讨论帖非常棒,但我希望在你阅读过后的印象是:这是他们的主观经验,而不是一个刻板的印象如:「就是这样,你绝对会感到同样的方式」。


taion的回复:


我们最近从 Theano+Lasagne 转到了 TensorFlow。


我还没有尝试过任何分布式的架构,但总体上用过 Theano 之后再用 TensorFlow 感觉非常熟悉——甚至更好。对你提到的几点,回复如下:


等效的图形编译(graph compilation)要快得多;我们用了几秒而不是几分钟。但是它仍然不够快,如果我们想要将它的大部分添加到我们的 CI 套件(CI suite),但我们不需要等待很长时间来开始训练。


从 Lasagne 转到 TensorFlow 之后,我喜欢 tf.layers 和 tf.contrib.layers 中更高层次的功能;它们为接受张量(tensor)并返回张量的功能性 API,因此更容易与「原始」的 TensorFlow 集成。我们可以做普通的张量操作,而不用写一个层那么麻烦。


在我们使用的模型上,TensorFlow 的速度稍稍快于 Theano(20%-30%)。当第一次使用时,我们看到大致相同的性能,并认为这可以接受,但然后我们阅读 TensorFlow 的性能指南(www.tensorflow.org/performance…),并切换到 NCHW 并融入批处理规范(batch norm),然后一切运行得更快了。我猜 Theano 本身就不是很快……


关于开发人员的反馈速度:我曾在 TF 的问题区提出了一些微不足道的问题,但 TF 开发人员通常在一两天内就回复我了。


此外,工具是相当好的。TensorBoard 绝对好用,用来表示的时间线(timeline)/跟踪(trace)的工具也一样好用。但是我还没有尝试新加入的 tfdbg。


TensorFlow 当然也有几个缺点,例如在实践中部署到 iOS,但这说来话长。使用 TensorFlow 不是没有痛苦,但与需要 Python runtime 的 Theano 相比,这还算什么事情吗?这是相当大的进步。


如果你使用 TensorFlow,我强烈建议你看看 tf.layers 或 TF-Slim。具体的说,tf.layers 本质上嵌入了 Keras API。


尽管我不指望任何有意义的性能差异;本帖讨论的操作最终定义了一个静态计算图形(computation graph),所以使用像 Keras 这样的包装器本身并不增加资源消耗,除了在图形定义时最小的资源占用,但是如果你原来使用 Theano,你会感到 TensorFlow 的启动时间快得多(以秒计而不是以分钟计的编译速度)。


遵循 TensorFlow 性能指南(TensorFlow performance guide)非常有用。在 DenseNet(L = 40,k = 12)模型上,从默认的 NHWC 和未融入批处理规范切换到 NCHW 和融入批处理规范后,我们的每个 epoch 时间都下降了超过 30%。在 WRN-16-4 模型上,我们看到 epoch 时间下降了超过 20%。


badmephisto(Andrej Karpathy)的回复:


我认为在深度神经网络库的设计方面,PyTorch 目前已然接近启发的高度。


  • 它属于轻量级;

  • 它目前位于 Python 中;

  • 它使你能够明确地控制计算。没有编译器能自己妄图变聪明来「帮助你」,或是将你的代码加速;事实上大多编译器在调试中会产生大量麻烦;

  • 它使 GPU 内核调用之上仅有少量(可解释的)抽象层,而这恰恰是高性能的保证;

  • 也许这是个人偏好,但我得到了与抽象有关的特定 OCD。每当我要做艰巨的工作时都会很紧张,因为一旦我的未来被泄漏,我便能感觉到它那些无法摆脱且难以忍受的痛苦。相对简单的事情理应在引擎盖之下发生的大多数情况下,这种感觉尤为强烈;

  • 调试更容易,因为特定代码中会是特定行(而不是在距离使用大型或生成的 Graph 对象的 sess.run()很远的地方)失败。你的堆栈跟踪不会填满三个屏幕来让你玩「找找错误在哪里!」的竖版卷轴游戏;

  • 不存在编译时间。我无法理解 Theano 用户是如何处理的,他们一定更有耐心;

  • 你可以直接操作渐变,显然,做一些事情时可以更容易,也更自然(如在反向传播过程中的渐变剪辑,或各种「破碎的反向传播」的有关想法,就像最近的 Shake Shake reg 命令一样;的确,我认为你可以用 stop_gradient 破解一个解决方案);

  • 它对动态图的支持从一开始就是自上而下的设计原则,而非随之而至的事后想法。并且我们会看到更多的动态图表,如做成一大块 NLP,或是神经模块网 ;

  • 它没有缩进或膨胀你的代码的显式会话对象;

  • 它获得的抽象是正确的:raw numpy - > Tensors(但 GPU 上的 raw numpy 可能对深度学习一无所知!)- >变量(它们了解深度学习),并且 Modules 或 Optim 等等会稍有益处。


到目前为止,我与 TF 的有关经验有些膨胀,所以即便是像数据驱动初始化这样理应很简单的事情,也会用到一些 tricks。当然,TF 的开发者有他们的一套解决方案,但往往涉及你从未听说过的 5 个 TensorFlow 函数的组合。我不记得曾用 Torch 做过这些,又或许我现在做的事情更复杂。


免责声明:我仍行进于对 PyTorch 进行尝试的漫漫征途中;所以我的经验是基于在 TensorFlow 做了很多复杂事情,而在 PyTorch 上才刚刚开始的背景上得到的。让我们看看未来会发生什么。


jeremyhoward的回复:


对于 Practical Deep Learning For Coders-18 hours of lessons for free 的第 2 部分,我们从 keras + theano(第 1 部分)切换到 Keras、TensorFlow 和 PyTorch 合用的状态。一般而言,使用 PyTorch 总是令人愉快的,主要是因为:


  • 动态计算使很多事情更加容易,如 seq2seq + attention 的神经翻译很难通过 keras + tf 来实现,但使用 PyTorch 便会很容易;

  • 更容易调试,因为你可以只使用标准的 PyThon 工具;

  • PyTorch 让自定义的实现更加容易,所以你得以将更多时间专注于算法中,这样往往能够改进主要性能;

  • 使 Multi-gpu 简单易懂;

  • Torch-vision 使加载和变换图像变得容易。


TensorFlow 的 API 非常荒谬,它在每个阶段都会重新发明轮子,并且要求开发者学习很多本不必要的新概念。然而,开发者峰会表示这一境况正在改善——而且同时使用 TensorFlow Servin 和 Cloud ML 会提高你的生产力。


Powlerbare的回复:


我大约在半年前使用 TensorFlow 实现了一些 seq2seq 模型,并意识到为何 TensorFlow 很好用:它的内置组件很棒,让研究变得就像有老师在推动着你一样容易,而注意与损失函数就如同噪声对比估测,等等。倘若我收集基线或修改函数,一切都会变容易。我已经习惯于搜索代码库,并确定究竟哪种函数在运作(如果不小心,某些可选的函数默认值便会得到不好的结果)——并且我对基于这些实现的大部分报告结果非常有信心。


下面是几点与我所爱的 PyTorch 有关,而 TensorFlow 却不会提供的事项:


1)PyTorch 提供了一个强化功能,我很喜欢它。增强功能基本上不会在实现中产生过多资源消耗,能有一些内置函数来调用 RL 的感觉真棒。


2)我并未大量使用 autograd,因为那时它速度很慢,但人们感觉用它来做一些没谱的事情很有趣。我是这个范例的死忠粉,因为我没来由地钟爱在 numpy 上编写网络。

选自Reddit机器之心编译