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^)=−N1i=0∑N−1(yilogyi^+(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=0∏N−1yi^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=0∑N−1yilnyi^+(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^)=−N1i=0∑N−1k=0∑K−1I(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^)=−N1i=0∑N−1log(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^)=−N1i=0∑N−1zi[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=0∑K−1pkln(qkpk)=k=0∑K−1pk(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^)=−N1i=0∑N−1(yilogyi^+(1−yi)log(1−yi^))+N1i=0∑N−1(yilogyi+(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.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)
相关文章:
5-3.损失函数
文章最前: 我是Octopus,这个名字来源于我的中文名–章鱼;我热爱编程、热爱算法、热爱开源。所有源码在我的个人github ;这博客是记录我学习的点点滴滴,如果您对 Python、Java、AI、算法有兴趣,可以关注我的…...
SCSA第四天
ASPF FTP --- 文件传输协议 Tftp --- 简单文件传输协议 FTP协议相较于Tftp协议 ---- 1,需要进行认证 2,拥有一套完整的命令集 用户认证 防火墙管理员认证 ---- 校验登录者身份合法性 用户认证 --- 上网行为管理中的一环 上网用户认证 --- 三层认证…...
品牌策划必读:9本改变游戏规则的营销经典
作为深耕品牌十余年的策划人,这些年自学啃下的书不计其数。 这里特意挑选了几本知名度不高但是却非常有用的“遗珠”优质品牌策划书籍分享出来。 如果你是一位初步了解品牌的人,这些书籍既包含了品牌理论基础,也有实用的实践指导。 这些书…...
泛型
背景 优点 类型绝对安全避免强制类型转换 泛型类 定义 使用 举例 泛型类 // 泛型类 T就是类型参数 public class Generic<T>{// key这个成员变量的类型为T,T的类型由外部指定private T t;public void set(T t){this.t t;}public T get(){return t;} }使用 // 创建一个泛…...
react动态渲染列表与函数式组件
1.如何使用jsx语法动态渲染列表呢,下边我用一个例子来切实总结一下 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scal…...
小程序内容管理系统设计
设计一个小程序内容管理系统(CMS)时,需要考虑以下几个关键方面来确保其功能完善、用户友好且高效: 1. 需求分析 目标用户:明确你的目标用户群体,比如企业、媒体、个人博主等,这将决定系统的功…...
HDFS 块重构和RedundancyMonitor详解
文章目录 1. 前言2 故障块的重构(Reconstruct)2.1 故障块的状态定义和各个状态的统计信息2.2 故障文件块的查找收集2.5.2.1 misReplica的检测2.5.2.2 延迟队列(postponedMisreplicatedBlocks)的构造和实现postponedMisreplicatedBlocks中Block的添加postponedMisreplicatedBloc…...
Power BI DAX常用函数使用场景和代码示例
Power BI函数表达式对于没有接触过的朋友可能会有些迷茫,花一点时间了解一下原理在学习一些常用的DAX函数,就可以解决工作中绝大部分问题,函数使用都是共同的。 以下是一些最常用的DAX函数,如聚合,计数,日期…...
机器学习与深度学习:区别与联系(含工作站硬件推荐)
一、机器学习与深度学习区别 机器学习(ML:Machine Learning)与深度学习(DL:Deep Learning)是人工智能(AI)领域内两个重要但不同的技术。它们在定义、数据依赖性以及硬件依赖性等方面…...
大模型/NLP/算法面试题总结5——Transformer和Rnn的区别
Transformer 和 RNN(循环神经网络)是两种常见的深度学习模型,广泛用于自然语言处理(NLP)任务。 它们在结构、训练方式以及处理数据的能力等方面有显著的区别。以下是它们的主要区别: 架构 RNN࿰…...
【RHCE】转发服务器实验
1.在本地主机上操作 2.在客户端操作设置主机的IP地址为dns 3.测试,客户机是否能ping通...
AI提示词:打造爆款标题生成器
打开GPT输入以下内容: # Role 爆款标题生成器## Profile - author: 姜小尘 - version: 02 - LLM: Kimi - language: 中文 - description: 利用心理学和市场趋势,生成吸引眼球的自媒体文章标题。## Background 一个吸引人的标题是提升文章点击率和传播力…...
skywalking-1-服务端安装
skywalking很优秀。 安装服务端 skywalking的服务端主要是aop服务,为了方便查看使用还需要安装ui。另外采集的数据我们肯定要存起来,这个数据库就直接用官方的banyandb。也就是aop、ui、banyandb都使用官方包。 我们的目的是快速使用和体验,…...
查看oracle ojdbc所支持的JDBC驱动版本
oracle jcbc驱动的下载地址参考:JDBC and UCP Downloads page 其实上文中对ojdbc所支持的JDBC驱动版本已经有说明了,不过,因为oracle的驱动包很多时间,都是在公司内部私服里上传维护的,上传的时候,可能又没…...
自媒体运营怎样引流客源?
不管是企业还是个人,越来越多都在做自媒体引流运营,那有什么引流客源的方式呢? 高质量内容:创作并分享有价值的内容,吸引目标受众,提升内容的分享和传播效果。 SEO优化:优化文章标题、关键词和…...
【算法】十进制转换为二进制
目的:将十进制转换为二进制 思路: 首先我们手算的情况是通过求余数算出进制数,同样代码也是通过做除法和求余数的方式,除法是得出下一次的被除数,而求余数是得到进制数 代码: #include<stdio.h>/…...
Postman中的API安全堡垒:全面安全性测试指南
🛡️ Postman中的API安全堡垒:全面安全性测试指南 在当今的数字化世界中,API安全性是保护数据和系统不可或缺的一环。Postman作为API开发和测试的领先工具,提供了多种功能来帮助开发者进行API安全性测试。本文将深入探讨如何在Po…...
学圣学最终的目的是:达到思无邪的状态( 纯粹、思想纯正、积极向上 )
学圣学最终的目的是:达到思无邪的状态( 纯粹、思想纯正、积极向上 ) 中华民族,一直以来,教学都是以追随圣学为目标,所以中华文化也叫圣学文化,是最高深的上等学问; 圣人那颗心根本…...
JS进阶-构造函数
学习目标: 掌握构造函数 学习内容: 构造函数 构造函数: 封装是面向对象思想中比较重要的一部分,js面向对象可以通过构造函数实现的封装。 同样的将变量和函数组合到了一起并能通过this实现数据的共享,所不同的是借助…...
使用Spring Boot和Couchbase实现NoSQL数据库
使用Spring Boot和Couchbase实现NoSQL数据库 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿! 一、引言 NoSQL数据库越来越受到开发者的欢迎,特别是…...
【数据库】Redis主从复制、哨兵模式、集群
目录 一、Redis的主从复制 1.1 主从复制的架构 1.2 主从复制的作用 1.3 注意事项 1.4 主从复制用到的命令 1.5 主从复制流程 1.6 主从复制实现 1.7 结束主从复制 1.8 主从复制优化配置 二、哨兵模式 2.1 哨兵模式原理 2.2 哨兵的三个定时任务 2.3 哨兵的结构 2.4 哨…...
C基础day8
一、思维导图 二、课后习题 #include<myhead.h> #define Max_Stu 100 //函数声明 //学生信息录入函数 void Enter_stu(int *Num_Stu,char Stu_name[][50],int Stu_score[]); //查看学生信息 void Print_stu(int Num_Stu,char Stu_name[][50],int Stu_score[]); //求出成绩…...
【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 小总…...
轻松理解c++17的string_view
文章目录 轻松理解c17的string_view设计初衷常见用法构造 std::string_view常用操作作为函数参数 注意事项总结 轻松理解c17的string_view std::string_view 是 C17 引入的一个轻量级、不拥有(non-owning)的字符串视图类。它的设计初衷是提供一种高效、…...
【机器学习理论基础】回归模型定义和分类
定义 回归分析是研究自变量与因变量之间数量变化关系的一种分析方法,它主要是通过因变量 Y Y Y与影响它的自变量 X i X_i Xi 之间的回归模型,衡量自变量 X i X_i Xi 对因变量 Y Y Y 的影响能力的,进而可以用来预测因变量Y的发展趋势。…...
探讨4层代理和7层代理行为以及如何获取真实客户端IP
准备工作 实验环境 IP角色192.168.1.100客户端请求IP192.168.1.100python 启动的HTTP服务192.168.1.102nginx服务192.168.1.103haproxy 服务 HTTP服务 这是一个简单的HTTP服务,主要打印HTTP报文用于分析客户端IP #!/usr/bin/env python # coding: utf-8import …...
java算法day11
二叉树的递归遍历二叉树的非递归遍历写法层序遍历 递归怎么写? 按照三要素可以保证写出正确的递归算法: 1.确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且…...
linux下安装cutecom串口助手;centos安装cutecom串口助手;rpm安装包安装cutecom串口助手
在支持apt-get的系统下安装 在终端命令行中输入: sudo apt-get install cutecom 安装好后输入 sudo cutecom 就可以了 关于如何使用,可以看这个https://www.cnblogs.com/xingboy/p/14388610.html 如果你的电脑不支持apt-get。 那我们就通过安装包…...
2024年信息系统项目管理师2批次上午客观题参考答案及解析(1)
1、关于收集需求管理过程及相关技术的描述,正确的是() A.需求跟踪矩阵是把产品需求从其来源链接到能满足需求的可交付成果的一种表格 B.原型法是一种结构化的头脑风暴形式,通过投票排列最有用的创意 C&am…...
Xinstall揭秘:APP推广数据背后的真相,让你的营销更精准!
在这个移动互联网时代,APP如同雨后春笋般涌现,但如何在这片红海中脱颖而出,成为每一个开发者与运营者面临的共同难题。其中,APP推广统计作为衡量营销效果、优化推广策略的关键环节,更是不可忽视的一环。今天࿰…...
阳信网站建设/徐州新站百度快照优化
每天分享一个sql,帮助大家找到sql的快乐 hive sql系列(总结)介绍 hive sql系列主打sql,通过案例,从实现到分析,帮助大家找到写sql的快乐 hive sql系列目录 1. hive sql系列(一)&a…...
阿里云部署一个自己做的网站/菏泽seo
http://www.bootcss.com/p/chart.js/docs/...
东莞凤岗网站建设制作/快照关键词优化
浙大版《Python 程序设计》题目集 第2章-14 求整数段和 (15分) 给定两个整数A和B,输出从A到B的所有整数以及这些数的和。 输入格式: 输入在一行中给出2个整数A和B,其中−100≤A≤B≤100,其间以空格分隔。 输出格式:…...
vps做网站/网络营销的优势
绍过了SOAP,让我们关注Web Service中另外一个重要的组成WSDL。 WSDL的主要文档元素 WSDL文档可以分为两部分。顶部分由抽象定义组成,而底部分则由具体描述组成。抽象部分以独立于平台和语言的方式定义SOAP消息,它们并不包含任何随机器或语言而…...
某宝购买的wordpress/网络服务器价格
1. 继承关系 java.lang.Object |____android.os.Looper 2. 类概要 这个类被用来给线程返回一个消息循环。默认情况下,没有跟线程相关联的消息循环;在线程中调用prepare()方法会运行这个循环,并且loop()方法会一直处理消息,直到循…...
济南网站排名推广/企业营销
前言: 在前两篇的文章中,我们学会了给组件添加属性、事件,以及对这些属性和事件进行描述添加,今天,我们就来小试一把这个组件吧,如果你忘记了前两篇文章的内容,可以从这里回顾一下: …...