【问题标题】:Why the predictions are very off (which causes very large losses)?为什么预测非常偏离(这会导致非常大的损失)?
【发布时间】:2021-01-29 03:28:21
【问题描述】:

我有一个非常简单的 resnet18 网络,我正在尝试从头开始训练以完成地标估计任务(我有 4 个地标):

num_classes = 4 * 2 #4 coordinates X and Y flattened --> 4 of 2D keypoints or landmarks

class Network(nn.Module):
    def __init__(self,num_classes=8):
        super().__init__()
        self.model_name = 'resnet18'
        self.model = models.resnet18()
        self.model.fc = nn.Linear(self.model.fc.in_features, num_classes)
        
    def forward(self, x):
        x = x.float()
        out = self.model(x)
        return out

以下代码:

network = Network()
network.cuda()    

criterion = nn.MSELoss()
optimizer = optim.Adam(network.parameters(), lr=0.0001)

loss_min = np.inf
num_epochs = 1

start_time = time.time()
for epoch in range(1,num_epochs+1):
    
    loss_train = 0
    loss_test = 0
    running_loss = 0
    
    
    network.train()
    print('size of train loader is: ', len(train_loader))

    for step in range(1,len(train_loader)+1):

        
        batch = next(iter(train_loader))
        images, landmarks = batch['image'], batch['landmarks']
        #RuntimeError: Given groups=1, weight of size [64, 3, 7, 7], expected input[64, 600, 800, 3] to have 3 channels, but got 600 channels instead
        #using permute to fix the above error
        images = images.permute(0,3,1,2)
        
        images = images.cuda()
    
        landmarks = landmarks.view(landmarks.size(0),-1).cuda() 
        
        
        ##images = torchvision.transforms.Normalize(images) #find the args later
        ##landmarks = torchvision.transforms.Normalize(landmarks) #find the args later
        
        predictions = network(images)
        
        # clear all the gradients before calculating them
        optimizer.zero_grad()
        
        print('predictions are: ', predictions.float())
        print('landmarks are: ', landmarks.float())
        # find the loss for the current step
        loss_train_step = criterion(predictions.float(), landmarks.float())
        
        
        loss_train_step = loss_train_step.to(torch.float32)
        print("loss_train_step before backward: ", loss_train_step)
        
        # calculate the gradients
        loss_train_step.backward()
        
        # update the parameters
        optimizer.step()
        
        print("loss_train_step after backward: ", loss_train_step)

        
        loss_train += loss_train_step.item()
        
        print("loss_train: ", loss_train)
        running_loss = loss_train/step
        print('step: ', step)
        print('running loss: ', running_loss)
        
        print_overwrite(step, len(train_loader), running_loss, 'train')
        
    network.eval() 
    with torch.no_grad():
        
        for step in range(1,len(test_loader)+1):
            
            batch = next(iter(train_loader))
            images, landmarks = batch['image'], batch['landmarks']
            images = images.permute(0,3,1,2)
            images = images.cuda()
            landmarks = landmarks.view(landmarks.size(0),-1).cuda()
        
            predictions = network(images)

            # find the loss for the current step
            loss_test_step = criterion(predictions, landmarks)

            loss_test += loss_test_step.item()
            running_loss = loss_test/step

            print_overwrite(step, len(test_loader), running_loss, 'Validation')
    
    loss_train /= len(train_loader)
    loss_test /= len(test_loader)
    
    print('\n--------------------------------------------------')
    print('Epoch: {}  Train Loss: {:.4f} Valid Loss: {:.4f}'.format(epoch, loss_train, loss_test))
    print('--------------------------------------------------')
    
    if loss_test < loss_min:
        loss_min = loss_test
        torch.save(network.state_dict(), '../moth_landmarks.pth') 
        print("\nMinimum Valid Loss of {:.4f} at epoch {}/{}".format(loss_min, epoch, num_epochs))
        print('Model Saved\n')
     
print('Training Complete')
print("Total Elapsed Time : {} s".format(time.time()-start_time))

我得到这个 NAN 以及非常大的 MSE 损失(仅显示一步):

size of train loader is:  90
predictions are:  tensor([[-0.0380, -0.1871,  0.0729, -0.3570, -0.2153,  0.3066,  1.1273, -0.0558],
        [-0.0316, -0.1876,  0.0317, -0.3613, -0.2333,  0.3023,  1.0940, -0.0665],
        [-0.0700, -0.1882,  0.0068, -0.3201, -0.1884,  0.2953,  1.0516, -0.0567],
        [-0.0844, -0.2009,  0.0573, -0.3166, -0.2597,  0.3127,  1.0343, -0.0573],
        [-0.0486, -0.2333,  0.0535, -0.3245, -0.2310,  0.2818,  1.0590, -0.0716],
        [-0.0240, -0.1989,  0.0572, -0.3135, -0.2435,  0.2912,  1.0612, -0.0560],
        [-0.0942, -0.2439,  0.0277, -0.3147, -0.2368,  0.2978,  1.0110, -0.0874],
        [-0.0356, -0.2285,  0.0064, -0.3179, -0.2432,  0.3083,  1.0300, -0.0756]],
       device='cuda:0', grad_fn=<AddmmBackward>)
landmarks are:  tensor([[501.9200, 240.1600, 691.0000, 358.0000, 295.0000, 294.0000, 488.6482,
         279.6466],
        [495.6300, 246.0600, 692.0000, 235.0000, 286.0000, 242.0000, 464.0000,
         339.0000],
        [488.7100, 240.8900, 613.4007, 218.3425, 281.0000, 220.0000, 415.9966,
         338.4796],
        [502.5721, 245.4983, 640.0000, 131.0000, 360.0000, 143.0000, 542.9840,
         321.8463],
        [505.1393, 246.4364, 700.0000, 306.0000, 303.0000, 294.0000, 569.6925,
         351.8367],
        [501.0900, 244.0100, 724.0000, 251.0000, 302.0000, 276.0000, 504.6415,
         291.7443],
        [495.9500, 244.2800, 608.0000, 127.0000, 323.0000, 166.0000, 491.0000,
         333.0000],
        [490.2500, 241.3400, 699.0000, 304.0000, 398.6197, 313.8339, 429.1374,
         303.8483]], device='cuda:0')
loss_train_step before backward:  tensor(166475.6875, device='cuda:0', grad_fn=<MseLossBackward>)
loss_train_step after backward:  tensor(166475.6875, device='cuda:0', grad_fn=<MseLossBackward>)
loss_train:  166475.6875
step:  1
running loss:  166475.6875

除了网络之外我还怀疑的另一件事是转换:

这是我正在使用的转换:

transformed_dataset = MothLandmarksDataset(csv_file='moth_gt.csv',
                                           root_dir='.',
                                           transform=transforms.Compose(
                                               [
                                               Rescale(256),
                                               RandomCrop(224),
                                               
                                               ToTensor()#,
                                               ##transforms.Normalize(mean = [ 0.485, 0.456, 0.406 ],
                                               ##         std = [ 0.229, 0.224, 0.225 ])
                                               ]
                                                                        )
                                           )

我该如何解决?此外,使用 Normalize 我仍然会遇到同样的问题(NAN 和非常大的损失值,因为预测非常偏离)。

我怎样才能基本上调试为什么预测非常不正确?

【问题讨论】:

  • 我看到你只使用了 1 个 epoch,你尝试过更多吗?
  • 嗯,情况更糟。我展示一个时代只是为了说明。

标签: python deep-learning pytorch prediction loss-function


【解决方案1】:

我认为您使用DataLoader 的方式有问题。 iter(train_loader) 从数据加载器中创建一个迭代器,调用 next 应该会为您提供数据集中的下一个示例。但是您在每次迭代中调用next(iter(train_loader)),它每次都会从train_loader 创建一个新的迭代器并返回下一个示例,该示例基本上是您数据集中的第一个示例。所以我认为这样你最终会在每次迭代中对同一个例子进行训练(和验证)。即使您的数据加载器每次都对数据集进行洗牌,您最终还是会在数据集中的一些随机样本上进行训练(因为每次只会使用第一个随机样本),而不是在完整的数据集上进行训练。尝试更改您的代码,使您只使用一次iter(train_loader),并在每次迭代中调用next

train_iter = iter(train_loader)
for step in range(1, len(train_loader)+1):
    batch = next(train_iter)
    # now batch contains (step)th batch (assuming 1-based indexing)

或者甚至更好地更改您的 for 循环以迭代 train_loader 本身:

for step, batch in enumerate(train_loader):
    # now batch contains (step)th batch (assuming 0-based indexing)

验证或评估也需要进行类似的更改。如果这能解决您的问题或有任何帮助,请告诉我。

【讨论】:

    猜你喜欢
    • 2017-01-11
    • 1970-01-01
    • 2017-12-04
    • 1970-01-01
    • 1970-01-01
    • 2022-01-02
    • 1970-01-01
    • 2015-06-08
    • 2014-12-04
    相关资源
    最近更新 更多