Python 如何从PyTorch中的ResNet模型中删除最后一个FC层?
我使用的是PyTorch的ResNet152型号。我想从模型中去掉最后一个FC层。这是我的密码:Python 如何从PyTorch中的ResNet模型中删除最后一个FC层?,python,pytorch,resnet,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
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)
)
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)
我想从模型中删除最后一个fc层
我在SO()上找到了答案,这里似乎提供了我想要的答案:
list(model.modules()) # to inspect the modules of your model
my_model = nn.Sequential(*list(model.modules())[:-1]) # strips off last linear layer
因此,我将这些行添加到我的代码中,如下所示:
(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)
)
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上测试) 更新:虽然对于这个问题没有一个通用的答案可以适用于所有pytorch模型,但它应该适用于所有结构良好的模型。添加到模型中的现有图层(例如,…)都基于。如果您实现了一个自定义层并将其添加到您的网络中,您应该从pytorch的torch.nn.Module类继承它。如中所述,children属性允许您访问类/模型/网络的模块
def children(self):
r"""Returns an iterator over immediate children modules.
更新:需要注意的是,children()返回“立即”模块,这意味着如果网络的最后一个模块是顺序模块,它将返回整个顺序模块。如果您不仅希望剥离最后一个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
您只需通过以下方式即可完成:
Model.fc = nn.Sequential()
或者,您也可以创建标识层:
class Identity(nn.Module):
def __init__(self):
super().__init__()
def forward(self, x):
return x
并用它替换fc层:
Model.fc = Identity()
从PyTorch教程:
这里我们使用Resnet18,因为我们的数据集很小,只有两个类。打印模型时,我们看到最后一层是完全连接的层,如下所示:
(fc):线性(输入特征=512,输出特征=1000,偏差=True)
因此,我们必须重新初始化model.fc
,使其成为一个具有512个输入特性和2个输出特性的线性层,其中:
model.fc=nn.Linear(512,num_类)
不太确定,但是这里应该可以基本删除,
del(model['fc'])
。你能试试吗?用文档参考更新了我的答案,如果缺少什么,请提醒。PyTorch现在有一个内置的身份模块: