Pytorch学习 - Task6 PyTorch常见的损失函数和优化器使用
Pytorch學習 - Task6 PyTorch常見的損失函數和優化器使用
- 官方參考鏈接
- 1. 損失函數
- (1)BCELoss 二分類
- 計算公式
- 小例子:
- (2) BCEWithLogitsLoss 將Sigmoid函數和BCELoss方法結合到一個類中
- 計算公式
- 多出參數:
- 小例子
- (3)NLLLoss(多分類問題) - 多分類的負對數似然損失函數(negative log likelihood loss)
- 計算公式
- 多出參數
- 小例子
- (4)CrossEntropyLoss 多分類問題 - 將nn.LogSoftmax()和nn.NLLLoss()方法結合到一個類中
- 計算公式
- 小例子
- (5)L1Loss(L1 norm) 計算平均絕對誤差
- 計算公式
- 小例子
- (6)MSELoss(L2 norm) 計算均方誤差
- 計算公式
- 小例子
- (7)SmoothL1Loss - 絕對元素誤差小于1,則使用平方項。否則使用L1項。
- 計算公式
- 小例子
- 總結
- 常見錯誤
- 2. 優化器 - 主要使用四個
- 使用示例
- 具體講解
- (1) SGD
- 功能
- 參數
- 小例子 - 不推薦
- (1.1)帶動量Momentum的SGD - 可以一試
- (1.2)使用牛頓加速法NAG的SGD - 不如不用
- (2) RMSprop - 均方根傳遞 - 推薦
- 參數
- (3) Adam(AMSGrad) - 將Momentum算法和RMSProp算法結合起來使用的一種算法
- 參數
- 3. 小練習
- 題目
- (1)損失函數MSE、優化器SGD、學習率0.1
- (2)損失函數MSE、優化器SGD、學習率0.5
- (3)損失函數MSE、優化器SGD、學習率0.01
官方參考鏈接
參考文檔鏈接:損失函數
參考文檔鏈接:【英文】優化器的使用
參考文檔鏈接:【中文】優化器的使用
1. 損失函數
損失函數的基本用法
criterion = LossCriterion() # 構造函數有自己的參數 loss = criterion(x,y) # 調用標準時也有參數!!! 得到的loss結果已經對mini-batch進行取平均操作
(1)BCELoss 二分類
使用
CLASS torch.nn.BCELoss(weight=None, size_average=None, reduce=None, reduction='mean') ''' # BCELoss二分類 # 創建一個衡量目標和輸出之間二進制交叉熵的criterion 參數:weight(Tensor,可選) 每批元素損失的手工重標權重。如果給定,必須是一個大小為nbatch大小的張量size_average(bool,可選) 棄用(見reduction參數)。默認情況下,設置為True,即對批處理中的每個損失元素進行平均。注意,對于某些損失,每個樣本有多個元素。如果字段size_average設置為False,則對每個小批的損失求和。當reduce為False時,該參數被忽略。默認值:Truereduce(bool,可選)棄用(見reduction參數)。默認情況下,設置為True,即根據size_average參數的值決定對每個小批的觀察值是進行平均或求和。如果reduce為False,則返回每個批處理元素的損失,不進行平均和求和操作,即忽略size_average參數。默認值:Truereduction(string,可選)指定要應用于輸出的reduction,操作'none|mean|sum'。 默認值mean'none':表示不進行任何reduction操作'mean':求平均值,輸出的和 除以輸出中的元素數'sum':輸出求和!!!指定任何size_average和reduce參數都將使reduction參數失效 形狀:輸入:(N,*) 目標: (N,*) 與輸入相同維度輸出:標量scalar。如果reduce為false,不做任何處理則為(N,*) '''計算公式
其中N代表batch size,xn為輸出,yn為目標。
當reduction不同設置時,如mean和sum,返回值的變化:
小例子:
進行二分類問題時 即激活函數采用sigmoid時,常使用交叉熵作為損失函數。能夠解決因sigmoid函數導致的梯度消失問題
如果使用MSELoss作為損失函數,會產生梯度消失問題。
(2) BCEWithLogitsLoss 將Sigmoid函數和BCELoss方法結合到一個類中
CLASS torch.nn.BCEWithLogitsLoss(weight=None, size_average=None, reduce=None, reduction='mean', pos_weight=None)計算公式
利用log-sum-exp技巧來實現數值穩定性
多出參數:
- pos_weight (Tensor,可選) –正值例子的權重,必須是有著與分類數目相同的長度的向量
- 參數作用:可以通過增加正值示例的權重來權衡召回率和準確性。在多標簽分類的情況下,損失可以描述為:
c表示類的數量(c>1表明是多標簽二進制分類,c=1表明是單標簽二進制分類),n為一批中的例子數量,pc為類別c的正值的權重,解決正負例樣本不均衡的情況
pc>1增加召回率,pc<1增加準確性
小例子
上一個損失函數的例子等價于
loss = nn.BCEWithLogicLoss() input = nn.randn(3,requires_grad=True) target = torch.empty(3).random_(2) output = loss(input,target)''' 區別 無需自定義m函數對input進行操作(nn.sigmoid()) '''(3)NLLLoss(多分類問題) - 多分類的負對數似然損失函數(negative log likelihood loss)
使用:
CLASS torch.nn.NLLLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction='mean')計算公式
- reduction=none
如果提供了,可選的參數weight權重應該是一個一維張量,為每個類分配權重。當你有一個不平衡的訓練集時,這是特別有用的。
通過轉發調用給出的輸入 (即nn.LogSoftmax()后的輸出) 應該包含每個類的log-probability。輸入要么是大小為(minibatch,C)或大小(minibatch,C,d1,d2,…,dK)的Tensor,k>=1表示k維的輸入
通過在網絡的最后一層添加LogSoftmax層,可以很容易地獲得神經網絡中的log-probability。如果不喜歡添加額外的層,可以使用CrossEntropyLoss損失函數來替代。
損失預期的目標應該是[0,c - 1]范圍內的類索引,其中C =類的數量;如果指定ignore_index參數,該損失函數也接受這個類索引(這個索引不一定在類范圍內)。
- reduction = mean / sum時的計算公式
多出參數
- ignore_index(int,optional) - 指定一個被忽略的目標值,該目標值不影響輸入梯度。當size_average為真時,對非忽略目標的損失進行平均。
小例子
# 多分類問題 低維舉例 m = nn.LogSoftmax(dim=1) loss = nn.NLLLoss() # input is of size N*c = 3*5 input = torch.randn(3,5,requires_grad=True) print("input : ",input) print("m(input): ",m(input)) # 對input先進行softmax計算(轉化成0-1之間的數值) 再取log 得到的都是負數 target = torch.tensor([1,0,4]) print("target: ",target) output = loss(m(input),target) print("output: ",output)結果: input : tensor([[ 0.1047, -0.5505, -0.3458, -0.1031, -0.7769],[-0.3304, -0.7051, 0.5704, 1.2910, -0.1523],[ 0.5005, 1.4218, 0.9723, 0.4399, -2.0973]], requires_grad=True) m(input): tensor([[-1.2188, -1.8741, -1.6693, -1.4266, -2.1004],[-2.3422, -2.7169, -1.4414, -0.7208, -2.1641],[-1.8133, -0.8921, -1.3416, -1.8739, -4.4112]],grad_fn=<LogSoftmaxBackward0>) target: tensor([1, 0, 4]) output: tensor(2.8758, grad_fn=<NllLossBackward0>) # 多分類問題 高維舉例 N,C = 5,4 loss = nn.NLLLoss()data = torch.randn(N,16,10,10) print("data: ",data)conv = nn.Conv2d(16,C,(3,3)) # 輸出為5*8*8 print("conv: ",conv) m = nn.LogSoftmax(dim=1) # each element in target has to in 0<=value<=C target = torch.empty(N,8,8,dtype=torch.long).random_(0,C) print("target:",target) print("conv(data):",conv(data)) print("m(conv(data)):",m(conv(data)))print("data shape : ",data.shape) print("target shape",target.shape) print("conv(data).shape:",conv(data).shape) print("m(conv(data)).shape:",m(conv(data)).shape)output = loss(m(conv(data)),target) print("output : ",output) print("output shape : ",output.shape)結果: conv: Conv2d(16, 4, kernel_size=(3, 3), stride=(1, 1)) data shape : torch.Size([5, 16, 10, 10]) conv(data).shape: torch.Size([5, 4, 8, 8]) m(conv(data)).shape: torch.Size([5, 4, 8, 8])(4)CrossEntropyLoss 多分類問題 - 將nn.LogSoftmax()和nn.NLLLoss()方法結合到一個類中
使用:
loss = nn.CrossEntropyLoss()當用C類訓練分類問題時,它是有用的。如果提供了,可選的參數weight權重應該是一個一維張量,為每個類分配權重。當你有一個不平衡的訓練集時,這是特別有用的。
每個類的輸入應該包含原始的、未標準化的分數。
輸入應該是大小為(minibatch,C)或大小(minibatch,C,d1,d2,…,dK)的Tensor,k>=1表示k維的輸入
該criterion期望在[0,c - 1]范圍內的一個類指標作為小batch大小的一維張量的每個值的目標值;如果指定ignore_index,該criterion也接受這個類索引值(這個索引不一定在類范圍內)。
計算公式
小例子
上面先使用nn.LogSoftmax(dim=1),再使用nn.NLLLoss()的等價于下面這段代碼
!!注意事項:nn.CrossEntropyLoss() 是一個類,應該先行進行實例化。否則會報錯“RuntimeError: Boolean value of Tensor with more than one value is ambiguous”
(5)L1Loss(L1 norm) 計算平均絕對誤差
使用:計算input x和target y中每個元素的平均絕對誤差MAE
CLASS torch.nn.L1Loss(size_average=None, reduce=None, reduction='mean')計算公式
reduction=none
reduction = mean/sum
小例子
loss = nn.L1Loss() input = torch.randn(1,2,requires_grad=True) print("input:",input) target = torch.randn(1,2) print("target:",target) output = loss(input,target) print("output:",output)結果: input: tensor([[-0.3543, -0.8127]], requires_grad=True) target: tensor([[-1.0530, -1.4032]]) output: tensor(0.6446, grad_fn=<L1LossBackward0>)output = (abs(-0.3543+1.0530) + abs(-0.8127+1.4032))/2(6)MSELoss(L2 norm) 計算均方誤差
使用:計算input x和target y中每個元素的均方誤差MAE
CLASS torch.nn.MSELoss() loss = nn.MSELoss()計算公式
reduction = none
reduction = mean/sum
小例子
loss = nn.MSELoss() input = torch.randn(1,2,requires_grad=True) print("input: ",input) target = torch.rand(1,2) print("target: ",target) output = loss(input,target) print("output: ",output)結果: input: tensor([[-0.5910, 0.0345]], requires_grad=True) target: tensor([[0.9664, 0.4840]]) output: tensor(1.3138, grad_fn=<MseLossBackward0>) ? output = (pow((-0.5910-0.9664),2) + pow((0.0345-0.4840),2))/2 = 1.313772505(7)SmoothL1Loss - 絕對元素誤差小于1,則使用平方項。否則使用L1項。
使用:對異常值敏感度較低
CLASS torch.nn.SmoothL1Loss(size_average=None, reduce=None, reduction='mean')計算公式
小例子
loss = nn.SmoothL1Loss() input = torch.randn(3,2,requires_grad=True) print("input: ",input) target = torch.rand(3,2) print("target: ",target) output = loss(input,target) print("output: ",output)結果: input: tensor([[ 1.2615, -0.8428],[-1.0714, -0.4162],[-0.4159, -1.0941]], requires_grad=True) target: tensor([[0.0581, 0.2579],[0.1083, 0.9786],[0.5719, 0.9244]]) output: tensor(0.8142, grad_fn=<SmoothL1LossBackward0>)output計算驗證函數 l = input t = target >>> s = 0 >>> for i in range(len(l)): ... for j in range(len(l[0])): ... if abs(l[i][j] - t[i][j]) < 1: ... s+=0.5*pow((l[i][j] - t[i][j]),2) ... else: ... s += abs(l[i][j] - t[i][j]) - 0.5 ... print(abs(l[i][j] - t[i][j])) >>> output = s/6 >>> output > 0.8141624033333335總結
| torch.nn.BCELoss() | 二分類交叉損失函數 | 二分類問題(激活函數sigmoid) |
| torch.nn.BCEWithLogitsLoss() | 多分類交叉損失函數 | 多分類問題(sigmoid和BCELoss結合) |
| torch.nn.NLLLoss() | 多分類的負對數似然損失函數 | 多分類問題 |
| torch.nn.CrossEntropyLoss() | 交叉熵損失函數 | 多分類問題 |
| torch.nn.L1Loss() | 平均絕對誤差 L1 norm | 回歸 |
| torch.nn.MSELoss() | 均方誤差L2 norm | 回歸 |
| torch.nn.SmoothL1Loss() | 平滑的L1損失 | 回歸 |
常見錯誤
1、loss.backward()使用前不要忘記設置loss保存梯度
- 報錯:“RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn”
- 修改:在 backward()使用前增加 loss.requires_grad_(True)
2、在使用CrossEntropyLoss()交叉熵損失函數中遇到的問題
- 報錯:IndexError: Dimension out of range (expected to be in range of [-1, 0], but got 1)
- 原因分析:參考鏈接: 感謝!!!!
錯誤代碼
a1 = torch.Tensor([ 0.0606,0.1610,0.2990,0.2101, 0.5104]) a2 = torch.Tensor([0.6388,0.4053, 0.4196, 0.7060, 0.2793]) a3 = torch.Tensor([ 0.3973,0.6114, 0.1127, 0.7732, 0.0592])b1 = torch.Tensor([3]) b2 = torch.Tensor([1]) b3 = torch.Tensor([0])loss_1 = func(a1,b1.long()) print(loss_1) loss_2 = func(a2,b2.long()) print(loss_2) loss_3 = func(a3,b3.long()) print(loss_3)報錯了!! 檢查一下a1.shape torch.Size([5]) 維度不對了 因此需要升維 a1.unsqueeze(0) tensor([[0.0606, 0.1610, 0.2990, 0.2101, 0.5104]]) a1.unsqueeze(0).shape torch.Size([1, 5])正確代碼
a1 = torch.Tensor([ 0.0606,0.1610,0.2990,0.2101, 0.5104]) a2 = torch.Tensor([0.6388,0.4053, 0.4196, 0.7060, 0.2793]) a3 = torch.Tensor([ 0.3973,0.6114, 0.1127, 0.7732, 0.0592])b1 = torch.Tensor([3]) b2 = torch.Tensor([1]) b3 = torch.Tensor([0])loss_1 = func(a1.unsqueeze(0),b1.long()) print(loss_1) loss_2 = func(a2.unsqueeze(0),b2.long()) print(loss_2) loss_3 = func(a3.unsqueeze(0),b3.long()) print(loss_3)結果: tensor(1.6595) tensor(1.7065) tensor(1.6410)2. 優化器 - 主要使用四個
參考博文1:
參考博文2:
torch.optim包是一個實現了各種優化算法的庫。構建一個optimizer對象
常用優化器SGD/Adam/RMSprop
使用示例
import torch.optim as optim optimizer = optim.SGD(model.parameters(),lr=0.01,momentum=0.9) optimizer = optim.Adam([var1,var2],lr=0.00001)具體講解
(1) SGD
class torch.optim.SGD(params, lr=, momentum=0, dampening=0, weight_decay=0, nesterov=False)功能
SGD優化算法,帶動量momentum的SGD優化算法
參數
- params 參數組,優化器需要管理的那部分參數
- lr 學習率,可隨著訓練過程不斷調整
- momentum 動量,常設置為0.8,0.9
- dampening 暫時用不了
- weight_decay 權值衰減系數,L2正則項的系數
- nesterov bool選項,是否使用NAG??
注意事項:
pytroch中使用SGD十分需要注意的是,更新公式與其他框架略有不同!
- pytorch中是這樣的:
v=ρ?v+g
p=p?lr?v = p - lr?ρ?v - lr?g - 其他框架:
v=ρ?v+lr?g
p=p?v = p - ρ?v - lr?g - ρ是動量,v是速率,g是梯度,p是參數,其實差別就是在ρ?v這一項,pytorch中將此項也乘了一個學習率。
小例子 - 不推薦
optimizer = optim.SGD(model.parameters(),lr=0.01,momentum=0.9) optimizer.zero_grad() loss_fn(model(input),target).backward() optimizer.step()(1.1)帶動量Momentum的SGD - 可以一試
更新的時候在一定程度上保留之前更新的方向
(1.2)使用牛頓加速法NAG的SGD - 不如不用
可以理解為往標準動量中添加了一個校正因子
(2) RMSprop - 均方根傳遞 - 推薦
**思想:**梯度震動較大的項,在下降時,減小其下降速度;對于震動幅度小的項,在下降時,加速其下降速度
對于RNN有很好的效果
參數
- params(iterable) 待優化參數組
- lr(float,可選) 學習率
- **alpha(float,可選) 平滑常數,默認0.99
- eps(float,可選) 為了增加數值計算的穩定性而加到分母里的項,默認:1e-8
- weight_decay(float,可選) 權重衰減L2懲罰,默認:0
- momentum(float,可選) 動量因子,默認:0
- centered(bool,可選) 如果為True,計算中心化的RMSProp,并且用它的方差預測值對梯度進行歸一化**
(3) Adam(AMSGrad) - 將Momentum算法和RMSProp算法結合起來使用的一種算法
torch.optim.Adam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0)參數
- params
- lr 默認1e-3
- betas (Tuple[float,float], 可選) – 用于計算梯度以及梯度平方的運行平均值的系數(默認:0.9,0.999)
- eps 為了增加數值計算的穩定性而加到分母里的項,默認:1e-8
- weight_decay 權重衰減系數
3. 小練習
題目
設置不同的優化器和學習率,重復任務2的回歸過程1. 損失函數MSE、優化器SGD、學習率0.12. 損失函數MSE、優化器SGD、學習率0.53. 損失函數MSE、優化器SGD、學習率0.01 import torch import torch.nn as nn import numpy as npclass Net(nn.Module):def __init__(self):super(Net,self).__init__()self.w = torch.nn.Parameter(torch.tensor([7.]))self.b = torch.nn.Parameter(torch.tensor([6.]))def forward(self,x):return self.w * x+self.b(1)損失函數MSE、優化器SGD、學習率0.1
net = Net() optimizer = torch.optim.SGD(net.parameters(),lr=0.1) loss_func = torch.nn.MSELoss() for step in range(1000):output = net(x)loss = loss_func(output,y)optimizer.zero_grad()loss.backward()optimizer.step()if step%10 == 0:print(loss)(2)損失函數MSE、優化器SGD、學習率0.5
net = Net() optimizer = torch.optim.SGD(net.parameters(),lr=0.5) loss_func = torch.nn.MSELoss() for step in range(1000):output = net(x)loss = loss_func(output,y)optimizer.zero_grad()loss.backward()optimizer.step()if step%10 == 0:print(loss)(3)損失函數MSE、優化器SGD、學習率0.01
net = Net() optimizer = torch.optim.SGD(net.parameters(),lr=0.01) loss_func = torch.nn.MSELoss() for step in range(1000):output = net(x)loss = loss_func(output,y)optimizer.zero_grad()loss.backward()optimizer.step()if step%10 == 0:print(loss)總結
以上是生活随笔為你收集整理的Pytorch学习 - Task6 PyTorch常见的损失函数和优化器使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Pytorch学习- 小型知识点汇总 u
- 下一篇: Pytorch学习:Task4 PyTo