https://discuss.pytorch.org/t/how-to-modify-a-pretrained-model/60509
https://discuss.pytorch.org/t/how-to-modify-the-final-fc-layer-based-on-the-torch-model/766/7
https://greeksharifa.github.io/pytorch/2018/11/10/pytorch-usage-03-How-to-Use-PyTorch/
https://pytorch.org/docs/stable/generated/torch.nn.Module.html
엄청나게 다양한 방법이 존재한다.

3. Change(eliminate and add) specific layer in Loaded models

이제 바꿔보자.
test_model의 마지막을 바꿔보자.

for name, module in test_model.named_modules():
    if name == 'fc.3':
        module == nn.Linear(in_features=100, out_features=555, bias=True)

이렇게 하면 될줄 알았는데 안된다.
그래서 찾아보다가 model을 보는 데 굳이 앞에서 처럼 for문을 사용할 필요가 없다는 것을 알았다.

1. 2. 을 그냥 바로 list로 반환하면 더 쉽다.

다음을 보자.

list(vgg16.named_modules())
list(vgg16.named_children())
list(vgg16.modules())
list(vgg16.children())
list(vgg16.features)  이때 feature는 vgg16안에 있음 주의

즉, 그냥 list로 바로 반환 해준다.

다만 차이점은 있다. 앞의 1,2는 말 그대로 iterator로 원래 model에 직접 접근 하는 것이고 여기처럼 이를 list로 반환하면 구조가 복사된다고 보면 된다.

이제 변경 해보자.
이때 크게 두가지의 방법이 있다. 첫번째는 직접 접근하여 특정 layer를 변경(추가,삭제)하는 것이고 두번째는 model을 원하는 만큼 복사하여 다시 새로운 model class로 만드는 것이다.

첫번째 방법

변경

vgg16 = torchvision.models.vgg16(pretrained = True)
vgg16
------------------------------------------------------------------------------
VGG(
  (features): Sequential(
    (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU(inplace=True)
    (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (3): ReLU(inplace=True)
    (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (6): ReLU(inplace=True)
    (7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (8): ReLU(inplace=True)
    (9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (11): ReLU(inplace=True)
    (12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (13): ReLU(inplace=True)
    (14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (15): ReLU(inplace=True)
    (16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (18): ReLU(inplace=True)
    (19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (20): ReLU(inplace=True)
    (21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (22): ReLU(inplace=True)
    (23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (25): ReLU(inplace=True)
    (26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (27): ReLU(inplace=True)
    (28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (29): ReLU(inplace=True)
    (30): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, 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, out_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)
  )
)

이게 진짜 쉽다. 찍어 보니 위와 같이 나왔고 여기서 바로 직접 접근 할 수 있다.
예를들어

vgg16.classifier      \ type = torch.nn.modules.container.Sequential
------------------------------------------------------------------------------
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, out_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)
)

이다. 여기서 마지막을 변경하고 싶으면

vgg16.classifier[6]
------------------------------------------------------------------------------
Linear(in_features=4096, out_features=1000, bias=True)

위와 같이 볼수 있으므로

vgg16.classifier[6] = nn.Linear(in_features=4096, out_features=100, bias=True)
vgg16.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, out_features=4096, bias=True)
  (4): ReLU(inplace=True)
  (5): Dropout(p=0.5, inplace=False)
  (6): Linear(in_features=4096, out_features=100, bias=True)
)

이렇게 하면 변경된다. 당연히 vgg16을 찍어봐도 잘 변경 되었다는 것을 알 수 있다.

삭제

위의 변경된 vgg16을 그대로 사용한다.
마지막의 Linear를 삭제해 보자.

del(vgg16.classifier[6])

이렇게 하면 삭제 된다.

추가

vgg16.classifier.add_module('test_add', nn.Linear(in_features=4096, out_features=555, bias=True))
vgg16.add_module('test_add', nn.Linear(in_features=4096, out_features=555, bias=True))
vgg16
------------------------------------------------------------------------------
VGG(
  (features): Sequential(
    (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU(inplace=True)
    (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (3): ReLU(inplace=True)
    (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (6): ReLU(inplace=True)
    (7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (8): ReLU(inplace=True)
    (9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (11): ReLU(inplace=True)
    (12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (13): ReLU(inplace=True)
    (14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (15): ReLU(inplace=True)
    (16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (18): ReLU(inplace=True)
    (19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (20): ReLU(inplace=True)
    (21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (22): ReLU(inplace=True)
    (23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (25): ReLU(inplace=True)
    (26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (27): ReLU(inplace=True)
    (28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (29): ReLU(inplace=True)
    (30): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, 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, out_features=4096, bias=True)
    (4): ReLU(inplace=True)
    (5): Dropout(p=0.5, inplace=False)
    (test_add): Linear(in_features=4096, out_features=555, bias=True)
  )
  (test_add): Linear(in_features=4096, out_features=555, bias=True)
)

model.add_module('name', layer)하면 잘 되고 앞에 model말고 구성 요소를 추가하여 더 구체적인 위치에 추가 가능하다.

추가인데 이제 새로운 model class를 만든다.

단 이때도 pre-trianed parameter가 그대로 유지된다.

class vgg16__(nn.Module):
    def __init__(self, originalModel):
        super(vgg16__, self).__init__()
        self.original = nn.Sequential(*list(originalModel.features)) 
        self.add = nn.Linear(1000, 8)
    def forward(self, x):
        x = self.original(x)
        x = self.add(x)
        return x

이렇게 하면 되는데 몇가지의 문제가 있다.
일단 feature말고 전체가 불가능 하다. 또한 module에 하나만 있는 경우도 불가능 하다....

추가 내용

def modify_resnet_for_fsl(model, fc_out_features=5):
    for name, module in model.named_modules():
        if type(module) == torch.nn.BatchNorm2d:
            module.track_running_stats = False
    model.fc.out_features = fc_out_features

이렇게 해서 전체적으로 바꿀 수도 있다.

0개의 댓글

관련 채용 정보

Powered by GraphCDN, the GraphQL CDN