快速入门Pytorch(1)--安装、张量以及梯度
原文鏈接:mp.weixin.qq.com/s/WZdBm2JQ4…
這是翻譯自官方的入門教程,教程地址如下:
DEEP LEARNING WITH PYTORCH: A 60 MINUTE BLITZ
雖然教程名字是 60 分鐘入門,但是內容還是比較多,雖然之前多次更新了好多篇有接近 1 萬字的文章,但這次還是分成大概 4 篇來介紹,這是第一篇,目錄如下:
1. Pytorch 是什么
Pytorch 是一個基于 Python 的科學計算庫,它面向以下兩種人群:
- 希望將其代替 Numpy 來利用 GPUs 的威力;
- 一個可以提供更加靈活和快速的深度學習研究平臺。
1.1 安裝
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 版本,如果希望安裝之前的版本,可以點擊下面的網址:
pytorch.org/get-started…
如下圖所示,安裝 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() 復制代碼1.2 張量(Tensors)
Pytorch 的一大作用就是可以代替 Numpy 庫,所以首先介紹 Tensors ,也就是張量,它相當于 Numpy 的多維數組(ndarrays)。兩者的區別就是 Tensors 可以應用到 GPU 上加快計算速度。
首先導入必須的庫,主要是 torch
from __future__ import print_function import torch 復制代碼1.2.1 聲明和定義
首先是對 Tensors 的聲明和定義方法,分別有以下幾種:
- torch.empty(): 聲明一個未初始化的矩陣。
輸出結果如下:
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]]) 復制代碼- torch.rand():隨機初始化一個矩陣
輸出結果:
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]]) 復制代碼- torch.zeros():創建數值皆為 0 的矩陣
輸出結果如下:
tensor([[0, 0, 0],[0, 0, 0],[0, 0, 0],[0, 0, 0],[0, 0, 0]]) 復制代碼類似的也可以創建數值都是 1 的矩陣,調用 torch.ones
- torch.tensor():直接傳遞 tensor 數值來創建
輸出結果:
tensor([5.5000, 3.0000]) 復制代碼除了上述幾種方法,還可以根據已有的 tensor 變量創建新的 tensor 變量,這種做法的好處就是可以保留已有 tensor 的一些屬性,包括尺寸大小、數值屬性,除非是重新定義這些屬性。相應的實現方法如下:
- tensor.new_ones():new_*() 方法需要輸入尺寸大小
輸出結果:
tensor([[1., 1., 1.],[1., 1., 1.],[1., 1., 1.],[1., 1., 1.],[1., 1., 1.]], dtype=torch.float64) 復制代碼- torch.randn_like(old_tensor):保留相同的尺寸大小
輸出結果,這里是根據上個方法聲明的 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)類型,所以支持所有的元組操作。
1.2.2 操作(Operations)
操作也包含了很多語法,但這里作為快速入門,僅僅以加法操作作為例子進行介紹,更多的操作介紹可以點擊下面網址查看官方文檔,包括轉置、索引、切片、數學計算、線性代數、隨機數等等:
pytorch.org/docs/stable…
對于加法的操作,有幾種實現方式:
- +
- torch.add(tensor1, tensor2, [out=tensor3])
- tensor1.add_(tensor2):直接修改 tensor 變量
輸出結果
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 復制代碼更多的運算操作可以查看官方文檔的介紹:
pytorch.org/docs/stable…
1.3 和 Numpy 數組的轉換
Tensor 和 Numpy 的數組可以相互轉換,并且兩者轉換后共享在 CPU 下的內存空間,即改變其中一個的數值,另一個變量也會隨之改變。
1.3.1 張量轉換為 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.] 復制代碼此外,剛剛說了兩者是共享同個內存空間的,例子如下所示,修改 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.] 復制代碼1.3.2 Numpy 數組轉換為張量
轉換的操作是調用 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 數組的相互轉換操作。
1.4. CUDA 張量
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 上的一個 tensorx = x.to(device) # 也可以采用 .to("cuda") z = x + yprint(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.org/tutorials/b…
本小節的代碼:
github.com/ccc013/Deep…
2. autograd
對于 Pytorch 的神經網絡來說,非常關鍵的一個庫就是 autograd ,它主要是提供了對 Tensors 上所有運算操作的自動微分功能,也就是計算梯度的功能。它屬于 define-by-run 類型框架,即反向傳播操作的定義是根據代碼的運行方式,因此每次迭代都可以是不同的。
接下來會簡單介紹一些例子來說明這個庫的作用。
2.1 張量
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 。
FalseTrue<SumBackward0 object at 0x00000216D25ED710> 復制代碼2.2 梯度
接下來就是開始計算梯度,進行反向傳播的操作。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 * 2print(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) 復制代碼輸出結果:
TrueTrueFalse 復制代碼更多有關 autograd 和 Function 的介紹:
pytorch.org/docs/autogr…
本小節教程:
pytorch.org/tutorials/b…
本小節的代碼:
github.com/ccc013/Deep…
小結
第一篇主要簡單介紹 Pytorch 的兩大作用,替代 Numpy 以及一個新的深度學習工具,當然主要還是后者讓其能夠在短短兩三年內快速發展,并且由于 Tensorflow 的一些缺點,越來越多人會選擇采用 Pytorch 工具,特別是對于學術界的科研學者來說,Pytorch 其實會上手更加快。
另外,還介紹了最重要也是最基礎的張量的知識,其方法、操作和 Numpy 的數組非常相似,兩者還可以互相轉換,稍微不同的是張量可以應用到 GPU 上加快計算速度。
最后簡單介紹了 autograd 這個庫,對于深度學習非常重要,它可以自動計算梯度,非常有用。
歡迎關注我的微信公眾號--機器學習與計算機視覺,或者掃描下方的二維碼,大家一起交流,學習和進步!
往期精彩推薦
機器學習系列
- 初學者的機器學習入門實戰教程!
- 模型評估、過擬合欠擬合以及超參數調優方法
- 常用機器學習算法匯總比較(完)
- 常用機器學習算法匯總比較(上)
- 機器學習入門系列(2)--如何構建一個完整的機器學習項目(一)
- 特征工程之數據預處理(上)
- 來了解下計算機視覺的八大應用
Github項目 & 資源教程推薦
- [Github 項目推薦] 一個更好閱讀和查找論文的網站
- [資源分享] TensorFlow 官方中文版教程來了
- 必讀的AI和深度學習博客
- [教程]一份簡單易懂的 TensorFlow 教程
- [資源]推薦一些Python書籍和教程,入門和進階的都有!
- [Github項目推薦] 機器學習& Python 知識點速查表
- [Github項目推薦] 推薦三個助你更好利用Github的工具
- Github上的各大高校資料以及國外公開課視頻
- 這些單詞你都念對了嗎?順便推薦三份程序員專屬英語教程!
轉載于:https://juejin.im/post/5ce0d34f6fb9a07eeb137821
總結
以上是生活随笔為你收集整理的快速入门Pytorch(1)--安装、张量以及梯度的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 做梦梦到乌龟咬脚是什么意思
- 下一篇: 大学刚毕业,零基础大数据如何入门?