ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

深度学习25:PyTorch:损失函数

深度学习25:PyTorch:损失函数

目录标题

      • 一、分类任务损失函数
      • 二、回归任务损失函数
      • 三、综合测试

一、分类任务损失函数

1)二分类任务损失函数

二分类任务常用二元交叉熵损失函数(Binary Cross-Entropy Loss)。

L = − 1 n ∑ i = 1 n ( y i log ⁡ y ^ i + ( 1 − y i ) log ⁡ ( 1 − y ^ i ) ) L = -\frac{1}{n}\sum_{i=1}^{n} \left( y_i \log \hat{y}_i + (1 - y_i)\log(1 - \hat{y}_i) \right)L=−n1​i=1∑n​(yi​logy^​i​+(1−yi​)log(1−y^​i​))

其中:

y i y_iyi​为真实值(通常为 0 或 1)

y ^ i \hat{y}_iy^​i​为预测值(表示样本i ii为 1 的概率)

在 PyTorch 中可使用torch.nn.BCELoss实现:

importtorchimporttorch.nnasnn# 真实值target=torch.tensor([[1],[0],[0]],dtype=torch.float32)# 预测值input=torch.randn((3,1))prediction=torch.sigmoid(input)# 实例化损失函数loss=nn.BCELoss()print(loss(prediction,target))

2)多分类任务损失函数

多分类任务常用多类交叉熵损失函数(Categorical Cross-Entropy Loss)。它是对每个类别的预测概率与真实标签之间差异的加权平均。

L = − 1 n ∑ i = 1 n ∑ c = 1 C y i , c log ⁡ y ^ i , c L = -\frac{1}{n}\sum_{i=1}^{n}\sum_{c=1}^{C} y_{i,c} \log \hat{y}_{i,c}L=−n1​i=1∑n​c=1∑C​yi,c​logy^​i,c​

其中:

C CC是类别数

y i , c y_{i,c}yi,c​为真实值(表示y i y_iyi​是否为类别c cc,通常为 0 或 1)

y ^ i , c \hat{y}_{i,c}y^​i,c​为预测值(表示样本i ii为类别c cc的概率)

在 PyTorch 中可使用torch.nn.CrossEntropyLoss实现:

注意:调用torch.nn.CrossEntropyLoss相当于调用了torch.nn.LogSoftmax之后再调用torch.nn.NLLLoss。即使用CrossEntropyLoss时上一层的输出不需要Softmax激活函数,因为该损失函数内会自动处理。

importtorchimporttorch.nnasnn# 1.目标值为顺序编码的标签input=torch.randn(6,8)print(input)# 目标值,6个数据的类别标签(0-7)# IndexError: Target 9 is out of bounds.# target = torch.tensor([1,0,2,7,5,9])target=torch.tensor([1,0,2,7,5,3])#定义损失函数loss=nn.CrossEntropyLoss()print(loss(input,target))

二、回归任务损失函数

1)MAE

平均绝对误差(Mean Absolute Error,MAE),也称 L1 Loss:

L = 1 n ∑ i = 1 n ∣ y i − y ^ i ∣ L = \frac{1}{n}\sum_{i=1}^{n}|y_i - \hat{y}_i|L=n1​i=1∑n​∣yi​−y^​i​∣

L1 Loss 对异常值鲁棒,但在 0 点处不可导

importtorchimporttorch.nnasnn# 1.定义数据input=torch.randn(3,5)target=torch.randn(3,5)#MSE L1 Lossmse_loss1=nn.L1Loss()print(mse_loss1(input,target))

2)MSE

均方误差(Mean Squared Error,MSE),也称 L2 Loss:

L2 Loss 对异常值敏感,遇到异常值时易发生梯度爆炸。

importtorchimporttorch.nnasnn# 1.定义数据input=torch.randn(3,5)target=torch.randn(3,5)#MSE L2 Lossmse_loss=nn.MSELoss()print(mse_loss(input,target))

3)Smooth L1

平滑 L1:

S m o o t h L 1 = { 1 2 ( y i − y ^ i ) 2 , ∣ y i − y ^ i ∣ < 1 ∣ y i − y ^ i ∣ − 1 2 , ∣ y i − y ^ i ∣ ≥ 1 Smooth\ L1 = \begin{cases} \frac{1}{2}(y_i - \hat{y}_i)^2, & |y_i - \hat{y}_i| < 1 \\ |y_i - \hat{y}_i| - \frac{1}{2}, & |y_i - \hat{y}_i| \ge 1 \end{cases}SmoothL1={21​(yi​−y^​i​)2,∣yi​−y^​i​∣−21​,​∣yi​−y^​i​∣<1∣yi​−y^​i​∣≥1​

当误差较小时(( ∣ y i − y ^ i ∣ < 1 (|y_i - \hat{y}_i| < 1(∣yi​−y^​i​∣<1))使用 L2 Loss,使得损失函数平滑可导。当误差较大时(( ∣ y i − y ^ i ∣ ≥ 1 (|y_i - \hat{y}_i| \ge 1(∣yi​−y^​i​∣≥1))使用 L1 Loss 降低异常值的影响。

importtorchimporttorch.nnasnn# 1.定义数据input=torch.randn(3,5)target=torch.randn(3,5)#Smooth L1smooth_l1_loss=nn.SmoothL1Loss()print(smooth_l1_loss(input,target))

三、综合测试

importtorchfromtorchimportnn,optim# 定义模型classModel(nn.Module):# 初始化def__init__(self):super().__init__()# 只定义一个全连接层self.linear=nn.Linear(in_features=5,out_features=3)# 权重初始化(这里自定义权重,是为了观看权重变化)self.linear.weight.data=torch.tensor([[0.1,0.2,0.3],[0.4,0.5,0.6],[0.7,0.8,0.9],[1.0,1.1,1.2],[1.3,1.4,1.5]]).T self.linear.bias.data=torch.tensor([1.0,2.0,3.0])# 前向传播defforward(self,x):x=self.linear(x)returnx# 主流程# 1. 定义数据# 输入数据 2x5X=torch.tensor(data=[[1,2,3,4,5],[6,7,8,9,10]],dtype=torch.float)# 目标值 2x3target=torch.tensor(data=[[0,0,0],[0,0,0]],dtype=torch.float)# 2. 创建模型model=Model()# 3. 前向传播,预测输出output=model(X)# 4. 定义损失函数,计算损失loss=nn.MSELoss()loss_value=loss(output,target)# 5. 反向传播,计算梯度loss_value.backward()# 6. 定义优化器optimizer=optim.SGD(model.parameters(),lr=0.1)# 7. 更新参数optimizer.step()optimizer.zero_grad()#打印模型参数 (看看经过一步迭代后参数变化)forparamNameinmodel.state_dict():print(paramName)print(model.state_dict()[paramName])''' 打印结果和原始参数差别很大 linear.weight tensor([[-6.7833, -8.0333, -9.2833, -10.5333, -11.7833], [-7.7667, -9.2667, -10.7667, -12.2667, -13.7667], [-8.7500, -10.5000, -12.2500, -14.0000, -15.7500]]) linear.bias tensor([-0.5500, 0.2000, 0.9500]) '''
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进