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

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

