我正在使用 Pytorch 从头开始创建 CNN。我有一个平衡的图像数据集,将两个类别分成两半。我正在尝试使用 torch.nn 中的 BCEwithLogitsLoss 函数,因为我读到这通常最适合像我这样的用例。然而,由于某种原因,当我使用这个损失函数时,我的网络似乎根本没有学到任何东西!它的准确率一直停滞在 50% 左右,只猜测一类。当我使用常规的 CrossEntropyLoss 函数并将最后一层的输出节点扩展为 2 时,我的网络实际上开始学习!虽然使用“正确”的损失函数,我的网络对于目标类的准确率甚至达不到 1%,但使用交叉熵损失,我在几个时期后甚至可以达到 90% 以上。
根据我的理解,交叉熵损失更适合多类分类问题,而二元交叉熵更适合二元分类问题,如名称所示,所以我不明白这是怎么回事。
最初,我从一个更简单的 CNN 开始,因为这是我第一次构建 CNN。因此,经过更多研究后,我得出的结论是,部分原因可能是由于缺乏层次和复杂性。因此,我添加了更多层并最终得到了这个蓝图:
import torch.nn as nn
import torch.nn.functional as F
class ConvolutionalNN(nn.Module):
def __init__(self):
super(ConvolutionalNN, self).__init__()
self.conv1 = nn.Conv2d(3, 9, 5)
self.conv2 = nn.Conv2d(9, 27, 5)
self.conv3 = nn.Conv2d(27, 54, 5)
self.conv4 = nn.Conv2d(54, 108, 5)
self.conv5 = nn.Conv2d(108, 216, 5)
self.conv6 = nn.Conv2d(216, 432, 5)
self.pool = nn.MaxPool2d(3, 3)
self.fc1 = nn.Linear(432*4*4, 256)
self.fc2 = nn.Linear(256, 64)
self.fc3 = nn.Linear(64, 2)
def forward(self, x):
x = (F.relu(self.conv1(x))) #First convolutional layer, then activation function
x = self.pool(F.relu(self.conv2(x))) #Second layer, activation function, then pooling layer
x = (F.relu(self.conv3(x)))
x = self.pool(F.relu(self.conv4(x)))
x = (F.relu(self.conv5(x)))
x = self.pool(F.relu(self.conv6(x)))
x = x.reshape(-1, 432*4*4) #Flattens the tensor
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
我的部分灵感来自 VGGNET 中使用的双卷积层。此外,我在这方面缺乏经验,所以如果有人有任何建议,我非常乐意接受。
我使用了 0.001 和 0.0001 的学习率。我正在使用 Adam 优化器。此外,我的标签不是一次性编码的。在上面的例子中,我使用了 2 个输出节点来与 CrossEntropyLoss 配合,但是之前我为 BCE 使用了 1 个输出节点。
我期待任何帮助!非常感谢!
您在应用 BCELoss 之前是否使用 sigmoid 函数?如果没有,请尝试使用 BCEWithLogitsLoss,因为它能够接受神经网络的原始输出。 BCELoss 期望的是概率,而不是逻辑。