反向傳播可以求出神經網路中每個需要調節引數的梯度(grad),優化器可以根據梯度進行調整,達到降低整體誤差的作用。下面我們對優化器進行介紹。
舉個栗子:
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
optimizer = optim.Adam([var1, var2], lr=0.0001)
首先選擇優化器的演演算法optim.SGD
之後在優化器中放入模型引數model.parameters()
,這一步是必備的
還可在函數中設定一些引數,如學習速率lr=0.01
(這是每個優化器中幾乎都會有的引數)
step()
方法就是利用我們之前獲得的梯度,對神經網路中的引數進行更新。
舉個栗子:
for input, target in dataset:
optimizer.zero_grad()
output = model(input)
loss = loss_fn(output, target)
loss.backward()
optimizer.step()
步驟optimizer.zero_grad()
是必選的
我們的輸入經過了模型,並得到了輸出output
之後計算輸出和target之間的誤差loss
呼叫誤差的反向傳播loss.backwrd
,更新每個引數對應的梯度。
呼叫optimizer.step()
對摺積核中的引數進行優化調整。
之後繼續進入for
迴圈,使用函數optimizer.zero_grad()
對每個引數的梯度進行清零,防止上一輪迴圈中計算出來的梯度影響下一輪迴圈。
優化器中演演算法共有的引數(其他引數因優化器的演演算法而異):
params: 傳入優化器模型中的引數
lr: learning rate,即學習速率
關於學習速率:
一般來說,學習速率設定得太大,模型執行起來會不穩定
學習速率設定得太小,模型訓練起來會過慢
建議在最開始訓練模型的時候,選擇設定一個較大的學習速率;訓練到後面的時候,再選擇一個較小的學習速率
程式碼栗子:
import torch.optim
import torchvision
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.data import DataLoader
dataset=torchvision.datasets.CIFAR10("./dataset",train=False,download=True,transform=torchvision.transforms.ToTensor())
dataloder=DataLoader(dataset,batch_size=1)
class Demo(nn.Module):
def __init__(self):
super(Demo,self).__init__()
self.model1=Sequential(
Conv2d(3,32,5,padding=2),
MaxPool2d(2),
Conv2d(32, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 64, 5, padding=2),
MaxPool2d(2),
Flatten(),
Linear(1024, 64),
Linear(64, 10)
)
def forward(self,x):
x=self.model1(x)
return x
demo=Demo()
loss=nn.CrossEntropyLoss()
#設定優化器
#選擇隨機梯度下降
optim=torch.optim.SGD(demo.parameters(),lr=0.01) #一般來說,學習速率設定得太大,模型執行起來會不穩定;設定得太小,模型訓練起來會比較慢
#對資料進行20次迴圈
for epoch in range(20):
running_loss=0.0 #初始化loss
#該回圈只對資料進行了一次訓練
for data in dataloder:
imgs,targets=data
output=demo(imgs)
result_loss=loss(output,targets)
#----------------優化器訓練過程---------------------
optim.zero_grad() #各個引數對應的梯度設定為0
result_loss.backward() #反向傳播,得到每個節點對應的梯度
optim.step() #根據每個引數的梯度,對引數進行調優
running_loss=running_loss+result_loss #累加該輪迴圈的loss,計算該輪迴圈整體誤差的總和
print(running_loss) #輸出該輪迴圈整體誤差的總和
[Run]
tensor(18713.4336, grad_fn=)
tensor(16178.3564, grad_fn=)
tensor(15432.6172, grad_fn=)
tensor(16043.1025, grad_fn=)
tensor(18018.3359, grad_fn=)
......
總結(使用優化器訓練的訓練套路):
設定損失函數loss function
定義優化器optim
從使用迴圈dataloader中的資料:for data in dataloder
取出圖片imgs,標籤targets:imgs,targets=data
將圖片放入神經網路,並得到一個輸出:output=model(imgs)
計算誤差:loss_result=loss(output,targets)
使用優化器,初始化引數的梯度為0:optim.zero_grad()
使用反向傳播求出梯度:loss_result.backward()
根據梯度,對每一個引數進行更新:optim.step()
進入下一個迴圈,直到完成訓練所需的迴圈次數
再複製貼上一次:
一般來說,學習速率設定得太大,模型執行起來會不穩定
學習速率設定得太小,模型訓練起來會過慢
建議在最開始訓練模型的時候,選擇設定一個較大的學習速率;訓練到後面的時候,再選擇一個較小的學習速率
pytorch中提供了一些方法,可以動態地調整學習速率
引數介紹:
optimizer: 放入模型所使用的優化器名稱
step_size(int): 訓練的時候,每多少步進行一個更新
gamma(float): 預設為0.1。在迴圈中,每次訓練的時候,新的學習速率=原來學習速率×gamma
不同的優化器中有很多不同的引數,但是這些引數都是跟幾個特定的演演算法相關的,這些需要使用的時候再去了解。
如果只是單純地使用優化器,那麼只需設定optimizer和學習速率,就可以滿足絕大部分的訓練需求。
import torch.optim
import torchvision
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.data import DataLoader
dataset=torchvision.datasets.CIFAR10("./dataset",train=False,download=True,transform=torchvision.transforms.ToTensor())
dataloder=DataLoader(dataset,batch_size=1)
class Demo(nn.Module):
def __init__(self):
super(Demo,self).__init__()
self.model1=Sequential(
Conv2d(3,32,5,padding=2),
MaxPool2d(2),
Conv2d(32, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 64, 5, padding=2),
MaxPool2d(2),
Flatten(),
Linear(1024, 64),
Linear(64, 10)
)
def forward(self,x):
x=self.model1(x)
return x
demo=Demo()
loss=nn.CrossEntropyLoss()
#設定優化器
#選擇隨機梯度下降
optim=torch.optim.SGD(demo.parameters(),lr=0.01) #一般來說,學習速率設定得太大,模型執行起來會不穩定;設定得太小,模型訓練起來會比較慢
#加入學習速率更新
scheduler = torch.optim.lr_scheduler.StepLR(optim, step_size=5, gamma=0.1)
#對資料進行20次迴圈
for epoch in range(20):
running_loss=0.0 #初始化loss
#該回圈只對資料進行了一次訓練
for data in dataloder:
imgs,targets=data
output=demo(imgs)
result_loss=loss(output,targets)
#----------------優化器訓練過程---------------------
optim.zero_grad() #各個引數對應的梯度設定為0;如果不寫這行程式碼,那麼每次迴圈中都會對這個梯度進行累加
result_loss.backward() #反向傳播,得到每個節點對應的梯度
#optim.step() #根據每個引數的梯度,對引數進行調優
scheduler.step() #對每個引數的學習速率進行調整;通過scheduler可以在每次迴圈中對學習速率進行下降
running_loss=running_loss+result_loss #累加該輪迴圈的loss,計算該輪迴圈整體誤差的總和
print(running_loss) #輸出該輪迴圈整體誤差的總和