T1_longskr 2024-12-05 17:00 采纳率: 0%
浏览 10

resnet50加入se注意力机制后精度低。

为什么resnet50加入se注意力机制后前几轮的训练精度特别低只有0.01,精度提升也慢,而原本最终的训练精度有0.90。

# 自定义注意力模块
class SELayer(nn.Module):
    def __init__(self, channel, reduction=16):
        super(SELayer, self).__init__()
        self.fc1 = nn.Linear(channel, channel // reduction, bias=False)
        self.relu = nn.ReLU(inplace=True)
        self.fc2 = nn.Linear(channel // reduction, channel, bias=False)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        b, c, _, _ = x.size()
        y = x.mean(dim=(2, 3), keepdim=True)  # Global Average Pooling
        y = self.fc1(y.view(b, c))
        y = self.relu(y)
        y = self.fc2(y)
        y = self.sigmoid(y)
        return x * y.view(b, c, 1, 1)



class ResNetWithSE(nn.Module):
    def __init__(self, num_classes, pretrained=True):
        super(ResNetWithSE, self).__init__()
        self.resnet = models.resnet50(pretrained=pretrained)
        self.se = SELayer(2048)  # ResNet50的输出通道数

        self.resnet.fc = nn.Sequential(
            nn.Dropout(0.5),
            nn.Linear(self.resnet.fc.in_features, num_classes)
        )

    def forward(self, x):
        x = self.resnet.conv1(x)
        x = self.resnet.bn1(x)
        x = self.resnet.relu(x)
        x = self.resnet.maxpool(x)

        x = self.resnet.layer1(x)
        x = self.resnet.layer2(x)
        x = self.resnet.layer3(x)
        x = self.resnet.layer4(x)

        # 加入Squeeze-and-Excitation模块
        x = self.se(x)

        x = self.resnet.avgpool(x)
        x = torch.flatten(x, 1)
        x = self.resnet.fc(x)

        return x



# 修改后的build_model函数
def build_model(num_classes, previous_weights_file=None):
    model = ResNetWithSE(num_classes=num_classes, pretrained=True)

    # 如果有预训练权重文件,加载权重
    if previous_weights_file and os.path.exists(previous_weights_file):
        model = model.to(torch.device('cuda' if torch.cuda.is_available() else 'cpu'))
        print(f"加载之前的权重到模型设备:{next(model.parameters()).device}")

        # 加载模型参数
        pretrained_dict = torch.load(previous_weights_file)

        # 创建当前模型的参数字典
        model_dict = model.state_dict()

        # 过滤掉不匹配的全连接层参数
        pretrained_dict = {k: v for k, v in pretrained_dict.items() if
                           k in model_dict and v.size() == model_dict[k].size()}

        # 更新当前模型的权重
        model_dict.update(pretrained_dict)

        # 加载更新后的权重到模型中
        model.load_state_dict(model_dict)

    return model

  • 写回答

1条回答 默认 最新

  • 程风破~ Java领域新星创作者 2024-12-05 18:51
    关注

    本答案参考 多次询问 ChatGPT-3.5 后选择的最佳回答,若是满意,还请采纳,谢谢

    ResNet50加入SE注意力机制后前几轮训练精度低且提升慢可能有以下几个原因:

    一、初始化相关

    1. 权重初始化
      • 分析
        • 在加入SE层后,网络结构发生了改变。SE层中的全连接层(self.fc1self.fc2)的权重初始化可能会影响整个网络的训练。如果初始化不当,可能导致梯度传播问题。例如,如果全连接层的权重初始化为较大的值,可能会使激活函数(如ReLUsigmoid)在开始阶段进入饱和区,从而减缓梯度下降的速度。
      • 改进措施
        • 可以尝试不同的初始化方法,如Xavier初始化或Kaiming初始化。在PyTorch中,可以通过修改nn.Linear层的初始化方式来实现。例如,对于Xavier初始化:
          import torch.nn as nn
          # 对于SELayer中的fc1和fc2
          self.fc1 = nn.Linear(channel, channel // reduction, bias = False)
          nn.init.xavier_uniform_(self.fc1.weight)
          self.fc2 = nn.Linear(channel // reduction, channel, bias = False)
          nn.init.xavier_uniform_(self.fc2.weight)
          
    2. 预训练权重的影响
      • 分析
        • 原ResNet50的预训练权重是针对没有SE层的结构进行训练的。当加入SE层后,预训练权重与新结构不完全匹配。特别是在SE层部分,初始权重是随机初始化的,而前面ResNet50部分的权重是预训练的,这种不匹配可能导致前几轮训练不稳定。例如,预训练权重可能已经将ResNet50的特征提取部分调整到一个较好的状态,而新加入的SE层的随机权重会干扰这个状态,使得网络在开始阶段难以快速适应数据。
      • 改进措施
        • 一种方法是对整个网络进行微调,而不仅仅是加载预训练权重到ResNet50部分。可以先将整个网络(包括SE层)在小数据集上进行预训练,使得SE层的权重也能得到一定程度的调整,然后再在完整数据集上进行训练。或者在加载预训练权重时,对预训练权重进行适当的调整,使其更适合新的网络结构。

    二、超参数设置

    1. 学习率
      • 分析
        • 学习率对于网络训练的收敛速度和稳定性至关重要。在加入SE层后,网络的复杂度增加,原有的学习率可能不再适合。如果学习率过高,可能会导致梯度爆炸或在局部最优解附近震荡,使得前几轮训练精度很低且提升缓慢。例如,对于ResNet50原本合适的学习率可能会使带有SE层的网络在训练初期出现较大的参数更新,从而远离最优解。
      • 改进措施
        • 可以尝试降低学习率。例如,使用学习率衰减策略,如余弦退火学习率(Cosine Annealing Learning Rate)。在PyTorch中,可以使用torch.optim.lr_scheduler.CosineAnnealingLR来实现:
          optimizer = torch.optim.Adam(model.parameters(), lr = 0.001)
          scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max = 10)
          for epoch in range(num_epochs):
          scheduler.step()
          # 训练代码
          
    2. 正则化参数
      • 分析
        • 正则化有助于防止过拟合,但如果正则化参数设置不当,可能会影响网络的训练。在加入SE层后,网络结构发生变化,原有的正则化参数(如Dropout概率)可能不再合适。如果Dropout概率过高,可能会导致模型在训练初期难以学习到有效的特征,从而降低精度。
      • 改进措施
        • 可以调整Dropout概率或者尝试其他正则化方法,如L1或L2正则化。对于Dropout,可以降低其概率值并观察训练效果。例如,将Dropout概率从0.5降低到0.3:
          self.resnet.fc = nn.Sequential(
          nn.Dropout(0.3),
          nn.Linear(self.resnet.fc.in_features, num_classes)
          )
          

    三、数据相关

    1. 数据增强
      • 分析
        • 数据增强操作可能与SE层的交互效果不佳。例如,某些数据增强操作(如随机裁剪、旋转等)可能会改变图像的特征分布,而SE层在这种改变后的特征上可能无法有效地发挥作用。如果数据增强过于激进,可能会使网络在开始阶段难以学习到稳定的特征表示,从而导致精度低且提升缓慢。
      • 改进措施
        • 可以调整数据增强的策略。例如,减少随机裁剪的比例或者缩小旋转的角度范围,使数据增强后的图像更接近原始数据的特征分布,以便SE层能够更好地适应。
    2. 数据量
      • 分析
        • 如果数据量相对较少,加入SE层后网络可能会过拟合。SE层增加了网络的复杂度,在数据量不足的情况下,网络可能会在训练初期就开始拟合噪声,而不是真正的数据模式,从而导致精度低且提升缓慢。
      • 改进措施
        • 可以考虑增加数据量,如使用数据扩充技术(生成对抗网络生成更多数据等)或者收集更多的原始数据。如果增加数据量不可行,可以减少网络的复杂度,例如减少SE层中的全连接层的神经元数量或者调整网络结构。
    评论

报告相同问题?

问题事件

  • 创建了问题 12月5日