Keras 和 PyTorch 當然是對初學者最友好的深度學習框架,它們用起來就像描述架構的簡單語言一樣,告訴框架哪一層該用什麼。這樣減少了很多抽象工作,例如設計靜態計算圖、分別定義各張量的維度與內容等等。
但是,到底哪一個框架更好一點呢?當然不同的開發者和研究者會有不同的愛好,也會有不同的看法。本文主要從抽象程度和效能兩個方面對比 PyTorch 與 Keras,並介紹了一個新的基準,它復現並對比了兩個框架的所有預訓練模型。
在 Keras 和 PyTorch 基準專案中,MIT 在讀博士 Curtis G. Northcutt 復現了 34 個預訓練模型。該基準結合了 Keras 和 PyTorch,並將它們統一到一個框架內,這樣我們就能知道這兩個框架的對比結果,知道不同模型用什麼框架好。例如,專案作者表示 ResNet 架構的模型使用 PyTorch 要比 Keras 效果好,Inception 架構的模型使用 Keras 又要比 PyTorch 好。
Keras 和 PyTorch 基準專案:https://github.com/cgnorthcutt/benchmarking-keras-pytorch
兩大框架的效能與易用性
作為 TensorFlow 的高度封裝,Keras 的抽象層次非常高,很多 API 細節都隱藏了起來。雖然 PyTorch 比 TensorFlow 的靜態計算圖更容易使用,但總體上 Keras 隱藏的細節更多一些。而對於效能,其實各框架都會經過大量的優化,它們的差別並不是很明顯,也不會作為主要的選擇標準。
易用性
Keras 是一個更高階別的框架,將常用的深度學習層和運算封裝進便捷的構造塊,並像積木一樣搭建複雜模型,開發者和研究者不需要考慮深度學習的複雜度。
PyTorch 提供一個相對較低階別的實驗環境,使使用者可以更加自由地編寫自定義層、檢視數值優化任務等等。例如在 PyTorch 1.0 中,編譯工具 torch.jit 就包含一種名為 Torch Script 的語言,它是 Python 的子語言,開發者使用它能進一步對模型進行優化。
我們可以通過定義簡單的卷積網路看看兩者的易用性:
model = Sequential()model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)))model.add(MaxPool2D())model.add(Conv2D(16, (3, 3), activation='relu'))model.add(MaxPool2D())model.add(Flatten())model.add(Dense(10, activation='softmax'))複製程式碼
如上所示為 Keras 的定義方式,很多時候運算都會作為引數嵌入到 API 中,因此程式碼會顯得非常簡潔。如下所示為 PyTorch 的定義方式,它一般都是通過類和例項的方式定義,且具體運算的很多維度引數都需要定義。
class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Conv2d(3, 32, 3) self.conv2 = nn.Conv2d(32, 16, 3) self.fc1 = nn.Linear(16 * 6 * 6, 10) self.pool = nn.MaxPool2d(2, 2) def forward(self, x): x = self.pool(F.relu(self.conv1(x))) x = self.pool(F.relu(self.conv2(x))) x = x.view(-1, 16 * 6 * 6) x = F.log_softmax(self.fc1(x), dim=-1) return xmodel = Net()複製程式碼
雖然 Keras 感覺比 PyTorch 更易於使用,但兩者的差別不大,都期望模型的編寫能更便捷。
效能
目前有很多對比各框架效能的實驗都表明 PyTorch 的訓練速度相比 Keras 會快一些。如下兩張圖表展示了不同框架在不同硬體和模型型別的表現:
下面兩張同樣展示了不同模型在 PyTorch 和 Keras 框架下的效能,這兩份 18 年的測試都表明 PyTorch 的速度要比 Keras 快那麼一點點。
這兩份對比細節可查閱:
https://github.com/ilkarman/DeepLearningFrameworks/
https://wrosinski.github.io/deep-learning-frameworks/
Keras 和 PyTorch Benchmark
現在如果我們從預訓練模型的角度看,那麼相同的模型在不同的框架上,驗證集準確度又是什麼樣的?在這個專案中,作者用兩個框架一共復現了 34 個預訓練模型,並給出了所有預訓練模型的驗證準確率。所以該專案不僅能作為對比依據,同時還能作為學習資源,又有什麼比直接學習經典模型程式碼更好的方法呢?
預訓練模型不是已經可以復現了嗎?
在 PyTorch 中是這樣的。然而有些 Keras 使用者卻覺得復現非常難,他們遇見的問題可以分為三類:
1. 不能復現 Keras 已釋出的基準結果,即使完全複製示例程式碼也沒有用。實際上,他們報告的準確率(截止到 2019 年 2 月)通常略高於實際準確率。
2. 一些預訓練的 Keras 模型在部署到某個伺服器或與其他 Keras 模型一起依次執行時會產生不一致或較低的準確率。
3. 使用批歸一化(BN)的 Keras 模型可能並不可靠。對於一些模型,前向傳播評估仍然會導致推理階段中的權重改變。
這些問題都是現實存在的,原 GitHub 專案為每個問題都提供了連結。專案作者的目標之一是通過為 Keras 預訓練模型建立可復現基準,從而幫助解決上述的一些問題。解決方法可分為以下三個方面,在 Keras 中要做到:
推理期間避免分批(batches)。
每次執行一個樣本,這樣做非常慢,但可以為每個模型得出一個可復現的輸出。
只在本地函式或 with 語句中執行模型,以確保在載入下一個模型時,前一個模型的任何東西都不會儲存在記憶體中。
預訓練模型復現結果
以下是 Keras 和 PyTorch 的「實際」驗證集準確度表(已經在 macOS 10.11.6、Linux Debian 9 和 Ubuntu 18.04 上得到驗證)。
復現方法
首先需要下載 ImageNet 2012 驗證集,該資料集包含 50000 張圖片。在 ILSVRC2012_img_val.tar 下載完成後,執行以下命令列預處理/提取驗證集:
# Credit to Soumith: https://github.com/soumith/imagenet-multiGPU.torch$ cd ../ && mkdir val && mv ILSVRC2012_img_val.tar val/ && cd val && tar -xvf ILSVRC2012_img_val.tar$ wget -qO- https://raw.githubusercontent.com/soumith/imagenetloader.torch/master/valprep.sh | bash複製程式碼
ImageNet 驗證集中每個示例的 top 5 預測已經進行了預計,執行以下命令列將直接使用這些預計算結果,並在幾秒內復現 Keras 和 PyTorch 基準。
$ git clone https://github.com:cgnorthcutt/imagenet-benchmarking.git$ cd benchmarking-keras-pytorch$ python imagenet_benchmarking.py /path/to/imagenet_val_data複製程式碼
不使用預計算資料也可以復現每個 Keras 和 PyTorch 的推理輸出。Keras 的推理要花很長時間(5-10 小時),因為每次只計算一個示例的前向傳播,還要避免向量計算。如果要可靠地復現同樣的準確率,這是目前發現的唯一的方法。PyTorch 的推理非常快(一個小時都不到)。復現程式碼如下:
$ git clone https://github.com:cgnorthcutt/imagenet-benchmarking.git$ cd benchmarking-keras-pytorch$ # Compute outputs of PyTorch models (1 hour)$ ./imagenet_pytorch_get_predictions.py /path/to/imagenet_val_data$ # Compute outputs of Keras models (5-10 hours)$ ./imagenet_keras_get_predictions.py /path/to/imagenet_val_data$ # View benchmark results$ ./imagenet_benchmarking.py /path/to/imagenet_val_data複製程式碼
你可以控制 GPU 的使用、批大小、輸出儲存目錄等。執行時加上-h flag,可以檢視命令列引數選項。
看完文章之後,你更中意誰呢?