pytorch基礎(chǔ)之損失函數(shù)與反向傳播詳解
1 損失函數(shù)
1.1 Loss Function的作用
- 每次訓(xùn)練神經(jīng)網(wǎng)絡(luò)的時(shí)候都會(huì)有一個(gè)目標(biāo),也會(huì)有一個(gè)輸出。目標(biāo)和輸出之間的誤差,就是用Loss Function來(lái)衡量的。所以L(fǎng)oss誤差是越小越好的。
- 此外,我們可以根據(jù)誤差Loss,指導(dǎo)輸出output接近目標(biāo)target。即我們可以以L(fǎng)oss為依據(jù),不斷訓(xùn)練神經(jīng)網(wǎng)絡(luò),優(yōu)化神經(jīng)網(wǎng)絡(luò)中各個(gè)模塊,從而優(yōu)化output 。
Loss Function的作用:
(1)計(jì)算實(shí)際輸出和目標(biāo)之間的差距
(2)為我們更新輸出提供一定的依據(jù),這個(gè)提供依據(jù)的過(guò)程也叫反向傳播。
我們可以看下pytorch為我們提供的損失函數(shù):https://pytorch.org/docs/stable/nn.html#loss-functions
1.2 損失函數(shù)簡(jiǎn)單示例
以L(fǎng)1Loss損失函數(shù)為例子,他其實(shí)很簡(jiǎn)單,就是把實(shí)際值與目標(biāo)值,挨個(gè)相減,再求個(gè)均值。就是結(jié)果。(這個(gè)結(jié)果就反映了實(shí)際值的好壞程度,這個(gè)結(jié)果越小,說(shuō)明越靠近目標(biāo)值)

示例代碼
import torch from torch.nn import L1Loss inputs = torch.tensor([1,2,3],dtype=torch.float32) # 實(shí)際值 targets = torch.tensor([1,2,5],dtype=torch.float32) # 目標(biāo)值 loss = L1Loss() result = loss(inputs,targets) print(result)
輸出結(jié)果:tensor(0.6667)
接下來(lái)我們看下兩個(gè)常用的損失函數(shù):均方差和交叉熵誤差
1.3 均方差
均方差:實(shí)際值與目標(biāo)值對(duì)應(yīng)做差,再平方,再求和,再求均值。
那么套用剛才的例子就是:(0+0+2^2)/3=4/3=1.33333…
代碼實(shí)現(xiàn)
import torch from torch.nn import L1Loss, MSELoss inputs = torch.tensor([1,2,3],dtype=torch.float32) # 實(shí)際值 targets = torch.tensor([1,2,5],dtype=torch.float32) # 目標(biāo)值 loss_mse = MSELoss() result = loss_mse(inputs,targets) print(result)
輸出結(jié)果:tensor(1.3333)
1.4 交叉熵誤差:
這個(gè)比較復(fù)雜一點(diǎn),首先我們看官方文檔給出的公式
這里先用代碼實(shí)現(xiàn)一下他的簡(jiǎn)單用法:
import torch from torch.nn import L1Loss, MSELoss, CrossEntropyLoss x = torch.tensor([0.1,0.2,0.3]) # 預(yù)測(cè)出三個(gè)類(lèi)別的概率值 y = torch.tensor([1]) # 目標(biāo)值 應(yīng)該是這三類(lèi)中的第二類(lèi) 也就是下標(biāo)為1(從0開(kāi)始的) x = torch.reshape(x,(1,3)) # 修改格式 交叉熵函數(shù)的要求格式是 (N,C) N是bitch_size C是類(lèi)別 # print(x.shape) loss_cross = CrossEntropyLoss() result = loss_cross(x,y) print(result)
輸出結(jié)果:tensor(1.1019)
1.5 如何在神經(jīng)網(wǎng)絡(luò)中用到Loss Function
# -*- coding: utf-8 -*-
# 作者:小土堆
# 公眾號(hào):土堆碎念
import torchvision
from torch import nn
from torch.nn import Sequential, Conv2d, MaxPool2d, Flatten, Linear
from torch.utils.data import DataLoader
dataset = torchvision.datasets.CIFAR10("../data", train=False, transform=torchvision.transforms.ToTensor(),
download=True)
dataloader = DataLoader(dataset, batch_size=1)
class Tudui(nn.Module):
def __init__(self):
super(Tudui, 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
loss = nn.CrossEntropyLoss()
tudui = Tudui()
for data in dataloader:
imgs, targets = data
outputs = tudui(imgs)
result_loss = loss(outputs, targets)
print(result_loss)2 反向傳播
所謂的反向傳播,就是利用我們得到的loss值,來(lái)對(duì)我們神經(jīng)網(wǎng)絡(luò)中的一些參數(shù)做調(diào)整,以達(dá)到loss值降低的目的。(圖片經(jīng)過(guò)一層一層網(wǎng)絡(luò)的處理,最終得到結(jié)果,這是正向傳播。最終結(jié)果與期望值運(yùn)算得到loss,用loss反過(guò)來(lái)調(diào)整參數(shù),叫做反向傳播。個(gè)人理解,不一定嚴(yán)謹(jǐn)?。?/p>
2.1 backward
這里利用loss來(lái)調(diào)整參數(shù),主要使用的方法是梯度下降法。
這個(gè)方法原理其實(shí)還是有點(diǎn)復(fù)雜的,但是pytorch為我們實(shí)現(xiàn)好了,所以用起來(lái)很簡(jiǎn)單。
調(diào)用損失函數(shù)得到的值的backward函數(shù)即可。
loss = CrossEntropyLoss() # 定義loss函數(shù)
# 實(shí)例化這個(gè)網(wǎng)絡(luò)
test = Network()
for data in dataloader:
imgs,targets = data
outputs = test(imgs) # 輸入圖片
result_loss = loss(outputs,targets)
result_loss.backward() # 反向傳播
print('ok')打斷點(diǎn)調(diào)試,可以看到,grad屬性被賦予了一些值。如果不用反向傳播,是沒(méi)有值的
當(dāng)然,計(jì)算出這個(gè)grad值只是梯度下降法的第一步,算出了梯度,如何下降呢,要靠?jī)?yōu)化器
2.2 optimizer
優(yōu)化器也有好幾種,官網(wǎng)對(duì)優(yōu)化器的介紹:https://pytorch.org/docs/stable/optim.html
不同的優(yōu)化器需要設(shè)置的參數(shù)不同,但是有兩個(gè)是大部分都有的:模型參數(shù)與學(xué)習(xí)速率
我們以SDG優(yōu)化器為例,看下用法:
# 實(shí)例化這個(gè)網(wǎng)絡(luò)
test = Network()
loss = CrossEntropyLoss() # 定義loss函數(shù)
# 構(gòu)造優(yōu)化器
# 這里我們選擇的優(yōu)化器是SGD 傳入兩個(gè)參數(shù) 第一個(gè)是個(gè)模型test的參數(shù) 第二個(gè)是學(xué)習(xí)率
optim = torch.optim.SGD(test.parameters(),lr=0.01)
for data in dataloader:
imgs,targets = data
outputs = test(imgs) # 輸入圖片
result_loss = loss(outputs,targets) # 計(jì)算loss
optim.zero_grad() #因?yàn)檫@是在循環(huán)里面 所以每次開(kāi)始優(yōu)化之前要把梯度置為0 防止上一次的結(jié)果影響這一次
result_loss.backward() # 反向傳播 求得梯度
optim.step() # 對(duì)參數(shù)進(jìn)行調(diào)優(yōu)這里面我們剛學(xué)得主要是這三行:
清零,反向傳播求梯度,調(diào)優(yōu)
optim.zero_grad() #因?yàn)檫@是在循環(huán)里面 所以每次開(kāi)始優(yōu)化之前要把梯度置為0 防止上一次的結(jié)果影響這一次 result_loss.backward() # 反向傳播 求得梯度 optim.step() # 對(duì)參數(shù)進(jìn)行調(diào)優(yōu)
我們可以打印一下loss,看下調(diào)優(yōu)后得loss有什么變化。
注意:我們dataloader是把數(shù)據(jù)拿出來(lái)一遍,那么看了一遍之后,經(jīng)過(guò)這一遍的調(diào)整,下一遍再看的時(shí)候,loss才有變化。
所以,我們先讓讓他學(xué)習(xí)20輪,然后看一下每一輪的loss是多少
# 實(shí)例化這個(gè)網(wǎng)絡(luò)
test = Network()
loss = CrossEntropyLoss() # 定義loss函數(shù)
# 構(gòu)造優(yōu)化器
# 這里我們選擇的優(yōu)化器是SGD 傳入兩個(gè)參數(shù) 第一個(gè)是個(gè)模型test的參數(shù) 第二個(gè)是學(xué)習(xí)率
optim = torch.optim.SGD(test.parameters(),lr=0.01)
for epoch in range(20):
running_loss = 0.0
for data in dataloader:
imgs,targets = data
outputs = test(imgs) # 輸入圖片
result_loss = loss(outputs,targets) # 計(jì)算loss
optim.zero_grad() #因?yàn)檫@是在循環(huán)里面 所以每次開(kāi)始優(yōu)化之前要把梯度置為0 防止上一次的結(jié)果影響這一次
result_loss.backward() # 反向傳播 求得梯度
optim.step() # 對(duì)參數(shù)進(jìn)行調(diào)優(yōu)
running_loss = running_loss + result_loss # 記錄下這一輪中每個(gè)loss的值之和
print(running_loss) # 打印每一輪的loss值之和
可以看到,loss之和一次比一次降低了。
總結(jié)
具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
相關(guān)文章
tensorflow mnist 數(shù)據(jù)加載實(shí)現(xiàn)并畫(huà)圖效果
TensorFlow™ 是一個(gè)采用數(shù)據(jù)流圖(data flow graphs),用于數(shù)值計(jì)算的開(kāi)源軟件庫(kù)。這篇文章給大家介紹tensorflow mnist 數(shù)據(jù)加載實(shí)現(xiàn)并畫(huà)圖效果,感興趣的朋友一起看看吧2020-02-02
Python程序員鮮為人知但你應(yīng)該知道的17個(gè)問(wèn)題
這篇文章主要介紹了Python程序員代碼編寫(xiě)時(shí)應(yīng)該避免的17個(gè)“坑”,也可以說(shuō)成Python程序員代碼編寫(xiě)時(shí)應(yīng)該避免的17個(gè)問(wèn)題,需要的朋友可以參考下2014-06-06
Python Asyncio模塊實(shí)現(xiàn)的生產(chǎn)消費(fèi)者模型的方法
這篇文章主要介紹了Python Asyncio模塊實(shí)現(xiàn)的生產(chǎn)消費(fèi)者模型的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03
Python超越函數(shù)積分運(yùn)算以及繪圖實(shí)現(xiàn)代碼
今天小編就為大家分享一篇Python超越函數(shù)積分運(yùn)算以及繪圖實(shí)現(xiàn)代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11
python requests 庫(kù)請(qǐng)求帶有文件參數(shù)的接口實(shí)例
今天小編就為大家分享一篇python requests 庫(kù)請(qǐng)求帶有文件參數(shù)的接口實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-01-01

