Pytorch Resnet CNN 仅在测试数据包含所有 类 时才有效

Pytorch Resnet CNN only works when test data contains all classes

希望能解决一个奇怪的 CNN 训练问题。

我正在训练一个 Resnet classifier 来预测来自 ~10k 图像数据集的 4 classes 图像。代码非常简单。这是 Resnet/CNN 设置部分:

####################################
########### LOAD RESNET ############
####################################
device = torch.device("cuda" if torch.cuda.is_available() 
                                  else "cpu")
model = models.resnet50(pretrained=True)

# 
for param in model.parameters():
    param.requires_grad = False
    
# 
model.fc = nn.Sequential(nn.Linear(2048, 512),
                                 nn.ReLU(),
                                 #nn.Dropout(0.2),
                                 nn.Linear(512, 10),
                                 nn.LogSoftmax(dim=1))

# 
criterion = nn.NLLLoss()

# 
optimizer = optim.Adam(model.fc.parameters(), lr=0.003)

# move model to gpu
model.to(device) 

这里是训练阶段(它对 500 张图像中的数据进行批处理并打乱测试数据集)和一些时期后的一些准确性结果:

   trainloader, testloader, n_batches = make_trainloader(all_data, 
                                                          vals, 
                                                          batch_size=500,
                                                          randomize=True)
    ...
    for inputs, labels in trainloader:
        ...
        inputs, labels = inputs.to(device), labels.to(device)
        
        ...
        # PREDICT;
        outputs = model(inputs)

...

epoch #:  12
Loss: 0.1689 Acc: 0.9400
labels:       tensor([0, 0, 1, 0, 3, 0, 0, 2, 1, 2], device='cuda:0')
predictions:  tensor([0, 0, 1, 0, 3, 0, 0, 2, 1, 2], device='cuda:0') 

所以奇怪的是,我似乎无法很好地预测单个图像,而只能预测混合 classes 的大批量数据。例如,如果我提供来自 class 1 的 500 张图像,则预测是随机的,但如果我提供来自 4 class 的 500 张混合图像(很像在训练期间),则预测很好(只是就像在训练中一样)。

我似乎对如何在单个图像上使用 ResNet classifier 感到困惑,尽管它似乎确实学会了预测输入数据的各个标签(参见上面的标签和预测输出).或者我的 classifier 不是学习单个图像,而是学习图像组,不确定。

感谢任何帮助或指导(我可以提供更多代码,但不想写太长的消息)。这是预测代码:

# Predict
randomize = False

# load data from above
inputs = test_data[:2000]
vals_inputs = test_vals[:2000]

print ("test data size: ", vals_inputs.shape)

trainloader, testloader, n_batches = make_trainloader(inputs, 
                                                      vals_inputs, 
                                                      batch_size=500,
                                                      randomize=randomize)
for inputs, labels in trainloader:
    # load to device
    inputs, labels = inputs.to(device), labels.to(device)

    # PREDICT;
    outputs = model(inputs)
    _, preds = torch.max(outputs, 1)

    print ("prediction: ", preds[:10])
    print ("labels: ", labels[:10])
    ...

test data size:  torch.Size([2000])
prediction:  tensor([1, 1, 2, 1, 2, 3, 2, 3, 2, 3], device='cuda:0')
labels:      tensor([0, 0, 0, 0, 0, 0, 0, 0, 0, 0], device='cuda:0')
0 Loss: 3.2936 Acc: 0.1420

prediction:  tensor([1, 3, 3, 3, 3, 1, 2, 1, 1, 2], device='cuda:0')
labels:      tensor([1, 1, 1, 1, 1, 1, 1, 1, 1, 1], device='cuda:0')
0 Loss: 2.1462 Acc: 0.2780

prediction:  tensor([3, 3, 1, 2, 0, 1, 2, 1, 3, 2], device='cuda:0')
labels:      tensor([2, 2, 2, 2, 2, 2, 2, 2, 2, 2], device='cuda:0')
0 Loss: 2.1975 Acc: 0.2560

与我简单地打乱数据相比,准确率非常高:

# Predict
randomize = True
...
test data size:  torch.Size([2000])
prediction:  tensor([0, 0, 3, 2, 0, 2, 0, 3, 0, 2], device='cuda:0')
labels:      tensor([0, 0, 3, 2, 0, 2, 0, 3, 0, 2], device='cuda:0')
0 Loss: 0.1500 Acc: 0.9580

prediction:  tensor([0, 3, 3, 3, 0, 0, 3, 2, 3, 3], device='cuda:0')
labels:      tensor([0, 2, 3, 0, 0, 0, 3, 2, 0, 3], device='cuda:0')
0 Loss: 0.1714 Acc: 0.9340

prediction:  tensor([3, 3, 2, 2, 3, 1, 3, 0, 2, 2], device='cuda:0')
labels:      tensor([3, 3, 2, 2, 3, 1, 3, 0, 2, 2], device='cuda:0')
0 Loss: 0.1655 Acc: 0.9400

您需要在测试前调用 model.eval()。 (并在训练前通过调用 model.train() 将其改回)

在训练模式下,BatchNorm 将通过均值和方差对您的特征进行归一化。您可以预期所有 类 均为 1 的批次与混合 类.

的批次具有非常不同的统计数据