如何使用PyTorch在预训练模型上添加新图层? 给出了Keras示例

问题描述

我正在与Keras一起工作,并尝试分析一些具有有意义权重的层以及一些具有随机初始化的层建立的模型对准确性的影响。

Keras:

我在加载方法上使用VGG19参数加载了include_top = False预训练模型。

model = keras.applications.VGG19(include_top=False,weights="imagenet",input_shape=(img_width,img_height,3))

PyTorch:

我加载VGG19预先训练的模型,直到与先前加载Keras的模型位于同一层为止。

model = torch.hub.load('pytorch/vision:v0.6.0','vgg19',pretrained=True)
new_base =  (list(model.children())[:-2])[0]

加载模型后,以下图像显示了它们的摘要。 (PytorchKeras

PyTorch - VGG19 model without top layers

Keras - VGG19 model without top layers

到目前为止,没有问题。之后,我想在这些预训练的模型上添加一个Flatten层和一个Fully Connected层。我用Keras做到了,但我不能用PyTorch。

Keras - Add new layers on pretrained model

new_model.summary()的输出是:

Model summary after adding the new layers

我的问题是,如何在PyTorch添加新图层?

解决方法

如果您要做的只是替换分类器部分,则只需这样做。那是:

model = torch.hub.load('pytorch/vision:v0.6.0','vgg19',pretrained=True)
model.classifier = nn.Linear(model.classifier[0].in_features,4096)
print(model)

会给您:

之前:

VGG(
  (features): Sequential(
    (0): Conv2d(3,64,kernel_size=(3,3),stride=(1,1),padding=(1,1))
    (1): ReLU(inplace=True)
    (2): Conv2d(64,1))
    (3): ReLU(inplace=True)
    (4): MaxPool2d(kernel_size=2,stride=2,padding=0,dilation=1,ceil_mode=False)
    (5): Conv2d(64,128,1))
    (6): ReLU(inplace=True)
    (7): Conv2d(128,1))
    (8): ReLU(inplace=True)
    (9): MaxPool2d(kernel_size=2,ceil_mode=False)
    (10): Conv2d(128,256,1))
    (11): ReLU(inplace=True)
    (12): Conv2d(256,1))
    (13): ReLU(inplace=True)
    (14): Conv2d(256,1))
    (15): ReLU(inplace=True)
    (16): Conv2d(256,1))
    (17): ReLU(inplace=True)
    (18): MaxPool2d(kernel_size=2,ceil_mode=False)
    (19): Conv2d(256,512,1))
    (20): ReLU(inplace=True)
    (21): Conv2d(512,1))
    (22): ReLU(inplace=True)
    (23): Conv2d(512,1))
    (24): ReLU(inplace=True)
    (25): Conv2d(512,1))
    (26): ReLU(inplace=True)
    (27): MaxPool2d(kernel_size=2,ceil_mode=False)
    (28): Conv2d(512,1))
    (29): ReLU(inplace=True)
    (30): Conv2d(512,1))
    (31): ReLU(inplace=True)
    (32): Conv2d(512,1))
    (33): ReLU(inplace=True)
    (34): Conv2d(512,1))
    (35): ReLU(inplace=True)
    (36): MaxPool2d(kernel_size=2,ceil_mode=False)
  )
  (avgpool): AdaptiveAvgPool2d(output_size=(7,7))
  (classifier): Sequential(
    (0): Linear(in_features=25088,out_features=4096,bias=True)
    (1): ReLU(inplace=True)
    (2): Dropout(p=0.5,inplace=False)
    (3): Linear(in_features=4096,bias=True)
    (4): ReLU(inplace=True)
    (5): Dropout(p=0.5,inplace=False)
    (6): Linear(in_features=4096,out_features=1000,bias=True)
  )
)

之后:

VGG(
  (features): Sequential(
    (0): Conv2d(3,7))
  (classifier): Linear(in_features=25088,bias=True)
)

还要注意,当您要更改现有体系结构时,有两个阶段。您首先要获得所需的模块(这就是您在此处完成的工作),然后必须将其包装在nn.Sequential中,因为列表没有实现forward(),因此您无法真正提供任何内容。它只是模块的集合。

因此,您通常需要执行以下操作(作为示例):

features = nn.ModuleList(your_model.children())[:-1]
model = nn.Sequential(*features) 
# carry on with what other changes you want to perform on your model

请注意,如果您想创建一个新模型并打算像以下那样使用它:

output = model(imgs)

您需要在第二个顺序中包装要素和新图层。也就是说,执行以下操作:

features = nn.ModuleList(your_model.children())[:-1]
model_features = nn.Sequential(*features) 
some_more_layers = nn.Sequential(Layer1,Layer2,... ) 
                                 
model = nn.Sequential(model_features,some_more_layers)
#
output = model(imgs)

否则,您必须执行以下操作:

features_output = model.features(imgs)
output = model.classifier(features_output)

,

来自 PyTorch 教程 "Finetuning TorchVision Models"

Torchvision 提供了八种不同长度的 VGG 版本,其中一些版本具有批量归一化层。这里我们使用 VGG-11 和批量归一化。输出层类似于Alexnet,即

(classifier): Sequential(
   ...
   (6): Linear(in_features=4096,bias=True)
)

因此,我们使用相同的技术来修改输出层

model.classifier[6] = nn.Linear(4096,num_classes)