摘要:上一篇 2020年計算機視覺學習指南 介紹了兩種深度學習框架--Keras 和 PyTorch ,這篇文章的作者就對這兩個框架進行了對比,分別通過實現一個簡單的模型來對比兩個不同的代碼風格,最後還給出了他的個人建議。目前有很多深度學習的框架或者庫,但本文會對比兩個框架,Keras 和 PyTorch ,這是兩個非常好開始使用的框架,並且它們都有一個很低的學習曲線,初學者可以很快就學會它們,因此在本文,我將分享一個辦法來解決如何選擇其中一個框架進行使用。

點擊上方“ 算法猿的成長 “, 關注公衆號,選擇加“星標“或“置頂”

總第 135 篇文章,本文大約 7000   字,閱讀大約需要 20 分鐘

原文:https://medium.com/@karan_jakhar/keras-vs-pytorch-dilemma-dc434e5b5ae0

作者:Karan Jakhar

前言

上一篇 2020年計算機視覺學習指南 介紹了兩種深度學習框架--Keras 和 PyTorch ,這篇文章的作者就對這兩個框架進行了對比,分別通過實現一個簡單的模型來對比兩個不同的代碼風格,最後還給出了他的個人建議。

當你決定開始學習深度學習,那麼應該選擇使用什麼工具呢?目前有很多深度學習的框架或者庫,但本文會對比兩個框架,Keras 和 PyTorch ,這是兩個非常好開始使用的框架,並且它們都有一個很低的學習曲線,初學者可以很快就學會它們,因此在本文,我將分享一個辦法來解決如何選擇其中一個框架進行使用。

最好的辦法就是查看兩個框架各自的代碼風格。設計任何方案的前提和最重要的事情就是你的工具,當你開始一個項目前必須安裝配置好你的工具,並且一旦開始項目後,就不應該更改時用的工具。它會影響到你的生產力。作爲一個初學者,你應該儘量嘗試不同的工具,並且找到合適你的,但如果你正在參加一個非常正式的項目工作,那麼這些事情都應該提早計劃好。

每天都會有新的框架和工具面世,對你最好的工具應該是在個性化和抽象做好平衡的,它應該可以同步你的思考和代碼風格,那麼如何找到這樣合適的工具呢, 答案就是你需要嘗試不同的工具

接下來,讓我們分別用 Keras 和 PyTorch 訓練一個簡單的模型吧。如果你是深度學習的初學者,那麼不要擔心理解不了某些名詞概念, 目前你只需要關注這兩個框架的代碼風格,並思考哪個纔是最合適你的,也就是讓你感覺更舒適並且更容易上手的

這兩個框架的主要不同點是 PyTorch 默認是 eager 模式,而 Keras 是在 TensorFlow 和其他框架的基礎上進行工作,但目前主要是基於 TensorFlow 框架的,因此其默認是圖( graph )模式。當然,最新版本的 TensorFlow 也提供了和 PyTorch 一樣的 eager 模式。如果你對 NumPy 很熟悉的話,你可以把 PyTorch 看作是有 GPU 支持的 NumPy 。此外,也有不少類似 Keras 一樣的第三方庫作爲高級 API 接口,它們使用 PyTorch 作爲後端支持,比如 Fastai (提供了免費的很好的課程)、 Lightning , Ignite 等等。也可以去了解這些框架,如果你發現它們很有趣,那你就多了一個理由使用 PyTorch 。

這兩種框架都有不同的方法來實現一個模型。這裏都分別選擇了一種簡單的實現方式。下面是分別在谷歌的 Colab 上實現的代碼的鏈接,打開鏈接並運行代碼,這更加有助於找到更合適你的框架:

Keras: https://colab.research.google.com/drive/1QH6VOY_uOqZ6wjxP0K8anBAXmI0AwQCm?usp=sharing#forceEdit=true&sandboxMode=true

PyTorch: https://colab.research.google.com/drive/1irYr0byhK6XZrImiY4nt9wX0fRp3c9mx?usp=sharing#scrollTo=FoKO0mEScvXi&forceEdit=true&sandboxMode=true

也可以在後臺直接回復【 keras_pytorch 】或者【 20200509 】獲取分享的代碼,代碼分爲 jupyter 形式的 ipynb 文件和 py 文件兩種。

本文並不會介紹太細節的東西,因爲我們的目標只是對兩個框架的代碼結構和風格進行查看和了解。

基於 Keras 的模型實現

下面是實現數字識別的代碼實現。代碼非常容易理解,你最好在 colab 中查看並且進行實驗,至少要開始運行起來。

from keras.datasets import mnist
from keras.utils import to_categorical
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPooling2D

img_rows, img_cols = 28, 28
num_classes = 10
batch_size = 128
epochs = 10

(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
x_train = x_train/255
x_test  = x_test/255
y_train = to_categorical(y_train, num_classes)
y_test = to_categorical(y_test, num_classes)

在 Keras 中有一些作爲樣例的數據集,其中一個就是 MNIST 手寫數字數據集,上述代碼主要是實現加載數據集的功能,圖片是 NumPy 的數組格式。另外,上述代碼也做了一點的圖像處理來將數據可以應用到模型中。

model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3),
     activation='relu',
     input_shape=(img_rows, img_cols, 1)))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss='categorical_crossentropy',
      optimizer='adam',
      metrics=['accuracy'])

上述代碼就是模型的代碼實現。在 Keras(TensorFlow) 中,我們需要先定義想使用的所有東西,然後它們會只運行一次。我們不能對它們進行實驗,但是在 PyTorch 中是可以做到的。

model.fit(x_train, y_train,
          batch_size=batch_size,
          epochs=epochs,
          verbose=1,
          validation_data=(x_test, y_test))

score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])
model.save("test_model.h5")

# load the model
from keras.models import load_model
model = load_model("test_model.h5")

# predict digit
prediction = model.predict(gray)
print(prediction.argmax())

上述代碼就是訓練和驗證模型,可以使用 save() 方法來保存模型,然後通過 load_model() 方法來加載保存的模型文件, predict() 方法是用於對測試數據進行預測得到預測結果。

這就是使用 Keras 簡單實現一個模型的概覽,下面看看 PyTorch 是怎麼實現模型的吧。

基於 PyTorch 的模型實現

研究者主要用 PyTorch ,因爲它的靈活性以及偏實驗的代碼風格,這包括可以對 PyTorch 的一切都進行修改調整,對 也就是可以完全控制一切,進行實驗也是非常容易。在 PyTorch 中,不需要先定義所有的事情再運行,對每個單獨的步驟的測試都非常容易。因此,它比 Keras 更容易調試。

下面也是利用 PyTorch 實現一個簡單的數字識別模型。

import torch
import torchvision
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

n_epochs = 3
batch_size_train = 64
batch_size_test = 1000
learning_rate = 0.01
momentum = 0.5
log_interval = 10

random_seed = 1
torch.backends.cudnn.enabled = False
torch.manual_seed(random_seed)

上述代碼主要是導入需要的庫以及定義了一些變量,這些變量如 n_epochs, momentum 等都是必須設置的超參數,但這裏不會詳細展開說明,因爲我們也說過本文的目標是理解框架的代碼結構和風格。

train_loader = torch.utils.data.DataLoader(
  torchvision.datasets.MNIST('/files/', train=True, download=True,
                             transform=torchvision.transforms.Compose([
                               torchvision.transforms.ToTensor(),
                               torchvision.transforms.Normalize(
                                 (0.1307,), (0.3081,))
                             ])),
  batch_size=batch_size_train, shuffle=True)

test_loader = torch.utils.data.DataLoader(
  torchvision.datasets.MNIST('/files/', train=False, download=True,
                             transform=torchvision.transforms.Compose([
                               torchvision.transforms.ToTensor(),
                               torchvision.transforms.Normalize(
                                 (0.1307,), (0.3081,))
                             ])),
  batch_size=batch_size_test, shuffle=True)

examples = enumerate(test_loader)
batch_idx, (example_data, example_targets) = next(examples)

example_data.shape

這段代碼則是聲明瞭一個數據加載器用於加載訓練數據集進行訓練和測試。數據集有多種下載數據的方法,這和框架沒有關係。當然上面這段代碼對於深度學習的初學者可能是有些複雜了。

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 10, kernel_size=5)
        self.conv2 = nn.Conv2d(10, 20, kernel_size=5)
        self.conv2_drop = nn.Dropout2d()
        self.fc1 = nn.Linear(320, 50)
        self.fc2 = nn.Linear(50, 10)

    def forward(self, x):
        x = F.relu(F.max_pool2d(self.conv1(x), 2))
        x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))
        x = x.view(-1, 320)
        x = F.relu(self.fc1(x))
        x = F.dropout(x, training=self.training)
        x = self.fc2(x)
        return F.log_softmax(x)

接下來這段代碼就是定義模型。這是一個很通用的創建一個網絡模型的方法,定義一個類繼承 nn.Moduleforward() 方法是實現網絡的前向傳播。PyTorch 的實現是非常直接,並且可以根據需要進行修改。

network = Net()
optimizer = optim.SGD(network.parameters(), lr=learning_rate,
                      momentum=momentum)
train_losses = []
train_counter = []
test_losses = []
test_counter = [i*len(train_loader.dataset) for i in range(n_epochs + 1)]

def train(epoch):
  network.train()
  for batch_idx, (data, target) in enumerate(train_loader):
    optimizer.zero_grad()
    output = network(data)
    loss = F.nll_loss(output, target)
    loss.backward()
    optimizer.step()
    if batch_idx % log_interval == 0:
      print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
        epoch, batch_idx * len(data), len(train_loader.dataset),
        100. * batch_idx / len(train_loader), loss.item()))
      train_losses.append(loss.item())
      train_counter.append(
        (batch_idx*64) + ((epoch-1)*len(train_loader.dataset)))
      torch.save(network.state_dict(), 'model.pth')
      torch.save(optimizer.state_dict(), 'optimizer.pth')

def test():
  network.eval()
  test_loss = 0
  correct = 0
  with torch.no_grad():
    for data, target in test_loader:
      output = network(data)
      test_loss += F.nll_loss(output, target, size_average=False).item()
      pred = output.data.max(1, keepdim=True)[1]
      correct += pred.eq(target.data.view_as(pred)).sum()
  test_loss /= len(test_loader.dataset)
  test_losses.append(test_loss)
  print('\nTest set: Avg. loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
    test_loss, correct, len(test_loader.dataset),
    100. * correct / len(test_loader.dataset)))

test()
for epoch in range(1, n_epochs + 1):
  train(epoch)
  test()

接下來這段代碼,我們分別定義了訓練和測試函數, train()test() 。在 Keras 中直接調用 fit() 函數,然後所有事情都給我們實現好了,但是在 PyTorch 中我們需要手動實現這些步驟。當然,在一些高級 API 庫,比如 Fastai 裏將這部分也變得很簡單,減少了需要的代碼量。

#loading the model
continued_network = Net()
continued_optimizer = optim.SGD(network.parameters(), lr=learning_rate,
                                momentum=momentum)
network_state_dict = torch.load('model.pth')
continued_network.load_state_dict(network_state_dict)

optimizer_state_dict = torch.load('optimizer.pth')
continued_optimizer.load_state_dict(optimizer_state_dict)

最後就是保存和加載模型用於再次訓練或者進行預測的代碼。PyTorch 的模型文件通常是以 pt 或者 pth 爲後綴名。

個人的建議

當你開始學習一個模型,並且理解它的理念後,從一個框架轉移到另一個並不困難,這隻需要幾天的工作。**我的建議就是兩個框架都要學習,但不需要學得非常深入。你應該選擇一個框架並開始實現你的模型代碼,但同時也需要對另一個框架有所瞭解。這有助於你閱讀用另一個框架實現的模型代碼。**你不應該被框架所約束,它們都是很好的框架。

我最初開始使用的是 Keras,但現在我在工作中使用 PyTorch,因爲它可以更好的進行實驗。我喜歡 PyTorch 的 python 風格。所以首先使用一個你覺得更適合你的框架,然後同時也嘗試去學習另一個框架,如果學習後發現它使用更加舒適,那就改爲使用它,並且這兩個框架的核心概念都是非常相似的,兩者的相互轉換都非常容易。

最後祝你在深度學習之旅中好運。你應該更專注算法的理論概念以及它們在現實生活中如何使用和實現的。

最後再次給出兩份模型代碼實現的 colab 鏈接:

  • PyTorch: https://colab.research.google.com/drive/1irYr0byhK6XZrImiY4nt9wX0fRp3c9mx?usp=sharing

  • Keras: https://colab.research.google.com/drive/1QH6VOY_uOqZ6wjxP0K8anBAXmI0AwQCm?usp=sharing

也可以關注我的公衆號--【 算法猿的成長 】,然後在後臺直接回復【 keras_pytorch 】或者【 20200509 】獲取分享的代碼,代碼分爲 jupyter 形式的 ipynb 文件和 py 文件兩種。

精選AI文章

1.   2020年計算機視覺學習指南

2.  編寫高效的PyTorch代碼技巧(上)

3.  編寫高效的PyTorch代碼技巧(下)

4.  深度學習算法簡要綜述(上)

5.  深度學習算法簡要綜述(上)

6.  常見的數據增強項目和論文介紹

7.  實戰|手把手教你訓練一個基於Keras的多標籤圖像分類器

精選python文章

1.  python數據模型

2. python版代碼整潔之道

3.  快速入門 Jupyter notebook

4. Jupyter 進階教程

5. 10個高效的pandas技巧

精選 教程資源文章

1.  [資源分享] TensorFlow 官方中文版教程來了

3.   [Github項目推薦] 推薦三個助你更好利用Github的工具

4.  Github上的各大高校資料以及國外公開課視頻

5.  GitHub上有哪些比較好的計算機視覺/機器視覺的項目?

歡迎關注我的微信公衆號-- 算法猿的成長 ,或者掃描下方的二維碼,大家一起交流,學習和進步!

如果覺得不錯,在看、轉發就是對小編的一個支持!

相關文章