神经网络训练有问题。损失没有减少

时间:2019-01-09 18:14:29

标签: python machine-learning pytorch

我主要关注this项目,但正在按像素分类。我有8个班级和9个波段图像。我的图像被网格化为9x128x128。我的损失并没有减少,培训的准确性也没有太大的波动。我猜我的模型有问题。任何建议深表感谢!使用随机森林,至少可以达到91%的准确性。

我的课程非常不平衡,因此我尝试根据培训数据中课程的比例来调整培训权重。

# get model
learning_rate = 0.0001
model = unet.UNetSmall(8)
optimizer = optim.Adam(model.parameters(), lr=learning_rate)

# set up weights based on data proportion
weights = np.array([0.79594768, 0.07181202, 0.02347426, 0.0042031, 0.00366211, 0.00764327, 0.07003923, 0.02321833])
weights = (1 - weights)/7
print('Weights of training data based on proportion of the training labels.  Not compted here')
print(weights)
print(sum(weights))
criterion = nn.CrossEntropyLoss(weight = weight)
lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.1)
  

基于训练标签比例的训练数据权重。   此处未编译[0.02915033 0.13259828 0.13950368 0.1422567   0.14233398 0.14176525    0.13285154 0.13954024]   1.0000000000000002

我已经使用transforms.functional.normalize函数对数据进行了标准化。我计算了训练数据的均值和标准差,并将这种扩充添加到了数据加载器中。

dataset_train = data_utils.SatIn(data_path, 'TrainValTest.csv', 'train', transform=transforms.Compose([aug.ToTensorTarget(), aug.NormalizeTarget(mean=popmean, std=popstd)]))

我通过旋转和翻转图像来增强预处理中的训练数据。 1个图像网格变为8个。

我检查了我的训练数据是否与我的课程匹配,并且所有内容都已签出。 由于我正在使用8个类,因此我选择使用CrossEntropyLoss,因为它内置了Softmax。

当前模型

class UNetSmall(nn.Module):
    """
    Main UNet architecture
    """
    def __init__(self, num_classes=1):
        super().__init__()
        # encoding
        self.conv1 = encoding_block(9, 32)
        self.maxpool1 = nn.MaxPool2d(kernel_size=2)
        self.conv2 = encoding_block(32, 64)
        self.maxpool2 = nn.MaxPool2d(kernel_size=2)
        self.conv3 = encoding_block(64, 128)
        self.maxpool3 = nn.MaxPool2d(kernel_size=2)
        self.conv4 = encoding_block(128, 256)
        self.maxpool4 = nn.MaxPool2d(kernel_size=2)

        # center
        self.center = encoding_block(256, 512)

        # decoding
        self.decode4 = decoding_block(512, 256)
        self.decode3 = decoding_block(256, 128)
        self.decode2 = decoding_block(128, 64)
        self.decode1 = decoding_block(64, 32)

        # final
        self.final = nn.Conv2d(32, num_classes, kernel_size=1)

    def forward(self, input):

        # encoding
        conv1 = self.conv1(input)
        maxpool1 = self.maxpool1(conv1)
        conv2 = self.conv2(maxpool1)
        maxpool2 = self.maxpool2(conv2)
        conv3 = self.conv3(maxpool2)
        maxpool3 = self.maxpool3(conv3)
        conv4 = self.conv4(maxpool3)
        maxpool4 = self.maxpool4(conv4)

        # center
        center = self.center(maxpool4)

        # decoding
        decode4 = self.decode4(conv4, center)
        decode3 = self.decode3(conv3, decode4)
        decode2 = self.decode2(conv2, decode3)
        decode1 = self.decode1(conv1, decode2)
        # final
        final = nn.functional.upsample(self.final(decode1), input.size()[2:], mode='bilinear')
        return final

训练方法

def train(train_loader, model, criterion, optimizer, scheduler, epoch_num):

    correct = 0
    totalcount = 0

    scheduler.step()

    # iterate over data
    for idx, data in enumerate(tqdm(train_loader, desc="training")):
        # get the inputs and wrap in Variable
        if torch.cuda.is_available():
            inputs = Variable(data['sat_img'].cuda())
            labels = Variable(data['map_img'].cuda())
        else:
            inputs = Variable(data['sat_img'])
            labels = Variable(data['map_img'])

        optimizer.zero_grad()
        outputs = model(inputs)
        loss = criterion(outputs, labels.long())
        loss.backward()
        optimizer.step()

        test = torch.max(outputs.data, 1)[1] == labels.long()
        correct += test.sum().item()
        totalcount += test.size()[0] * test.size()[1] * test.size()[2]

    print('Training Loss: {:.4f}, Accuracy: {:.2f}'.format(loss.data[0], correct/totalcount))
    return {'train_loss': loss.data[0], 'train_acc' : correct/totalcount}

时代循环中的训练电话

lr_scheduler.step()
train_metrics = train(train_dataloader, model, criterion, optimizer, lr_scheduler, epoch)

一些时代迭代输出

  ####时代0/19      

----------培训:100%|█████████████████████████████████ ██████████████████████████████████████████|   84/84 [00:17 <00:00,5.77it / s]训练损失:0.8901,准确性:0.83   当前经过时间2m 6s

     ####时代1/19      

----------培训:100%|█████████████████████████████████ ██████████████████████████████████████████|   84/84 [00:17 <00:00,5.72it / s]训练损失:0.7922,准确性:0.83   当前经过时间2m 24s

     ####时代2/19      

----------培训:100%|█████████████████████████████████ ██████████████████████████████████████████|   84/84 [00:18 <00:00,5.44it / s]训练损失:0.8753,准确性:0.84   当前经过时间2m 42s

     ####时代3/19      

----------培训:100%|█████████████████████████████████ ██████████████████████████████████████████|   84/84 [00:18 <00:00,5.53it / s]训练损失:0.7741,准确性:0.84   当前经过时间3m 1s

2 个答案:

答案 0 :(得分:1)

该模型不适合我的目的,我对它们的了解还不足以知道原因。我切换到另一个here发现的unet模型,一切开始正常工作。
随随机森林生产的产品而增加的准确性。当我尝试消除权重时,我正在遭受损失。使用新方法时,损失从原来的0.5降低到了〜0.2。在最初的50个时期中,训练的准确性很快就提高到了80年代的高点,在接下来的50个时期中并没有超过。

我计划测试一些不同的模型,这些模型与作者在this论文中所做的相似。我将创建一个简单的基础并将结果与​​UNet和VGG16进行比较。

答案 1 :(得分:0)

很难用这些信息调试模型,但是也许其中一些想法会以某种方式为您提供帮助:

  1. 请尝试在较小的数据和许多纪元上使网络过拟合,而不要先扩充,例如说许多纪元要进行两个批处理。如果此方法不起作用,则说明您的模型无法为数据与所需目标之间的关系建模,或者您在某处出错。此外,以这种方式进行调试更容易。
  2. 我不确定权重的想法,也许尝试对代表性不足的类进行上采样,以使其更加平衡(在数据集中重复一些代表性不足的示例)。好奇这个想法从何而来,从未听说过。
  3. 您是否尝试过应用自定义项之前从提供的存储库中运行模型?效果如何,您能否复制他们的发现?从我的理解来看,您为什么认为这种体系结构适合您的不同情况?您提供的链接中的损失函数是不同的,而体系结构是相同的。我还没有阅读本文,也没有尝试过您的模型,但这似乎有些奇怪。
  4. GitHub存储库中的链接指向一个博客文章,在此文章中建议进行较大批量以稳定培训,您的批量大小是多少?
  5. 也许可以从更小,更简单的模型开始,然后逐步发展?

最重要的是最后一个;我不认为SO是解决此类问题的最佳地点(尤其是面向研究的问题),但是我看到您已经在GitHub问题上提出了要求,也许尝试直接与作者联系?

如果我是您,那么我将从最后一点开始,并彻底了解操作及其对您目标的影响,祝您好运。