我正在使用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上找到的唯一答案实际上没有用。
答案 0 :(得分:7)
对于ResNet模型,由于pytorch中的ResNet模型包含nn个模块,因此可以使用children属性访问层。 (在pytorch 0.4.1上测试)
model = models.resnet152(pretrained=True)
newmodel = torch.nn.Sequential(*(list(model.children())[:-1]))
print(newmodel)
更新:尽管没有一个通用的答案可以在所有pytorch模型上使用,但它应该在所有结构良好的模型上都可以使用。您添加到模型中的现有图层(例如torch.nn.Linear,torch.nn.Conv2d,torch.nn.BatchNorm2d ...)全部基于torch.nn.Module class。而且,如果您实现自定义层并将其添加到网络,则应该从pytorch的torch.nn.Module类继承它。如documentation所述,children属性使您可以访问类/模型/网络的模块。
def children(self):
r"""Returns an iterator over immediate children modules.
更新:值得注意的是children()返回“立即”模块,这意味着如果网络的最后一个模块是顺序的,它将返回整个顺序。
答案 1 :(得分:1)
如果您不仅要剥离最后一个FC层的模型,而且要用自己的模型替换它,因此可以利用转移学习技术,则可以采用以下方式:
import torch.nn as nn
from collections import OrderedDict
n_inputs = model.fc.in_features
# add more layers as required
classifier = nn.Sequential(OrderedDict([
('fc1', nn.Linear(n_inputs, 512))
]))
model.fc = classifier
答案 2 :(得分:1)
您可以通过:
Model.fc = nn.Sequential()
或者您也可以创建身份层:
class Identity(nn.Module):
def __init__(self):
super().__init__()
def forward(self, x):
return x
并用它替换fc层:
Model.fc = Identity()
答案 3 :(得分:1)
来自 PyTorch 教程 "Finetuning TorchVision Models":
<块引用>这里我们使用 Resnet18,因为我们的数据集很小,只有两个类。当我们打印模型时,我们看到最后一层是全连接层,如下图:
(fc): Linear(in_features=512, out_features=1000, bias=True)
因此,我们必须将 model.fc
重新初始化为具有 512 个输入特征和 2 个输出特征的线性层:
model.fc = nn.Linear(512, num_classes)