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で見つけた唯一の答えは実際には機能しません。
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.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()は「即時」モジュールを返すことに注意することが重要です。つまり、ネットワークの最後のモジュールが順次である場合、全体が順次を返します。
あなたは単にそれを行うことができます:
Model.fc = nn.Sequential()
または、IDレイヤーを作成できます。
class Identity(nn.Module):
def __init__(self):
super().__init__()
def forward(self, x):
return x
そして、fcレイヤーをそれに置き換えます:
Model.fc = Identity()
最後の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