web-dev-qa-db-ja.com

PyTorchのResNetモデルから最後のFCレイヤーを削除する方法は?

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( トレーニング済みのFCレイヤーをPytorchのCONVレイヤーに変換する方法 )で答えを見つけました、ここで 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の最初のレイヤーのように見えます。

第3に、my_model.forward()を呼び出そうとすると、pytorchはサイズの不一致について不平を言います。サイズは[1、3、224、224]である必要がありますが、入力は[1、1000]でした。そのため、モデル全体(fcレイヤーを除く)のコピーが元のモデルに追加されているように見えます。

結論、SOで見つけた唯一の答えは実際には機能しません。

10
Lee Jenkins

PytorchのResNetモデルはnn個のモジュールで構成されるため、ResNetモデルの場合、子属性を使用してレイヤーにアクセスできます。 (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()は「即時」モジュールを返すことに注意することが重要です。つまり、ネットワークの最後のモジュールが順次である場合、全体が順次を返します。

12
unlut

あなたは単にそれを行うことができます:

Model.fc = nn.Sequential()

または、IDレイヤーを作成できます。

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

    def forward(self, x):
        return x

そして、fcレイヤーをそれに置き換えます:

Model.fc = Identity()
4
saeid nejati

最後のFCレイヤーのモデルを削除するだけでなく、それを独自の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
3
Artem Trunov