分类图像的准确性没有增加

accuracy is not increasing in classification images

我尝试使用 dropout 用贝叶斯 CNN 实现图像分类。
我定义了两个 类:

  1. 训练阶段有 dropout
  2. 无辍学(不辍学?请确认)

当我启动程序时,我重新设置 train/test 准确度保持稳定,不会增加。没看出来是什么问题
不知道是因为卷积层和池化层的参数还是什么?有什么想法吗

class Net(nn.Module):
   
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5, padding=2)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5, padding=2)
        self.fc1 = nn.Linear(16 * 8 * 8, 1024)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 192 * 8 * 8)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

            # Lenet with MCDO
    class Net_MCDO(nn.Module):
        def __init__(self):
            super(Net_MCDO, self).__init__()
            self.conv1 = nn.Conv2d(3, 6, 5, padding=2)
            self.pool = nn.MaxPool2d(2, 2)
            self.conv2 = nn.Conv2d(16, 192, 5, padding=2)
            self.fc1 = nn.Linear(16 * 8 * 8, 120)
            self.fc2 = nn.Linear(120, 84)
            self.fc3 = nn.Linear(84, 10)
            self.dropout = nn.Dropout(p=0.3)

    def forward(self, x):
            x = self.pool(self.dropout(self.conv1(x)))
            x = self.pool(self.dropout(self.conv2(x)))
            x = x.view(-1, 192 * 8 * 8)
            x = F.relu(self.fc1(x))
            x = F.relu(self.fc2(self.dropout(x)))
            x = F.softmax(self.fc3(self.dropout(x)),dim=1)
            return x
    net=Net()
    mcdo=Net_MCDO()
    
    CE = nn.CrossEntropyLoss()
    learning_rate=0.001
    optimizer=optim.SGD(net.parameters(), lr=learning_rate, momentum=0.9)
    epoch_num = 30
    train_accuracies=np.zeros(epoch_num)
    test_accuracies=np.zeros(epoch_num)
    for epoch in range(epoch_num):
        average_loss = 0.0
        total=0
        success=0
        
        for i, data in enumerate(trainloader, 0):
            inputs, labels = data
            inputs, labels = Variable(inputs), Variable(labels)
            
            optimizer.zero_grad()
            outputs = mcdo(inputs)
            loss=CE(outputs, labels)
            loss.backward()
            optimizer.step()
 
            average_loss += loss.item()
            _, predicted = torch.max(outputs.data, 1)
            total += labels.size(0)
            success += (predicted==labels.data).sum()
 
        train_accuracy = 100.0*success/total
        succes=0
        total=0

        for (inputs, labels) in testloader:
            inputs, labels = Variable(inputs), Variable(labels)
            outputs = net(inputs)
            _,predicted = torch.max(outputs.data, 1)
            total += labels.size(0)
            success += (predicted==labels.data).sum()

        test_accuracy = 100.0*success/total
        print(u"epoch{}, average_loss{}, train_accuracy{},                 
          test_accuracy{}".format(
          epoch,
          average_loss/n_batches,
          train_accuracy,
          100*success/total
          ))
            #save
            train_accuracies[epoch] = train_accuracy
            test_accuracies[epoch] = 100.0*success/total

    plt.plot(np.arange(1, epoch_num+1), train_accuracies)
    plt.plot(np.arange(1, epoch_num+1), test_accuracies)
    plt.show()

是的,你是对的:测试时不要使用 dropout(也不是 batchnorm)。但是您不必为此创建不同的模型。您可以在训练模式和测试模式之间进行选择。只需创建一个模型,例如 'net':

# when training
outputs = net.train()(inputs)

# when testing:
outputs = net.eval()(inputs)

但是无论如何你都不应该真的使用 dropout 和 conv-layers。就在最后的致密层上。这可能是它没有改善的原因。 而且您的架构很小。你的图片有多大?如果它们超过 32x32,您可以尝试再添加一层。您也可以尝试从大约 0.001 的学习率开始,然后每次在某些时期的准确性没有提高时将其除以二。希望这会对你有所帮助:)

编辑 我刚刚看到您在第二个模型(带 dropout)上缺少 relu 激活,这应该会导致问题。

Pytorch 将 Softmax 合并到 CrossEntroplyLoss 中以获得数值稳定性(以及更好的训练)。所以你应该删除模型的 softmax 层。 (查看此处的文档:https://pytorch.org/docs/stable/nn.html#crossentropyloss)。在模型中保留 Sofmax 层会导致训练速度变慢,指标可能更差,这是因为您 压缩 梯度两次,因此权重更新的意义不大.

将您的代码更改为:

 class Net_MCDO(nn.Module):
        def __init__(self):
            super(Net_MCDO, self).__init__()
            self.conv1 = nn.Conv2d(3, 6, 5, padding=2)
            self.pool = nn.MaxPool2d(2, 2)
            self.conv2 = nn.Conv2d(16, 192, 5, padding=2)
            self.fc1 = nn.Linear(16 * 8 * 8, 120)
            self.fc2 = nn.Linear(120, 84)
            self.fc3 = nn.Linear(84, 10)
            self.dropout = nn.Dropout(p=0.3)

    def forward(self, x):
            x = self.pool(F.relu(self.dropout(self.conv1(x))))  # recommended to add the relu
            x = self.pool(F.relu(self.dropout(self.conv2(x))))  # recommended to add the relu
            x = x.view(-1, 192 * 8 * 8)
            x = F.relu(self.fc1(x))
            x = F.relu(self.fc2(self.dropout(x)))
            x = self.fc3(self.dropout(x)) # no activation function needed for the last layer
            return x 

此外,我建议您在每个 conv 或线性层之后使用激活函数,例如 ReLU()。否则你只是在执行一堆可以在一个单层中学习的线性操作。

希望对您有所帮助=)