0


交叉熵损失与二元交叉熵损失:区别、联系及实现细节

在机器学习和深度学习中,交叉熵损失(Cross-Entropy Loss)和二元交叉熵损失(Binary Cross-Entropy Loss)是两种常用的损失函数,它们在分类任务中发挥着重要作用。本文将详细介绍这两种损失函数的区别和联系,并通过具体的代码示例来说明它们的实现细节。

交叉熵损失(Cross-Entropy Loss)常用于多类分类问题,即每个样本只能属于一个类别,但总类别数量较多。例如,在手写数字识别中,一个图片只能代表一个数字(0-9)。

在 PyTorch 中,你可以使用

  1. torch.nn.CrossEntropyLoss

作为多类分类的交叉熵损失函数。这个损失函数结合了

  1. Softmax

层和交叉熵损失,可以更稳定地处理数值问题。我们使用MNIST数据集作为示例,这是一组手写数字(0-9)的图片,每个图片属于一个类别,代码如下。

  1. import torch
  2. import torch.nn as nn
  3. import torch.optim as optim
  4. from torchvision import datasets, transforms
  5. from torch.utils.data import DataLoader
  6. # 设置超参数
  7. batch_size = 64
  8. learning_rate = 0.001
  9. num_epochs = 5
  10. # 定义数据转换
  11. transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])
  12. # 加载MNIST数据集
  13. train_dataset = datasets.MNIST(root='./data', train=True, transform=transform, download=True)
  14. test_dataset = datasets.MNIST(root='./data', train=False, transform=transform)
  15. train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
  16. test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=False)
  17. # 定义模型
  18. class SimpleCNN(nn.Module):
  19. def __init__(self):
  20. super(SimpleCNN, self).__init__()
  21. self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1)
  22. self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)
  23. self.fc1 = nn.Linear(64 * 7 * 7, 128)
  24. self.fc2 = nn.Linear(128, 10)
  25. self.pool = nn.MaxPool2d(2)
  26. def forward(self, x):
  27. x = self.pool(F.relu(self.conv1(x)))
  28. x = self.pool(F.relu(self.conv2(x)))
  29. x = x.view(-1, 64 * 7 * 7)
  30. x = F.relu(self.fc1(x))
  31. x = self.fc2(x)
  32. return x
  33. # 实例化模型和损失函数
  34. model = SimpleCNN()
  35. criterion = nn.CrossEntropyLoss()
  36. optimizer = optim.Adam(model.parameters(), lr=learning_rate)
  37. # 训练模型
  38. for epoch in range(num_epochs):
  39. model.train()
  40. for images, labels in train_loader:
  41. optimizer.zero_grad()
  42. outputs = model(images)
  43. loss = criterion(outputs, labels)
  44. loss.backward()
  45. optimizer.step()
  46. print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')
  47. # 测试模型
  48. model.eval()
  49. with torch.no_grad():
  50. correct = 0
  51. total = 0
  52. for images, labels in test_loader:
  53. outputs = model(images)
  54. _, predicted = torch.max(outputs.data, 1)
  55. total += labels.size(0)
  56. correct += (predicted == labels).sum().item()
  57. print(f'Accuracy: {100 * correct / total:.2f}%')

二元交叉熵损失(Binary Cross-Entropy Loss)常用于多标签分类问题,即每个样本可以属于多个类别。例如,在多标签图像分类中,一个图片可以同时包含多种物体(猫、狗、车等)。

在 PyTorch 中,你可以使用

  1. torch.nn.BCEWithLogitsLoss

作为二元交叉熵损失函数。这个损失函数结合了

  1. Sigmoid

层和二元交叉熵损失,可以更稳定地处理数值问题。

为了演示多标签分类,我们假设有一个自定义的数据集,每个样本可以同时属于多个类别。

  1. import torch
  2. import torch.nn as nn
  3. import torch.optim as optim
  4. from torch.utils.data import Dataset, DataLoader
  5. import numpy as np
  6. # 自定义数据集
  7. class MultiLabelDataset(Dataset):
  8. def __init__(self, num_samples, num_features, num_classes):
  9. self.num_samples = num_samples
  10. self.num_features = num_features
  11. self.num_classes = num_classes
  12. self.data = np.random.randn(num_samples, num_features).astype(np.float32)
  13. self.labels = np.random.randint(0, 2, (num_samples, num_classes)).astype(np.float32)
  14. def __len__(self):
  15. return self.num_samples
  16. def __getitem__(self, idx):
  17. sample = self.data[idx]
  18. label = self.labels[idx]
  19. return sample, label
  20. # 设置超参数
  21. num_samples = 1000
  22. num_features = 20
  23. num_classes = 5
  24. batch_size = 64
  25. learning_rate = 0.001
  26. num_epochs = 5
  27. # 创建数据集和数据加载器
  28. dataset = MultiLabelDataset(num_samples, num_features, num_classes)
  29. data_loader = DataLoader(dataset, batch_size=batch_size, shuffle=True)
  30. # 定义模型
  31. class SimpleMLP(nn.Module):
  32. def __init__(self, input_size, num_classes):
  33. super(SimpleMLP, self).__init__()
  34. self.fc1 = nn.Linear(input_size, 128)
  35. self.fc2 = nn.Linear(128, num_classes)
  36. def forward(self, x):
  37. x = F.relu(self.fc1(x))
  38. x = torch.sigmoid(self.fc2(x))
  39. return x
  40. # 实例化模型和损失函数
  41. model = SimpleMLP(num_features, num_classes)
  42. criterion = nn.BCEWithLogitsLoss()
  43. optimizer = optim.Adam(model.parameters(), lr=learning_rate)
  44. # 训练模型
  45. for epoch in range(num_epochs):
  46. model.train()
  47. for samples, labels in data_loader:
  48. optimizer.zero_grad()
  49. outputs = model(samples)
  50. loss = criterion(outputs, labels)
  51. loss.backward()
  52. optimizer.step()
  53. print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')
  54. # 测试模型
  55. model.eval()
  56. with torch.no_grad():
  57. total_loss = 0
  58. for samples, labels in data_loader:
  59. outputs = model(samples)
  60. loss = criterion(outputs, labels)
  61. total_loss += loss.item()
  62. print(f'Test Loss: {total_loss / len(data_loader):.4f}')

通过本文的介绍和代码示例,希望读者能更好地理解这两种损失函数的区别与联系,并能在实际项目中正确选择和应用它们。


本文转载自: https://blog.csdn.net/qq_42754434/article/details/140690491
版权归原作者 专业发呆业余科研 所有, 如有侵权,请联系我们删除。

“交叉熵损失与二元交叉熵损失:区别、联系及实现细节”的评论:

还没有评论