PyTorch 提供了两种损失函数的使用方法:函数形式、模块形式,函数形式的损失函数定义在 torch.nn.functional 库中,使用时传入神经网络的预测值和目标值来计算损失,模型形式是通过构建一个模块的实例对象,然后通过模块的 forward 方法来计算损失,损失函数模型在 torch.nn 库。
在分类问题中,常用的损失函数有: BCELoss、BCEWithLogitsLoss、CrossEntropyLoss。
下面为损失函数使用代码示例:
import torch.nn as nn
import torch.nn.functional as F
import torch
# 1. 函数形式
def test01():
# 固定随机数种子
torch.manual_seed(0)
inputs = torch.randint(0, 10, size=[10, 1]).float()
target = torch.randint(0, 10, size=[10, 1]).float()
print(inputs)
print(target)
# 第一个参数为网络的预测值
# 第二个参数为目标值
loss = F.mse_loss(inputs, target)
print('loss: %.2f' % loss.item())
# 2. 模块形式:
def test02():
# 固定随机数种子
torch.manual_seed(0)
inputs = torch.randint(0, 10, size=[10, 1]).float()
target = torch.randint(0, 10, size=[10, 1]).float()
# 实例化模块对象
criterion = nn.MSELoss()
# 计算损失
loss = criterion(inputs, target)
print('loss: %.2f' % loss.item())
if __name__ == '__main__':
test01()
test02()
程序输出结果:
tensor([[4.],
[9.],
[3.],
[0.],
[3.],
[9.],
[7.],
[3.],
[7.],
[3.]])
tensor([[1.],
[6.],
[6.],
[9.],
[8.],
[6.],
[6.],
[8.],
[4.],
[3.]])
loss: 17.70
loss: 17.70
2. BCELoss
BCELoss 用于单标签、多标签的二分类问题,输出和目标值的维度为:(B, C),B 表示样本数量,C 表示类别数量,每一个 C 值表示属于某个标签的概率。

- N 表示样本数量;
- y 表示样本的真实标签,0 或者 1;
- x 表示样本的预测为正确类别的概率;
- 如果样本真实标签为 1,则希望 x 的值概率越大越好。如果样本的真实标签为 0,则希望 x 的值越小越好.

- N 表示样本数量;
- M 表示每个样本的真实标签数量;
- y 表示某个样本属于某个标签,标签值为 0 或者 1;
- x 表示某个样本属于某个标签的概率;
下面为单标签和多标签计算损失的示例代码:
import torch
import torch.nn as nn
import torch.nn.functional as F
# 1. 单标签
def test01():
# 固定随机数种子
torch.manual_seed(0)
# 模块方式初始化损失函数
criterion = nn.BCELoss()
# 构建目标标签和预测概率值
y_true = torch.randint(0, 2, size=[10, 1]).float()
y_pred = torch.sigmoid(torch.randn(10, 1)).float()
print(y_true)
print(y_pred)
# 输入形状: (batch_size, pred_proba)
loss = criterion(y_pred, y_true)
print('loss: %.2f' % loss.item())
# 2. 多标签
def test02():
# 固定随机数种子
torch.manual_seed(0)
# 模块方式初始化损失函数
criterion = nn.BCELoss()
# 构建目标标签和预测概率值
y_true = torch.randint(0, 2, size=[10, 2]).float()
y_pred = torch.sigmoid(torch.randn(10, 2)).float()
print(y_true)
print(y_pred)
# 输入形状: (batch_size, pred_proba)
loss = criterion(y_pred, y_true)
print('loss: %.2f' % loss.item())
if __name__ == '__main__':
test01()
print('-' * 30)
test02()
程序输出结果:
tensor([[0.],
[1.],
[1.],
[0.],
[1.],
[1.],
[1.],
[1.],
[1.],
[1.]])
tensor([[0.5400],
[0.3529],
[0.3137],
[0.7431],
[0.4350],
[0.7440],
[0.6025],
[0.6984],
[0.3044],
[0.3111]])
loss: 0.87
------------------------------
tensor([[0., 1.],
[1., 0.],
[1., 1.],
[1., 1.],
[1., 1.],
[1., 0.],
[0., 1.],
[0., 0.],
[0., 0.],
[0., 1.]])
tensor([[0.6454, 0.1744],
[0.4155, 0.8645],
[0.4462, 0.3224],
[0.6371, 0.5645],
[0.4566, 0.3365],
[0.7187, 0.6198],
[0.7691, 0.5211],
[0.2315, 0.4988],
[0.3733, 0.4239],
[0.1707, 0.8464]])
loss: 0.81
2. BCEWithLogitsLoss
BCEWithLogitsLoss 和 BCELoss 一样用于单标签、或者多标签的二分类问题,它相当于 Sigmoid 和 BCELoss 的结合,对网络的输出结果先进行 Sigmoid 计算将预测值的映射到 (0, 1) 之间,再对其使用 BCELoss 计算损失。
由此可见,当我们的神经网络最后一层使用的是 Sigmoid 时,则直接使用 BCELoss 计算损失,否则使用 BCEWithLogitsLoss 损失函数。


BCEWithLogitsLoss 的计算公式中只是比 BCELoss 多个一个 sigmoid 函数计算。
下面的示例代码仅仅把 sigmoid 函数去除,其他并没有改变:
import torch
import torch.nn as nn
import torch.nn.functional as F
# 1. 单标签
def test01():
# 固定随机数种子
torch.manual_seed(0)
# 模块方式初始化损失函数
criterion = nn.BCEWithLogitsLoss()
# 构建目标标签和预测概率值
y_true = torch.randint(0, 2, size=[10, 1]).float()
y_pred = torch.randn(10, 1).float()
print(y_true)
print(y_pred)
# 输入形状: (batch_size, pred_proba)
loss = criterion(y_pred, y_true)
print('loss: %.2f' % loss.item())
# 2. 多标签
def test02():
# 固定随机数种子
torch.manual_seed(0)
# 模块方式初始化损失函数
criterion = nn.BCEWithLogitsLoss()
# 构建目标标签和预测概率值
y_true = torch.randint(0, 2, size=[10, 2]).float()
y_pred = torch.randn(10, 2)
print(y_true)
print(y_pred)
# 输入形状: (batch_size, pred_proba)
loss = criterion(y_pred, y_true)
print('loss: %.2f' % loss.item())
if __name__ == '__main__':
test01()
print('-' * 30)
test02()
程序输出结果:
tensor([[0.],
[1.],
[1.],
[0.],
[1.],
[1.],
[1.],
[1.],
[1.],
[1.]])
tensor([[ 0.1604],
[-0.6065],
[-0.7831],
[ 1.0622],
[-0.2613],
[ 1.0667],
[ 0.4159],
[ 0.8396],
[-0.8265],
[-0.7949]])
loss: 0.87
------------------------------
tensor([[0., 1.],
[1., 0.],
[1., 1.],
[1., 1.],
[1., 1.],
[1., 0.],
[0., 1.],
[0., 0.],
[0., 0.],
[0., 1.]])
tensor([[ 0.5988, -1.5551],
[-0.3414, 1.8530],
[-0.2159, -0.7425],
[ 0.5627, 0.2596],
[-0.1740, -0.6787],
[ 0.9383, 0.4889],
[ 1.2032, 0.0845],
[-1.2001, -0.0048],
[-0.5181, -0.3067],
[-1.5810, 1.7066]])
loss: 0.81
3. CrossEntropyLoss
CrossEntropyLoss 主要用于多分类问题,输出和目标的维度是 (batch, C) ,batch 表示样本数量,C 表示类别数量。假设:某个样本预测的类别有 10 个,神经网络对 10 个类别都得到了 logits,CrossEntropyLoss 会对这 10 个 logits 计算 softmax,即: 属于某个类别的概率,然后找到最大概率的索引作为预测类别.

下列为使用示例代码:
import torch
import torch.nn as nn
import torch.nn.functional as F
# 1. 单标签
def test01():
# 固定随机数种子
torch.manual_seed(0)
# 模块方式初始化损失函数
criterion = nn.CrossEntropyLoss()
# 程序表示10个样本的标签为 0-7
y_true = torch.randint(0, 4, size=[10,])
# 程序表示10个样本,每个样本都预测为8个标签的logits
y_pred = torch.randn(10, 4).float()
print(y_true)
print(y_pred)
# 输入形状: (batch_size, pred_proba)
loss = criterion(y_pred, y_true)
print('loss: %.2f' % loss.item())
# 2. 多标签
def test02():
# 固定随机数种子
torch.manual_seed(0)
# 模块方式初始化损失函数
criterion = nn.CrossEntropyLoss()
# 程序表示10个样本,每个样本有2个目标标签
y_true = torch.randint(0, 4, size=[5, 2])
# 程序表示10个样本,每个样本预测8个类别,每个类别预测2个标签的logits
y_pred = torch.randn(5, 4, 2).float()
print(y_true)
print(y_pred)
# 输入形状: (batch_size, pred_proba)
loss = criterion(y_pred, y_true)
print('loss: %.2f' % loss.item())
if __name__ == '__main__':
test01()
print('-' * 30)
test02()
程序的输出结果:
tensor([0, 3, 1, 0, 3, 3, 3, 3, 1, 3])
tensor([[ 0.4913, -0.2041, -0.0885, 0.5239],
[-0.6659, 0.8504, -1.3527, -1.6959],
[ 0.7854, 0.9928, -0.1932, -0.3090],
[ 0.5026, -0.8594, 0.7502, -0.5855],
[ 1.4437, 0.2660, 0.1665, 0.8744],
[-0.1435, -0.1116, -0.6136, 0.0316],
[ 1.0554, 0.1778, -0.2303, -0.3918],
[ 0.5433, -0.3952, 0.2055, -0.4503],
[ 1.5210, 3.4105, -1.5312, -1.2341],
[ 1.8197, -0.5515, -1.3253, 0.1886]])
loss: 1.45
------------------------------
tensor([[0, 3],
[1, 0],
[3, 3],
[3, 3],
[1, 3]])
tensor([[[ 0.4913, -0.2041],
[-0.0885, 0.5239],
[-0.6659, 0.8504],
[-1.3527, -1.6959]],
[[ 0.7854, 0.9928],
[-0.1932, -0.3090],
[ 0.5026, -0.8594],
[ 0.7502, -0.5855]],
[[ 1.4437, 0.2660],
[ 0.1665, 0.8744],
[-0.1435, -0.1116],
[-0.6136, 0.0316]],
[[ 1.0554, 0.1778],
[-0.2303, -0.3918],
[ 0.5433, -0.3952],
[ 0.2055, -0.4503]],
[[ 1.5210, 3.4105],
[-1.5312, -1.2341],
[ 1.8197, -0.5515],
[-1.3253, 0.1886]]])
loss: 2.14
CrossEntropyLoss 等价于使用 LogSoftmax 和 NLLLoss 的组合。

冀公网安备13050302001966号