FCN8进行图像语义分割总是欠拟合,效果很差,如何解决

选的adam优化器,损失函数用的交叉熵,学习率0.0001,学习率大了loss也比较大效果最后也不好
这是标签各种像素的占比

img

这是根据占比胡乱试的损失函数的权重,现在不知道咋解决欠拟合,第一次弄,请教

img

  • 你可以参考下这个问题的回答, 看看是否对你有帮助, 链接: https://ask.csdn.net/questions/7642390
  • 除此之外, 这篇博客: 语义分割之FCN中的 2.4 网络loss层 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • FCN网络的输入batchsize是1,因为分割loss的计算在每一个像素点都一个真值(标签),相当于每一个像素点的都是一个分类任务softmax,一个图像就有对应像素点个样本。所以分割任务的batch是一个图片,将一个图片最后在所有像素点上的分类loss加起来计算一次梯度的更新。

该回答通过自己思路及引用到GPTᴼᴾᴱᴺᴬᴵ搜索,得到内容具体如下:
以下是一些具体的改进建议:

1、 增加模型复杂度

您可以尝试增加 FCN8 模型的通道数或增加网络的层数。例如,可以将 FCN8 中的卷积层和池化层的通道数增加到更大的值,例如 64、128、256 等。您还可以考虑增加更多的卷积层和池化层,以增加模型的深度和复杂度。

2、 增加训练数据

您可以尝试使用数据增强技术,例如随机旋转、平移、缩放、裁剪等来生成更多的训练数据。以下是一些常用的数据增强方法:

transforms.Compose([
    transforms.RandomRotation(degrees=15),
    transforms.RandomHorizontalFlip(),
    transforms.RandomVerticalFlip(),
    transforms.RandomResizedCrop(size=256, scale=(0.8, 1.0)),
    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])

3、 调整优化器和学习率

您可以尝试使用其他优化器,例如 SGD、RMSprop 等,或者调整 Adam 优化器的超参数,例如 beta1、beta2、epsilon 等。此外,您可以尝试调整学习率的初始值和衰减策略,以获得更好的性能。以下是一个示例:

optimizer = torch.optim.Adam(model.parameters(), lr=0.0001, betas=(0.9, 0.999), eps=1e-08)
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)

4、 调整损失函数的权重

根据您提供的标签像素占比,可以看出背景和水体的像素占比较大,而水藻、枯枝败叶和垃圾的像素占比较小。因此,您可能需要调整损失函数的权重,使得模型更加关注水藻、枯枝败叶和垃圾等类别。以下是一个示例:

class_weights = torch.tensor([0.0016, 30, 20, 10, 0.0015])
criterion = nn.CrossEntropyLoss(weight=class_weights)

5、 调整训练策略

您可以尝试调整训练的批量大小、训练的轮数、数据的随机顺序等,以获得更好的性能。以下是一个示例:

batch_size = 8
num_epochs = 50

for epoch in range(num_epochs):
    for i, (images, masks) in enumerate(train_loader):
        # Forward pass
        outputs = model(images)
        loss = criterion(outputs, masks)

        # Backward and optimize
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        # Update learning rate
        scheduler.step()

        # Print loss
        if (i+1) % 10 == 0:
            print ('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}'
                   .format(epoch+1, num_epochs, i+1, len(train_loader), loss.item()))

最后,还可以尝试使用预训练模型或迁移学习的方法,以加速模型的训练和提高模型的性能。


如果以上回答对您有所帮助,点击一下采纳该答案~谢谢

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
欠拟合的原因可能有很多,以下是一些可能的解决方案:

  1. 数据集太小:如果数据集太小,可能无法充分训练模型。可以尝试通过数据增强(如旋转、翻转、缩放等)来扩充数据集,或者使用预训练模型进行迁移学习。

  2. 学习率太低:学习率太低可能会导致模型收敛缓慢。可以尝试增加学习率,或者使用学习率衰减策略。

  3. 模型过于简单:如果模型太简单,可能无法捕捉到数据中复杂的模式。可以尝试增加网络层数或者使用更复杂的模型。

  4. 损失函数过于简单:如果损失函数过于简单,可能无法充分表达目标函数。可以尝试使用更复杂的损失函数。

  5. 训练次数太少:如果训练次数太少,可能无法将模型训练到最优。可以尝试增加训练次数或者使用早停策略。

以下是一个简单的代码示例,展示了如何进行图像分割任务:

import torch
import torch.nn as nn
import torch.optim as optim

class FCN8(nn.Module):
    def __init__(self, num_classes):
        super(FCN8, self).__init__()
        self.conv_block1 = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=100),
            nn.ReLU(inplace=True),
            nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True)
        )
        self.conv_block2 = nn.Sequential(
            nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True)
        )
        self.conv_block3 = nn.Sequential(
            nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True)
        )
        self.conv_block4 = nn.Sequential(
            nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True)
        )
        self.conv_block5 = nn.Sequential(
            nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True)
        )
        self.fc6 = nn.Sequential(
            nn.Conv2d(512, 4096, kernel_size=7),
            nn.ReLU(inplace=True),
            nn.Dropout2d()
        )
        self.fc7 = nn.Sequential(
            nn.Conv2d(4096, 4096, kernel_size=1),
            nn.ReLU(inplace=True),
            nn.Dropout2d()
        )
        self.score_fr = nn.Conv2d(4096, num_classes, kernel_size=1)
        self.score_pool3 = nn.Conv2d(256, num_classes, kernel_size=1)
        self.score_pool4 = nn.Conv2d(512, num_classes, kernel_size=1)
        self.upscore2 = nn.ConvTranspose2d(num_classes, num_classes, kernel_size=4, stride=2, bias=False)
        self.upscore8 = nn.ConvTranspose2d(num_classes, num_classes, kernel_size=16, stride=8, bias=False)
        self.upscore_pool4 = nn.ConvTranspose2d(num_classes, num_classes, kernel_size=4, stride=2, bias=False)

    def forward(self, x):
        conv1 = self.conv_block1(x)
        conv2 = self.conv_block2(conv1)
        conv3 = self.conv_block3(conv2)
        conv4 = self.conv_block4(conv3)
        conv5 = self.conv_block5(conv4)
        fc6 = self.fc6(conv5)
        fc7 = self.fc7(fc6)
        score_fr = self.score_fr(fc7)
        upscore2 = self.upscore2(score_fr)
        score_pool4 = self.score_pool4(conv4)
        upscore_pool4 = self.upscore_pool4(score_pool4)
        score_pool3 = self.score_pool3(conv3)
        score = upscore2 + upscore_pool4[:, :, :, :score_pool4.size()[3]] + score_pool3[:, :, :upscore2.size()[2]:, :upscore2.size()[3]]
        upscore8 = self.upscore8(score)
        return upscore8

# 定义损失函数
criterion = nn.CrossEntropyLoss()

# 定义优化器
optimizer = optim.Adam(model.parameters(), lr=0.0001)

# 训练模型
for epoch in range(num_epochs):
    # 进行前向传播
    outputs = model(inputs)

    # 计算损失函数
    loss = criterion(outputs, labels)

    # 反向传播和优化
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    # 统计结果
    _, predicted = torch.max(outputs.data, 1)
    total_correct += (predicted == labels).sum().item()
    total_loss += loss.item()

    # 打印结果
    if (epoch+1) % print_interval == 0:
        print("Epoch [{}/{}], Loss: {:.4f}, Accuracy: {:.4f}".format(epoch+1, num_epochs, total_loss/print_interval, total_correct/total_samples))
        total_correct = 0
        total_loss = 0.0

如果我的回答解决了您的问题,请采纳!