5-3.損失函數

文章最前: 我是Octopus,這個名字來源于我的中文名–章魚;我熱愛編程、熱愛算法、熱愛開源。所有源碼在我的個人github ;這博客是記錄我學習的點點滴滴,如果您對 Python、Java、AI、算法有興趣,可以關注我的動態,一起學習,共同進步。

一般來說,監督學習的目標函數由損失函數和正則化項組成。(Objective = Loss + Regularization)

Pytorch中的損失函數一般在訓練模型時候指定。

注意Pytorch中內置的損失函數的參數和tensorflow不同,是y_pred在前,y_true在后,而Tensorflow是y_true在前,y_pred在后。

對于回歸模型,通常使用的內置損失函數是均方損失函數nn.MSELoss 。

對于二分類模型,通常使用的是二元交叉熵損失函數nn.BCELoss (輸入已經是sigmoid激活函數之后的結果)
或者 nn.BCEWithLogitsLoss (輸入尚未經過nn.Sigmoid激活函數) 。

對于多分類模型,一般推薦使用交叉熵損失函數 nn.CrossEntropyLoss。
(y_true需要是一維的,是類別編碼。y_pred未經過nn.Softmax激活。)

此外,如果多分類的y_pred經過了nn.LogSoftmax激活,可以使用nn.NLLLoss損失函數(The negative log likelihood loss)。
這種方法和直接使用nn.CrossEntropyLoss等價。

如果有需要,也可以自定義損失函數,自定義損失函數需要接收兩個張量y_pred,y_true作為輸入參數,并輸出一個標量作為損失函數值。

Pytorch中的正則化項一般通過自定義的方式和損失函數一起添加作為目標函數。

如果僅僅使用L2正則化,也可以利用優化器的weight_decay參數來實現相同的效果。

一,內置損失函數

內置的損失函數一般有類的實現和函數的實現兩種形式。

如:nn.BCE 和 F.binary_cross_entropy 都是二元交叉熵損失函數,前者是類的實現形式,后者是函數的實現形式。

實際上類的實現形式通常是調用函數的實現形式并用nn.Module封裝后得到的。

一般我們常用的是類的實現形式。它們封裝在torch.nn模塊下,并且類名以Loss結尾。

常用的一些內置損失函數說明如下。

  • nn.MSELoss(均方誤差損失,也叫做L2損失,用于回歸)

  • nn.L1Loss (L1損失,也叫做絕對值誤差損失,用于回歸)

  • nn.SmoothL1Loss (平滑L1損失,當輸入在-1到1之間時,平滑為L2損失,用于回歸)

  • nn.BCELoss (二元交叉熵,用于二分類,輸入已經過nn.Sigmoid激活,對不平衡數據集可以用weigths參數調整類別權重)

  • nn.BCEWithLogitsLoss (二元交叉熵,用于二分類,輸入未經過nn.Sigmoid激活)

  • nn.CrossEntropyLoss (交叉熵,用于多分類,要求label為稀疏編碼,輸入未經過nn.Softmax激活,對不平衡數據集可以用weigths參數調整類別權重)

  • nn.NLLLoss (負對數似然損失,用于多分類,要求label為稀疏編碼,輸入經過nn.LogSoftmax激活)

  • nn.KLDivLoss (KL散度損失,也叫相對熵,等于交叉熵減去信息熵,用于標簽為概率值的多分類,要求輸入經過nn.LogSoftmax激活)

  • nn.CosineSimilarity(余弦相似度,可用于多分類)

  • nn.AdaptiveLogSoftmaxWithLoss (一種適合非常多類別且類別分布很不均衡的損失函數,會自適應地將多個小類別合成一個cluster)

重點介紹一下 二元交叉熵、多元交叉熵、對數損失LogLoss、負對數似然損失NLLLoss、KL散度之間的區別和聯系。

1,二分類的交叉熵的計算公式是什么?為什么是這樣一種形式?

B i n a r y C r o s s E n t r o p y L o s s ( Y , Y ^ ) = ? 1 N ∑ i = 0 N ? 1 ( y i l o g y i ^ + ( 1 ? y i ) l o g ( 1 ? y i ^ ) ) BinaryCrossEntropyLoss(Y,\hat{Y}) = - \frac{1}{N}\sum_{i=0}^{N-1} (y_i log \hat{y_i} + (1-y_i) log(1-\hat{y_i})) BinaryCrossEntropyLoss(Y,Y^)=?N1?i=0N?1?(yi?logyi?^?+(1?yi?)log(1?yi?^?))

該公式由極大似然原理推導得來。由于 y i ^ \hat{y_i} yi?^?表示的是樣本標簽為1的概率, 1 ? y i ^ 1-\hat{y_i} 1?yi?^?表示的是樣本標簽為0的概率,
那么訓練集中的全部樣本取得對應標簽的概率即似然函數可以寫成如下形式

L ( Y , Y ^ ) = ∏ i = 0 N ? 1 y i ^ y i ( 1 ? y i ^ ) ( 1 ? y i ) L(Y,\hat{Y}) = \prod_{i=0}^{N-1} \hat{y_i}^{y_i} (1-\hat{y_i})^{(1-y_i)} L(Y,Y^)=i=0N?1?yi?^?yi?(1?yi?^?)(1?yi?)

注意當 y i = 1 y_i = 1 yi?=1為時,連乘中的項為 y i ^ \hat{y_i} yi?^?,當 y i = 0 y_i = 0 yi?=0為時,連乘中的項為 ( 1 ? y i ^ ) (1-\hat{y_i}) (1?yi?^?)

轉換成對數似然函數,得到

l n L ( Y , Y ^ ) = ∑ i = 0 N ? 1 y i l n y i ^ + ( 1 ? y i ) l n ( 1 ? y i ^ ) lnL(Y,\hat{Y}) = \sum_{i=0}^{N-1} y_i ln{\hat{y_i}} + (1-y_i)ln{(1-\hat{y_i})} lnL(Y,Y^)=i=0N?1?yi?lnyi?^?+(1?yi?)ln(1?yi?^?)

對數似然函數求極大值,等價于對對數似然函數的負數求極小值,考慮樣本數量維度歸一化,于是得到了二元交叉熵損失函數的形式。

2,多元交叉熵的計算公式是什么?和二元交叉熵有什么聯系?

C r o s s E n t r o p y L o s s ( Y , Y ^ ) = ? 1 N ∑ i = 0 N ? 1 ∑ k = 0 K ? 1 I ( y i = = k ) l o g y i , k ^ where I ( x ) is?the?Indicator?function I ( T r u e ) = 1 and? I ( F a l s e ) = 0 CrossEntropyLoss(Y,\hat{Y}) = - \frac{1}{N}\sum_{i=0}^{N-1} \sum_{k=0}^{K-1} I(y_i==k) log \hat{y_{i,k}} \\ \text{where} I(x) \text{ is the Indicator function} \\ I(True)= 1 \text{ and } I(False) = 0 CrossEntropyLoss(Y,Y^)=?N1?i=0N?1?k=0K?1?I(yi?==k)logyi,k?^?whereI(x)?is?the?Indicator?functionI(True)=1?and?I(False)=0

多元交叉熵是二元交叉熵的自然拓展,其中 y i y_i yi?取0~K-1其中的一個類別編碼序號, y i ^ \hat{y_i} yi?^? 是一個長度為K的概率向量。多元交叉熵的類別數K取2時即可得到二元交叉熵對應的公式。

3,sklearn,catboost等庫中常常看到logloss對數損失函數,這個損失函數如何計算,和交叉熵有什么關系?

L o g L o s s ( Y , Y ^ ) = ? 1 N ∑ i = 0 N ? 1 l o g ( y i ^ [ y i ] ) LogLoss(Y,\hat{Y}) = - \frac{1}{N}\sum_{i=0}^{N-1} log(\hat{y_{i}}[y_i]) LogLoss(Y,Y^)=?N1?i=0N?1?log(yi?^?[yi?])

公式中的方括號和Python中的索引的用法一致,表示取 y i ^ \hat{y_{i}} yi?^? 的第 y i y_i yi?個元素。

容易證明,對數損失函數與交叉熵函數完全等價,是交叉熵的另外一種視角: 即每個樣本對其標簽對應類別的預測概率值求對數,求平均再取負數即可。

4,pytorch中的 nn.NLLLoss 和 nn.CrossEntropyLoss有什么區別和聯系?

NLLoss 全稱是 Negative Log Likelihood Loss,即 負對數似然損失。其計算公式如下

N L L o s s ( Y , Z ^ ) = ? 1 N ∑ i = 0 N ? 1 z i [ y i ] NLLoss(Y,\hat{Z}) = - \frac{1}{N}\sum_{i=0}^{N-1} {z_{i}}[y_i] NLLoss(Y,Z^)=?N1?i=0N?1?zi?[yi?]

公式中的方括號和Python中的索引的用法一致,表示取 z i ^ \hat{z_{i}} zi?^? 的第 y i y_i yi?個元素。

注意的是這里的 Z ^ \hat{Z} Z^實際上不是概率值,而是概率值取了對數,所以,和LogLoss一對比,很容易發現,LogSoftmax+NLLLoss 等價于 Softmax+LogLoss,等價于 Softmax+CrossEntropyLoss。為了數值精度考慮,pytorch中的nn.CrossEntropyLoss要求輸入未經過Softmax激活,所以有 nn.LogSoftmax+nn.NLLLoss 等價于 nn.CrossEntropyLoss.

5,KL散度的計算公式是什么?有什么現實含義?和交叉熵有什么關系?

KL散度也叫相對熵,可以衡量兩個概率分布之間的差異。

KL散度的計算公式是交叉熵減去信息熵。注意KL散度是不對稱的, 即 K L ( P , Q ) ≠ K L ( Q , P ) KL(P,Q)\neq KL(Q,P) KL(P,Q)=KL(Q,P), 所以不能夠叫做KL距離。

兩個隨機變量P和Q之間的KL散度定義如下:
K L ( P , Q ) = ∑ k = 0 K ? 1 p k l n ( p k q k ) = ∑ k = 0 K ? 1 p k ( l n p k ? l n q k ) KL(P,Q) = \sum_{k=0}^{K-1}p_k ln(\frac{p_k}{q_k}) = \sum_{k=0}^{K-1} p_k (ln{p_k} - ln{q_k}) KL(P,Q)=k=0K?1?pk?ln(qk?pk??)=k=0K?1?pk?(lnpk??lnqk?)

對二分類情況下,有:

K L ( Y , Y ^ ) = ? 1 N ∑ i = 0 N ? 1 ( y i l o g y i ^ + ( 1 ? y i ) l o g ( 1 ? y i ^ ) ) + 1 N ∑ i = 0 N ? 1 ( y i l o g y i + ( 1 ? y i ) l o g ( 1 ? y i ) ) KL(Y,\hat{Y}) = - \frac{1}{N}\sum_{i=0}^{N-1} (y_i log \hat{y_i} + (1-y_i) log(1-\hat{y_i})) + \frac{1}{N}\sum_{i=0}^{N-1} (y_i log y_i + (1-y_i) log(1- y_i)) KL(Y,Y^)=?N1?i=0N?1?(yi?logyi?^?+(1?yi?)log(1?yi?^?))+N1?i=0N?1?(yi?logyi?+(1?yi?)log(1?yi?))

y i y_i yi?取0或1的情況下,信息熵部分為0,所以KL散度就等于交叉熵,但是在一些情況下,例如使用標簽平滑處理技術后, y i y_i yi?的取值不是0或1,這時候,KL散度相當于在交叉熵的基礎上減去了一個常數,KL散度作為損失函數去優化模型的效果和交叉熵是完全一樣的,但是在這種情況下當模型完美擬合標簽的情況下KL散度的最小值可取到0,而此時交叉熵能夠取到的最小值是信息熵不為0,所以這種情況下使用KL散度更符合我們對Loss的一般認識。

import numpy as np
import pandas as pd
import torch 
from torch import nn 
import torch.nn.functional as F # nn.BCELoss() 和 nn.BCEWithLogitsLoss() 關系y_pred = torch.tensor([5.0,3,10,-5,-3,-10.0])
y_true = torch.tensor([1.0,1,1,0,0,0])bce = nn.BCELoss()(torch.sigmoid(y_pred),y_true)
print(bce)bce_logits = nn.BCEWithLogitsLoss()(y_pred,y_true)
print(bce_logits)
tensor(0.0184)
tensor(0.0184)
# nn.CrossEntropyLoss() 和  nn.NLLLoss() 關系y_pred = torch.tensor([[10.0,0.0,-10.0],[8.0,8.0,8.0]])
y_true = torch.tensor([0,2])# 直接調用交叉熵損失
ce = nn.CrossEntropyLoss()(y_pred,y_true)
print(ce)# 等價于先計算nn.LogSoftmax激活,再調用nn.NLLLoss
y_pred_logsoftmax = nn.LogSoftmax(dim = 1)(y_pred)
nll = nn.NLLLoss()(y_pred_logsoftmax,y_true)
print(nll)
tensor(0.5493)
tensor(0.5493)
# nn.CrossEntropyLoss() 和  KLDivLoss 關系
import torch.nn.functional as F y_pred = torch.tensor([[10.0,0.0,-10.0],[8.0,8.0,8.0]],requires_grad=True)
y_true = torch.tensor([0,2])ce = nn.CrossEntropyLoss(reduction="mean")(y_pred,y_true)
print(ce)#KLDivLoss要求target為向量形式編碼且preds經過LogSoftmax激活
pred = F.log_softmax(y_pred,dim=1)
target = F.one_hot(y_true).float()
kl = nn.KLDivLoss(reduction="batchmean")(pred,target)
print(kl)
tensor(0.5493, grad_fn=<NllLossBackward0>)
tensor(0.5493, grad_fn=<DivBackward0>)

二,自定義損失函數

自定義損失函數接收兩個張量y_pred,y_true作為輸入參數,并輸出一個標量作為損失函數值。

也可以對nn.Module進行子類化,重寫forward方法實現損失的計算邏輯,從而得到損失函數的類的實現。

下面演示兩個比較著名的范例。

1,自定義損失函數之FocalLoss范例

下面是一個Focal Loss的自定義實現示范。Focal Loss是一種對binary_crossentropy的改進損失函數形式。

它在樣本不均衡和存在較多易分類的樣本時相比binary_crossentropy具有明顯的優勢。

它有兩個可調參數,alpha參數和gamma參數。其中alpha參數主要用于衰減負樣本的權重,gamma參數主要用于衰減容易訓練樣本的權重。

從而讓模型更加聚焦在正樣本和困難樣本上。這就是為什么這個損失函數叫做Focal Loss。

詳見《5分鐘理解Focal Loss與GHM——解決樣本不平衡利器》

https://zhuanlan.zhihu.com/p/80594704

f o c a l _ l o s s ( y , p ) = { ? α ( 1 ? p ) γ log ? ( p ) if?y?=?1 ? ( 1 ? α ) p γ log ? ( 1 ? p ) if?y?=?0 focal\_loss(y,p) = \begin{cases} -\alpha (1-p)^{\gamma}\log(p) & \text{if y = 1}\\ -(1-\alpha) p^{\gamma}\log(1-p) & \text{if y = 0} \end{cases} focal_loss(y,p)={?α(1?p)γlog(p)?(1?α)pγlog(1?p)?if?y?=?1if?y?=?0?

import torch 
from torch import nn 
class FocalLoss(nn.Module):def __init__(self,gamma=2.0,alpha=0.75):super().__init__()self.gamma = gammaself.alpha = alphadef forward(self,y_pred,y_true):bce = torch.nn.BCELoss(reduction = "none")(y_pred,y_true)p_t = (y_true * y_pred) + ((1 - y_true) * (1 - y_pred))alpha_factor = y_true * self.alpha + (1 - y_true) * (1 - self.alpha)modulating_factor = torch.pow(1.0 - p_t, self.gamma)loss = torch.mean(alpha_factor * modulating_factor * bce)return loss
#困難樣本
y_pred_hard = torch.tensor([[0.5],[0.5]])
y_true_hard = torch.tensor([[1.0],[0.0]])#容易樣本
y_pred_easy = torch.tensor([[0.9],[0.1]])
y_true_easy = torch.tensor([[1.0],[0.0]])focal_loss = FocalLoss()
bce_loss = nn.BCELoss()print("focal_loss(easy samples):", focal_loss(y_pred_easy,y_true_easy))
print("bce_loss(easy samples):", bce_loss(y_pred_easy,y_true_easy))print("focal_loss(hard samples):", focal_loss(y_pred_hard,y_true_hard))
print("bce_loss(hard samples):", bce_loss(y_pred_hard,y_true_hard))#可見 focal_loss讓容易樣本的權重衰減到原來的 0.0005/0.1054 = 0.00474
#而讓困難樣本的權重只衰減到原來的 0.0866/0.6931=0.12496# 因此相對而言,focal_loss可以衰減容易樣本的權重。
focal_loss(easy samples): tensor(0.0005)
bce_loss(easy samples): tensor(0.1054)
focal_loss(hard samples): tensor(0.0866)
bce_loss(hard samples): tensor(0.6931)

FocalLoss的使用完整范例可以參考下面中自定義L1和L2正則化項中的范例,該范例既演示了自定義正則化項的方法,也演示了FocalLoss的使用方法。

2,SCELoss

Symmetric Cross Entropy Loss 也是一種對交叉熵損失的改進損失,主要用在標簽中存在明顯噪聲的場景。

s c e _ l o s s ( y , p ) = α c e _ l o s s ( y , p ) + β r c e _ l o s s ( y , p ) c e _ l o s s ( y , p ) = ? y l o g ( p ) ? ( 1 ? y ) l o g ( 1 ? p ) r c e _ l o s s ( y , p ) = c e _ l o s s ( p , y ) r c e _ l o s s ( y , p ) = ? p l o g ( y ) ? ( 1 ? p ) l o g ( 1 ? y ) sce\_loss(y,p) = \alpha\;ce\_loss(y,p) + \beta\;rce\_loss(y,p)\\ ce\_loss(y,p) = - y log(p) -(1-y) log(1-p) \\ rce\_loss(y,p) = ce\_loss(p,y) \\ rce\_loss(y,p)= - p log(y) -(1-p) log(1-y) sce_loss(y,p)=αce_loss(y,p)+βrce_loss(y,p)ce_loss(y,p)=?ylog(p)?(1?y)log(1?p)rce_loss(y,p)=ce_loss(p,y)rce_loss(y,p)=?plog(y)?(1?p)log(1?y)

其基本思想可以簡單描述如下:

當 y是正常標簽的時候,y和p較容易取得一致【例如 y=1時,p取到0.8】,這時候 rce與ce的比值相對較大,引入rce可以增加正常標簽樣本在總Loss中的貢獻。

當y時噪聲標簽的時候,y和p很難取得一致,相當于困難樣本 【例如 y=0時,p取到0.8】,這時候rce與ce的比值相對較小,引入rce可以減小噪聲標簽樣本在總Loss中的貢獻。

參考文章

《SCE 損失》 https://zhuanlan.zhihu.com/p/420827592

《噪聲損失 》https://zhuanlan.zhihu.com/p/420913134

def ce(y,p):p = torch.clamp(p,min=1e-4,max=1-1e-4)y = torch.clamp(y,min=1e-4,max=1-1e-4)return -y*torch.log(p) - (1-y)*torch.log(1-p)def rce(y,p):return ce(p,y)#正常標簽
y = torch.tensor(1.0)
p = torch.tensor(0.8)
print(rce(y,p)/ce(y,p))#噪聲標簽
y = torch.tensor(0.0)
p = torch.tensor(0.8)
print(rce(y,p)/ce(y,p))
tensor(8.2502)
tensor(4.5786)
import torch 
from torch import nn
import  torch.nn.functional as F class SCELoss(nn.Module):def __init__(self, num_classes=10, a=1, b=1):super(SCELoss, self).__init__()self.num_classes = num_classesself.a = a #兩個超參數self.b = bself.cross_entropy = nn.CrossEntropyLoss()def forward(self, pred, labels):# CE 部分,正常的交叉熵損失ce = self.cross_entropy(pred, labels)# RCEpred = F.softmax(pred, dim=1)pred = torch.clamp(pred, min=1e-4, max=1.0)label_one_hot = F.one_hot(labels, self.num_classes).float().to(pred.device)label_one_hot = torch.clamp(label_one_hot, min=1e-4, max=1.0) #最小設為 1e-4,即 A 取 -4rce = (-1 * torch.sum(pred * torch.log(label_one_hot), dim=1))loss = self.a * ce + self.b * rce.mean()return loss

## 三,L1和L2正則化項L1正則、L2正則、Dropout、Early_stopping是神經網絡常用的正則化方法。1,L1正則和L2正則的效果有什么差異?為什么?通常認為L1 正則化可以產生稀疏權值矩陣,即產生一個參數稀疏的模型。而L2 正則化可以讓模型的參數取絕對值較小的數。考慮兩種正則化函數的等值面與原始Loss函數的等值面的關系。以二維情況為例,L1正則化函數的等值面是個菱形,L2正則化函數的等值面是個圓形。最優參數必定取在正則化函數的某條等值面和原始Loss函數的某條等值面的切點處。從求導角度考慮,最優參數是個極值點,要求該處 正則化函數的梯度等于 原始Loss函數的梯度的負數。而梯度方向必定垂直于等值面的切線方向,所以可以推斷必定極值點必定在正則化函數某條等值面和原始Loss函數的某條等值面的切點處。從數值角度考慮,如果該極值點不在兩個等值面的切點,那么沿著原始函數Loss的等值面(原始Loss不變),一定可以找到一個點正則化函數取值更小。這樣就用反證法證明了最優參數必定取在正則化函數的某條等值面和原始Loss函數的某條等值面的切點處。由于L1正則化函數的等值面是個菱形,更容易和凸的Loss函數的等值面相切在坐標軸上,所以傾向于取得參數稀疏的模型,而L2正則化則更傾向于使得極小點到坐標原點的距離更近,但不會導致參數稀疏。![](https://tva1.sinaimg.cn/large/e6c9d24egy1h5q2vhkvz9j20pa0ctjsg.jpg)參考文章《L1正則化與L2正則化》:https://zhuanlan.zhihu.com/p/35356992 ```python
import torch 
# L2正則化
def L2Loss(model,alpha):l2_loss = torch.tensor(0.0, requires_grad=True)for name, param in model.named_parameters():if 'bias' not in name: #一般不對偏置項使用正則l2_loss = l2_loss + (0.5 * alpha * torch.sum(torch.pow(param, 2)))return l2_loss# L1正則化
def L1Loss(model,beta):l1_loss = torch.tensor(0.0, requires_grad=True)for name, param in model.named_parameters():if 'bias' not in name:l1_loss = l1_loss +  beta * torch.sum(torch.abs(param))return l1_loss

四,L1L2正則項使用完整范例

下面以一個二分類問題為例,演示給模型的目標函數添加自定義L1和L2正則化項的方法。

這個范例同時演示了以下FocalLoss的使用。

1,準備數據

import numpy as np 
import pandas as pd 
from matplotlib import pyplot as plt
import torch
from torch import nn
import torch.nn.functional as F
from torch.utils.data import Dataset,DataLoader,TensorDataset
import torchkeras 
%matplotlib inline
%config InlineBackend.figure_format = 'svg'#正負樣本數量
n_positive,n_negative = 1000,6000#生成正樣本, 小圓環分布
r_p = 5.0 + torch.normal(0.0,1.0,size = [n_positive,1]) 
theta_p = 2*np.pi*torch.rand([n_positive,1])
Xp = torch.cat([r_p*torch.cos(theta_p),r_p*torch.sin(theta_p)],axis = 1)
Yp = torch.ones_like(r_p)#生成負樣本, 大圓環分布
r_n = 8.0 + torch.normal(0.0,1.0,size = [n_negative,1]) 
theta_n = 2*np.pi*torch.rand([n_negative,1])
Xn = torch.cat([r_n*torch.cos(theta_n),r_n*torch.sin(theta_n)],axis = 1)
Yn = torch.zeros_like(r_n)#匯總樣本
X = torch.cat([Xp,Xn],axis = 0)
Y = torch.cat([Yp,Yn],axis = 0)#可視化
plt.figure(figsize = (6,6))
plt.scatter(Xp[:,0],Xp[:,1],c = "r")
plt.scatter(Xn[:,0],Xn[:,1],c = "g")
plt.legend(["positive","negative"]);
ds = TensorDataset(X,Y)ds_train,ds_val = torch.utils.data.random_split(ds,[int(len(ds)*0.7),len(ds)-int(len(ds)*0.7)])
dl_train = DataLoader(ds_train,batch_size = 100,shuffle=True,num_workers=2)
dl_val = DataLoader(ds_val,batch_size = 100,num_workers=2)features,labels = next(iter(dl_train))

2,定義模型


class Net(nn.Module):def __init__(self):super().__init__()self.fc1 = nn.Linear(2,4)self.fc2 = nn.Linear(4,8) self.fc3 = nn.Linear(8,1)def forward(self,x):x = F.relu(self.fc1(x))x = F.relu(self.fc2(x))y = self.fc3(x)return ynet = Net() from torchkeras import summarysummary(net,features);
--------------------------------------------------------------------------
Layer (type)                            Output Shape              Param #
==========================================================================
Linear-1                                     [-1, 4]                   12
Linear-2                                     [-1, 8]                   40
Linear-3                                     [-1, 1]                    9
==========================================================================
Total params: 61
Trainable params: 61
Non-trainable params: 0
--------------------------------------------------------------------------
Input size (MB): 0.000069
Forward/backward pass size (MB): 0.000099
Params size (MB): 0.000233
Estimated Total Size (MB): 0.000401
--------------------------------------------------------------------------

3,訓練模型

# L2正則化
def L2Loss(model,alpha):l2_loss = torch.tensor(0.0, requires_grad=True)for name, param in model.named_parameters():if 'bias' not in name: #一般不對偏置項使用正則l2_loss = l2_loss + (0.5 * alpha * torch.sum(torch.pow(param, 2)))return l2_loss# L1正則化
def L1Loss(model,beta):l1_loss = torch.tensor(0.0, requires_grad=True)for name, param in model.named_parameters():if 'bias' not in name:l1_loss = l1_loss +  beta * torch.sum(torch.abs(param))return l1_loss
from torchkeras import KerasModel
from torchkeras.metrics import AUCnet = Net()# 將L2正則和L1正則添加到FocalLoss損失,一起作為目標函數
def focal_loss_with_regularization(y_pred,y_true):y_probs = torch.sigmoid(y_pred)focal = FocalLoss()(y_probs,y_true) l2_loss = L2Loss(net,0.001) #注意設置正則化項系數l1_loss = L1Loss(net,0.001)total_loss = focal + l2_loss + l1_lossreturn total_lossoptimizer = torch.optim.Adam(net.parameters(),lr = 0.002)
model = KerasModel(net=net,loss_fn = focal_loss_with_regularization ,metrics_dict = {"auc":AUC()},optimizer= optimizer )dfhistory = model.fit(train_data=dl_train,val_data=dl_val,epochs=20,ckpt_path='checkpoint',patience=3,monitor='val_auc',mode='max',plot=True,cpu=True)
[0;31m<<<<<< 🐌 cpu is used >>>>>>[0m
100% [20/20] [00:54]
████████████████████100.00% [21/21] [val_loss=0.0276, val_auc=0.9819]
# 結果可視化
fig, (ax1,ax2) = plt.subplots(nrows=1,ncols=2,figsize = (12,5))
ax1.scatter(Xp[:,0],Xp[:,1], c="r")
ax1.scatter(Xn[:,0],Xn[:,1],c = "g")
ax1.legend(["positive","negative"]);
ax1.set_title("y_true");Xp_pred = X[torch.squeeze(torch.sigmoid(net.forward(X))>=0.5)]
Xn_pred = X[torch.squeeze(torch.sigmoid(net.forward(X))<0.5)]ax2.scatter(Xp_pred[:,0],Xp_pred[:,1],c = "r")
ax2.scatter(Xn_pred[:,0],Xn_pred[:,1],c = "g")
ax2.legend(["positive","negative"]);
ax2.set_title("y_pred");

五,通過優化器實現L2正則化

如果僅僅需要使用L2正則化,那么也可以利用優化器的weight_decay參數來實現。

weight_decay參數可以設置參數在訓練過程中的衰減,這和L2正則化的作用效果等價。

before L2 regularization:gradient descent: w = w - lr * dloss_dw after L2 regularization:gradient descent: w = w - lr * (dloss_dw+beta*w) = (1-lr*beta)*w - lr*dloss_dwso (1-lr*beta)is the weight decay ratio.

Pytorch的優化器支持一種稱之為Per-parameter options的操作,就是對每一個參數進行特定的學習率,權重衰減率指定,以滿足更為細致的要求。

weight_params = [param for name, param in model.named_parameters() if "bias" not in name]
bias_params = [param for name, param in model.named_parameters() if "bias" in name]optimizer = torch.optim.SGD([{'params': weight_params, 'weight_decay':1e-5},{'params': bias_params, 'weight_decay':0}],lr=1e-2, momentum=0.9)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/43338.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/43338.shtml
英文地址,請注明出處:http://en.pswp.cn/web/43338.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Nginx -Web服務器/反向代理/負載均衡

文章目錄 一、web服務1.1 nginx安裝1.2 配置文件1.3 Nginx處理Web機制 二、反向代理三、負載均衡3.1 分類3.2 負載相關配置文件3.3 keepalive 提高吞吐量3.4 配置瀏覽器緩存 附、JMeter性能測試工具 以賽促學內容,大概率感覺會使用nginx做web服務,特對nginx做總結歸納. Nginx是…

(7.10)Java面向對象有關知識點思考

1、繼承中要關注如何訪問父類中的方法&#xff0c;其中有傳遞一個隱藏的形參this&#xff0c;及當前對象的地址&#xff0c;通過它調用方法沒有問題。 2、抽象時對繼承關系的一種優化&#xff1a; ①父類中的方法可以沒有方法體&#xff1b; ②子類必須按照規定重寫抽象方法…

【性能工程 - eBPF 技術】小白也能學會的 eBPF 技術——初步了解 eBPF 技術(一)

eBPF&#xff0c;即擴展的伯克利包過濾器&#xff08;Extended Berkeley Packet Filter&#xff09;&#xff0c;是從早期的BPF技術發展而來&#xff0c;起初用于高效地過濾網絡數據包。隨著時間的推移&#xff0c;eBPF已經成為一個強大的、靈活的內核技術&#xff0c;不僅限于…

echart5.5.1版本,倒三角柱狀圖

加載方法 initChart1(title, id, tag) {var myChart echarts5.init(this.$refs[id]);const _this this;var option {title:{text: title||"",show: title?true:false,top: 24,left: 24},grid:{left: 54,top: 74,bottom: 44,right: 30,},xAxis: {type: category,d…

【Spring成神之路】老兄,來一杯Spring AOP源碼嗎?

文章目錄 一、引言二、Spring AOP的使用三、Spring AOP的組件3.1 Pointcut源碼3.2 Advice源碼3.3 Advisor源碼3.4 Aspect源碼 四、Spring AOP源碼刨析4.1 configureAutoProxyCreator源碼解析4.2 parsePointcut源碼解析4.3 parseAdvisor源碼解析4.4 parseAspect源碼解析4.5 小總…

電腦缺少dll文件是怎么回事?教你5種有效的解決方法

當您的計算機顯示DLL文件已經遺失時&#xff0c;您應如何應對呢&#xff1f;實際上&#xff0c;針對此類DLL文件的處置過程相對來說較為簡易。今日&#xff0c;我們在此為大家詳細介紹此領域的相關知識&#xff0c;讓大家輕松解決電腦中因丟失DLL文件而產生的問題。 一、關于DL…

案例開發-日程管理-第一期

九 案例開發-日程管理-第一期 共7期 9.1 登錄頁及校驗 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><style>.ht{text-align: center;color: cadetblue;font-family: 幼…

MVC 生成驗證碼

在mvc 出現之前 生成驗證碼思路 在一個html頁面上&#xff0c;生成一個驗證碼&#xff0c;在把這個頁面嵌入到需要驗證碼的頁面中。 JS生成驗證碼 <script type"text/javascript">jQuery(function ($) {/**生成一個隨機數**/function randomNum(min, max) {…

Python占位符匯總

# f-string (重點掌握) 3.6版本之后才有的 name "杰倫" print(大家好&#xff0c;我是杰倫) print(大家好&#xff0c;我是, name, sep) # 可以但不推薦 name "杰倫" age 45 salary 1.4567 print(大家好&#xff0c;我是杰倫&#xff0c;我今年45&a…

《妃夢千年》第三十章:意外的來信

第三十章&#xff1a;意外的來信 林清婉在皇宮中的地位穩固后&#xff0c;生活似乎又回歸了平靜。然而&#xff0c;這種平靜并沒有持續多久。一天早晨&#xff0c;她收到了一個意外的來信&#xff0c;信封上沒有署名&#xff0c;但她一眼就認出了那熟悉的筆跡——這是她已故父…

RedHat Linux8 修改root管理員賬戶密碼命令

RedHat Linux8 修改root管理員賬戶密碼命令&#xff1a; sudo passwd root RedHat重置root管理員密碼&#xff1a; 1. 查看Linux系統版本信息 cat /etc/redhat-release2. 重置密碼 2.1 進入內核編輯界面 重啟Linux系統并出現引導界面&#xff0c;按下鍵盤上的e鍵進入內…

Prometheus+Grafana主機運行數據

目錄 介紹 安裝Node Exporter 配置Prometheus 驗證配置 導入儀表盤 介紹 Prometheus是一款開源的監控和警報工具&#xff0c;而Node Exporter是Prometheus的一個官方插件&#xff0c;用于采集主機上的各種系統和硬件指標。 安裝Node Exporter 下載最新版本的Node Export…

【AI大模型】ChatGPT-4 對比 ChatGPT-3.5:有哪些優勢

引言 ChatGPT4相比于ChatGPT3.5,有著諸多不可比擬的優勢&#xff0c;比如圖片生成、圖片內容解析、GPTS開發、更智能的語言理解能力等&#xff0c;但是在國內使用GPT4存在網絡及充值障礙等問題&#xff0c;如果您對ChatGPT4.0感興趣&#xff0c;可以私信博主為您解決賬號和環境…

FLinkCDC引起的生產事故(二)

背景&#xff1a; 最近在做實時數據的抽取工作&#xff0c;利用FLinkCDC實時抽取目標庫Oracle的數據到Doris中&#xff0c;但是在抽取的過程中&#xff0c;會導致目標庫的生產庫數據庫非常卡頓&#xff0c;為了避免對生產環境的數據庫造成影響&#xff0c;對生產環境的數據庫利…

谷歌優化的坑與甜:方法策略決定成敗,并非難易程度

對于谷歌優化&#xff0c;本人頗為惱火。眾所周知&#xff0c;我們開設網站旨在吸引眾多訪客&#xff0c;然谷歌這位傲慢的“高嶺之花”&#xff0c;卻令我們煞費苦心。有位友人為提升其網站排名&#xff0c;不惜耗盡心血&#xff0c;然而成效甚微&#xff0c;猶如坐過山車般起…

P3110 [USACO14DEC] Piggy Back S

題意 有一張 n n n 點 m m m 邊的無向圖&#xff0c;Alice 要從 1 1 1 走到 n n n&#xff0c;Bob 要從 2 2 2 走到 n n n。Alice 走一條邊需要花費 B B B&#xff0c;Bob 走一條邊需要花費 E E E&#xff0c;當他們一起走時&#xff0c;走一條邊需要花費 P P P。求他…

OpenJudge 奇數求和

目錄 描述思路樣例輸入樣例輸出CodeCC 總時間限制: 1000ms 內存限制: 65536kB 描述 計算非負整數 m 到 n&#xff08;包括m 和 n &#xff09;之間的所有奇數的和&#xff0c;其中&#xff0c;m 不大于 n&#xff0c;且n 不大于300。例如 m3, n12, 其和則為&#xff1a;357911…

qcom 平臺efuse機器抓取dump log的方法

引言&#xff1a; qcom 平臺機器&#xff0c;一旦efuse后機器將無法抓取dump log qcom 原文&#xff1a; efuse機器抓取dump log的方法如下&#xff1a; 一、修改配置文件&#xff1a; 把kamorta_debugpolicy.xml 在配置了debugpolicy&#xff08;加入串號和打開開關&#x…

怎么檢查SSL證書是否有效?

SSL證書的有效性對于保護網站數據安全和用戶隱私至關重要。然而&#xff0c;有時可能會出現證書過期、無效或被吊銷的情況。為了確保網站的安全性&#xff0c;對SSL證書的有效性進行檢查至關重要。本文將介紹幾種常用的方法來檢查SSL證書的有效性&#xff0c;幫助大家有效評估和…

Android Studio Download Gradle 時慢問題解決

1.騰訊gradle 下載&#xff1a;后面拼接版本&#xff08;gradle-8.0-bin.zip&#xff09; https://mirrors.cloud.tencent.com/gradle/gradle-8.0-bin.zip 2.Android Studio 配置&#xff1a;setting-->gradle-->Use Gradle from 選擇本地文件夾&#xff08;解壓后的bi…