损失函数

在深度学习中,损失函数是用来衡量模型参数的质量的函数, 衡量的方式是比较网络输出和真实输 出的差异:

损失函数在不同的文献中名称是不一样的,主要有以下几种命名方式:

多分类损失函数

在多分类任务通常使用softmax将logits转换为概率的形式,所以多分类的交叉熵损失也叫做softmax损失,它的计算方 法是:

其中:

1. y是样本x属于某一个类别的真实概率

2. 而f(x)是样本属于某一类别的预测分数

3. S是softmax激活函数,将属于某一类别的预测分数转换成概率

4. L用来衡量真实值y和预测值f(x)之间差异性的损失结果

上图中的交叉熵损失为:

从概率角度理解,我们的目的是最小化正确类别所对应的预测概率的对数的负值(损失值最小),如下图所示:

在pytorch中使用nn.CrossEntropyLoss()实现,如下所示:

import torch
import torch.nn as nn


# 分类损失函数:交叉熵损失使用nn.CrossEntropyLoss()实现。nn.CrossEntropyLoss()=softmax+ 损失计算
def test():
    # 设置真实值: 可以是热编码后的结果也可以不进行热编码
    # y_true = torch.tensor([[1, 0, 0], [0, 1, 0], [0, 0, 1]], dtype=torch.float32)
    # 注意的类型必须是64位整型数据
    y_true = torch.tensor([0, 1, 2], dtype=torch.int64)
    print(y_true)
    y_pred = torch.tensor([[0.6, 0.3, 0.1], [0.2, 0.6, 0.2], [0.1, 0.8, 0.1]], dtype=torch.float32)
    print(y_pred)
    # 实例化交叉熵损失
    loss = nn.CrossEntropyLoss()
    # 计算损失结果
    my_loss = loss(y_pred, y_true).numpy()
    print('loss:', my_loss)


test()
tensor([0, 1, 2])
tensor([[0.6000, 0.3000, 0.1000],
        [0.2000, 0.6000, 0.2000],
        [0.1000, 0.8000, 0.1000]])
loss: 1.0311458

二分类任务损失函数

在处理二分类任务时,我们不再使用softmax激活函数,而是使用sigmoid激活函数,那损失函数也相应的进行调整, 使用二分类的交叉熵损失函数:

其中:

1. y是样本x属于某一个类别的真实概率

2. 而y^是样本属于某一类别的预测概率

3. L用来衡量真实值y与预测值y^之间差异性的损失结果。

在pytorch中实现时使用nn.BCELoss() ,如下所示:

import torch
import torch.nn as nn



def test2():
    # 1 设置真实值和预测值
    # 预测值是sigmoid输出的结果
    y_pred = torch.tensor([0.6901, 0.5459, 0.2469], requires_grad=True)
    y_true = torch.tensor([0, 1, 0], dtype=torch.float32)
    # 2 实例化二分类交叉熵损失
    criterion = nn.BCELoss()
    # 3 计算损失
    my_loss = criterion(y_pred, y_true).detach().numpy()
    print('loss:', my_loss)


test2()
loss: 0.6867941

回归任务损失函数-MAE损失函数

Mean absolute loss(MAE)也被称为L1 Loss,是以绝对误差作为距离。损失函数公式:

特点是:

1. 由于L1 loss具有稀疏性,为了惩罚较大的值,因此常常将其作为 正则项添加到其他loss中作为约束。

2. L1 loss的最大问题是梯度在零点不平滑,导致会跳过极小值。

import torch
import torch.nn as nn


def test3():
    # 1 设置真实值和预测值
    y_pred = torch.tensor([1.0, 1.0, 1.9], requires_grad=True)
    y_true = torch.tensor([2.0, 2.0, 2.0], dtype=torch.float32)
    # 2 实例MAE损失对象
    loss = nn.L1Loss()
    # 3 计算损失
    my_loss = loss(y_pred, y_true).detach().numpy()
    print('loss:', my_loss)


test3()
loss: 0.7

回归任务损失函数-MSE损失函数

Mean Squared Loss/ Quadratic Loss(MSE loss)也被称为L2 loss,或欧氏距离,它以误差的平方和的均值作为距离 损失函数公式:

曲线如下图所示:

特点是:

1. L2 loss也常常作为正则项。

2. 当预测值与目标值相差很大时, 梯度容易爆炸。

import torch
import torch.nn as nn


def test4():
    # 1 设置真实值和预测值
    y_pred = torch.tensor([1.0, 1.0, 1.9], requires_grad=True)
    y_true = torch.tensor([2.0, 2.0, 2.0], dtype=torch.float32)
    # 2 实例MSE损失对象
    loss = nn.MSELoss()
    # 3 计算损失
    my_loss = loss(y_pred, y_true).detach().numpy()
    print('loss:', my_loss)


test4()
loss: 0.67

回归任务损失函数-smooth L1损失函数

smooth L1说的是光滑之后的L1。损失函数公式:

其中:𝑥=f(x)−y 为真实值和预测值的差值。

从右图中可以看出,该函数实际上就是一个分段函数

1. 在[-1,1]之间实际上就是L2损失,这样解决了L1的不光滑问题

2. 在[-1,1]区间外,实际上就是L1损失,这样就解决了离群点梯度爆炸的问题

import torch
import torch.nn as nn


def test5():
    # 1
    y_true = torch.tensor([0, 3])
    y_pred = torch.tensor([0.6, 0.4], requires_grad=True)
    # 2 smmothL1
    loss = nn.SmoothL1Loss()
    # 3
    my_loss = loss(y_pred, y_true).detach().numpy()
    print('loss:', my_loss)


test5()
loss: 1.14

梯度下降算法

梯度下降法是一种寻找使损失函数最小化的方法。从数学上的角度来看,梯度的方向是函数增长速度最快的方向,那么 梯度的反方向就是函数减少最快的方向,所以有:

其中,η是学习率,如果学习率太小,那么每次训练之后得到的效果都太小,增大训练的时间成本。如果,学习率太大, 那就有可能直接跳过最优解,进入无限的训练中。解决的方法就是,学习率也需要随着训练的进行而变化。

在进行模型训练时,有三个基础的概念:

1. Epoch: 使用全部数据对模型进行以此完整训练,训练轮次

2. Batch_size: 使用训练集中的小部分样本对模型权重进行以此反向传播的参数更新,每次训练每批次样本数量

3. Iteration: 使用一个 Batch 数据对模型进行一次参数更新的过程

假设数据集有50000 个训练样本,现在选择Batch Size = 256 对模型进行训练。

每个Epoch 要训练的图片数量:50000

训练集具有的Batch 个数:50000/256+1=196

每个Epoch 具有的Iteration 个数:196

10个Epoch 具有的Iteration 个数:1960

在深度学习中,梯度下降的几种方式的根本区别就在于Batch Size不同,如下表所示:

注:上表中Mini-Batch 的Batch 个数为N / B + 1 是针对未整除的情况。整除则是N / B。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐