损失函数
均方误差损失
均方误差损失,MSELoss,用于回归任务,计算预测值和真实值之间的均方误差
1 | |
reduction:指定如何对输出进行降维,可选值为none、mean和sumnone:不进行降维,返回每个样本的损失mean:返回损失的均值,这是默认行为sum:返回损失的总和
对创建的MSELoss对象传入预测值和真实值张量,确保预测值和真实值的形状相同,返回均方误差损失张量
比如:
1 | |
输出结果:
1 | |
平均绝对值误差损失
与 MSE 相比,L1Loss 对异常值不那么敏感,因为它是基于绝对误差而不是平方误差
1 | |
reduction:指定如何对输出进行降维,可选值为none、mean和sum
none:不进行降维,返回每个样本的损失mean:返回损失的均值,这是默认行为sum:返回损失的总和
对创建的L1Loss对象传入预测值和真实值张量,确保预测值和真实值的形状相同,返回均方误差损失张量
比如:
1 | |
输出结果:
1 | |
交叉熵损失
1 | |
参数:
weight:一个可选的向量,用于为每个类别的损失赋予不同的权重。这对于处理类别不平衡的数据集很有用。ignore_index:指定一个标签值,该值在计算损失时会被忽略。reduction:指定如何对输出进行降维,可选值为none、mean和sumnone:不进行降维,返回每个样本的损失mean:返回损失的均值,这是默认行为sum:返回损失的总和
CrossEntropyLoss首先对预测输出应用LogSoftmax,将预测输出转换为概率分布的对数形式。然后计算每个样本的负对数似然损失。最后,根据reduction参数对结果进行降维
在损失函数中使用LogSoftmax而不是直接在模型中使用Softmax的原因:
softmax函数: \[ \hat y_j = \frac{\exp(o_j)}{\sum_k\exp(o_k)} \] 其中\(\hat y_j\)是预测的概率分布,\(o_j\)是未规范化的预测\(\mathbf{o}\)的第\(j\)个元素。
如果\(o_k\)中的一些数值非常大,那么\(\exp(o_k)\)可能大于数据类型容许的最大数字,即上溢(overflow)。这将使分母或分子变为inf(无穷大),最后得到的是0、inf或nan(不是数字)的\(\hat y_j\)
解决这个问题的一个技巧是:在继续softmax计算之前,先从所有\(o_k\)中减去\(\max(o_k)\): \[ \begin{aligned} \hat y_j &= \frac{\exp(o_j)}{\sum_k\exp(o_k)}\\ &= \frac{e^{o_j}}{\sum_k e^{o_k}}\\ &= \frac{e^{o_j-\max(o_k)+\max(o_k)}}{\sum_k e^{o_k-\max(o_k)+\max(o_k)}}\\ &= \frac{e^{o_j-\max(o_k)}e^{\max(o_k)}}{e^{\max(o_k)}\sum_k e^{o_k-\max(o_k)}}\\ &= \frac{e^{o_j-\max(o_k)}}{\sum_k e^{o_k-\max(o_k)}}\\ &= \frac{\exp(o_j-\max(o_k))}{\sum_k\exp(o_k-\max(o_k))} \end{aligned} \]
在减法和规范化步骤后,可能有些\(o_j-\max(o_k)\)具有较大的负值。由于精度受限,\(\exp(o_j-\max(o_k))\)将有接近零的值,即下溢(underflow)。这些值可能会四舍五入为零,使\(\hat y_j\)为零,并且使得\(\log(\hat
y_j)\)的值为-inf,反向传播时可能造成梯度爆炸
尽管我们要计算指数函数,但我们最终在计算交叉熵损失时会取它们的对数。我们可以将这两个结合在一起:
\[
\begin{aligned}
\log(\hat y_j) &=
\log\bigg(\frac{\exp(o_j-\max(o_k))}{\sum_k\exp(o_k-\max(o_k))}\bigg)\\
&= \log\big(\exp(o_j-\max(o_k))\big) -
\log\Bigg(\sum_k\exp(o_k-\max(o_k))\Bigg)\\
&= o_j-\max(o_k) - \log\Bigg(\sum_k\exp(o_k-\max(o_k))\Bigg)
\end{aligned}
\]
因此,在训练时,我们的神经网络中不会有Softmax,而是直接在CrossEntropyLoss中计算LogSoftmax,NLLLoss(负对数似然损失)
CrossEntropyLoss对象传入的y_hat和y应该满足如下要求:
y_hat(模型输出):- 形状:
y_hat应该是一个二维张量(Tensor),形状为(N, C),其中N是批量大小(batch size),C是类别的数量 - 数值:
y_hat应该是模型的原始输出,通常是经过线性层(如全连接层)的输出,但没有应用 softmax 函数。CrossEntropyLoss内部会自动应用LogSoftmax - 类型:
y_hat的数据类型通常是浮点数(如torch.float32)
- 形状:
y(真实标签):- 形状:
y可以是一个一维张量(Tensor),形状为(N,),其中每个元素是一个类别索引(从 0 到C-1)。也可以是一个二维张量,形状为(N, 1),但内部元素仍然是一个类别索引 - 数值:
y中的每个元素都应该是一个整数,表示对应样本的真实类别索引 - 类型:
y的数据类型通常是长整型(如torch.long),因为它们是类别索引
- 形状:
比如:
1 | |
在设计神经网络时,不需要softmax层,不仅是在训练时使用softmax很可能会导致上溢或下溢,在推理时,如果我们仅关心预测的类别,线性输出的最大值就代表了softmax后概率的最大值,可以直接取线性输出的最大值索引
二元交叉熵损失
1 | |
参数:
weight:Tensor类型,可选。对每个样本的损失值进行加权,常用于处理类别不平衡问题。例如,若正样本数量较少,可通过增大正样本权重来平衡训练。必须是一维张量,形状与输入数据相同。若不指定,默认所有样本权重为1reduction:str类型,可选。指定损失值的聚合方式:none:不聚合,返回每个样本的损失值mean:计算所有样本损失的均值(默认)sum:计算所有样本损失的总和
BCELoss()对象传入的y_hat和y应该满足如下要求:
y_hat(模型输出):二维张量,形状为(N, 1),也可以是一维张量,形状为(N,),其中N是批量大小(batch size),每个元素是对应数据的预测概率(即模型最后必须通过Sigmoid压缩到[0, 1]区间,否则可能导致数值溢出或梯度异常)y(真实标签):可以是一维张量,形状为(N,),也可以是二维张量,形状为(N, 1),每个元素是对应数据的真实概率(0或1,要求是浮点类型的张量)
y_hat与y的维度形状必须相同
比如:
1 | |
1 | |