PyTorch VS TensorFlow:細(xì)數(shù)兩者的不同之處
在今年 5 月初召開的 Facebook F8 開發(fā)者大會上,F(xiàn)acebook 宣布將推出旗下機(jī)器學(xué)習(xí)開發(fā)框架 PyTorch 的新一代版本 PyTorch 1.0。據(jù) Facebook 介紹,PyTorch 1.0 結(jié)合了 Caffe2 和 ONNX 模塊化、面向生產(chǎn)的特性,和 PyTorch 自身靈活、面向研究的特性結(jié)合起來,為廣泛的 AI 項(xiàng)目提供了一個從科研原型到生產(chǎn)部署的快速、無縫途徑,讓用戶可以快速實(shí)驗(yàn),通過一個能在強(qiáng)制執(zhí)行模式和聲明執(zhí)行模式之間無縫切換的混合前端優(yōu)化性能。
Facebook F8 開發(fā)者大會
除了將研究和生產(chǎn)特性結(jié)合起來,PyTorch 1.0 還將 ONNX 包含進(jìn)來。ONNX 是 Facebook 去年聯(lián)合多家軟硬件公司發(fā)布的神經(jīng)網(wǎng)絡(luò)模型轉(zhuǎn)換協(xié)議,現(xiàn)在,它新增了對蘋果的 Core ML、百度 PaddlePaddle、高通 SNPE 的支持,再加上原本支持的 MXNet、Caffe2、PyTorch、TensorFlow、CNTK 等框架,實(shí)現(xiàn)了神經(jīng)網(wǎng)絡(luò)模型在各種主流框架之間的轉(zhuǎn)換。
PyTorch 1.0 beta 版將在今年夏天和用戶見面。
整體來看,剛發(fā)布一年左右的 PyTorch 仍然是款比較新的框架,尤其是和 TensorFlow 相比較而言,但 PyTorch 發(fā)展非常迅猛。
比如今年 3 月,人工智能大神 Andrej Karpathy 在推特上曬出了過去 6 年 aXriv 論文中各主要深度學(xué)習(xí)框架的使用比例(單次計(jì)算):TensorFlow 14.3%,PyTorch 4.7%,Keras 4.0%,Caffe 3.8%,Theano 2.3%,Torch 1.5%,MXNet、Chainer 和 CNTK 均小于1%:
如果我們細(xì)看會發(fā)現(xiàn) PyTorch 增長勢頭驚人:

因此,未來在深度學(xué)習(xí)框架領(lǐng)域預(yù)計(jì) PyTorch 會成為 TensorFlow 的主要挑戰(zhàn)者。
那么這兩種框架有何不同之處?自己學(xué)習(xí)使用時,該選哪一種?
Cinimex DataLab CTO Kirill Dubovikov 發(fā)文詳細(xì)分析了 PyTorch 和 TensorFlow 的區(qū)別,可以參考一下。(注:本文寫于去年,當(dāng)前一些性能細(xì)節(jié)可能已經(jīng)更新)。
本文我(Kirill Dubovikov——譯者注)想探究一下 PyTorch 和 TensorFlow 這兩種框架之間的重要區(qū)別。為何選它們?現(xiàn)在市面上有很多深度學(xué)習(xí)框架,其中有些都是很不錯的工具,我選這兩個是因?yàn)槲覍υ敿?xì)比較它們很感興趣。
起源
TensorFlow 由谷歌大腦開發(fā),并被谷歌應(yīng)用在研究和產(chǎn)品需求中。它的前身是閉源工具DistBelief。
PyTorch 算是基于 Lua 語言的框架 Torch 的近親,Torch 廣泛應(yīng)用在 Facebook 研發(fā)中。然而,PyTorch 并非簡單的只是一套支持流行編程語言的封裝器,它被重新編寫,運(yùn)行速度更快,感覺更原生。
比較這兩種框架的最好方式就是用它們寫寫代碼。我給本文也寫了個比較它們的 Jupyter notebook,可以點(diǎn)擊這里查看(https://github.com/kdubovikov/tf-vs-pytorch/blob/master/pytorch_vs_tf_simple_model.ipynb)。后面我也會引用里面的代碼。
首先,我們用這兩個框架為下面這個函數(shù)寫一個簡單的逼近器(approximator):
我們用 PyTorch:
如果你有過使用深度學(xué)習(xí)框架的經(jīng)驗(yàn),你可能會注意到我們是在手動實(shí)現(xiàn)梯度下降。覺得不是很方便?幸好 PyTorch 有 optimize 模塊,應(yīng)用了不少流行的優(yōu)化算法比如 RMSProp 和Adam。
我們會使用 SGD 算法:

可以看到,我們從訓(xùn)練數(shù)據(jù)中快速的引用了真正的指數(shù)。下面我們試試TensorFlow:

同樣可以看到,在TensorFlow中也能實(shí)現(xiàn)。雖然TensorFlow獲得指數(shù)用的迭代次數(shù)更多,但我確定是因?yàn)槲覜]有認(rèn)真調(diào)整優(yōu)化器的參數(shù),達(dá)到可以比較兩者結(jié)果的水平。
現(xiàn)在,我們接著探究更多的不同之處。
區(qū)別#0 —— 應(yīng)用
目前很多研究人員和從業(yè)人員把 TensorFlow 看作一款隨手可用的工具。TensorFlow 官方提供了很好的使用文檔,如果文檔中沒有,網(wǎng)上也有很多寫的非常詳細(xì)的教程。GitHub 上也能找到一大堆用 TensorFlow 實(shí)現(xiàn)和訓(xùn)練的模型。
PyTorch 和 TensorFlow 相比,還是個比較新的工具,但發(fā)展勢頭很猛。官方文檔和教程也不錯。PyTorch 也包含了流行計(jì)算機(jī)視覺框架的實(shí)現(xiàn),非常易用。
區(qū)別 #1——動態(tài)及靜態(tài)圖形定義
兩種框架都在張量上運(yùn)行,把任何模型都看作一個有向非循環(huán)圖(DAG),但對于如何定義它們,PyTorch 和 TensorFlow 區(qū)別很大。
TensorFlow 遵循“數(shù)據(jù)即是代碼,代碼就是數(shù)據(jù)”的理念。在 TensorFlow 中,在跑模型之前會靜態(tài)的定義圖形。和外界的所有聯(lián)系都是通過 tf.Session 對象和 tf.Placeholder,它們都是會在模型運(yùn)行被外部數(shù)據(jù)取代的張量。
在 PyTorch 中,會更動態(tài)一些:你可以隨著進(jìn)展定義、更改和執(zhí)行節(jié)點(diǎn),沒有特殊的會話界面或占位符。整體來看,PyTorch 和 Python 結(jié)合的更緊湊些,多數(shù)時候會感覺更原生。而在 TensorFlow 里寫東西時,有時你會覺得你的模型好像躲在一堵墻后面一樣,就通過墻上的幾個洞洞跟你交流。當(dāng)然了,這也看每個人的喜好和品味。
不過,不單單是在軟件工程方面有區(qū)別,一些動態(tài)神經(jīng)網(wǎng)絡(luò)架構(gòu)可以從這種動態(tài)方法種受益。回想一下循環(huán)神經(jīng)網(wǎng)絡(luò):有靜態(tài)圖形,輸入序列長度會保持不變。這意味著如果你開發(fā)一個應(yīng)用于英語句子的情緒分析模型,就必須將序列長度修正為某些最大值,用 0 填補(bǔ)所有較小的序列。這比較麻煩吧。在遞歸循環(huán)神經(jīng)網(wǎng)絡(luò)和樹形循環(huán)神經(jīng)網(wǎng)絡(luò)方面,你會遇到更多問題。
目前,TensorFlow 對于動態(tài)輸入的支持比較有限,而 PyTorch 則是默認(rèn)的支持動態(tài)輸入。
區(qū)別 #2—— 調(diào)試
由于 PyTorch 的計(jì)算圖是在運(yùn)行時定義,因此可以用 pdb,ipdb,PyCharm 這些 Python 調(diào)試工具或者以前的可靠的打印語句也行。
TensorFlow 則不同,你可以選擇用一個叫 tfdbg 的特殊工具,它能讓你在運(yùn)行時評估 TensorFlow 表達(dá)式,瀏覽所有張量,在會話范圍中操作。當(dāng)然,無法用它調(diào)試 Python 代碼,因此無需單獨(dú)使用 pdb。
區(qū)別 #3——可視化
在可視化方面,TensorFlow 的 Tensorboard 是個非常棒的功能。它內(nèi)置在 TensorFlow 中,在調(diào)試和比較不同的訓(xùn)練狀況時非常有用。例如,假設(shè)你訓(xùn)練了一個模型,然后調(diào)整一些超參數(shù)后又訓(xùn)練一次。而在 Tensorboard 上可以將這兩次模型運(yùn)行狀況同時展現(xiàn)出來,從而看出兩次的差異。Tensorboard 可以:
展示模型圖形
繪制標(biāo)量變量
可視化分布和直方圖
可視化圖形
播放音頻
Tensorboard 可以展示多種總結(jié),通過 tf.summary 模塊就可以收集到。我們可以為前面的指數(shù)例子定義總結(jié)操作,用 tf.summary.FileWriter 將它們保存到桌面。
執(zhí)行 tensorboard --logdir=./tensorboard 就可啟動 Tensorboard。由于它是 web 應(yīng)用,因此可以很方便的用在云實(shí)例上。
目前 PyTorch 并沒有可以和 Tensorboard 匹敵的工具,不過倒是存在一些集成功能。雖然也能用一些繪圖工具比如 matplotlib 和 seaborn,但在可視化這方面,PyTorch 要遜于 TensorFlow。
區(qū)別 #4——部署
在部署這方面,TensorFlow 很明顯目前略勝一籌:其內(nèi)置框架 TensorFlow Serving 能讓你在特制的 gPRC 服務(wù)器上部署你的模型。也同樣支持移動端。
在 PyTorch 上,我們就需要用 Flask 或其它工具在模型上編寫一個 REST API。在使用 TensorFlow 的時候,如果 gPRC 不是很適用,我們同樣可以這么做。不過,如果考慮性能的話,TensorFlow Serving 會是更好的選擇。
TensorFlow 同樣支持分布式訓(xùn)練,這點(diǎn) PyTorch 目前尚不具備。
區(qū)別 #5—— 數(shù)據(jù)并行
PyTorch 不同于 TensorFlow 的最大特性之一就是聲明式數(shù)據(jù)并行:你可以用 torch.nn.DataParellel 封裝任何模型,而且模型能在批處理維度上實(shí)現(xiàn)并行。這樣你就可以毫不費(fèi)力的使用多個 GPU。
另一方面,TensorFlow 能讓你調(diào)試在具體設(shè)備上運(yùn)行的所有操作。不過,數(shù)據(jù)并行不僅需要手動調(diào)整,還需要深思熟慮。我們看看在 TensorFlow 中實(shí)現(xiàn)數(shù)據(jù)并行的代碼:
def make_parallel(fn, num_gpus, **kwargs):
in_splits = {}
for k, v in kwargs.items():
in_splits[k] = tf.split(v, num_gpus)
out_split = []
for i in range(num_gpus):
with tf.device(tf.DeviceSpec(device_type="GPU", device_index=i)):
with tf.variable_scope(tf.get_variable_scope(), reuse=tf.AUTO_REUSE):
out_split.append(fn(**{k : v[i] for k, v in in_splits.items()}))
return tf.concat(out_split, axis=0)
def model(a, b):
return a + b
c = make_parallel(model, 2, a=a, b=b)
我們可以看到,用 TensorFlow 也能實(shí)現(xiàn)用 PyTorch 做到的所有操作,但是要麻煩的多(不過相應(yīng)會有更多的控制權(quán))。
此外值得一提的是,兩個框架都支持分布式執(zhí)行,提供用于定義集群的高水平界面。
區(qū)別 #6——一個更像框架,一個更像庫
我們搭建一個分類手寫數(shù)字的 CNN 分類器。PyTorch 開始會看起來很像一個框架。回想一下,編程框架會在特定領(lǐng)域?yàn)槲覀兲峁┯杏玫某橄?,用它們可以很方便的解決具體問題。而這是框架和庫的的本質(zhì)區(qū)別之處。
這里我們引入 datasets 模塊,它包含的封裝器適用于眾多用于基準(zhǔn)測試深度學(xué)習(xí)架構(gòu)的常見數(shù)據(jù)集。此外,nn.Module 用于搭建自定義 CNN 分類器,就好比 PyTorch 中的程序塊(building block),能讓我們創(chuàng)建復(fù)雜的深度學(xué)習(xí)架構(gòu)。在 torch.nn 包中有很多現(xiàn)成可用的模塊,可以作為我們模型的基礎(chǔ)。PyTorch 用面向?qū)ο蟮姆椒▉矶x基本的程序塊,在通過子類化拓展功能的同時,也給了我們一些“通道”繼續(xù)前行。
這是略微修改后的模型版本:
https://github.com/pytorch/examples/blob/master/mnist/main.py
相比之下,TensorFlow 給人的感覺更像是一個庫,而非一個框架:所有的操作都為低階操作,你需要寫很多樣板代碼,即便你可能并不想寫(比如,一遍又一遍的定義方差和權(quán)重···)。隨著時間推移,也漸漸出現(xiàn)了一批圍繞 TensorFlow 的高級封裝器,都是為了簡化我們使用 TensorFlow 的方式。它們大部分目前都在 tensorflow.contrib 模塊中(很多人并不將它看做一個穩(wěn)定的 API),有些也遷移到了主庫中(見 tf.layers)。
所以,你在如何使用 TensorFlow 上有很大的自由度,同樣也能自由選擇使用最匹配任務(wù)的框架:TFLearn,tf.contrib.learn,Sonnet,Keras,plain tf.layers 等等。說實(shí)話,僅 Keras 這一個框架,就能單獨(dú)寫一篇文章討論。不過這已超出本文討論范圍,暫且不表。
這里我們用 tf.layers 和 tf.contrib.learn 搭建我們的 CNN 分類器,代碼和 tf.layers 官方教程一致:https://www.tensorflow.org/tutorials/layers
因此,TensorFlow 和 PyTorch 都能提供有用的抽象,減少樣板代碼的數(shù)量,加快模型的部署速度。這兩者的主要不同之處是 PyTorch 感覺更有“Python 味”一些,采用面向?qū)ο蟮姆椒?,?TensorFlow 有多種供你選擇的選項(xiàng)。
總結(jié)
TensorFlow 是一款強(qiáng)大而成熟的深度學(xué)習(xí)庫,有強(qiáng)大的可視化性能,以及用于高水平模型開發(fā)的多個選項(xiàng)。它具備生產(chǎn)就緒的部署選項(xiàng),也支持移動平臺。如果你符合以下情況, TensorFlow 會是個很好的選擇:
開發(fā)用于生產(chǎn)的模型
開發(fā)需要在移動平臺上部署的模型
想要非常好的社區(qū)支持和較為全面的幫助文檔
想要豐富的多種形式的學(xué)習(xí)資源
想要或需要使用 Tensorboard
需要用到大規(guī)模的分布式模型訓(xùn)練
轉(zhuǎn)自網(wǎng)絡(luò)