我主要关注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)
Weights of training data based on proportion of the training labels. Not compted here [0.02915033 0.13259828 0.13950368 0.1422567 0.14233398 0.14176525 0.13285154 0.13954024] 1.0000000000000002
我已经使用transforms.function.normalize函数对数据进行了标准化。我计算了训练数据的平均值和标准差,并将此增强添加到我的数据加载器中。
dataset_train = data_utils.SatIn(data_path, 'TrainValTest.csv', 'train', transform=transforms.Compose([aug.ToTensorTarget(), aug.NormalizeTarget(mean=popmean, std=popstd)]))
我通过旋转和翻转图像来增强预处理中的训练数据。 1 个图像网格然后变成 8 个。
我检查了我的训练数据是否与我的类(class)相匹配,并且所有内容都已检查完毕。 由于我使用 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)
一些纪元迭代输出
#### Epoch 0/19---------- training: 100%|████████████████████████████████████████████████████████████████████████| 84/84 [00:17<00:00, 5.77it/s] Training Loss: 0.8901, Accuracy: 0.83 Current elapsed time 2m 6s
#### Epoch 1/19---------- training: 100%|████████████████████████████████████████████████████████████████████████| 84/84 [00:17<00:00, 5.72it/s] Training Loss: 0.7922, Accuracy: 0.83 Current elapsed time 2m 24s
#### Epoch 2/19---------- training: 100%|████████████████████████████████████████████████████████████████████████| 84/84 [00:18<00:00, 5.44it/s] Training Loss: 0.8753, Accuracy: 0.84 Current elapsed time 2m 42s
#### Epoch 3/19---------- training: 100%|████████████████████████████████████████████████████████████████████████| 84/84 [00:18<00:00, 5.53it/s] Training Loss: 0.7741, Accuracy: 0.84 Current elapsed time 3m 1s
最佳答案
很难用这些信息来调试你的模型,但也许其中一些想法会以某种方式帮助你:
- 尝试在更小的数据和许多纪元上过度拟合您的网络,而不首先进行扩充,例如对于许多纪元的一到两批。如果此方法不起作用,则您的模型无法对数据和所需目标之间的关系进行建模,或者您在某处出现错误。此外,这样调试起来也更容易。
- 我不确定权重的想法,也许可以尝试对代表性不足的类进行上采样,以使其更加平衡(重复数据集中的一些代表性不足的示例)。很好奇这个想法是从哪里来的,从来没有听说过。
- 在应用您自己的自定义设置之前,您是否尝试过从您提供的存储库运行模型?它的表现如何,你能够复制他们的发现吗?据我了解,为什么您认为这种架构非常适合您的不同情况?您提供的链接中的损失函数不同,但架构是相同的。我没有读过这篇论文,也没有尝试过你的模型,但这似乎有点奇怪。
- GitHub 存储库内的链接指向一篇博文,其中建议使用更大的批处理以稳定训练,您的批处理大小是多少?
- 也许可以从更小、更简单的模型开始,然后逐步升级?
最重要的放在最后;我不认为 SO 是解决此类问题的最佳地点(特别是因为它是研究导向的),我看到您已经在 GitHub 问题上提出过这个问题,也许尝试直接联系作者?
如果我是你,我会从最后一点开始,彻底了解运营及其对你目标的影响,祝你好运。
关于python - 神经网络训练有问题。损失不减,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54116080/