loss函数之PoissonNLLLoss,GaussianNLLLoss

PoissonNLLLoss

真实标签服从泊松分布的负对数似然损失,神经网络的输出作为泊松分布的参数 λ \lambda λ

泊松分布是一种离散分布,概率计算如下:

P ( Y = k ) = λ k k ! e − λ P(Y=k)=\frac{\lambda^{k}}{k !} e^{-\lambda} P(Y=k)=k!λkeλ

对于包含 N N N个样本的batch数据 D ( x , y ) D(x, y) D(x,y) y y y是样本对应的类别标签,服从泊松分布。 x x x y y y的维度相同。

(1)若 x x x是神经网络的输出,且未进行归一化和对数化处理。第 n n n个样本对应的损失 l n l_{n} ln 为:

由泊松分布的公式得到: P ( Y = y n ) = x n y n y n ! e − x n P(Y=y_{n})=\frac{x_{n}^{y_{n}}}{y_{n}!} e^{-x_{n}} P(Y=yn)=yn!xnynexn
l n = − l o g P ( Y = y n ) = x n − y n l o g x n + l o g ( y n ! ) l_{n}=-logP(Y=y_{n}) =x_{n}-y_{n}logx_{n}+ log(y_{n}!) ln=logP(Y=yn)=xnynlogxn+log(yn!)

(2)若 x x x 是神经网络的输出,进行了归一化和对数化处理。第 n n n个样本对应的损失 l n l_{n} ln 为:

将(1) 公式中的 x n x_{n} xn 替换为 e x p ( x n ) exp(x_{n}) exp(xn) l o g x n logx_{n} logxn替换为 x n x_{n} xn
l n = − l o g P ( Y = y n ) = e x p ( x n ) − y n x n + l o g ( y n ! ) l_{n}=-logP(Y=y_{n}) =exp(x_{n}) -y_{n}x_{n}+ log(y_{n}!) ln=logP(Y=yn)=exp(xn)ynxn+log(yn!)

最后一项 l o g ( y n ! ) log(y_{n}!) log(yn!)可以省略或者用斯特林公式(Stirling’s formula)近似。

一个样本可能对应多个输出,每个输出都服从泊松分布,有自己的泊松分布参数。因此, l n l_{n} ln可能是一个值,也可能是一个向量。

class PoissonNLLLoss(_Loss):
    __constants__ = ['log_input', 'full', 'eps', 'reduction']
    def __init__(self, log_input=True, full=False, size_average=None,
                 eps=1e-8, reduce=None, reduction='mean'):
        super(PoissonNLLLoss, self).__init__(size_average, reduce, reduction)
        self.log_input = log_input
        self.full = full
        self.eps = eps
    def forward(self, log_input, target):
        return F.poisson_nll_loss(log_input, target, log_input=self.log_input, full=self.full,
                                  eps=self.eps, reduction=self.reduction)

pytorch中通过torch.nn.PoissonNLLLoss类实现,也可以直接调用F.poisson_nll_loss 函数,代码中的size_averagereduce已经弃用。reduction有三种取值mean, sum, none,对应不同的返回 ℓ ( x , y ) \ell(x, y) (x,y)。 默认为mean,对应于一般情况下 l o s s loss loss的计算

L = { l 1 , … , l N } L=\left\{l_{1}, \ldots, l_{N}\right\} L={l1,,lN}

ℓ ( x , y ) = { L ⁡ ,  if reduction  =  ’none’  mean ⁡ ( L ) ,  if reduction  =  ’mean’  sum ⁡ ( L ) ,  if reduction  =  ’sum’  \ell(x, y)=\left\{\begin{array}{ll}\operatorname L, & \text { if reduction }=\text { 'none' } \\ \operatorname{mean}(L), & \text { if reduction }=\text { 'mean' } \\ \operatorname{sum}(L), & \text { if reduction }=\text { 'sum' }\end{array} \right. (x,y)=L,mean(L),sum(L), if reduction = ’none’  if reduction = ’mean’  if reduction = ’sum’ 

log_input 对应与输入是否进行对数化。

full表示loss计算是否保留 l o g ( y n ! ) log(y_{n}!) log(yn!)。 如果保留使用

  • y n ≤ 1 y_{n}\leq 1 yn1 l o g ( y n ! ) log(y_{n}!) log(yn!) 近似为0。
  • y n > 1 y_{n}>1 yn>1,使用斯特林公式(Stirling’s formula), l o g ( y n ! ) log(y_{n}!) log(yn!) 近似为 y n ∗ l o g ( y n ) − y n + 0.5 ∗ l o g ( 2 π y n ) . y_{n}∗log(y_{n})−y_{n}+0.5∗log(2\pi y_{n}). ynlog(yn)yn+0.5log(2πyn).

eps是为了防止 x n = = 0 x_{n}==0 xn==0时, l o g x n logx_{n} logxn计算出错

代码示例:

import torch
import torch.nn as nn
import math


def validate_loss(output, target, flag, full, eps=1e-08):
    val = 0
    for li_x, li_y in zip(output, target):
        for i, xy in enumerate(zip(li_x, li_y)):
            x, y = xy
            if flag:
                loss_val = math.exp(x) - y * x
                if full:
                    if y <= 1:
                        loss_val = math.exp(x) - y * x + 0
                    else:
                        loss_val = math.exp(x) - y * x + \
                                   y * math.log(y) - y + 0.5 * math.log(2 * math.pi * y)
            else:
                loss_val = x - y * math.log(x + eps)
                if full:
                    if y <= 1:
                        loss_val = x - y * math.log(x + eps) + 0
                    else:
                        loss_val = x - y * math.log(x + eps) + \
                                   y * math.log(y) - y + 0.5 * math.log(2 * math.pi * y)
            val += loss_val
    return val / output.nelement()


log_input = True
full = True
loss = nn.PoissonNLLLoss(log_input=log_input, full=full)
input_src = torch.Tensor([[0.8, 0.9, 0.3],
                          [0.8, 0.9, 0.3],
                          [0.8, 0.9, 0.3],
                          [0.8, 0.9, 0.3]])
target = torch.Tensor([[1, 3, 5], [1, 0, 6], [1, 4, 5], [1, 1, 7]])
print(input_src.size())
print(target.size())
output = loss(input_src, target)
print(output.item())
# 验证
validateloss = validate_loss(input_src, target, log_input, full)
print(validateloss.item())
# none
loss = nn.PoissonNLLLoss(log_input=log_input, full=full, reduction="none")
output = loss(input_src, target)
print(output)

结果输出:

torch.Size([4, 3])
torch.Size([4, 3])
3.0318071842193604
3.0318076610565186
tensor([[1.4255, 1.5237, 4.6207],
        [1.4255, 2.4596, 6.1152],
        [1.4255, 2.0169, 4.6207],
        [1.4255, 1.5596, 7.7631]])

GaussianNLLLoss

真实标签服从高斯分布的负对数似然损失,神经网络的输出作为高斯分布的均值和方差。

对于包含 N N N个样本的batch数据 D ( x , v a r , y ) D(x, var, y) D(x,var,y) x x x神经网络的输出,作为高斯分布的均值, v a r var var神经网络的输出,作为高斯分布的方差, y y y是样本对应的标签,服从高斯分布。 x x x y y y的维度相同, v a r var var x x x的维度相同,或者最后一个维度不同且最后一个维度为1,可以进行broadcast。

服从高斯分布的标签对应的概率是积分的形式(不懂如何推导,望指教)。 这里仅仅给出结论,具体可参考论文Estimating the mean and variance of the target probability distribution

n n n个样本对应的损失 l n l_{n} ln 为:

l n = 0.5 ∗ ( l o g ( m a x ( v a r n , e p s ) ) + ( x n − y n ) m a x ( v a r n , e p s ) ) l_{n}=0.5*\left(log(max(var_{n},eps)) + \frac{(x_{n}-y_{n})}{max(var_{n},eps)}\right) ln=0.5(log(max(varn,eps))+max(varn,eps)(xnyn))

e p s eps eps是为了防止 v a r n var_{n} varn为0

代码示例:

import torch
import torch.nn.functional as F
import torch.nn as nn
import math

torch.manual_seed(20)
loss = nn.GaussianNLLLoss(reduction='mean')
input = torch.randn(5, 2, requires_grad=True)
# 高斯分布的均值,神经网络输出
var = torch.ones(5, 2, requires_grad=True)  # 序列中标签对应的方差不同
# 高斯分布的方差,神经网络的输出
target = torch.randn(5, 2)
output = loss(input, target, var)
print(output.item())

var = torch.ones(5, 1, requires_grad=True)  # 序列中标签对应的方差相同
output = loss(input, target, var)
print(output.item())

var = torch.ones(5, requires_grad=True)  # 序列中标签对应的方差相同
output = loss(input, target, var)
print(output.item())

loss = nn.GaussianNLLLoss(reduction='none')
var = torch.ones(5, requires_grad=True)  # 序列中标签对应的方差相同
output = loss(input, target, var)
print(output)

结果输出:

2.7238247394561768
2.7238247394561768
2.7238247394561768
tensor([1.5049, 2.6215, 1.1505, 6.3066, 2.0357], grad_fn=<MulBackward0>)
val_loss函数是指用于评估模型在验证集上的损失函数。在机器学习中,我们通常将数据集划分为训练集和验证集,用训练集训练模型,然后用验证集验证模型的性能。val_loss函数被用来衡量模型预测结果与验证集标签之间的差异程度。 val_loss函数的代码实现通常与模型训练过程中的损失函数的代码实现类似。在训练过程中,模型会根据训练集的输入和标签生成预测结果,并计算与标签之间的差异,即损失值。同样地,在验证过程中,模型会根据验证集的输入生成预测结果,并计算与验证集的标签之间的差异,这就是val_loss函数的计算方式。 具体的val_loss函数的代码实现可能会根据具体的机器学习框架和任务而有所不同。一般来说,val_loss函数的计算会涉及到模型的预测结果和验证集标签的对比,计算它们之间的差异,并根据差异的大小来评估模型在验证集上的性能。 val_loss函数的数值越小,表示模型在验证集上的性能越好。在训练过程中,我们通常会监控val_loss函数的数值变化,以判断模型是否出现过拟合或欠拟合的情况。如果val_loss函数的数值一直在下降,说明模型在训练过程中在验证集上的表现一直在改善。如果val_loss函数的数值开始上升,说明模型可能已经开始过拟合了,需要调整模型的复杂度或者调整其他超参数。 总之,val_loss函数是用于评估模型在验证集上的损失函数,通过计算模型预测结果与验证集标签之间的差异来评估模型在验证集上的性能。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

旺旺棒棒冰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值