前言
本文旨在介紹Pytorch的入門知識。在第一部分,我們簡單介紹了當前的主流深度學習框架,并介紹了選擇Pytorch的理由及其安裝方法。在第二部分,我們給出了Pytorch的一個簡單入門,包括張量的使用,如何借助Cuda在Pytorch中使用GPU進行計算,以及Pytorch中的求導(dǎo)運算等。最后在第三部分,我們對文中講到的關(guān)鍵操作進行了總結(jié)。
1. 深度學習框架的簡單介紹
1.1 主流深度學習框架
PyTorch是一個基于Python的庫,用來提供一個具有靈活性的深度學習開發(fā)平臺。PyTorch的工作流程非常接近Python的科學計算庫numpy。
當前主流的深度學習框架有兩種,一種是以Tensorflow為代表的靜態(tài)圖框架,另一種就是以Pytorch為代表的動態(tài)圖框架。靜態(tài)圖框架要求我們先定義好模型結(jié)構(gòu)再運行模型,而動態(tài)圖框架意味著程序?qū)凑彰铐樞驁?zhí)行,這種機制使得我們調(diào)試更加容易。用編程語言做類比,Tensorflow更像C++,而Pytorch更像Python。
Pytorch在近年來發(fā)展迅速,下圖對比了Pytorch和Tensorflow在論文中的使用情況:

從圖中可以看到,2019年1月到6月底,在arXiv.org上發(fā)表的論文中,提及TensorFlow和PyTorch的數(shù)量相差無幾,PyTorch僅稍稍落后。但最關(guān)鍵的在于增長速度:與2018年1月到6月相比,PyTorch增長了194%,相比之下,TensorFlow的增長幅度僅為23%。從當前的數(shù)據(jù)可以看出,Pytorch因其簡單易用而越來越受到大家的青睞。
1.2 為什么選擇Pytorch
首先不得不提Tensorflow的反人類設(shè)計。Tensorflow的邏輯有兩種,一種是建graph時的邏輯,另一種是運行時的邏輯。當要實現(xiàn)的算法比較復(fù)雜的時候就會很麻煩,一不小心就會出錯。
其次,Pytorch可以和Python無縫銜接,學習成本很低,給人的直觀感受就是用著順手、舒服。
最后,Pytorch代碼簡潔易懂。因此,作為深度學習的入門工具來說,Pytorch再合適不過了。
1.3 Pytorch 的安裝
Pytorch 安裝起來十分簡單,只要三步即可完成,
(1) 進入 Pytorch 官網(wǎng)

(2) 選擇合適的操作系統(tǒng)和版本</br>
在YourOs一欄選擇你的操作系統(tǒng)。在CUDA一欄是選擇是否安裝GPU版本,如果要安裝GPU版本,首先要安裝上CUDA,然后選擇CUDA的版本。
(3) 拷貝 Run this Command 一欄中的命令
將命令拷貝到終端執(zhí)行,即可自動安裝。
2. Pytorch 的簡單入門
2.1 張量的概念
簡單的說,張量概念是矢量概念和矩陣概念的推廣。標量是零階張量,矢量是一階張量,矩陣(方陣)是二階張量,而三階張量則好比是立體矩陣,更高階的張量用圖形無法表達。機器學習中的數(shù)據(jù)往往以張量形式表達。
2.2 張量的創(chuàng)建
Pytorch 中張量的創(chuàng)建主要有以下幾種形式:
(1) torch.empty 函數(shù)
import torch
x = torch.empty(5,3) #創(chuàng)建一個5*3的矩陣
print(x)
y = torch.empty(2,2,2) #創(chuàng)建一個2*2*2的張量
print(y)
輸出:
tensor([[1.1210e-44, 0.0000e+00, 0.0000e+00],
[0.0000e+00, 0.0000e+00, 0.0000e+00],
[0.0000e+00, 0.0000e+00, 0.0000e+00],
[0.0000e+00, 0.0000e+00, 0.0000e+00],
[0.0000e+00, 0.0000e+00, 0.0000e+00]])
tensor([[[8.4078e-45, 0.0000e+00],
[1.2708e-31, 1.4013e-45]],
[[0.0000e+00, 0.0000e+00],
[0.0000e+00, 0.0000e+00]]])
empty函數(shù)返回填充有未初始化數(shù)據(jù)的張量,在我們不需要初始化具有特定分布的數(shù)據(jù)時可以使用。
(2) torch.rand 函數(shù)
x = torch.rand(5,3) #創(chuàng)建一個5*3的矩陣
print(x)
y = torch.rand(2,2,2) #創(chuàng)建一個2*2*2的張量
print(y)
輸出:
tensor([[0.1413, 0.5294, 0.6538],
[0.4040, 0.0293, 0.7876],
[0.8263, 0.2070, 0.5927],
[0.4749, 0.7163, 0.4874],
[0.2791, 0.3276, 0.1504]])
tensor([[[0.2636, 0.9148],
[0.9117, 0.9742]],
[[0.4946, 0.6069],
[0.5841, 0.6050]]])
torch.rand 建立一個張量,默認將數(shù)據(jù)初始化為[0,1)的均勻分布。類似的函數(shù)有 torch.randn 將數(shù)據(jù)初始化為均值為0,方差為1的標準正態(tài)分布;torch.normal 可以生成指定均值和方差的正態(tài)分布。
(3) torch.ones 函數(shù)
x = torch.ones(5,3)
print(x)
輸出:
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]])
torch.ones 建立一個張量,并將值初始化為1。
(4) torch.zeros 函數(shù)
x = torch.zeros(5,3)
print(x)
輸出:
tensor([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
torch.zeros 建立一個張量,并將矩陣值初始化為0。
(5) 直接從數(shù)組建立一個張量
x = torch.tensor([2,3,4,5])
print(x)
輸出:
tensor([2, 3, 4, 5])
(6) new_ones,new_zeros,new_empty
x = torch.zeros(2,3,dtype=torch.int32) #新建一個張量
print(x)
y = x.new_ones(1,2) #從x中創(chuàng)建一個新的張量,數(shù)據(jù)類型不變
print(y)
輸出:
tensor([[0, 0, 0],
[0, 0, 0]], dtype=torch.int32)
tensor([[1, 1]], dtype=torch.int32)
這些函數(shù)可以從已有張量建立一個新的張量。
(7) ones_like,zeros_like,empty_like
x = torch.ones(4,4)
print(x)
y = torch.rand_like(x)
print(y)
輸出:
tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]])
tensor([[0.5023, 0.7911, 0.3639, 0.3315],
[0.8617, 0.0388, 0.1612, 0.2071],
[0.1755, 0.3988, 0.8381, 0.5835],
[0.9588, 0.3950, 0.8371, 0.5337]])
這些函數(shù)可以創(chuàng)建一個和目標張量形狀相同的張量。
2.3 張量的運算
張量常用的計算操作主要有張量的加法,張量乘法,張量形狀改變。
(1) 張量加法
主要有三種方式:
- x+y
- torch.add(x,y,out=result)
- y.add_(x)是將x增加到y(tǒng)上并改變y的值,運算符加“_”是將運算結(jié)果賦值給左邊的變量。
y = torch.rand(3,5)
x = torch.ones(5)
result = torch.empty(3,5)
print(x+y) #第一種方式
print(torch.add(x,y,out=result)) #第二種方式
y.add_(x) #第三種方式
print(y)
輸出:
tensor([[1.8442, 1.9501, 1.8182, 1.0880, 1.7674],
[1.5743, 1.5252, 1.8656, 1.2426, 1.4136],
[1.9056, 1.3625, 1.8482, 1.6156, 1.7287]])
tensor([[1.8442, 1.9501, 1.8182, 1.0880, 1.7674],
[1.5743, 1.5252, 1.8656, 1.2426, 1.4136],
[1.9056, 1.3625, 1.8482, 1.6156, 1.7287]])
tensor([[1.8442, 1.9501, 1.8182, 1.0880, 1.7674],
[1.5743, 1.5252, 1.8656, 1.2426, 1.4136],
[1.9056, 1.3625, 1.8482, 1.6156, 1.7287]])
(2) 張量乘法
- mm 只能是矩陣乘法,也就是輸入的兩個tensor維度只能是(n,m)和(m,p)
- bmm 是兩個三維張量相乘,兩個tensor維度是(b,m,p)和(b,p,n),b一般是batch_size
- matmul 可以進行張量乘法,輸入可以是高維的
mm 操作示例:
x = torch.ones(3,2)
y = torch.ones(2,3)
x.mm(y)
輸出:
tensor([[2., 2., 2.],
[2., 2., 2.],
[2., 2., 2.]])
bmm 操作示例:
x = torch.ones(2,3,2)
y = torch.ones(2,2,3)
x.bmm(y)
輸出:
tensor([[[2., 2., 2.],
[2., 2., 2.],
[2., 2., 2.]],
[[2., 2., 2.],
[2., 2., 2.],
[2., 2., 2.]]])
(3) Resize 操作
view函數(shù)實現(xiàn)了torch中張量的Resize操作。
x = torch.rand(2,2)
y = x.view(-1) # 從x生成一維向量,長度自動計算
print(y)
z = y.view(2,-1) #從y生成行數(shù)為2的矩陣,列的長度自動計算
print(z)
輸出:
tensor([[0.2995, 0.2133],
[0.6413, 0.7581]])
tensor([0.2995, 0.2133, 0.6413, 0.7581])
tensor([[0.2995, 0.2133],
[0.6413, 0.7581]])
Resize操作在很多時候都有用,例如我們進行圖像識別時,卷積層是n個方陣,要將卷積核輸出為類別,通常是先將它們展成一維,再帶入softmax函數(shù)計算進行分類。
(4) 轉(zhuǎn)置操作 t.()
x = torch.empty(3,4)
print(x)
print(x.t())
輸出:
tensor([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])
tensor([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
2.4 Pytorch 中張量和 NumPy Array 的相互轉(zhuǎn)化
在Torch Tensor和NumPy array之間相互轉(zhuǎn)化非常容易。Torch Tensor和NumPy array共享內(nèi)存,所以改變其中一項也會改變另一項。
把Torch Tensor轉(zhuǎn)變成NumPy Array:
a = torch.ones(5)
print(a)
b = a.numpy()
print(b)
輸出:
tensor([1., 1., 1., 1., 1.])
[1. 1. 1. 1. 1.]
把上面的a增加1:
a.add_(1)
print(a)
print(b)
輸出:
tensor([2., 2., 2., 2., 2.])
[2. 2. 2. 2. 2.]
把NumPy Array轉(zhuǎn)變成Torch Tensor:
import numpy as np
a = np.ones(5)
b = torch.from_numpy(a)
print(a)
print(b)
np.add(a,1,out=a)
print(a)
print(b)
輸出:
[1. 1. 1. 1. 1.]
tensor([1., 1., 1., 1., 1.], dtype=torch.float64)
[2. 2. 2. 2. 2.]
tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
2.5 Pytorch 中使用GPU計算
在Pytorch 中,使用GPU計算是很方便的,可以在創(chuàng)建張量的時候指定張量計算位置,也可以將張量轉(zhuǎn)移到GPU上計算。
if torch.cuda.is_available():
device = torch.device("cuda")
y = torch.ones(2,3,device=device) #在GPU上創(chuàng)建張量
x = torch.empty(4,5)
x.to(device) #將張量x轉(zhuǎn)移到GPU上
z = x+y
2.6 Pytorch 中的求導(dǎo)運算
我們在進行模型訓(xùn)練的時候,常常需要用梯度下降法,所以求導(dǎo)是很重要的,在Pytorch中,求導(dǎo)非常方便。例如對Y = WX + B,我們計算Y關(guān)于W和B的導(dǎo)數(shù)。不難發(fā)現(xiàn),Y關(guān)于W的導(dǎo)數(shù)是X的轉(zhuǎn)置,Y關(guān)于B的導(dǎo)數(shù)是1。
操作示例:
w = torch.zeros((3,1),requires_grad=True) # 聲明W的形狀,以及可導(dǎo)性(默認不可導(dǎo))
x = torch.ones(1,3) # 聲明X形狀
b = torch.tensor([1.],requires_grad=True)
y = x.mm(w) + b # Y = wx + b
y.backward() # 求導(dǎo)操作
print(w.grad)
print(b.grad)
輸出:
tensor([[1.],
[1.],
[1.]])
tensor([1.])
3. 總結(jié)
本文我們簡單介紹了Pytorch基本知識,包括安裝方法,基本的張量操作。張量操作我們主要說明了Pytorch中張量的幾種創(chuàng)建方法,張量的運算。然后我們學習了如何在GPU上進行計算,最后我們介紹了Pytorch上的求導(dǎo)操作。
最后,要記住以下重要操作哦:
- 張量創(chuàng)建
- torch.ones(), torch.empty(), torch.zeros()
- x.new_ones(), x.new_rand()..
- torch.empty_like(),torch.zeros_like()
- 張量操作
- 加法 torch.add(x,y,result=z),add_(),"+"
- 乘法 mm(),bmm(),matmul()
- 和numpy的相互轉(zhuǎn)化 a.numpy(), torch.from_numpy()
- GPU計算
- 記住函數(shù) torch.cuda.is_available(),
- torch.device("cuda")
- to(device)
- 求導(dǎo)運算
- 記得在創(chuàng)建張量時加一個requires_grad=True
- loss.backward()函數(shù)
- 導(dǎo)數(shù)在W.grad中取得
下期我們將以房價預(yù)測為例,來搭建一個簡單的線性模型!