损失函数
损失函数
损失函数是衡量模型输出与真实标签之间的差异。我们还经常听到代价函数和目标函数,它们之间差异如下:
- 损失函数(Loss Function)是计算一个样本的模型输出与真实标签的差异 $Loss =f\left(y^{\wedge}, y\right)$
- 代价函数(Cost Function)是计算整个样本集的模型输出与真实标签的差异,是所有样本损失函数的平均值 $\cos t=\frac{1}{N} \sum_{i}^{N} f\left(y{i}^{\wedge}, y_{i}\right)$
- 目标函数(Objective Function)就是代价函数加上正则项
在 PyTorch 中的损失函数也是继承于nn.Module,所以损失函数也可以看作网络层。
loss.backward()
loss.backward() 是 PyTorch 中一个非常重要的方法,用于自动微分(autograd)系统来反向传播误差(或损失)。
PyTorch 的 autograd 系统
PyTorch 的 autograd 系统能够自动计算张量(tensor)上的所有操作的梯度。它采用计算图(computation graph)的方式来跟踪所有涉及的操作,从而可以轻松地计算梯度。
当你定义一个计算图时,例如通过定义一系列的张量操作和函数,autograd 会跟踪这些操作。然后,当你调用 loss.backward() 时,autograd 会从损失(loss)开始,反向遍历计算图,计算每个参数的梯度。
使用 loss.backward()
在训练神经网络时,我们通常有一个损失函数,它衡量模型预测与真实值之间的差异。我们的目标是优化模型的参数,以最小化这个损失。为了做到这一点,我们需要计算损失关于模型参数的梯度,并使用这些梯度来更新参数。
loss.backward() 就是用来计算这些梯度的。它会在计算图中反向传播误差,计算每个参数的梯度,并将这些梯度存储在参数的 .grad 属性中。
示例
下面是一个简单的示例,演示了如何在 PyTorch 中使用 loss.backward():
1 | |
注意事项
- 梯度累积:在某些情况下,你可能想要在多个小批量(mini-batches)上累积梯度,然后再更新参数。这可以通过多次调用
loss.backward()(而不是在每次调用之间调用model.zero_grad())来实现。然后,你可以使用优化器(如torch.optim.SGD)来更新参数。 - 不需要梯度的操作:如果你不想跟踪某个操作的梯度,可以使用
torch.no_grad()上下文管理器。这对于评估模型或生成不需要梯度的数据时很有用。 - 梯度清零:在每次新的迭代(或批次)开始时,通常需要清零模型的梯度,以避免梯度累积。这可以通过调用
model.zero_grad()来实现。
二分类交叉熵损失函数
1 | |
功能:计算二分类任务时的交叉熵(Cross Entropy)函数。在二分类中,label 是{0,1}。对于进入交叉熵函数的 input 为概率分布的形式。一般来说,input 为 sigmoid 激活层的输出,或者 softmax 的输出。
主要参数:
weight:每个类别的 loss 设置权值
size_average:数据为 bool,为 True 时,返回的 loss 为平均值;为 False 时,返回的各样本的 loss 之和。
reduce:数据类型为 bool,为 True 时,loss 的返回是标量。
计算公式如下:
$
\ell(x, y)=\left{\begin{array}{ll}
\operatorname{mean}(L), & \text { if reduction }=\text { ‘mean’ } \
\operatorname{sum}(L), & \text { if reduction }=\text { ‘sum’ }
\end{array}\right.
$
1 | |
1 | |
1 | |
交叉熵损失函数
1 | |
功能:计算交叉熵函数
主要参数:
weight:每个类别的 loss 设置权值。
size_average:数据为 bool,为 True 时,返回的 loss 为平均值;为 False 时,返回的各样本的 loss 之和。
ignore_index:忽略某个类的损失函数。
reduce:数据类型为 bool,为 True 时,loss 的返回是标量。
计算公式如下:
$
\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)
$
1 | |
1 | |
tensor(2.0115, grad_fn=<NllLossBackward>)
L1 损失函数
1 | |
功能: 计算输出y和真实标签target之间的差值的绝对值。
我们需要知道的是,reduction参数决定了计算模式。有三种计算模式可选:none:逐个元素计算。
sum:所有元素求和,返回标量。
mean:加权平均,返回标量。
如果选择none,那么返回的结果是和输入元素相同尺寸的。默认计算方式是求平均。
计算公式如下:
$
L_{n} = |x_{n}-y_{n}|
$
1 | |
1 | |
L1损失函数的计算结果为 tensor(1.5729, grad_fn=<L1LossBackward>)
MSE 损失函数
1 | |
功能: 计算输出y和真实标签target之差的平方。
和L1Loss一样,MSELoss损失函数中,reduction参数决定了计算模式。有三种计算模式可选:none:逐个元素计算。
sum:所有元素求和,返回标量。默认计算方式是求平均。
计算公式如下:
$
l_{n}=\left(x_{n}-y_{n}\right)^{2}
$
1 | |
1 | |
MSE损失函数的计算结果为 tensor(1.6968, grad_fn=<MseLossBackward>)
平滑 L1 (Smooth L1)损失函数
1 | |
功能: L1 的平滑输出,其功能是减轻离群点带来的影响
reduction参数决定了计算模式。有三种计算模式可选:none:逐个元素计算。
sum:所有元素求和,返回标量。默认计算方式是求平均。
提醒: 之后的损失函数中,关于reduction 这个参数依旧会存在。所以,之后就不再单独说明。
计算公式如下:
$
\operatorname{loss}(x, y)=\frac{1}{n} \sum_{i=1}^{n} z_{i}
$
其中,
$
z_{i}=\left{\begin{array}{ll}
0.5\left(x_{i}-y_{i}\right)^{2}, & \text { if }\left|x_{i}-y_{i}\right|<1 \
\left|x_{i}-y_{i}\right|-0.5, & \text { otherwise }
\end{array}\right.
$
1 | |
1 | |
SmoothL1Loss损失函数的计算结果为 tensor(0.7808, grad_fn=<SmoothL1LossBackward>)
平滑 L1 与 L1 的对比
这里我们通过可视化两种损失函数曲线来对比平滑 L1 和 L1 两种损失函数的区别。
1 | |

可以看出,对于smoothL1来说,在 0 这个尖端处,过渡更为平滑。
目标泊松分布的负对数似然损失
1 | |
功能: 泊松分布的负对数似然损失函数
主要参数:
log_input:输入是否为对数形式,决定计算公式。
full:计算所有 loss,默认为 False。
eps:修正项,避免 input 为 0 时,log(input) 为 nan 的情况。
数学公式:
当参数
log_input=True:
$
\operatorname{loss}\left(x_{n}, y_{n}\right)=e^{x_{n}}-x_{n} \cdot y_{n}
$当参数
log_input=False:$
\operatorname{loss}\left(x*{n}, y*{n}\right)=x*{n}-y*{n} \cdot \log \left(x_{n}+\text { eps }\right)
$
1 | |
1 | |
1 | |
KL 散度
1 | |
功能: 计算 KL 散度,也就是计算相对熵。用于连续分布的距离度量,并且对离散采用的连续输出空间分布进行回归通常很有用。
主要参数:
reduction:计算模式,可为 none/sum/mean/batchmean。
none:逐个元素计算。
sum:所有元素求和,返回标量。
mean:加权平均,返回标量。
batchmean:batchsize 维度求平均值。
计算公式:
$
\begin{aligned}
D_{\mathrm{KL}}(P, Q)=\mathrm{E}{X \sim P}\left[\log \frac{P(X)}{Q(X)}\right] &=\mathrm{E}{X \sim P}[\log P(X)-\log Q(X)] \
&=\sum_{i=1}^{n} P\left(x_{i}\right)\left(\log P\left(x_{i}\right)-\log Q\left(x_{i}\right)\right)
\end{aligned}
$
1 | |
KLDivLoss损失函数的计算结果为 tensor(-0.3335)
MarginRankingLoss
1 | |
功能: 计算两个向量之间的相似度,用于排序任务。该方法用于计算两组数据之间的差异。
主要参数:
margin:边界值,$x_{1}$ 与$x_{2}$ 之间的差异值。
reduction:计算模式,可为 none/sum/mean。
计算公式:
$
\operatorname{loss}(x 1, x 2, y)=\max (0,-y *(x 1-x 2)+\operatorname{margin})
$
1 | |
MarginRankingLoss损失函数的计算结果为 tensor(0.7740, grad_fn=<MeanBackward0>)
多标签边界损失函数
1 | |
功能: 对于多标签分类问题计算损失函数。
主要参数:
reduction:计算模式,可为 none/sum/mean。
计算公式:
$
\operatorname{loss}(x, y)=\sum_{i j} \frac{\max (0,1-x[y[j]]-x[i])}{x \cdot \operatorname{size}(0)}
$
$
\begin{array}{l}
\text { 其中, } i=0, \ldots, x \cdot \operatorname{size}(0), j=0, \ldots, y \cdot \operatorname{size}(0), \text { 对于所有的 } i \text { 和 } j \text {, 都有 } y[j] \geq 0 \text { 并且 }\
i \neq y[j]
\end{array}
$
1 | |
MultiLabelMarginLoss损失函数的计算结果为 tensor(0.4500)
二分类损失函数
1 | |
功能: 计算二分类的 logistic 损失。
主要参数:
reduction:计算模式,可为 none/sum/mean。
计算公式:
$
\operatorname{loss}(x, y)=\sum_{i} \frac{\log (1+\exp (-y[i] \cdot x[i]))}{x \cdot \operatorname{nelement}()}
$
$
\text { 其中, } x . \text { nelement() 为输入 } x \text { 中的样本个数。注意这里 } y \text { 也有 } 1 \text { 和 }-1 \text { 两种模式。 }
$
1 | |
SoftMarginLoss损失函数的计算结果为 tensor(0.6764)
多分类的折页损失
1 | |
功能: 计算多分类的折页损失
主要参数:
reduction:计算模式,可为 none/sum/mean。
p:可选 1 或 2。
weight:各类别的 loss 设置权值。
margin:边界值
计算公式:
$
\operatorname{loss}(x, y)=\frac{\sum_{i} \max (0, \operatorname{margin}-x[y]+x[i])^{p}}{x \cdot \operatorname{size}(0)}
$
$
\begin{array}{l}
\text { 其中, } x \in{0, \ldots, x \cdot \operatorname{size}(0)-1}, y \in{0, \ldots, y \cdot \operatorname{size}(0)-1} \text {, 并且对于所有的 } i \text { 和 } j \text {, }\
\text { 都有 } 0 \leq y[j] \leq x \cdot \operatorname{size}(0)-1, \text { 以及 } i \neq y[j] \text { 。 }
\end{array}
$
1 | |
MultiMarginLoss损失函数的计算结果为 tensor(0.6000)
三元组损失
1 | |
功能: 计算三元组损失。
三元组: 这是一种数据的存储或者使用格式。<实体 1,关系,实体 2>。在项目中,也可以表示为< anchor, positive examples , negative examples>
在这个损失函数中,我们希望去anchor的距离更接近positive examples,而远离negative examples
主要参数:
reduction:计算模式,可为 none/sum/mean。
p:可选 1 或 2。
margin:边界值
计算公式:
$
L(a, p, n)=\max \left{d\left(a_{i}, p_{i}\right)-d\left(a_{i}, n_{i}\right)+\operatorname{margin}, 0\right}
$
$
\text { 其中, } d\left(x_{i}, y_{i}\right)=\left|\mathbf{x}{i}-\mathbf{y}{i}\right|_{\text {・ }}
$
1 | |
TripletMarginLoss损失函数的计算结果为 tensor(1.1667, grad_fn=<MeanBackward0>)
HingEmbeddingLoss
1 | |
功能: 对输出的 embedding 结果做 Hing 损失计算
主要参数:
reduction:计算模式,可为 none/sum/mean。
margin:边界值
计算公式:
$
l_{n}=\left{\begin{array}{ll}
x_{n}, & \text { if } y_{n}=1 \
\max \left{0, \Delta-x_{n}\right}, & \text { if } y_{n}=-1
\end{array}\right.
$
注意事项: 输入 x 应为两个输入之差的绝对值。
可以这样理解,让个输出的是正例 yn=1,那么 loss 就是 x,如果输出的是负例 y=-1,那么输出的 loss 就是要做一个比较。
1 | |
HingEmbeddingLoss损失函数的计算结果为 tensor(0.7667)
余弦相似度
1 | |
功能: 对两个向量做余弦相似度
主要参数:
reduction:计算模式,可为 none/sum/mean。
margin:可取值[-1,1] ,推荐为[0,0.5] 。
计算公式:
$
\operatorname{loss}(x, y)=\left{\begin{array}{ll}
1-\cos \left(x_{1}, x_{2}\right), & \text { if } y=1 \
\max \left{0, \cos \left(x_{1}, x_{2}\right)-\text { margin }\right}, & \text { if } y=-1
\end{array}\right.
$
其中,
$
\cos (\theta)=\frac{A \cdot B}{|A||B|}=\frac{\sum_{i=1}^{n} A_{i} \times B_{i}}{\sqrt{\sum_{i=1}^{n}\left(A_{i}\right)^{2}} \times \sqrt{\sum_{i=1}^{n}\left(B_{i}\right)^{2}}}
$
这个损失函数应该是最广为人知的。对于两个向量,做余弦相似度。将余弦相似度作为一个距离的计算方式,如果两个向量的距离近,则损失函数值小,反之亦然。
1 | |
CosineEmbeddingLoss损失函数的计算结果为 tensor(0.5000)
CTC 损失函数
1 | |
功能: 用于解决时序类数据的分类
计算连续时间序列和目标序列之间的损失。CTCLoss 对输入和目标的可能排列的概率进行求和,产生一个损失值,这个损失值对每个输入节点来说是可分的。输入与目标的对齐方式被假定为 “多对一”,这就限制了目标序列的长度,使其必须是 ≤ 输入长度。
主要参数:
reduction:计算模式,可为 none/sum/mean。
blank:blank label。
zero_infinity:无穷大的值或梯度值为
1 | |
CTCLoss损失函数的计算结果为 tensor(16.0885, grad_fn=<MeanBackward0>)
焦点损失 FocalLoss
1 | |



