python - 如何从 PyTorch 的 ResNet 模型中删除最后一个 FC 层?

标签 python pytorch resnet

我正在使用 PyTorch 的 ResNet152 模型。我想从模型中剥离最后一个 FC 层。这是我的代码:

from torchvision import datasets, transforms, models
model = models.resnet152(pretrained=True)
print(model)

当我打印模型时,最后几行看起来像这样:

    (2):  Bottleneck(
      (conv1):  Conv2d(2048,  512,  kernel_size=(1,  1),  stride=(1,  1),  bias=False)
      (bn1):  BatchNorm2d(512,  eps=1e-05,  momentum=0.1,  affine=True,  track_running_stats=True)
      (conv2):  Conv2d(512,  512,  kernel_size=(3,  3),  stride=(1,  1),  padding=(1,  1),  bias=False)
      (bn2):  BatchNorm2d(512,  eps=1e-05,  momentum=0.1,  affine=True,  track_running_stats=True)
      (conv3):  Conv2d(512,  2048,  kernel_size=(1,  1),  stride=(1,  1),  bias=False)
      (bn3):  BatchNorm2d(2048,  eps=1e-05,  momentum=0.1,  affine=True,  track_running_stats=True)
      (relu):  ReLU(inplace)
    )
  )
  (avgpool):  AvgPool2d(kernel_size=7,  stride=1,  padding=0)
  (fc):  Linear(in_features=2048,  out_features=1000,  bias=True)
)

我想从模型中删除最后一个 fc 层。

我在 SO ( How to convert pretrained FC layers to CONV layers in Pytorch ) 上找到了答案,其中 mexmex似乎提供了我正在寻找的答案:

list(model.modules()) # to inspect the modules of your model
my_model = nn.Sequential(*list(model.modules())[:-1]) # strips off last linear layer

所以我将这些行添加到我的代码中,如下所示:

model = models.resnet152(pretrained=True)
list(model.modules()) # to inspect the modules of your model
my_model = nn.Sequential(*list(model.modules())[:-1]) # strips off last linear layer
print(my_model)

但是这段代码并不像宣传的那样有效——至少对我来说是这样。这篇文章的其余部分详细解释了为什么这个答案不起作用,所以这个问题不会作为重复问题被关闭。

首先,打印出来的模型比以前大了将近 5 倍。我看到了与之前相同的模型,但后面似乎是该模型的重复,但可能被压扁了。

    (2): Bottleneck(
      (conv1): Conv2d(2048, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv3): Conv2d(512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn3): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
    )
  )
  (avgpool): AvgPool2d(kernel_size=7, stride=1, padding=0)
  (fc): Linear(in_features=2048, out_features=1000, bias=True)
)
(1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
(2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(3): ReLU(inplace)
(4): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
(5): Sequential(
  . . . this goes on for ~1600 more lines . . .
  (415): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (416): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
  (417): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (418): Conv2d(512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False)
  (419): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (420): ReLU(inplace)
  (421): AvgPool2d(kernel_size=7, stride=1, padding=0)
)

其次,fc 层仍然存在 -- 之后的 Conv2D 层看起来就像 ResNet152 的第一层。

第三,如果我尝试调用 my_model.forward(),pytorch 会提示大小不匹配。它期望大小 [1, 3, 224, 224],但输入是 [1, 1000]。所以看起来整个模型的副本(减去 fc 层)被附加到原始模型。

最重要的是,我在 SO 上找到的唯一答案实际上并没有用。

最佳答案

对于 ResNet 模型,您可以使用 children 属性来访问层,因为 pytorch 中的 ResNet 模型由 nn 个模块组成。 (在pytorch 0.4.1上测试)

model = models.resnet152(pretrained=True)
newmodel = torch.nn.Sequential(*(list(model.children())[:-1]))
print(newmodel)

更新:虽然没有一个适用于所有 pytorch 模型的问题的通用答案,但它应该适用于所有结构良好的模型。您添加到模型中的现有层(例如 torch.nn.Lineartorch.nn.Conv2dtorch.nn.BatchNorm2d ...)均基于 torch.nn.Module class .如果你实现一个自定义层并将其添加到你的网络中,你应该从 pytorch 的 torch.nn.Module 类继承它。正如写在documentation , children 属性允许您访问类/模型/网络的模块。

def children(self):
        r"""Returns an iterator over immediate children modules.  

更新:重要的是要注意 children() 返回“立即”模块,这意味着如果网络的最后一个模块是顺序的,它将返回整个顺序。

关于python - 如何从 PyTorch 的 ResNet 模型中删除最后一个 FC 层?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52548174/

相关文章:

python - 将许多小图像连接成一个大图像

python - 使用python读取pcap头长度字段

python - 后端 CPU 的预期对象,但参数 #2 得到后端 CUDA 'source'

python - kaggle 无法下载 resnet50 预训练模型

python - 无法在 keras 中连接两个输入层。

python Pandas : How to select two equal column per row of a dataframe

python - app.yaml 处理程序登录 : admin option not effective on standard env python GAE app?

python - Anaconda与Cuda 9.0的集成显示不兼容的包错误

python - PyTorch 复制张量的首选方式

python - 如果输入数据被归一化,ML 模型会过拟合