常用的损失函数
pytorch的源码:torch.nn — PyTorch 1.11.0 documentationjittor的源码:jittor.nn — Jittor 1.3.2.6 文档 (tsinghua.edu.cn)目录一、回归损失函数1.1 MSE[均方误差Mean Square Error,二次损失Quadratic Loss,L2损失L2 Loss]1.2 MAE[平均绝对误差Mean Abs
pytorch的源码: torch.nn — PyTorch 1.11.0 documentation
jittor的源码:jittor.nn — Jittor 1.3.2.6 文档 (tsinghua.edu.cn)
paddle的实现:Paddle框架下常用损失函数总结和实现 - 飞桨AI Studio (baidu.com)
目录
1.1 MSE[均方误差Mean Square Error,二次损失Quadratic Loss,L2损失L2 Loss]
1.2 MAE[平均绝对误差Mean Absolute Error,L1损失L1 Loss]
1.4 Log-Cosh Loss[预测误差的双曲余弦的对数]
2.1 Cross Entropy Loss(CE)[Log Loss、交叉熵损失]
2.1.1 Binary Cross Entropy Loss
2.1.2 Binary Cross Entropy With Logits Loss
2.3 Relative Entropy [相对熵、KL散度(Kullback-Leibler divergence)]
一、回归损失函数
1.1 MSE[均方误差Mean Square Error,二次损失Quadratic Loss,L2损失L2 Loss]
调用
jittor.nn.MSELoss()
源码
class MSELoss(Module):
def __init__(self):
pass
def execute(self, output, target):
return mse_loss(output, target)
def mse_loss(output, target):
return (output-target).sqr().mean()
自定义实现如下
def mse(true, pred):
return np.sum((true - pred)**2)
损失范围为0至∞
如果离群点是会影响业务、而且是应该被检测到的异常值,那么我们应该使用MSE
1.2 MAE[平均绝对误差Mean Absolute Error,L1损失L1 Loss]
调用
jittor.nn.L1Loss()
源码
class L1Loss(Module):
def __init__(self):
pass
def execute(self, output, target):
return l1_loss(output, target)
def l1_loss(output, target):
return (output-target).abs().mean()
自定义实现
def mae(true, pred):
return np.sum(np.abs(true - pred))
损失范围也是0到∞
如果我们认为离群点仅仅代表数据损坏,那么我们应该选择MAE作为损失
1.3 Huber Loss[平滑的平均绝对误差]
调用
torch.nn.functional.huber_loss(input, target, reduction='mean', delta=1.0)
自定义实现如下
def huber(true, pred, delta):
loss = np.where(np.abs(true-pred) < delta , 0.5*((true-pred)**2), delta*np.abs(true -
pred) - 0.5*(delta**2))
return np.sum(loss)
当超参数(detail)趋近于0时,Huber Loss接近MAE,
当超参数(detail)趋近于∞时,Huber Loss接近MSE。
1.4 Log-Cosh Loss[预测误差的双曲余弦的对数]
log(cosh(x))对于小的x来说,其大约等于 (x ** 2) / 2,而对于大的x来说,其大约等于 abs(x) - log(2)。这意味着'logcosh'的作用大部分与均方误差一样。它具有Huber Loss的所有优点,和Huber Loss不同之处在于,其处处二次可导。
自定义实现
def logcosh(input, target):
loss = np.log(np.cosh(target - input))
return np.sum(loss)
1.5 Quantile Loss[分位数损失]
当我们有兴趣预测一个区间而不仅仅是预测一个点时,Quantile Loss函数就很有用。
所谓的0.9分位数回归,就是希望回归曲线之下能够包含90%的数据点(y),这也是分位数的概念,分位数回归是把分位数的概念融入到普通的线性回归而已。
调用
loss = quantile_loss(pred, gt, 0.5)
实现
import paddle.fluid as fluid
places = fluid.CPUPlace()
exe = fluid.Executor(places)
def quantile_loss(pred, label, gamma):
dist = fluid.layers.abs(pred - label)
cond = fluid.layers.greater_than(pred, label)
ie = fluid.layers.IfElse(cond)
with ie.true_block():
loss = ie.input(dist)
loss = (1 - gamma) * loss
ie.output(loss)
with ie.false_block():
loss = ie.input(dist)
loss = gamma * loss
ie.output(loss)
loss = ie()[0] # 返回的是一个list
loss = fluid.layers.reduce_mean(loss)
return loss
quantile_program = fluid.Program()
with fluid.program_guard(quantile_program):
pred = fluid.data('pred', shape=[4,1], dtype='float32')
gt = fluid.data('gt', shape=[4,1], dtype='float32')
loss = quantile_loss(pred, gt, 0.5)
二、分类损失函数
2.1 Cross Entropy Loss(CE)[Log Loss、交叉熵损失]
交叉熵主要是用来判定实际的输出与期望的输出的接近程度。
信息量:它是用来衡量一个事件的不确定性的;一个事件发生的概率越大,不确定性越小,则它所携带的信息量就越小。
熵:它是用来衡量一个系统的混乱程度的,代表一个系统中信息量的总和;信息量总和越大,表明这个系统不确定性就越大。
也叫Log Loss,两者等价,标签为{-1, 1}时为log loss, 标签为{0, 1}时为交叉熵。在做分类(具体几类)训练的时候是非常有用的。
调用
jittor.nn.CrossEntropyLoss(weight=None, ignore_index=None)
源码
class CrossEntropyLoss(Module):
def __init__(self, weight=None, ignore_index=None):
self.weight = weight
self.ignore_index = ignore_index
def execute(self, output, target):
return cross_entropy_loss(output, target, self.weight, self.ignore_index)
def cross_entropy_loss(output, target, weight=None, ignore_index=None,reduction='sum'):
if len(output.shape) == 4:
c_dim = output.shape[1]
output = output.transpose((0, 2, 3, 1))
output = output.reshape((-1, c_dim))
target = target.reshape((-1, ))
target_weight = jt.ones(target.shape[0], dtype='float32')
if weight is not None:
target_weight = weight[target]
if ignore_index is not None:
target_weight = jt.ternary(
target==ignore_index,
jt.array(0).broadcast(target_weight),
target_weight
)
target = target.broadcast(output, [1])
target = target.index(1) == target
output = output - output.max([1], keepdims=True)
logsum = output.exp().sum(1).log()
loss = (logsum - (output*target).sum(1)) * target_weight
if reduction == 'sum':
return loss.sum() / target_weight.sum()
elif reduction == 'mean':
return loss.mean() / target_weight.mean()
else:
return loss / target_weight
2.1.1 Binary Cross Entropy Loss
可视化理解Binary Cross-Entropy - 知乎 (zhihu.com)
调用
jittor.nn.BCELoss(weight=None, size_average=True)
源码
class BCELoss(Module):
def __init__(self, weight=None, size_average=True):
self.weight = weight
self.size_average = size_average
def execute(self, output, target):
return bce_loss(output, target, self.weight, self.size_average)
def bce_loss(output, target, weight=None, size_average=True):
loss = - (target * jt.log(jt.maximum(output, 1e-20)) + (1 - target) *
jt.log(jt.maximum(1 - output, 1e-20)))
if weight is not None:
loss *= weight
if size_average:
return loss.mean()
else:
return loss.sum()
2.1.2 Binary Cross Entropy With Logits Loss
有一个(类)损失函数名字中带了with_logits. 而这里的logits指的是,该损失函数已经内部自带了计算logit的操作,无需在传入给这个loss函数之前手动使用sigmoid/softmax将之前网络的输入映射到[0,1]之间
调用
jittor.nn.BCEWithLogitsLoss(weight=None, pos_weight=None, size_average=True)
torch.nn.BCEWithLogitsLoss(weight=None, size_average=None, reduce=None, reduction='mean',
pos_weight=None)
源码
class BCEWithLogitsLoss(Module):
def __init__(self, weight=None, pos_weight=None, size_average=True):
self.pos_weight = pos_weight
self.weight = weight
self.size_average = size_average
def execute(self, output, target):
return binary_cross_entropy_with_logits(output,target,
self.weight,
self.pos_weight,
self.size_average)
def binary_cross_entropy_with_logits(output, target, weight=None, pos_weight=None,
size_average=True):
# 将输入input张量每个元素的夹紧到区间 [min,max][min,max],并返回结果到一个新张量
# x = x.maximum(min_v)
max_val = jt.clamp(-output,min_v=0)
if pos_weight is not None:
log_weight = (pos_weight-1)*target + 1
loss = (1-target)*output+(log_weight*(((-max_val).exp()+(-output -
max_val).exp()).log()+max_val))
else:
loss = (1-target)*output+max_val+((-max_val).exp()+(-output -max_val).exp()).log()
if weight is not None:
loss *=weight
if size_average:
return loss.mean()
else:
return loss.sum()
实例
loss = nn.BCEWithLogitsLoss()
input = torch.randn(3, requires_grad=True)
target = torch.empty(3).random_(2)
output = loss(input, target)
output.backward()
2.2 Focal Loss
Focal loss的思路就是给损失加上权值,使当模型对样本的判断错误时,损失的权重更大,从而增加”困难样本“对模型的影响
#二分类情况:分别计算y_true为1处和y_true为0处的损失,相加
from keras import backend as K
def focal_loss(gamma=2., alpha=0.25):
def focal_loss_fixed(y_true, y_pred):
pt_1 = tf.where(tf.equal(y_true, 1), y_pred, tf.ones_like(y_pred))
pt_0 = tf.where(tf.equal(y_true, 0), y_pred, tf.zeros_like(y_pred))
return -K.sum(alpha * K.pow(1. - pt_1, gamma) * K.log(pt_1))-K.sum((1-alpha) * K.pow( pt_0, gamma) * K.log(1. - pt_0))
return focal_loss_fixed
#多分类情况:计算y_true为1处的损失(不考虑y_true为0处的y_pred值)
from keras import backend as K
def focal_loss(gamma=2.):
def focal_loss_fixed(y_true, y_pred):
pt_1 = tf.where(tf.equal(y_true, 1), y_pred, tf.ones_like(y_pred))
return -K.sum( K.pow(1. - pt_1, gamma) * K.log(pt_1))
return focal_loss_fixed
2.3 Relative Entropy [相对熵、KL散度(Kullback-Leibler divergence)]
信息熵代表的是随机变量或整个系统的不确定性,熵越大,随机变量或系统的不确定性就越大。根据真实分布,我们能够找到一个最优策略,以最小的代价消除系统的不确定性,而这个代价大小就是信息熵,记住,信息熵衡量了系统的不确定性,而我们要消除这个不确定性,所要付出的【最小努力】(猜题次数、编码长度等)的大小就是信息熵。
交叉熵,其用来衡量在给定的真实分布下,使用非真实分布所指定的策略消除系统的不确定性所需要付出的努力的大小。交叉熵越低,这个策略就越好,最低的交叉熵也就是使用了真实分布所计算出来的信息熵。因为此时交叉熵 = 信息熵。这也是为什么在机器学习中的分类算法中,我们总是最小化交叉熵,因为交叉熵越低,就证明由算法所产生的策略最接近最优策略,也间接证明我们算法所算出的非真实分布越接近真实分布。
相对熵,其用来衡量两个取值为正的函数或概率分布之间的差异。现在,假设我们想知道某个策略和最优策略之间的差异,我们就可以用相对熵来衡量这两者之间的差异。即,相对熵 = 某个策略的交叉熵 - 信息熵(根据系统真实分布计算而得的信息熵,为最优策略)。
调用
torch.nn.KLDivLoss(size_average=None, reduce=None, reduction='mean', log_target=False)
torch.nn.functional.kl_div(input, target, size_average=None, reduce=None, reduction='mean',
log_target=False)
实例
kl_loss = nn.KLDivLoss(reduction="batchmean")
# 输入应该是对数空间中的分布
input = F.log_softmax(torch.randn(3, 5, requires_grad=True))
# 对一批分布进行抽样。 通常这将来自数据集
target = F.softmax(torch.rand(3, 5))
output = kl_loss(input, target)
log_target = F.log_softmax(torch.rand(3, 5))
output = kl_loss(input, log_target, log_target=True)
2.4 Exponential Loss [指数损失]
对离群点、噪声非常敏感。主要用于 Adaboost 集成学习 算法,它是前向分步加法算法的特例,是一个加和模型。
指数损失是0-1损失函数的一种代理函数。
代码实现还未找到(待更新)。
2.5 Hinge Loss [铰链损失、合页损失]
在机器学习中常用于"最大间隔(maximum-margin)"的分类任务中,如支持向量机SVM。尽管不可微,但它是一个凸函数,因此可以轻而易举地使用机器学习领域中常用的凸优化器。
对于当前的一组分数,对应于不同的类别,我们希望属于真实类别的那个分数比其他的类别的分数要高,并且最好要高出一个margin,这样才是安全的。反映在这个函数中,就是0的那一项的取值范围,Syi表示的是xi样本的真实类别所得到的分数,而Sj指的是其他的类别的分数,如果真实类别的分数是最大的,且大一个margin 1,那么就表示满意,也就是说不惩罚,这一项的loss为0。如果不满足这一条件,我们用下面的一段,也就是Sj - Syi + 1, 1在这里是一个常数,可以使得函数连续起来,这个Sj - Syi表示,Syi,也就是真实样本的分数比别的少的越多,我们越不满意。
代码实现:kazuto1011/svm-pytorch: Linear SVM with PyTorch (github.com)
代码实现
output = model(x).squeeze()
weight = model.weight.squeeze()
loss = torch.mean(torch.clamp(1 - y * output, min=0))
loss += args.c * (weight.t() @ weight) / 2.0
更多推荐
所有评论(0)