目錄
一、PyTorch中的Tensor張量
1、Tensor張量
Tensor在PyTorch中負責存儲基本數據,PyTorch針對Tensor也提供了相對豐富的函數和方法,所以PyTorch中的Tensor與NumPy的數組具有極高的相似性,同時 Tensor可以使用 GPU 進行計算。
2、Tensor數據類型
(1)torch.FloatTensor # 此變量用於生成數據類型爲浮點型的Tensor,傳遞給torch.FloatTensor的參數可以是一個列表,也可以是一個維度值;
import torch
a=torch.FloatTensor(2,3) #生成數據類型爲浮點型的Tensor
print(a)
b=torch.FloatTensor([2,3,4,5])
print(b)
tensor([[0., 0., 0.],
[0., 0., 0.]])
tensor([2., 3., 4., 5.])
(2)torch.IntTensor # 用於生成數據類型爲整型的Tensor
3、Tensor常用函數
(1)torch.rand # 用於生成數據類型爲浮點型且維度指定的隨機Tensor,和在Numpy中使用numpy.rand生成隨機數的方法類似,隨機生成的浮點數據在0~1區間均勻分佈。
(2)torch.randn # 用於生成數據類型爲浮點型且維度指定的隨機Tensor,和在Numpy中使用numpy.randn生成隨機數的方法類似,隨機生成的浮點數的取值滿足均值爲0,方差爲1的正太分佈。
(3)torch.range # 用於生成數據類型爲浮點型且自定義其實範圍和結束範圍的Tensor,所以傳遞給torch.range的參數有三個,分別是範圍的起始值,範圍的結束值和步長,其中,步長用於指定從起始值到結束值的每步的數據間隔。
(4)torch.zeros # 用於生成數據類型爲浮點型且維度指定的Tensor,不過這個浮點型的Tensor中的元素值全部爲0。
(5)torch.abs # 將參數傳遞到torch.abs後返回輸入參數的絕對值作爲輸出,輸出參數必須是一個Tensor數據類型的變量。
(6)torch.add # 將參數傳遞到torch.add後返回輸入參數的求和結果作爲輸出,輸入參數既可以全部是Tensor數據類型的變量,也可以是一個Tensor數據類型的變量,另一個是標量。
(7)torch.clamp # 對輸入參數按照自定義的範圍進行裁剪,最後將參數裁剪的結果作爲輸出。所以輸入參數一共有三個,分別是需要進行裁剪的Tensor數據類型的變量、裁剪的上邊界和裁剪的下邊界,具體的裁剪過程是:使用變量中的每個元素分別和裁剪的上邊界及裁剪的下邊界的值進行比較,如果元素的值小於裁剪的下邊界的值,該元素就被重寫成裁剪的下邊界的值;同理,如果元素的值大於裁剪的上邊界的值,該元素就被重寫成裁剪的上邊界的值。
a=torch.randn(2,3)
print(a)
b=torch.clamp(a,-0.1,0.1) #邊界值裁剪
print(b)
tensor([[-0.6895, -0.2334, -1.1246],
[ 0.2961, -1.4742, 1.7083]])
tensor([[-0.1000, -0.1000, -0.1000],
[ 0.1000, -0.1000, 0.1000]])
(8)torch.div # 將參數傳遞到torch.div後返回輸入參數的求商結果作爲輸出,同樣,參與運算的參數可以全部是Tensor數據類型的變量,也可以是Tensor數據類型的變量和標量的組合。
(9)torch.pow # 將參數傳遞到torch.pow後返回輸入參數的求冪結果作爲輸出,參與運算的參數可以全部是Tensor數據類型的變量,也可以是Tensor數據類型的變量和標量的組合。
(10)torch.mul # 將參數傳遞到 torch.mul後返回輸入參數求積的結果作爲輸出,參與運算的參數可以全部是Tensor數據類型的變量,也可以是Tensor數據類型的變量和標量的組合。
(11)torch.mm # 將參數傳遞到 torch.mm後返回輸入參數的求積結果作爲輸出,不過這個求積的方式和之前的torch.mul運算方式不太樣,torch.mm運用矩陣之間的乘法規則進行計算,所以被傳入的參數會被當作矩陣進行處理,參數的維度自然也要滿足矩陣乘法的前提條件,即前一個矩陣的行數必須和後一個矩陣的列數相等,否則不能進行計算。
(12)torch.mv # 將參數傳遞到torch.mv後返回輸入參數的求積結果作爲輸出,torch.mv運用矩陣與向量之間的乘法規則進行計算,被傳入的參數中的第1個參數代表矩陣,第2個參數代表向量,順序不能顛倒。
(13)torch.view # 改變一個 tensor 的大小或者形狀。
x=torch.randn(4,4)
y=x.view(16)
z=x.view(-1,8) #-1表示該維度大小是從其他維度推斷出來的
print(x.size(),y.size(),z.size())
torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])
二、基於PyTorch搭建簡易神經網絡模型
1、簡易神經網絡模型
# coding:utf-8
import torch
batch_n = 100 #一個批次中輸入數據的數量,值是100表示在一個批次中輸入100個數據
input_data = 1000 #每個數據包含的數據特徵
hidden_layer = 100 #經過隱藏層後保留的數據特徵的個數
output_data = 10 #輸出數據表示分類結果值的數量
#初始化權重
x = torch.randn(batch_n, input_data) #輸入層維度爲(100,1000)
y = torch.randn(batch_n, output_data) #輸出層維度爲(100,10)
w1 = torch.randn(input_data, hidden_layer) #輸入層到隱藏層的權重參數維度爲(1000,100)
w2 = torch.randn(hidden_layer, output_data) #隱藏層到輸出層的權重參數維度爲(100,10)
epoch_n = 20 #訓練的次數
learning_rate = 1e-6 #學習效率
#梯度下降優化神經網絡參數
for epoch in range(epoch_n):
h1 = x.mm(w1) # 100*1000
h1 = h1.clamp(min=0) #使用clamp方法進行裁剪,將小於零的值全部重新賦值於0
y_pred = h1.mm(w2) # 100*10
# print(y_pred)
loss = (y_pred - y).pow(2).sum() #均方誤差計算損失
print("Epoch:{} , Loss:{:.4f}".format(epoch, loss))
gray_y_pred = 2 * (y_pred - y)
gray_w2 = h1.t().mm(gray_y_pred) #.t()是將Tensor進行轉置
grad_h = gray_y_pred.clone()
grad_h = grad_h.mm(w2.t())
grad_h.clamp_(min=0)
grad_w1 = x.t().mm(grad_h) #權重參數對應的梯度
w1 -= learning_rate * grad_w1 #根據學習率對w1和w2的權重參數進行更新
w2 -= learning_rate * gray_w2
結果如下:
2、Pytorch自動梯度
autograd package 是PyTorch中所有神經網絡的核心,它提供了Tensors上所有運算的自動求導功能,通過torch.autograd包,可以使模型參數自動計算在優化過程中需要用到的梯度值,在很大程度上幫助降低了實現後向傳播代碼的複雜度。
torch.autograd 包的主要功能是完成神經網絡後向傳播中的鏈式求導。
autograd.Variable 是這個package的中心類。它打包了一個Tensor,並且支持幾乎所有運算。一旦你完成了你的計算,可以調用.backward(),所有梯度就可以自動計算。
3、使用自動梯度和自定義函數搭建簡易神經網絡模型
import torch
from torch.autograd import Variable
#構建神經網絡模型
class Model(torch.nn.Module):
def __init__(self):
super(Model,self).__init__()
#super().__init__()
def forward(self,input,w1,w2):
x=torch.mm(input,w1)
x=torch.clamp(x,min=0)
x=torch.mm(x,w2)
return x
def backward(self):
pass
batch_n = 100 # 批量輸入的數據量
hidden_layer = 100 # 通過隱藏層後輸出的特徵數
input_data = 1000 # 輸入數據的特徵個數
output_data = 10 # 最後輸出的分類結果數
#初始化權重
x = Variable(torch.randn(batch_n, input_data), requires_grad=False)
y = Variable(torch.randn(batch_n, output_data), requires_grad=False)
w1 = Variable(torch.randn(input_data, hidden_layer), requires_grad=True)
w2 = Variable(torch.randn(hidden_layer, output_data), requires_grad=True)
epoch_n = 20 #訓練的次數
learning_rate = 1e-6 #學習效率
model=Model() #對模型類進行調用
#模型訓練和參數優化
for epoch in range(epoch_n):
y_pred = model(x,w1,w2) #完成對模型預測值的輸出
loss = (y_pred - y).pow(2).sum()
print("Epoch:{} , Loss:{:.4f}".format(epoch, loss.data))
loss.backward() #自動計算所有梯度
w1.data -= learning_rate * w1.grad.data
w2.data -= learning_rate * w2.grad.data
w1.grad.data.zero_()
w2.grad.data.zero_()
結果如下:
代碼說明:
(1)class Model(torch.nn.Module)
首先通過class Model(torch.nn.Module)完成了類繼承的操作,之後分別是類的初始化,以及forward函數和backward函數。forward函數實現了模型的前向傳播中的矩陣運算,backward實現了模型的後向傳播中的自動梯度計算,後向傳播如果沒有特別的需求,則在一般情況下不用進行調整。
(2)requires_grad參數
這個參數的賦值類型是布爾型,如果requires_grad的值是False,那麼表示該變量在進行自動梯度計算的過程中不會保留梯度值。我們將輸入的數據x和輸出的數據y的requires_grad參數均設置爲False,這是因爲這兩個變量並不是我們的模型需要優化的參數,而兩個權重w1和w2的requires_grad參數的值爲True。
(3).backward()函數
這個函數的功能在於讓模型根據計算圖自動計算每個節點的梯度值並根據需求進行保留,有了這一步,我們的權重參數 w1.data和 w2.data就可以直接使用在自動梯度過程中求得的梯度值w1.data.grad和w2.data.grad,並結合學習速率來對現有的參數進行更新、優化了。
(4).zero_()函數
將本次計算得到的各個參數節點的梯度值通過grad.data.zero_()全部置零,如果不置零,則計算的梯度值會被一直累加,這樣就會影響到後續的計算。
三、torch.nn和torch.optim
torch.nn 包提供了很多與實現神經網絡中的具體功能相關的類,這些類涵蓋了深度神經網絡模型在搭建和參數優化過程中的常用內容,比如神經網絡中的卷積層、池化層、全連接層這類層次構造的方法、防止過擬合的參數歸一化方法、Dropout 方法,還有激活函數部分的線性激活函數、非線性激活函數相關的方法等。
torch.optim 包中提供了非常多的可實現參數自動優化的類,比如SGD、AdaGrad、RMSProp、Adam等。
1、使用torch.nn搭建神經網絡模型
# _*_coding:utf-8_*_
import torch
from torch.autograd import Variable
batch_n = 100 # 批量輸入的數據量
input_data = 1000 # 輸入數據的特徵個數
hidden_layer = 100 # 通過隱藏層後輸出的特徵數
output_data = 10 # 最後輸出的分類結果數
x = Variable(torch.randn(batch_n, input_data), requires_grad=False)
y = Variable(torch.randn(batch_n, output_data), requires_grad=False)
# 模型搭建
models = torch.nn.Sequential(
# 首先通過其完成從輸入層到隱藏層的線性變換
torch.nn.Linear(input_data, hidden_layer),
# 經過激活函數
torch.nn.ReLU(),
# 最後完成從隱藏層到輸出層的線性變換
torch.nn.Linear(hidden_layer, output_data)
)
epoch_n = 10000
learning_rate = 1e-4
loss_fn = torch.nn.MSELoss() #均方誤差損失函數
# 迭代優化
for epoch in range(epoch_n):
y_pred = models(x)
loss = loss_fn(y_pred, y)
if epoch % 1000 == 0:
print("Epoch:{},Loss:{:.4f}".format(epoch, loss.data))
models.zero_grad()
loss.backward()
# 訪問模型中的全部參數是通過對“models.parameters()”進行遍歷完成的
# 對每個遍歷的參數進行梯度更新
for param in models.parameters():
param.data -= param.grad.data * learning_rate
結果如下:
代碼說明:
(1)torch.nn.Sequential
torch.nn.Sequential 類是torch.nn中的一種序列容器,通過在容器中嵌套各種實現神經網絡中具體功能相關的類,來完成對神經網絡模型的搭建,最主要的是,參數會按照我們定義好的序列自動傳遞下去。我們可以將嵌套在容器中的各個部分看作各種不同的模塊,這些模塊可以自由組合。
模塊的加入一般有兩種方式,一種是在以上代碼中使用的直接嵌套,另一種是以 orderdict 有序字典的方式進行傳入,這兩種方式的唯一區別是,使用後者搭建的模型的每個模塊都有我們自定義的名字,而前者默認使用從零開始的數字序列作爲每個模塊的名字。兩種方式如下:
import torch
from torch.autograd import Variable
batch_n = 100 # 批量輸入的數據量
input_data = 1000 # 輸入數據的特徵個數
hidden_layer = 100 # 通過隱藏層後輸出的特徵數
output_data = 10 # 最後輸出的分類結果數
#模型搭建
models = torch.nn.Sequential(
# 首先通過其完成從輸入層到隱藏層的線性變換
torch.nn.Linear(input_data, hidden_layer),
# 經過激活函數
torch.nn.ReLU(),
# 最後完成從隱藏層到輸出層的線性變換
torch.nn.Linear(hidden_layer, output_data))
print(models)
結果如下:
import torch
from torch.autograd import Variable
from collections import OrderedDict
batch_n = 100 # 批量輸入的數據量
input_data = 1000 # 輸入數據的特徵個數
hidden_layer = 100 # 通過隱藏層後輸出的特徵數
output_data = 10 # 最後輸出的分類結果數
#模型搭建
models = torch.nn.Sequential(OrderedDict([
("Linel",torch.nn.Linear(input_data,hidden_layer)),
("ReLU1",torch.nn.ReLU()),
("Line2",torch.nn.Linear(hidden_layer,output_data))]))
print(models)
結果如下:
(2)torch.nn.ReLU
torch.nn.ReLU 類屬於非線性激活分類,在定義時默認不需要傳入參數。在 torch.nn包中還有許多非線性激活函數類可供選擇,比如PReLU、LeakyReLU、Tanh、Sigmoid、Softmax等。
(3)torch.nn.Linear
torch.nn.Linear 類用於定義模型的線性層,即完成前面提到的不同的層之間的線性變換。它接收的參數有三個,分別是輸入特徵數、輸出特徵數和是否使用偏置,設置是否使用偏置的參數是一個布爾值,默認爲True,即使用偏置。
在實際使用的過程中,我們只需將輸入的特徵數和輸出的特徵數傳遞給torch.nn.Linear類,就會自動生成對應維度的權重參數和偏置,對於生成的權重參數和偏置,我們的模型默認使用了一種比之前的簡單隨機方式更好的參數初始化方法。
(4)torch.nn.MSELoss
torch.nn.MSELoss 類使用均方誤差函數對損失值進行計算,在定義類的對象時不用傳入任何參數,但在使用實例時需要輸入兩個維度一樣的參數方可進行計算。
import torch
from torch.autograd import Variable
loss_f=torch.nn.MSELoss()
x=Variable(torch.randn(100,100))
y=Variable(torch.randn(100,100))
loss=loss_f(x,y)
print(loss)
tensor(2.0491)
其它損失函數使用方法同torch.nn.MSELoss是一樣的,如:torch.nn.L1Loss 類使用平均絕對誤差函數對損失值進行計算;torch.nn.CrossEntropyLoss 類用於計算交叉熵;
2、使用torch.optim優化模型
# _*_coding:utf-8_*_
import torch
from torch.autograd import Variable
batch_n = 100 # 批量輸入的數據量
input_data = 1000 # 輸入數據的特徵個數
hidden_layer = 100 # 通過隱藏層後輸出的特徵數
output_data = 10 # 最後輸出的分類結果數
x = Variable(torch.randn(batch_n, input_data), requires_grad=False)
y = Variable(torch.randn(batch_n, output_data), requires_grad=False)
# 模型搭建
models = torch.nn.Sequential(
# 首先通過其完成從輸入層到隱藏層的線性變換
torch.nn.Linear(input_data, hidden_layer),
# 經過激活函數
torch.nn.ReLU(),
# 最後完成從隱藏層到輸出層的線性變換
torch.nn.Linear(hidden_layer, output_data)
)
epoch_n = 20
learning_rate = 1e-4
loss_fn = torch.nn.MSELoss() # 均方誤差損失函數
optimzer=torch.optim.Adam(models.parameters(),lr=learning_rate) #
# 訓練模型
for epoch in range(epoch_n):
y_pred = models(x)
loss = loss_fn(y_pred, y)
print("Epoch:{},Loss:{:.4f}".format(epoch, loss.data))
optimzer.zero_grad() # 參數梯度的歸零
loss.backward()
optimzer.step() # 進行梯度更新
結果如下:
代碼說明:
(1)torch.optim.Adam
這裏使用了 torch.optim 包中的 torch.optim.Adam 類作爲我們的模型參數的優化函數,在 torch.optim.Adam 類中輸入的是被優化的參數和學習速率的初始值,如果沒有輸入學習速率的初始值,那麼默認使用0.001這個值。因爲我們需要優化的是模型中的全部參數,所以傳遞給torch.optim.Adam類的參數是models.parameters。另外,Adam優化函數還有一個強大的功能,就是可以對梯度更新使用到的學習速率進行自適應調節。
(2)optimzer.zero_grad 和 optimzer.step
optimzer.zero_grad 完成對模型參數梯度的歸零。
optimzer.step 主要功能是使用計算得到的梯度值對各個節點的參數進行梯度更新。
參看:
1. PyTorch安裝:PyTorch官網