原文連接:mp.weixin.qq.com/s/WZdBm2JQ4…html
這是翻譯自官方的入門教程,教程地址以下:python
DEEP LEARNING WITH PYTORCH: A 60 MINUTE BLITZgit
雖然教程名字是 60 分鐘入門,可是內容仍是比較多,雖然以前屢次更新了好多篇有接近 1 萬字的文章,但此次仍是分紅大概 4 篇來介紹,這是第一篇,目錄以下:程序員
Pytorch 是一個基於 Python 的科學計算庫,它面向如下兩種人羣:github
pytorch 的安裝能夠直接查看官網教程,以下所示,官網地址:pytorch.org/get-started…算法
根據提示分別選擇系統(Linux、Mac 或者 Windows),安裝方式(Conda,Pip,LibTorch 或者源碼安裝)、使用的編程語言(Python 2.7 或者 Python 3.5,3.6,3.7 或者是 C++),若是是 GPU 版本,就須要選擇 CUDA 的 版本,因此,若是如上圖所示選擇,安裝的命令是:編程
conda install pytorch torchvision cudatoolkit=9.0 -c pytorch
複製代碼
這裏推薦採用 Conda 安裝,即便用 Anaconda,主要是能夠設置不一樣環境配置不一樣的設置,關於 Anaconda 能夠查看我以前寫的 Python 基礎入門--簡介和環境配置 。數組
固然這裏會安裝最新版本的 Pytorch,也就是 1.1 版本,若是但願安裝以前的版本,能夠點擊下面的網址:bash
以下圖所示,安裝 0.4.1 版本的 pytorch,在不一樣版本的 CUDA 以及沒有 CUDA 的狀況。
而後還有其餘的安裝方式,具體能夠本身點擊查看。
安裝後,輸入下列命令:
from __future__ import print_function
import torch
x = torch.rand(5, 3)
print(x)
複製代碼
輸出結果相似下面的結果即安裝成功:
tensor([[0.3380, 0.3845, 0.3217],
[0.8337, 0.9050, 0.2650],
[0.2979, 0.7141, 0.9069],
[0.1449, 0.1132, 0.1375],
[0.4675, 0.3947, 0.1426]])
複製代碼
而後是驗證可否正確運行在 GPU 上,輸入下列代碼,這份代碼中 cuda.is_available()
主要是用於檢測是否可使用當前的 GPU 顯卡,若是返回 True,固然就能夠運行,不然就不能。
import torch
torch.cuda.is_available()
複製代碼
Pytorch 的一大做用就是能夠代替 Numpy 庫,因此首先介紹 Tensors ,也就是張量,它至關於 Numpy 的多維數組(ndarrays)。二者的區別就是 Tensors 能夠應用到 GPU 上加快計算速度。
首先導入必須的庫,主要是 torch
from __future__ import print_function
import torch
複製代碼
首先是對 Tensors 的聲明和定義方法,分別有如下幾種:
# 建立一個 5*3 的矩陣
x = torch.empty(5, 3)
print(x)
複製代碼
輸出結果以下:
tensor([[9.2737e-41, 8.9074e-01, 1.9286e-37],
[1.7228e-34, 5.7064e+01, 9.2737e-41],
[2.2803e+02, 1.9288e-37, 1.7228e-34],
[1.4609e+04, 9.2737e-41, 5.8375e+04],
[1.9290e-37, 1.7228e-34, 3.7402e+06]])
複製代碼
# 建立一個隨機初始化的 5*3 矩陣
rand_x = torch.rand(5, 3)
print(rand_x)
複製代碼
輸出結果:
tensor([[0.4311, 0.2798, 0.8444],
[0.0829, 0.9029, 0.8463],
[0.7139, 0.4225, 0.5623],
[0.7642, 0.0329, 0.8816],
[1.0000, 0.9830, 0.9256]])
複製代碼
# 建立一個數值皆是 0,類型爲 long 的矩陣
zero_x = torch.zeros(5, 3, dtype=torch.long)
print(zero_x)
複製代碼
輸出結果以下:
tensor([[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])
複製代碼
相似的也能夠建立數值都是 1 的矩陣,調用 torch.ones
# tensor 數值是 [5.5, 3]
tensor1 = torch.tensor([5.5, 3])
print(tensor1)
複製代碼
輸出結果:
tensor([5.5000, 3.0000])
複製代碼
除了上述幾種方法,還能夠根據已有的 tensor 變量建立新的 tensor 變量,這種作法的好處就是能夠保留已有 tensor 的一些屬性,包括尺寸大小、數值屬性,除非是從新定義這些屬性。相應的實現方法以下:
# 顯示定義新的尺寸是 5*3,數值類型是 torch.double
tensor2 = tensor1.new_ones(5, 3, dtype=torch.double) # new_* 方法須要輸入 tensor 大小
print(tensor2)
複製代碼
輸出結果:
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]], dtype=torch.float64)
複製代碼
# 修改數值類型
tensor3 = torch.randn_like(tensor2, dtype=torch.float)
print('tensor3: ', tensor3)
複製代碼
輸出結果,這裏是根據上個方法聲明的 tensor2
變量來聲明新的變量,能夠看出尺寸大小都是 5*3,可是數值類型是改變了的。
tensor3: tensor([[-0.4491, -0.2634, -0.0040],
[-0.1624, 0.4475, -0.8407],
[-0.6539, -1.2772, 0.6060],
[ 0.2304, 0.0879, -0.3876],
[ 1.2900, -0.7475, -1.8212]])
複製代碼
最後,對 tensors 的尺寸大小獲取能夠採用 tensor.size()
方法:
print(tensor3.size())
# 輸出: torch.Size([5, 3])
複製代碼
注意: torch.Size
其實是元組(tuple)類型,因此支持全部的元組操做。
操做也包含了不少語法,但這裏做爲快速入門,僅僅以加法操做做爲例子進行介紹,更多的操做介紹能夠點擊下面網址查看官方文檔,包括轉置、索引、切片、數學計算、線性代數、隨機數等等:
對於加法的操做,有幾種實現方式:
tensor4 = torch.rand(5, 3)
print('tensor3 + tensor4= ', tensor3 + tensor4)
print('tensor3 + tensor4= ', torch.add(tensor3, tensor4))
# 新聲明一個 tensor 變量保存加法操做的結果
result = torch.empty(5, 3)
torch.add(tensor3, tensor4, out=result)
print('add result= ', result)
# 直接修改變量
tensor3.add_(tensor4)
print('tensor3= ', tensor3)
複製代碼
輸出結果
tensor3 + tensor4= tensor([[ 0.1000, 0.1325, 0.0461],
[ 0.4731, 0.4523, -0.7517],
[ 0.2995, -0.9576, 1.4906],
[ 1.0461, 0.7557, -0.0187],
[ 2.2446, -0.3473, -1.0873]])
tensor3 + tensor4= tensor([[ 0.1000, 0.1325, 0.0461],
[ 0.4731, 0.4523, -0.7517],
[ 0.2995, -0.9576, 1.4906],
[ 1.0461, 0.7557, -0.0187],
[ 2.2446, -0.3473, -1.0873]])
add result= tensor([[ 0.1000, 0.1325, 0.0461],
[ 0.4731, 0.4523, -0.7517],
[ 0.2995, -0.9576, 1.4906],
[ 1.0461, 0.7557, -0.0187],
[ 2.2446, -0.3473, -1.0873]])
tensor3= tensor([[ 0.1000, 0.1325, 0.0461],
[ 0.4731, 0.4523, -0.7517],
[ 0.2995, -0.9576, 1.4906],
[ 1.0461, 0.7557, -0.0187],
[ 2.2446, -0.3473, -1.0873]])
複製代碼
注意:能夠改變 tensor 變量的操做都帶有一個後綴 _
, 例如 x.copy_(y), x.t_()
均可以改變 x 變量
除了加法運算操做,對於 Tensor 的訪問,和 Numpy 對數組相似,可使用索引來訪問某一維的數據,以下所示:
# 訪問 tensor3 第一列數據
print(tensor3[:, 0])
複製代碼
輸出結果:
tensor([0.1000, 0.4731, 0.2995, 1.0461, 2.2446])
複製代碼
對 Tensor 的尺寸修改,能夠採用 torch.view()
,以下所示:
x = torch.randn(4, 4)
y = x.view(16)
# -1 表示除給定維度外的其他維度的乘積
z = x.view(-1, 8)
print(x.size(), y.size(), z.size())
複製代碼
輸出結果:
torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])
複製代碼
若是 tensor 僅有一個元素,能夠採用 .item()
來獲取相似 Python 中整數類型的數值:
x = torch.randn(1)
print(x)
print(x.item())
複製代碼
輸出結果:
tensor([0.4549])
0.4549027979373932
複製代碼
更多的運算操做能夠查看官方文檔的介紹:
Tensor 和 Numpy 的數組能夠相互轉換,而且二者轉換後共享在 CPU 下的內存空間,即改變其中一個的數值,另外一個變量也會隨之改變。
實現 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.]
複製代碼
此外,剛剛說了二者是共享同個內存空間的,例子以下所示,修改 tensor
變量 a
,看看從 a
轉換獲得的 Numpy 數組變量 b
是否發生變化。
a.add_(1)
print(a)
print(b)
複製代碼
輸出結果以下,很明顯,b
也隨着 a
的改變而改變。
tensor([2., 2., 2., 2., 2.])
[2. 2. 2. 2. 2.]
複製代碼
轉換的操做是調用 torch.from_numpy(numpy_array)
方法。例子以下所示:
import numpy as np
a = np.ones(5)
b = torch.from_numpy(a)
np.add(a, 1, out=a)
print(a)
print(b)
複製代碼
輸出結果:
[2. 2. 2. 2. 2.]
tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
複製代碼
在 CPU
上,除了 CharTensor
外的全部 Tensor
類型變量,都支持和 Numpy
數組的相互轉換操做。
Tensors
能夠經過 .to
方法轉換到不一樣的設備上,即 CPU 或者 GPU 上。例子以下所示:
# 當 CUDA 可用的時候,可用運行下方這段代碼,採用 torch.device() 方法來改變 tensors 是否在 GPU 上進行計算操做
if torch.cuda.is_available():
device = torch.device("cuda") # 定義一個 CUDA 設備對象
y = torch.ones_like(x, device=device) # 顯示建立在 GPU 上的一個 tensor
x = x.to(device) # 也能夠採用 .to("cuda")
z = x + y
print(z)
print(z.to("cpu", torch.double)) # .to() 方法也能夠改變數值類型
複製代碼
輸出結果,第一個結果就是在 GPU 上的結果,打印變量的時候會帶有 device='cuda:0'
,而第二個是在 CPU 上的變量。
tensor([1.4549], device='cuda:0')
tensor([1.4549], dtype=torch.float64)
複製代碼
本小節教程:
本小節的代碼:
對於 Pytorch 的神經網絡來講,很是關鍵的一個庫就是 autograd
,它主要是提供了對 Tensors 上全部運算操做的自動微分功能,也就是計算梯度的功能。它屬於 define-by-run
類型框架,即反向傳播操做的定義是根據代碼的運行方式,所以每次迭代均可以是不一樣的。
接下來會簡單介紹一些例子來講明這個庫的做用。
torch.Tensor
是 Pytorch 最主要的庫,當設置它的屬性 .requires_grad=True
,那麼就會開始追蹤在該變量上的全部操做,而完成計算後,能夠調用 .backward()
並自動計算全部的梯度,獲得的梯度都保存在屬性 .grad
中。
調用 .detach()
方法分離出計算的歷史,能夠中止一個 tensor 變量繼續追蹤其歷史信息 ,同時也防止將來的計算會被追蹤。
而若是是但願防止跟蹤歷史(以及使用內存),能夠將代碼塊放在 with torch.no_grad():
內,這個作法在使用一個模型進行評估的時候很是有用,由於模型會包含一些帶有 requires_grad=True
的訓練參數,但實際上並不須要它們的梯度信息。
對於 autograd
的實現,還有一個類也是很是重要-- Function
。
Tensor
和 Function
兩個類是有關聯並創建了一個非循環的圖,能夠編碼一個完整的計算記錄。每一個 tensor 變量都帶有屬性 .grad_fn
,該屬性引用了建立了這個變量的 Function
(除了由用戶建立的 Tensors,它們的 grad_fn=None
)。
若是要進行求導運算,能夠調用一個 Tensor
變量的方法 .backward()
。若是該變量是一個標量,即僅有一個元素,那麼不須要傳遞任何參數給方法 .backward()
,當包含多個元素的時候,就必須指定一個 gradient
參數,表示匹配尺寸大小的 tensor,這部分見第二小節介紹梯度的內容。
接下來就開始用代碼來進一步介紹。
首先導入必須的庫:
import torch
複製代碼
開始建立一個 tensor, 並讓 requires_grad=True
來追蹤該變量相關的計算操做:
x = torch.ones(2, 2, requires_grad=True)
print(x)
複製代碼
輸出結果:
tensor([[1., 1.],
[1., 1.]], requires_grad=True)
複製代碼
執行任意計算操做,這裏進行簡單的加法運算:
y = x + 2
print(y)
複製代碼
輸出結果:
tensor([[3., 3.],
[3., 3.]], grad_fn=<AddBackward>)
複製代碼
y
是一個操做的結果,因此它帶有屬性 grad_fn
:
print(y.grad_fn)
複製代碼
輸出結果:
<AddBackward object at 0x00000216D25DCC88>
複製代碼
繼續對變量 y
進行操做:
z = y * y * 3
out = z.mean()
print('z=', z)
print('out=', out)
複製代碼
輸出結果:
z= tensor([[27., 27.],
[27., 27.]], grad_fn=<MulBackward>)
out= tensor(27., grad_fn=<MeanBackward1>)
複製代碼
實際上,一個 Tensor
變量的默認 requires_grad
是 False
,能夠像上述定義一個變量時候指定該屬性是 True
,固然也能夠定義變量後,調用 .requires_grad_(True)
設置爲 True
,這裏帶有後綴 _
是會改變變量自己的屬性,在上一節介紹加法操做 add_()
說明過,下面是一個代碼例子:
a = torch.randn(2, 2)
a = ((a * 3) / (a - 1))
print(a.requires_grad)
a.requires_grad_(True)
print(a.requires_grad)
b = (a * a).sum()
print(b.grad_fn)
複製代碼
輸出結果以下,第一行是爲設置 requires_grad
的結果,接着顯示調用 .requires_grad_(True)
,輸出結果就是 True
。
False
True
<SumBackward0 object at 0x00000216D25ED710>
複製代碼
接下來就是開始計算梯度,進行反向傳播的操做。out
變量是上一小節中定義的,它是一個標量,所以 out.backward()
至關於 out.backward(torch.tensor(1.))
,代碼以下:
out.backward()
# 輸出梯度 d(out)/dx
print(x.grad)
複製代碼
輸出結果:
tensor([[4.5000, 4.5000],
[4.5000, 4.5000]])
複製代碼
結果應該就是獲得數值都是 4.5 的矩陣。這裏咱們用 o
表示 out
變量,那麼根據以前的定義會有:
詳細來講,初始定義的 x
是一個全爲 1 的矩陣,而後加法操做 x+2
獲得 y
,接着 y*y*3
, 獲得 z
,而且此時 z
是一個 2*2 的矩陣,因此總體求平均獲得 out
變量應該是除以 4,因此獲得上述三條公式。
所以,計算梯度:
從數學上來講,若是你有一個向量值函數:
那麼對應的梯度是一個雅克比矩陣(Jacobian matrix):
通常來講,torch.autograd
就是用於計算雅克比向量(vector-Jacobian)乘積的工具。這裏略過數學公式,直接上代碼例子介紹:
x = torch.randn(3, requires_grad=True)
y = x * 2
while y.data.norm() < 1000:
y = y * 2
print(y)
複製代碼
輸出結果:
tensor([ 237.5009, 1774.2396, 274.0625], grad_fn=<MulBackward>)
複製代碼
這裏獲得的變量 y
再也不是一個標量,torch.autograd
不能直接計算完整的雅克比行列式,但咱們能夠經過簡單的傳遞向量給 backward()
方法做爲參數獲得雅克比向量的乘積,例子以下所示:
v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(v)
print(x.grad)
複製代碼
輸出結果:
tensor([ 102.4000, 1024.0000, 0.1024])
複製代碼
最後,加上 with torch.no_grad()
就能夠中止追蹤變量歷史進行自動梯度計算:
print(x.requires_grad)
print((x ** 2).requires_grad)
with torch.no_grad():
print((x ** 2).requires_grad)
複製代碼
輸出結果:
True
True
False
複製代碼
更多有關 autograd
和 Function
的介紹:
本小節教程:
本小節的代碼:
第一篇主要簡單介紹 Pytorch 的兩大做用,替代 Numpy 以及一個新的深度學習工具,固然主要仍是後者讓其可以在短短兩三年內快速發展,而且因爲 Tensorflow 的一些缺點,愈來愈多人會選擇採用 Pytorch 工具,特別是對於學術界的科研學者來講,Pytorch 其實會上手更加快。
另外,還介紹了最重要也是最基礎的張量的知識,其方法、操做和 Numpy 的數組很是類似,二者還能夠互相轉換,稍微不一樣的是張量能夠應用到 GPU 上加快計算速度。
最後簡單介紹了 autograd
這個庫,對於深度學習很是重要,它能夠自動計算梯度,很是有用。
歡迎關注個人微信公衆號--機器學習與計算機視覺,或者掃描下方的二維碼,你們一塊兒交流,學習和進步!