深度學習框架 PyTorch

隨著深度學習的研究熱潮持續高漲,各種開源深度學習框架也層出不窮,包括 TensorFlow、PyTorch、Caffe2、Keras、CNTK、MXNet、Paddle、DeepLearning4、Lasagne、Neon 等等。其中,谷歌推出的 TensorFlow 無疑在關注度和用戶數上都佔據絕對優勢,最為流行。但是,今天我將給大家介紹的卻是另外一個發展與流行勢頭強勁的深度學習框架:PyTorch。

為什麼選擇 PyTorch

首先,我們來看一張圖:

深度學習框架 PyTorch

這張圖來自斯坦福 Stanford CS231n (Spring 2017),我們可以看到如今幾個主流的深度學習框架。其中,Caffe2 由 Facebook 推出,它的前身是 UC Berkeley 推出的 Caffe。PyTorch 也由 Facebook 推出,它的前身是 NYU 和 Facebook 一起推出的 Torch。TensorFlow 由 Google 推出,它的前身是 U Montreal 推出的 Theano。另外,還有百度推出的 Paddle,Microsoft 推出的 CNTK,Amazon 推出的 MXNet,等等。總的來說,深度學習框架呈現出從學術研究到工業應用的發展趨勢。

下面,主要介紹一下與 TensorFlow 相比,PyTorch 的優勢有哪些。總的來說,PyTorch 更有利於研究人員、愛好者、小規模項目等快速搞出原型。而 TensorFlow 更適合大規模部署,特別是需要跨平臺和嵌入式部署時。

難易程度

PyTorch 實際上是 Numpy 的替代者,而且支持 GPU,帶有高級功能,可以用來搭建和訓練深度神經網絡。如果你熟悉 Numpy、Python 以及常見的深度學習概念(卷積層、循環層、SGD 等),會非常容易上手 PyTorch。

而 TensorFlow 可以看成是一個嵌入 Python 的編程語言。你寫的 TensorFlow 代碼會被 Python 編譯成一張圖,然後由 TensorFlow 執行引擎運行。我見過好多新手,因為這個增加的間接層而困擾。也正是因為同樣的原因,TensorFlow 有一些額外的概念需要學習,例如會話、圖、變量作用域(Variable Scoping)、佔位符等。另外還需要更多的樣板代碼才能讓一個基本的模型運行。所以 TensorFlow 的上手時間,肯定要比 PyTorch 長。

圖的創建和調試

創建和運行計算圖可能是兩個框架最不同的地方。在 PyTorch 中,圖結構是動態的,這意味著圖在運行時構建。而在 TensorFlow 中,圖結構是靜態的,這意味著圖先被“編譯”然後再運行。

舉一個簡單的例子,在 PyTorch 中你可以用標準的 Python 語法編寫一個 for 循環結構:

for _ in range(T):

h = torch.matmul(W, h) + b

此處 T 可以在每次執行代碼時改變。而 TensorFlow 中,這需要使用“控制流操作”來構建圖,例如 tf.while_loop。TensorFlow 確實提供了 dynamic_rnn 用於常見結構,但是創建自定義動態計算真的更加困難。

PyTorch 中簡單的圖結構更容易理解,更重要的是,還更容易調試。調試 PyTorch 代碼就像調試 Python 代碼一樣。你可以使用 pdb 並在任何地方設置斷點。調試 TensorFlow 代碼可不容易。要麼得從會話請求要檢查的變量,要麼學會使用 TensorFlow 的調試器(tfdbg)。

深度學習框架 PyTorch

總的來說,選擇 PyTorch 的原因很簡單,因為簡單易懂。而且,它還彌補了 Tensorflow 靜態構圖的致命弱點。PyTorch 是可以構建動態計算圖。也就是說你可以隨時改變神經網絡的結構,而不影響其計算過程。而 Tensorflow 這種靜態圖模塊,一旦搭建好了神經網絡, 你想修改結構也不行。PyTorch 既可以修改結構,也可以使用簡單易懂的搭建方法來創建神經網絡。而且你也可以用 GPU 來進行加速運算, 性能一點也不比 Tensorflow 差。

PyTorch 歷史

2017年1月,Facebook 人工智能研究院(FAIR)團隊在 GitHub 上開源了 PyTorch,並迅速佔領 GitHub 熱度榜榜首。

深度學習框架 PyTorch

PyTorch 的前身是 Torch,但是 Torch 是基於 Lua 語言。Lua 簡潔高效,但由於其過於小眾,用的人不是很多,以至於很多人聽說要掌握 Torch 必須新學一門語言就望而卻步(其實 Lua 是一門比 Python 還簡單的語言)。考慮到 Python 在計算科學領域的領先地位,以及其生態完整性和接口易用性,幾乎任何框架都不可避免地要提供 Python 接口。終於,在 2017 年,Torch 的幕後團隊推出了 PyTorch。PyTorch 不是簡單地封裝 Lua Torch 提供 Python 接口,而是對 Tensor 之上的所有模塊進行了重構,並新增了最先進的自動求導系統,成為當下最流行的動態圖框架。

如今,已經有很多科研機構和大公司在使用 PyTroch,用一張圖來表示。

深度學習框架 PyTorch

PyTorch 的安裝

PyTorch 的安裝非常簡單,目前已經支持 Windows 安裝了。打開 PyTorch 的官方網站:點擊這裡。

然後,選擇對應的操作系統 OS、包管理器 Package Manager、Python 版本、CUDA 版本,根據提示的命令,直接運行該命令即可完成安裝。CUDA(Compute Unified Device Architecture),是顯卡廠商 NVIDIA 推出的運算平臺,用於 GPU 運算。目前的 PyTorch 版本已經更新到 0.4.0 了。

深度學習框架 PyTorch

需要注意的是,由於防火牆限制,PyTorch 官網有時候會無法查看“Run this command”之後的指令。所以,建議使用其它安裝方法,請讀者自行搜索,這裡就不佔篇幅贅述了。

除了安裝 PyTorch 之外,建議也安裝 torchvision 包。torchvision 包是服務於 PyTorch 深度學習框架的,用來生成圖片、視頻數據集和一些流行的模型類和預訓練模型。簡單來說,torchvision 由 torchvision.datasets、torchvision.models、torchvision.transforms、torchvision.utils 四個模塊組成。

PyTorch 基礎知識

張量 Tensor

張量(Tensor)是所有深度學習框架中最核心的組件,因為後續的所有運算和優化算法都是基於張量進行的。幾何代數中定義的張量是基於向量和矩陣的推廣,通俗一點理解的話,我們可以將標量視為零階張量,矢量視為一階張量,那麼矩陣就是二階張量。

PyTorch 中的張量(Tensor)類似 NumPy 中的 ndarrays,之所以稱之為 Tensor 的另一個原因是它可以運行在 GPU 中,以加速運算。

構建一個 5x3 的隨機初始化矩陣,類型 dtype 是長整型 float:

import torch

x = torch.randn(5, 3, dtype=torch.float)

print(x)

輸出如下:

tensor([[-0.9508, 1.0049, -0.8923],

[-0.2570, 0.3362, 0.3103],

[-1.1511, 0.1061, -1.0930],

[-0.9184, 0.4947, -0.8810],

[-0.8143, 0.7078, 0.1530]])

直接把現成數據構建成 Tensor:

x = torch.tensor([0, 1, 2, 3, 4])

print(x)

輸出如下:

tensor([ 0, 1, 2, 3, 4])

Tensor 可以進行多種運算操作,以加法為例。

語法 1:提供一個輸出 Tensor 作為參數:

x = torch.randn(5, 3)

y = torch.randn(5, 3)

result = torch.empty(5, 3)

torch.add(x, y, out=result)

print(result)

輸出如下:

tensor([[ 0.2954, -0.7934, -1.5770],

[-0.2942, 0.7494, 0.7648],

[ 1.7711, -2.0219, -1.0717],

[ 2.0904, -1.4883, -1.8856],

[-0.0372, 0.0854, 2.9093]])

語法 2:替換

# adds x to y

y.add_(x)

print(y)

輸出如下:

tensor([[ 0.2954, -0.7934, -1.5770],

[-0.2942, 0.7494, 0.7648],

[ 1.7711, -2.0219, -1.0717],

[ 2.0904, -1.4883, -1.8856],

[-0.0372, 0.0854, 2.9093]])

注意:任何操作符都固定地在前面加上 _ 來表示替換。例如:y.copy_(x),y.t_(),都將改變 y。

另外,Tensor 還支持多種運算,包括轉置、索引、切片、數學運算、線性代數、隨機數,等等。

Tensor 與 NumPy

Tensor 可以與 NumPy 相互轉化。

Tensor 轉化為 NumPy:

a = torch.ones(5)

print(a)

b = a.numpy()

print(b)

輸出如下:

tensor([ 1., 1., 1., 1., 1.])

[ 1. 1. 1. 1. 1.]

NumPy 轉化為 Tensor:

import numpy as np

a = np.ones(5)

print(a)

b = torch.from_numpy(a)

print(b)

輸出如下:

[ 1. 1. 1. 1. 1.]

tensor([ 1., 1., 1., 1., 1.], dtype=torch.float64)

值得注意的是,Torch 中的 Tensor 和 NumPy 中的 Array 共享內存位置,一個改變,另一個也同樣改變。

a.add_(1)

print(a)

print(b)

輸出如下:

[ 2. 2. 2. 2. 2.]

tensor([ 2., 2., 2., 2., 2.], dtype=torch.float64)

Tensor 可以被移動到任何設備中,例如 GPU 以加速運算,使用 .to 方法即可。

x = torch.randn(1)

if torch.cuda.is_available():

device = torch.device("cuda")

y = torch.ones_like(x, device=device) # directly create a tensor on GPU

x = x.to(device)

z = x + y

print(z)

print(z.to("cpu", torch.double))

輸出如下:

tensor([ 2.0718], device='cuda:0')

tensor([ 2.0718], dtype=torch.float64)

自動求導 Autograd

Autograd 為所有 Tensor 上的操作提供了自動微分機制。這是一個動態運行的機制,也就是說你的代碼運行的時候,反向傳播過程就已經被定義了,且每迭代都會動態變化。如果把 Tensor 的屬性 .requires_grad 設置為 True,就會追蹤它的所有操作。完成計算後,可以通過 .backward() 來自動完成所有梯度計算。

首先,創建一個 Tensor,設置 requires_grad=True,跟蹤整個計算過程。

x = torch.ones(2, 2, requires_grad=True)

print(x)

輸出為:

tensor([[ 1., 1.],

[ 1., 1.]])

在 Tensor 上進行運算操作:

y = x + 1

z = y * y * 2

out = z.mean()

print(z, out)

輸出為:

tensor([[ 8., 8.],

[ 8., 8.]]) tensor(8.)

接下來進行反向傳播,因為 out 是標量,所以 out.backward() 等價於 out.backward(torch.tensor(1))。

out.backward()

print(x.grad)

輸出為:

tensor([[ 2., 2.],

[ 2., 2.]])

我們可以對求導結果做個簡單驗證。因為out=14∑izi=14∑ i2(xi+1)2,doutdxi=xi+1=1+1=2

總結

本文主要介紹了深度學習框架 PyTorch。通過介紹目前最流行的幾個深度學習框架,以及與 TensorFlow 的比較,闡述了選擇 PyTorch 的原因:上手簡單和動態圖調試。然後重點介紹了 PyTorch 的基礎語法知識,包括張量 Tensor 和自動求導機制 Autograd。


分享到:


相關文章: