在深度学习中,损失函数是用来衡量模型参数质量的函数。说人话就是:真实值和预测值之间的差值

分类任务中的损失函数

这里重点说交叉熵损失

①多分类任务

多分类任务需要用激活函数softmax将输出转变成概率的形式,在多分类任务中,交叉熵损失函数的计算方法为:

pytorch 打印tensor类型 pytorch打印loss_损失函数


为了熟悉理解这个公式,我们来看下面这个例子:

计算下面的交叉熵损失:

pytorch 打印tensor类型 pytorch打印loss_dnn_02


代入公式:L =-(0log0.1+1log0.7+0*log0.2)=-log0.7

从上面的公式可以看出,当经过softmax处理得到的概率越接近1,得到的损失函数越小,越接近0。

下面用代码演示下:

# 导入需要的包
import torch
import torch.nn as nn


def test01():
    # 设置真实值,可以进行热编码,也可以不进行热编码
    y_true = torch.tensor([[0, 1, 0], [0, 0, 1]], dtype=torch.float32)
    # 设置真实值,真实值为类别1和类别2
    # y_true = torch.tensor([1, 2], dtype=torch.int64)
    y_pred = torch.tensor([[0.2, 0.6, 0.2], [0.1, 0.8, 0.1]], dtype=torch.float32)
    # 实例化交叉熵损失
    loss = nn.CrossEntropyLoss()
    # 计算损失结果
    loss_result = loss(y_pred, y_true).numpy()
    # 打印损失结果
    print(loss_result)


if __name__ == '__main__':
    test01()

这里肯定有小伙伴很好奇,在公式中我们要对真实值进行one-hot编码(热编码)之后,才能计算,为什么pytorch不用进行热编码呢?
实际上,并不是不用进行热编码,而是pytorch帮我们做了,那他怎么做的呢?假设和代码中一样,我们传入了两个类别分别是[1,2],pytorch就会先自动补齐,默认总共三个类别,分别为:0,1,2,也就是[0,1,2]。接下来,会将0,1,2分别编码成:[1,0,0],[0,1,0],[0,0,1],那么代码中的[1,2]是不是很好理解了,就对应[0,1,0]和[0,0,1]是不是和我们自己手动转化成的热编码一致。

②二分类任务

二分类使用的激活函数为 sigmoid,而交叉熵损失函数的公式为:

pytorch 打印tensor类型 pytorch打印loss_pytorch 打印tensor类型_03


测试如下:

def test02():
    # 设置真实值
    y_true = torch.tensor([[0], [1]], dtype=torch.float32)
    # 设置真实值
    y_pred = torch.tensor([[0.3], [0.7]], dtype=torch.float32)
    # 实例化二分类交叉熵损失
    loss = nn.BCELoss()
    # 计算损失结果
    loss_result = loss(y_pred, y_true).numpy()
    # 打印损失结果
    print(loss_result)

回归任务的损失函数

①MAE损失(L1 Loss)

Mean Absolute Loss(MAE)通常用在正则化上,添加到其他的 loss 中作为约束,但是在零点不可导。公式如下:

pytorch 打印tensor类型 pytorch打印loss_pytorch_04


测试代码如下:

def test03():
    # 设置真实值
    y_true = torch.tensor([[0.], [1.]], dtype=torch.float32)
    # 设置真实值
    y_pred = torch.tensor([[1.], [0.]], dtype=torch.float32)
    # 实例化L1Loss
    loss = nn.L1Loss()
    # 计算损失结果
    loss_result = loss(y_pred, y_true).numpy()
    # 打印损失结果
    print(loss_result)

②MSE损失(L2 Loss)

Mean Squared Loss(MSE)通常用在正则化上,当预测值和真实值相差很大时,容易发生梯度爆炸。公式如下:

pytorch 打印tensor类型 pytorch打印loss_损失函数_05


测试代码如下:

def test04():
    # 设置真实值
    y_true = torch.tensor([[0.], [1.]], dtype=torch.float32)
    # 设置真实值
    y_pred = torch.tensor([[1.], [1.]], dtype=torch.float32)
    # 实例化MSELoss(L2Loss)
    loss = nn.MSELoss()
    # 计算损失结果
    loss_result = loss(y_pred, y_true).numpy()
    # 打印损失结果
    print(loss_result)

③smooth L1损失

简单的理解,就是把 L1 损失平滑一下,实际上就是为了解决 L1 中在零点不可导,在 L2 中梯度爆炸的问题。公式如下:

pytorch 打印tensor类型 pytorch打印loss_dnn_06


下面这个图就是三个损失函数的图像对比:

pytorch 打印tensor类型 pytorch打印loss_pytorch_07


测试代码如下:

def test05():
    # 设置真实值
    y_true = torch.tensor([[0.], [1.]], dtype=torch.float32)
    # 设置真实值
    y_pred = torch.tensor([[0.7], [2.]], dtype=torch.float32)
    # 实例化smooth L1损失
    loss = nn.HuberLoss()
    # 计算损失结果
    loss_result = loss(y_pred, y_true).numpy()
    # 打印损失结果
    print(loss_result)