Pytorch基礎(chǔ)模型組件
知道Pytorch中Module的使用方法
知道Pytorch中優(yōu)化器類的使用方法
知道Pytorch中常見的損失函數(shù)的使用方法
知道如何在GPU上運(yùn)行代碼
能夠說出常見的優(yōu)化器及其原理
在前一部分凿歼,我們自己實(shí)現(xiàn)了通過torch的相關(guān)方法完成反向傳播和參數(shù)更新窍奋,在pytorch中預(yù)設(shè)了一些更加靈活簡單的對(duì)象姜性,讓我們來構(gòu)造模型杈笔、定義損失道川,優(yōu)化損失等
那么接下來蒋腮,我們一起來了解一下其中常用的API
nn.Module?是torch.nn提供的一個(gè)類逗旁,是pytorch中我們自定義網(wǎng)絡(luò)的一個(gè)基類嘿辟,在這個(gè)類中定義了很多有用的方法,讓我們?cè)诶^承這個(gè)類定義網(wǎng)絡(luò)的時(shí)候非常簡單
當(dāng)我們自定義網(wǎng)絡(luò)的時(shí)候痢艺,有兩個(gè)方法需要特別注意:
__init__需要調(diào)用super方法仓洼,繼承父類的屬性和方法
forward方法必須實(shí)現(xiàn),用來定義我們的網(wǎng)絡(luò)的向前計(jì)算的過程
用前面的y = wx+b的模型舉例如下:
from torch import nn
class Lr(nn.Module):
def__init__(self):
super(Lr, self).__init__()#繼承父類init的參數(shù)
self.linear = nn.Linear(1,1)# 聲明網(wǎng)絡(luò)中的組件
def forward(self, x):
? ? ? ? out = self.linear(x)
return out
注意:
nn.Linear為torch預(yù)定義好的線性模型堤舒,也被稱為全鏈接層色建,傳入的參數(shù)為輸入的數(shù)量,輸出的數(shù)量(in_features, out_features),是不算(batch_size的列數(shù))
nn.Module定義了__call__方法舌缤,實(shí)現(xiàn)的就是調(diào)用forward方法箕戳,即Lr的實(shí)例鞭衩,能夠直接被傳入?yún)?shù)調(diào)用祭钉,實(shí)際上調(diào)用的是forward方法并傳入?yún)?shù)
# 實(shí)例化模型
model = Lr()
# 傳入數(shù)據(jù)辉饱,計(jì)算結(jié)果
predict = model(x)
如果模型結(jié)構(gòu)比較簡單匀油,在forward函數(shù)中沒有很復(fù)雜的操作够庙。這時(shí)可以用nn.Sequential來構(gòu)建模型房待,nn.Sequential會(huì)自動(dòng)完成forward函數(shù)的創(chuàng)建.
model = nn.Sequential(nn.Linear(2,64), nn.Linear(64,1))
x = torch.randn(10,2)# 10個(gè)樣本践盼,2個(gè)特征
model(x)
tensor([[-0.3507],
[-0.3708],
[-0.4118],
[-0.2604],
[-0.4318],
[-0.3503],
[-0.4953],
[-0.5464],
[-0.5273],
[-0.4542]], grad_fn=)
優(yōu)化器(optimizer)思瘟,可以理解為torch為我們封裝的用來進(jìn)行更新參數(shù)的方法环础,比如常見的隨機(jī)梯度下降(stochastic gradient descent,SGD)
優(yōu)化器類都是由torch.optim提供的囚似,例如
torch.optim.SGD(參數(shù),學(xué)習(xí)率)
torch.optim.Adam(參數(shù)线得,學(xué)習(xí)率)
注意:
參數(shù)可以使用model.parameters()來獲取饶唤,獲取模型中所有requires_grad=True的參數(shù)
優(yōu)化類的使用方法
實(shí)例化
所有參數(shù)的梯度,將其值置為0
反向傳播計(jì)算梯度
更新參數(shù)值
示例如下:
optimizer = optim.SGD(model.parameters(), lr=1e-3) #1. 實(shí)例化
optimizer.zero_grad() #2. 梯度置為0
loss.backward() #3. 計(jì)算梯度
optimizer.step() #4. 更新參數(shù)的值
前面的例子是一個(gè)回歸問題贯钩,torch中也預(yù)測(cè)了很多損失函數(shù)
均方誤差:nn.MSELoss(),常用于回歸問題
交叉熵?fù)p失:nn.CrossEntropyLoss()募狂,常用于分類問題
使用方法:
model = Lr() #1. 實(shí)例化模型
criterion = nn.MSELoss() #2. 實(shí)例化損失函數(shù)
optimizer = optim.SGD(model.parameters(), lr=1e-3) #3. 實(shí)例化優(yōu)化器類
for i in range(100):
?? ?y_predict = model(x_true) #4. 向前計(jì)算預(yù)測(cè)值
?? ?loss = criterion(y_true,y_predict) #5. 調(diào)用損失函數(shù)傳入真實(shí)值和預(yù)測(cè)值办素,得到損失結(jié)果
?? ?optimizer.zero_grad() #5. 當(dāng)前循環(huán)參數(shù)梯度置為0
?? ?loss.backward() #6. 計(jì)算梯度
?? ?optimizer.step() #7. 更新參數(shù)的值
知道如何使用pytorch模型組件構(gòu)建模型
知道如何在GPU上運(yùn)行代碼
能夠說出常見的優(yōu)化器及其原理
構(gòu)建模型,最重要的有兩個(gè)步驟:
找到合適的計(jì)算關(guān)系祸穷,隨即初始化參數(shù)來擬合輸入和輸出的關(guān)系(前向計(jì)算性穿,從輸入得到輸出)
選取合適的損失函數(shù)和優(yōu)化器來減小損失(反向傳播,得到合適的參數(shù))
import torch
from torchimportnn
fromtorchimportoptim
importnumpyasnp
frommatplotlibimportpyplotasplt
# 1. 定義數(shù)據(jù)
x = torch.rand([50,1])
y = x*3+0.8
#2 .定義模型
classLr(nn.Module):
def__init__(self):
? ? ? ? super(Lr,self).__init__()
self.linear = nn.Linear(1,1)
def forward(self, x):
? ? ? ? out = self.linear(x)
returnout
# 2. 實(shí)例化模型粱哼,loss季二,和優(yōu)化器
model = Lr()
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=1e-3)
#3. 訓(xùn)練模型
for i in range(30000):
out = model(x)#3.1 獲取預(yù)測(cè)值
loss = criterion(y,out)#3.2 計(jì)算損失
optimizer.zero_grad()#3.3 梯度歸零
loss.backward()#3.4 計(jì)算梯度
optimizer.step()# 3.5 更新梯度
if(i+1) %20==0:
print('Epoch[{}/{}], loss: {:.6f}'.format(i,30000,loss.data))
#4. 模型評(píng)估
model.eval()#設(shè)置模型為評(píng)估模式,即預(yù)測(cè)模式
predict = model(x)
predict = predict.data.numpy()
plt.scatter(x.data.numpy(),y.data.numpy(),c="r")
plt.plot(x.data.numpy(),predict)
plt.show()
輸出如下:
注意:
model.eval()表示設(shè)置模型為評(píng)估模式揭措,即預(yù)測(cè)模式
model.train(mode=True)?表示設(shè)置模型為訓(xùn)練模式
在當(dāng)前的線性回歸中胯舷,上述并無區(qū)別
但是在其他的一些模型中,訓(xùn)練的參數(shù)和預(yù)測(cè)的參數(shù)會(huì)不相同绊含,到時(shí)候就需要具體告訴程序我們是在進(jìn)行訓(xùn)練還是預(yù)測(cè)桑嘶,比如模型中存在Dropout,BatchNorm的時(shí)候
當(dāng)模型太大躬充,或者參數(shù)太多的情況下逃顶,為了加快訓(xùn)練速度,經(jīng)常會(huì)使用GPU來進(jìn)行訓(xùn)練
此時(shí)我們的代碼需要稍作調(diào)整:
判斷GPU是否可用torch.cuda.is_available()
torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# 2. 實(shí)例化模型充甚,loss以政,和優(yōu)化器
device = torch.device("cuda:0"iftorch.cuda.is_available()else"cpu")
x,y = x.to(device),y.to(device)
model = Lr().to(device)
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=1e-3)
#3. 訓(xùn)練模型
for i in range(300):
? ? out = model(x)
? ? loss = criterion(y,out)
? ? optimizer.zero_grad()
? ? loss.backward()
? ? optimizer.step()
if(i+1) %20==0:
print('Epoch[{}/{}], loss: {:.6f}'.format(i,30000,loss.data))
#4. 模型評(píng)估
model.eval()#
predict = model(x)
predict = predict.cpu().detach().numpy()#轉(zhuǎn)化為numpy數(shù)組
plt.scatter(x.cpu().data.numpy(),y.cpu().data.numpy(),c="r")
plt.plot(x.cpu().data.numpy(),predict,)
plt.show()
3.1 梯度下降算法(batch gradient descent BGD)
每次迭代都需要把所有樣本都送入,這樣的好處是每次迭代都顧及了全部的樣本伴找,做的是全局最優(yōu)化,但是有可能達(dá)到局部最優(yōu)盈蛮。
3.2 隨機(jī)梯度下降法 (Stochastic gradient descent SGD)
針對(duì)梯度下降算法訓(xùn)練速度過慢的缺點(diǎn),提出了隨機(jī)梯度下降算法技矮,隨機(jī)梯度下降算法算法是從樣本中隨機(jī)抽出一組抖誉,訓(xùn)練后按梯度更新一次,然后再抽取一組衰倦,再更新一次袒炉,在樣本量及其大的情況下,可能不用訓(xùn)練完所有的樣本就可以獲得一個(gè)損失值在可接受范圍之內(nèi)的模型了樊零。
torch中的api為:torch.optim.SGD()
3.3 小批量梯度下降 (Mini-batch gradient descent MBGD)
SGD相對(duì)來說要快很多我磁,但是也有存在問題,由于單個(gè)樣本的訓(xùn)練可能會(huì)帶來很多噪聲驻襟,使得SGD并不是每次迭代都向著整體最優(yōu)化方向,因此在剛開始訓(xùn)練時(shí)可能收斂得很快塑悼,但是訓(xùn)練一段時(shí)間后就會(huì)變得很慢。在此基礎(chǔ)上又提出了小批量梯度下降法楷掉,它是每次從樣本中隨機(jī)抽取一小批進(jìn)行訓(xùn)練霞势,而不是一組愕贡,這樣即保證了效果又保證的速度。
mini-batch SGD算法雖然這種算法能夠帶來很好的訓(xùn)練速度巷屿,但是在到達(dá)最優(yōu)點(diǎn)的時(shí)候并不能夠總是真正到達(dá)最優(yōu)點(diǎn)嘱巾,而是在最優(yōu)點(diǎn)附近徘徊憨琳。
另一個(gè)缺點(diǎn)就是mini-batch SGD需要我們挑選一個(gè)合適的學(xué)習(xí)率,當(dāng)我們采用小的學(xué)習(xí)率的時(shí)候旬昭,會(huì)導(dǎo)致網(wǎng)絡(luò)在訓(xùn)練的時(shí)候收斂太慢篙螟;當(dāng)我們采用大的學(xué)習(xí)率的時(shí)候,會(huì)導(dǎo)致在訓(xùn)練過程中優(yōu)化的幅度跳過函數(shù)的范圍问拘,也就是可能跳過最優(yōu)點(diǎn)遍略。我們所希望的僅僅是網(wǎng)絡(luò)在優(yōu)化的時(shí)候網(wǎng)絡(luò)的損失函數(shù)有一個(gè)很好的收斂速度同時(shí)又不至于擺動(dòng)幅度太大。
所以Momentum優(yōu)化器剛好可以解決我們所面臨的問題骤坐,它主要是基于梯度的移動(dòng)指數(shù)加權(quán)平均绪杏,對(duì)網(wǎng)絡(luò)的梯度進(jìn)行平滑處理的,讓梯度的擺動(dòng)幅度變得更小纽绍。
(注:t+1的的histroy_gradent 為第t次的gradent)
AdaGrad算法就是將每一個(gè)參數(shù)的每一次迭代的梯度取平方累加后在開方蕾久,用全局學(xué)習(xí)率除以這個(gè)數(shù),作為學(xué)習(xí)率的動(dòng)態(tài)更新顶岸,從而達(dá)到自適應(yīng)學(xué)習(xí)率的效果
Momentum優(yōu)化算法中腔彰,雖然初步解決了優(yōu)化中擺動(dòng)幅度大的問題,為了進(jìn)一步優(yōu)化損失函數(shù)在更新中存在擺動(dòng)幅度過大的問題,并且進(jìn)一步加快函數(shù)的收斂速度辖佣,RMSProp算法對(duì)參數(shù)的梯度使用了平方加權(quán)平均數(shù)霹抛。
Adam(Adaptive Moment Estimation)算法是將Momentum算法和RMSProp算法結(jié)合起來使用的一種算法,能夠達(dá)到防止梯度的擺幅多大,同時(shí)還能夠加開收斂速度
torch中的api為:torch.optim.Adam()
4 深度學(xué)習(xí)避免過擬合/加速訓(xùn)練
為了應(yīng)對(duì)神經(jīng)網(wǎng)絡(luò)很容易過擬合的問題卷谈,2014年 Hinton 提出了一個(gè)神器:?Dropout: A Simple Way to Prevent Neural Networks from Overfitting
實(shí)驗(yàn)結(jié)果:
dropout 是指在深度學(xué)習(xí)網(wǎng)絡(luò)的訓(xùn)練過程中杯拐,按照一定的概率將一部分神經(jīng)網(wǎng)絡(luò)單元暫時(shí)從網(wǎng)絡(luò)中丟棄,相當(dāng)于從原始的網(wǎng)絡(luò)中找到一個(gè)更瘦的網(wǎng)絡(luò)
在大規(guī)模的神經(jīng)網(wǎng)絡(luò)中有這樣兩個(gè)缺點(diǎn):1. 費(fèi)時(shí)世蔗;2. 容易過擬合
對(duì)于一個(gè)有 N 個(gè)節(jié)點(diǎn)的神經(jīng)網(wǎng)絡(luò)端逼,有了 dropout后,就可以看做是 2^N 個(gè)模型的集合了污淋,但此時(shí)要訓(xùn)練的參數(shù)數(shù)目卻是不變的顶滩,這就緩解了費(fèi)時(shí)的問題。
論文中做了這樣的類比寸爆,無性繁殖可以保留大段的優(yōu)秀基因礁鲁,而有性繁殖則將基因隨機(jī)拆了又拆盐欺,破壞了大段基因的聯(lián)合適應(yīng)性,但是自然選擇中選擇了有性繁殖仅醇,物競天擇冗美,適者生存,可見有性繁殖的強(qiáng)大析二。
dropout 也能達(dá)到同樣的效果粉洼,它強(qiáng)迫一個(gè)神經(jīng)單元,和隨機(jī)挑選出來的其他神經(jīng)單元共同工作叶摄,消除減弱了神經(jīng)元節(jié)點(diǎn)間的聯(lián)合適應(yīng)性属韧,增強(qiáng)了泛化能力。
Batch Normalization, 批標(biāo)準(zhǔn)化, 和普通的數(shù)據(jù)標(biāo)準(zhǔn)化類似, 是將分散的數(shù)據(jù)調(diào)整分布的一種做法, 也是優(yōu)化神經(jīng)網(wǎng)絡(luò)的一種方法.
Batch Normalization是基于Mini-Batch SGD的一種優(yōu)化方法准谚。
雖然BN層還解釋不清其理論原因挫剑,但是實(shí)踐證明加入BN層可以顯著提升模型收斂速度。
機(jī)器學(xué)習(xí)領(lǐng)域有個(gè)很重要的假設(shè):樣本獨(dú)立同分布假設(shè)柱衔,就是假設(shè)訓(xùn)練數(shù)據(jù)和測(cè)試數(shù)據(jù)是滿足相同分布的樊破,這是通過訓(xùn)練數(shù)據(jù)獲得的模型能夠在測(cè)試集獲得好的效果的一個(gè)基本保障。
但是隨著模型的訓(xùn)練唆铐,各層網(wǎng)絡(luò)參數(shù)的值一直在變化哲戚,各個(gè)隱藏層的輸入數(shù)據(jù)的分布也會(huì)隨之不停的變化,對(duì)于每個(gè)隱藏層來說艾岂,輸入就不符合樣本獨(dú)立同分布的假設(shè)顺少。
那BatchNorm的作用是什么呢?BatchNorm就是在深度神經(jīng)網(wǎng)絡(luò)訓(xùn)練過程中使得每一層神經(jīng)網(wǎng)絡(luò)的輸入保持相同分布的王浴。
每個(gè)隱層神經(jīng)元的激活值做BN脆炎,可以想象成每個(gè)隱層又加上了一層BN操作層,它位于A=X*W+B激活值獲得之后氓辣,非線性函數(shù)變換之前秒裕,其圖示如下