Как удалить последний слой FC из модели ResNet в PyTorch? - PullRequest
0 голосов
/ 28 сентября 2018

Я использую модель ResNet152 от PyTorch.Я хотел бы снять последний слой 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 ( Как преобразовать предварительно обученные слои FC в слои CONV в 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, на самом деле не работает.

Ответы [ 3 ]

0 голосов
/ 09 января 2019

Если вы ищете не просто раздеть модель последнего слоя 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
0 голосов
/ 12 июля 2019

Вы можете сделать это просто:

Model.fc = nn.Sequential()

или, альтернативно, вы можете создать слой Identity:

class Identity(nn.Module):
    def __init__(self):
        super().__init__()

    def forward(self, x):
        return x

и заменить им слой fc:

Model.fc = Identity()
0 голосов
/ 28 сентября 2018

Для модели ResNet вы можете использовать дочерний атрибут для доступа к слоям, поскольку модель ResNet в pytorch состоит из nn модулей.(Проверено на 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.Модуль класса .И если вы реализуете пользовательский слой и добавляете его в свою сеть, вы должны унаследовать его от класса torch.nn.Module в pytorch.Как написано в документации , атрибут children позволяет получить доступ к модулям вашего класса / модели / сети.

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

Обновление: важно отметить, что children () возвращает "немедленный"modules, что означает, что если последний модуль вашей сети является последовательным, он вернет весь последовательный.

...