文章目录
- 基础概念
- PyTorch实现与机制
-
- nn.CrossEntropyLoss
- nn.NLLLoss()
- nn.BCELoss()
- nn.BCEWithLogitsLoss()
- nn.L1Loss()
- nn.MSELoss()
- nn.SmoothL1Loss()
- nn.PoissonNLLLoss()
- nn.KLDivLoss()
- nn.MarginRankingLoss()
- nn.MultiLabelMarginLoss()
- nn.SoftMarginLoss()
- nn.MultiLabelSoftMarginLoss()
- nn.MultiMarginLoss()
- nn.TripletMarginLoss()
- nn.HingeEmbeddingLoss()
- nn.CosineEmbeddingLoss()
- nn.CTCLoss()
该篇笔记整理自余庭嵩的讲解。如果主要看损失函数如何使用则先看交叉熵损失函数的使用部分,该部分对损失函数pytorch实现时的各变量解释详细,并且其他损失函数的reduction变量与其大同小异,在这些部分里就不再重新说明reduction变量了。
基础概念
损失函数就是衡量模型输出与真实标签之间的差异。除损失函数外,平常接触到似乎也包含类似功能的还有代价函数和目标函数。那么这三者之间的区别和联系是什么呢?
损失函数(Loss Function)
功能:计算一个样本输出和真实标签之间的差异,表达式如下
Loss = f ( y ^ , y ) \text {Loss}=f\left(\hat y, y\right) Loss=f(y^,y)
代价函数(Cost Function)
功能:计算整个训练集的loss的平均值,表达式如下
c o s t = 1 N ∑ i N f ( y ^ i , y i ) \rm{cost}=\frac{1}{N} \sum_{i}^{N} f\left(\hat y_{i}, y_{i}\right) cost=N1i∑Nf(y^i,yi)
目标函数(Objective Function)
定义:在机器学习中代表最终的训练目标,表达式如下
O b j = c o s t + r e g u l a r i z a t i o n Obj = cost+regularization Obj=cost+regularization
这里的regularization代表正则化。
PyTorch实现与机制
在定义损失函数的时候,经常可以看到首先会对损失函数的计算规则进行定义,以交叉熵损失函数为例,定义语句如下:
criterion = torch.nn.CrossEntropyLoss()
执行这句话的时候,就可以看到,其实所有损失函数都会继承一个父类,这个父类的名称是_Loss,其内容如下:
class _Loss(Module):
def __init__(self, size_average=None, reduce=None, reduction='mean'):
super(_Loss, self).__init__()
if size_average is not None or reduce is not None:
self.reduction = _Reduction.legacy_get_string(size_average, reduce)
else:
self.reduction = reduction
定义完成之后,就是执行部分了,还是以交叉熵损失为例,执行的语句如下:
loss = criterion(outputs, labels)
这句话本质上也是属于前向传播的一部分,同样也是会执行torch.nn.Module的forward函数。forward函数内容如下:
def forward(self, input, target):
return F.cross_entropy(input, target, weight=self.weight,
ignore_index=self.ignore_index, reduction=self.reduction)
而forward函数的核心是调用了torch.nn.functional里定义的函数cross_entropy,这个函数的内容如下:
if size_average is not None or reduce is not None:
reduction = _Reduction.legacy_get_string(size_average, reduce)
return nll_loss(log_softmax(input, 1), target, weight, None, ignore_index, None, reduction)
于是我们就可以通过这样的调用关系清楚了解到损失函数的功能与运行机制。
nn.CrossEntropyLoss
功能与使用
由前面pytorch实现机制中的介绍可以看到,交叉熵函数是nn.Logsoftmax()与nn.NLLLoss()结合,进行交叉熵计算。这里的nn.Logsoftmax()函数将输入的数据进行了归一化处理,变成了概率分布的形式,再取log后进行输出。而nn.NLLLoss()则是取负号操作。整个过程的数学表达式如下,无weight时:
loss ( x , class ) = − log ( exp ( x [ class ] ) ∑ j exp ( x [ j ] ) ) = − x [ class ] + log ( ∑ j exp ( x [ j ] ) ) \operatorname{loss}(x, \text { class })=-\log \left(\frac{\exp (x[\text { class }])}{\sum_{j} \exp (x[j])}\right)=-x[\text { class }]+\log \left(\sum_{j} \exp (x[j])\right) loss(x, class )=−log(∑jexp(x[j])exp(x[ class ]))=−x[ class ]+log(j∑exp(x[j]))
有weight时:
loss ( x , class ) = weight [ class ] ( − x [ class ] + log ( ∑ j exp ( x [ j ] ) ) ) \operatorname{loss}(x, \text { class })=\text { weight }[\text { class }]\left(-x[\text { class }]+\log \left(\sum_{j} \exp (x[j])\right)\right) loss(x, class )= weight [ class ](−x[ class ]+log(j∑exp(x[j])))
在使用CrossEntropyLoss函数时,其主要参数有
- weight:各类别的loss设置权值(例如某类计算好loss后再乘1.5倍)
- ignore_ index:忽略某个类别(在某类不计算loss)
- reduction :计算模式,可为none/sum/mean
- size_average&reduce:不管,现在这两个变量用reduction就可以替代其作用了
其中
none代表逐个元素计算
sum代表所有元素求和,返回标量
mean代表加权平均,返回标量
reduction需要以字符串的的形式赋值上面三个字符串中的任意一个。
数学原理
如果需要了解交叉熵,首先需要了解信息熵以及相对熵的概念。
信息熵
先来解释信息熵的概念,信息熵由香农提出,从热力学领域借鉴而来,其主要衡量了信息的不确定程度,一个信息的熵越大说明越不确定。其表达式如下:
H ( P ) = E x ∼ p [ I ( x ) ] = − ∑ i N P ( x i ) log P ( x i ) \mathbf{H}(\mathbf{P})=\boldsymbol{E}_{\boldsymbol{x} \sim \boldsymbol{p}}[\boldsymbol{I}(\boldsymbol{x})]=-\sum_{\boldsymbol{i}}^{\boldsymbol{N}} \boldsymbol{P}\left(\boldsymbol{x}_{\boldsymbol{i}}\right) \log \boldsymbol{P}\left(\boldsymbol{x}_{\boldsymbol{i}}\right) H(P)=Ex∼p[I(x)]=−i∑NP(xi)logP(xi)
这里可以发现,如果把log以及后面看成一个整体,信息熵似乎是在求某个东西的期望,这个东西就叫做自信息,其表达式如下:
I ( x ) = − log [ p ( x ) ] \mathbf{I}(\boldsymbol{x})=-\boldsymbol{\operatorname { l o g }}[\boldsymbol{p}(\boldsymbol{x})] I(x)=−log[p(x)]
这样就可以理解熵的概念,信息熵就是描述整个概率分布的不确定性,所以需要对自信息求期望,这样得出的结果才能评价整个概率分布。
值得一提的是,如果只有两个类别,那么两个类别概率相等的时候信息熵最大,此时的loss值是0.69。这就说明模型对数据没有任何判别能力。
相对熵(KL散度)
接下来解释相对熵:相对熵主要衡量了两个分布之间的差异,描述了两个分布之间的距离。但是需要注意的是,相对熵和距离函数有着本质区别。距离函数满足一个重要性质就是对称性:点P到点Q的距离等于点Q到点P的距离,而相对熵并不满足这个基本性质。其表达式如下:
D K L ( P , Q ) = E x ∼ p [ log P ( x ) Q ( x ) ] = E x ∼ p [ log P ( x ) − log Q ( x ) ] = ∑ i = 1 N P ( x i ) [ log P ( x i ) − log Q ( x i ) ] = ∑ i = 1 N P ( x i ) log P ( x i ) − ∑ i = 1 N P ( x i ) log Q ( x i ) = H ( P , Q ) − H ( P ) \begin{aligned} \boldsymbol{D}_{\boldsymbol{K L}}(\boldsymbol{P}, \boldsymbol{Q}) &=\boldsymbol{E}_{\boldsymbol{x} \sim \boldsymbol{p}}\left[\log \frac{\boldsymbol{P}(\boldsymbol{x})}{\boldsymbol{Q}(\boldsymbol{x})}\right] \\ &=\boldsymbol{E}_{\boldsymbol{x} \sim \boldsymbol{p}}[\log \boldsymbol{P}(\boldsymbol{x})-\log \boldsymbol{Q}(\boldsymbol{x})] \\ &=\sum_{i=1}^{N} \boldsymbol{P}\left(\boldsymbol{x}_{i}\right)\left[\log P\left(\boldsymbol{x}_{i}\right)-\log \boldsymbol{Q}\left(\boldsymbol{x}_{i}\right)\right] \\ &=\sum_{i=1}^{N} \boldsymbol{P}\left(\boldsymbol{x}_{i}\right) \log \boldsymbol{P}\left(\boldsymbol{x}_{i}\right)-\sum_{i=1}^{N} \boldsymbol{P}\left(\boldsymbol{x}_{i}\right) \log \boldsymbol{Q}\left(\boldsymbol{x}_{i}\right) \\ &=\boldsymbol{H}(\boldsymbol{P}, \boldsymbol{Q})-\boldsymbol{H}(\mathrm{P}) \end{aligned} DKL(P,Q)=Ex∼p[logQ(x)P(x)]=Ex∼p[logP(x)−logQ(x)]=