CÃlimos 2023-10-23 14:09 采纳率: 64.4%
浏览 8
已结题

即改动主干网络又要使用预训练模型参数改怎么办

centernet模型使用resnet50作为主干网络,但是我在修改模型时增加了一层特征融合:


class ResNet(nn.Module):
    def __init__(self, block, layers, num_classes=1000):
        self.inplanes = 64
        super(ResNet, self).__init__()
        # 512,512,3 -> 256,256,64
        self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3,bias=False)
        self.bn1 = nn.BatchNorm2d(64)
        self.relu = nn.ReLU(inplace=True)
      
 
    
        #ASFF
        self.asff=ASFF(0,2)#两个参数:返回第一层的尺寸;尺寸放大两倍

        # 256x256x64 -> 128x128x64
        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=0, ceil_mode=True) # change

        # 128x128x64 -> 128x128x256
        self.layer1 = self._make_layer(block, 64, layers[0])

        # 128x128x256 -> 64x64x512
        self.layer2 = self._make_layer(block, 128, layers[1], stride=2)

        # 64x64x512 -> 32x32x1024
        self.layer3 = self._make_layer(block, 256, layers[2], stride=2)

        # 32x32x1024 -> 16x16x2048
        self.layer4 = self._make_layer(block, 512, layers[3],stride=2)
     

        self.avgpool = nn.AvgPool2d(7)
        self.fc = nn.Linear(512 * block.expansion, num_classes)
        #把通道变成16*16*128
        self.to16_16_128=nn.Sequential( nn.Conv2d(512, 128,
                     kernel_size=1, stride=1,padding=0),)
      
        # 权重初始化
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
                m.weight.data.normal_(0, math.sqrt(2. / n))
            elif isinstance(m, nn.BatchNorm2d):
                m.weight.data.fill_(1)
                m.bias.data.zero_()

    # 第一个参数表示是bottleneck类,第二个表示该block的输出channel,第三个表示每个block包含多少残差,对应下面的[3, 4, 6, 3]
    def _make_layer(self, block, planes, blocks,stride=1):
        downsample = None
        if stride != 1 or self.inplanes != planes * block.expansion:
            downsample = nn.Sequential(
                 nn.Conv2d(self.inplanes, planes * block.expansion,
                     kernel_size=1, stride=stride, bias=False),

            nn.BatchNorm2d(planes * block.expansion),
        )
        layers = []
        layers.append(block(self.inplanes, planes, stride, downsample))
        self.inplanes = planes * block.expansion
        for i in range(1, blocks):
            layers.append(block(self.inplanes, planes))

        return nn.Sequential(*layers)
    def forward(self, x):
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.maxpool(x)
        x = self.layer1(x)  # 128x128x64 -> 128x128x256

        x1 = self.layer2(x)    # 128x128x256 -> 64x64x512

        x2 = self.layer3(x1) # 64x64x512 -> 32x32x1024

        x3 = self.layer4(x2)# 32x32x1024 -> 16x16x2048

        x_asff=self.asff([x1,x2,x3])#将三种特征图融合

原来返回的是layer4前的几层,对应匹配了预训练模型的各个层参数:

def resnet50(pretrained = True):
    model = ResNet(Bottleneck, [3, 4, 6, 3])#第一个参数用的是bottleneck,第二个参数是每层里卷积数量
    if pretrained:
        state_dict = load_state_dict_from_url(model_urls['resnet50'], model_dir = 'model_data/')#导入预训练参数
        model.load_state_dict(state_dict)#用预训练的模型参数来初始化你构建的网络结构
    # #----------------------------------------------------------#
     #   获取特征提取部分
    # #----------------------------------------------------------#
    features = list([model.conv1, model.bn1, model.relu, model.maxpool, model.layer1, model.layer2, model.layer3, model.layer4])
    features = nn.Sequential(*features)

不知道现在加了一层后,怎么修改feature=list里,使得原来的预训练参数也可以用?
我现在是直接把最后两句改为return mdoel 导致训练时主干网络的预训练参数都用不上,收敛到以前的程度要更多世代

  • 写回答

2条回答 默认 最新

  • lIlIlllllIII 2023-10-23 14:56
    关注

    过滤更新一下只加载与预训练模型结构相匹配的参数,而不加载新加入的特征融合层的参数 我稍微改了一下你看看能不能运行

    def resnet50(pretrained=True):
        model = ResNet(Bottleneck, [3, 4, 6, 3])#第一个参数用的是bottleneck,第二个参数是每层里卷积数量
    
        if pretrained:
            # 加载预训练的权重
            state_dict = load_state_dict_from_url(model_urls['resnet50'], model_dir='model_data/')#导入预训练参数
    
            # 获取当前模型的状态字典
            model_dict = model.state_dict()
    
            # 过滤预训练权重,只更新存在的部分
            state_dict = {k: v for k, v in state_dict.items() if k in model_dict}
    
            # 更新模型状态字典并加载
            model_dict.update(state_dict)
            model.load_state_dict(model_dict)#用预训练的模型参数来初始化你构建的网络结构
    
        # #----------------------------------------------------------#
         #   获取特征提取部分
        # #----------------------------------------------------------#
        # 假设您的ResNet模型中有一个名为feature_xxxxx的属性
        features = list([model.conv1, model.bn1, model.relu, model.maxpool, model.layer1, model.layer2, model.layer3, model.layer4, model.feature_xxxxx])
        features = nn.Sequential(*features)
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 1月4日
  • 已采纳回答 12月27日
  • 创建了问题 10月23日

悬赏问题

  • ¥15 单纯型python实现编译报错
  • ¥15 c++2013读写oracle
  • ¥15 c++ gmssl sm2验签demo
  • ¥15 关于模的完全剩余系(关键词-数学方法)
  • ¥15 有没有人懂这个博图程序怎么写,还要跟SFB连接,真的不会,求帮助
  • ¥15 PVE8.2.7无法成功使用a5000的vGPU,什么原因
  • ¥15 is not in the mmseg::model registry。报错,模型注册表找不到自定义模块。
  • ¥15 安装quartus II18.1时弹出此error,怎么解决?
  • ¥15 keil官网下载psn序列号在哪
  • ¥15 想用adb命令做一个通话软件,播放录音