연세대 인공지능학회 YAI

[PyTorchZeroToAll] VGG-Net (Visual Geometry Group) 본문

강의 & 책/PyTorchZeroToAll

[PyTorchZeroToAll] VGG-Net (Visual Geometry Group)

_YAI_ 2022. 3. 18. 21:09

**YAI 9기 강재범님이 기초1팀에서 작성한 글입니다.


1. Introduction

기존의 CNN을 발전시킨 모델 중 하나이다.
특징은 convolution layer의 kernel (filter) size가 모두 3x3이고, input image는 3 channel의 224x224 픽셀의 이미지를 받도록 설계되어 있다는 점이다. 또, layer의 개수 (11개, 13개, 16개, 19개)에 따라 4가지 모델이 있다. 각각 vgg11, vgg13, vgg16, vgg19로 부른다. 각가의 구조는 다음 그림과 같다.

'C' type은 마지막 layer의 kernel size가 1x1인데 일반적으로 vgg16이라 부르는 모델은 'D' type을 사용한다.
'A-LRN'에서 LRN은 당시에 ReLu activation 함숫값이 너무 큰 경우를 방지하기 위해 사용하는 normalization 기법인데, 현재는 주로 Batch Normalization 기법을 적용한 vgg11_bn 모델이 주로 사용된다.
모든 모델이 kernel size=2, stride=2인 maxpooling이 총 5번 사용된다. 따라서 pooling할 때마다 size가 절반씩 감소한다. 따라서 FC network에 입력되는 size는 $224\div2^5=7$ 이므로 7x7이다.
FC network는 linear1(512*7*7, 4096)-(BN)-ReLU-linear2(4096, 4096)-(BN)-ReLU-linear3(4096, label)-(BN)-ReLU 의 형태로 모든 type에 공통적으로 사용된다. 위 그림에서는 마지막 layer를 FC-1000이라 했는데, 여기서 1000은 default class 값으로 dataset의 label class 개수에 맞춰서 바꿔서 구현할 수 있다.

2. VGG PyTorch Package

torchvision.models.vgg 패키지에 vgg 모델이 구현되어 있다. 지금부터는 이 구현 코드를 분석해보고자 한다.

우선 CNN layers를 생성하는 부분을 살펴보자. 그림의 맨 아래부분 (line 86-91) 에서 볼 수 있듯이 dictionary type으로 cfgs가 선언되어 있고, 이 안에 type별 layer 구조가 저장되어 있다. 각각의 숫자는 output channel의 수를 의미하고,'M'은 maxpooling을 의미한다.
cfgs에 저장되어 있는 설계도에 따라 make_layers 함수에서 layer들을 조립하는 것을 볼 수 있는데, 우선 input image가 RGB이므로 처음 input channel in_channels은 3으로 둔다. 만약 input image의 channel을 3이 아닌 다름 값으로 사용하고자 한다면 make_layers 함수를 수정해야 한다. 넘겨받은 cfg의 key에 맞게 layer를 for문으로 하나씩 쌓아올리는 단순한 구조로 구현되어 있는 것을 볼 수 있다. 이때 batch_norm option을 True로 하면 ReLU를 쌓기 전에 convolution layer 뒤에 BN module을 추가해주는 것을 볼 수 있다.

다음은 model design 부분이다.

마찬가지로 nn.Module을 상속받아 구현한다. __init__ 함수는 make_layers 에서 만들어줬던 CNN architecture features와 dataset의 output label 개수인 num_classes, weight initialize option인 init_weights를 parameter로 받는다. 이후, feature를 self 변수에 저장하고, avgpool(7, 7) module을 추가하는데, 이는 만약 224x224 보다 큰 image data를 input으로 경우 FC layer의 입력 크기가 맞지 않게 되므로 크기를 7x7으로 맞추기 위함이다. 그러나 입력되는 이미지의 크기가 224x224 보다 작을 경우에는 직접 VGG class를 상속받아 __init__ 함수를 Overriding 하여 FC1의 linear model size를 수정해줘야 한다. avgpool 이후에는 classifier sequential module로 FC network를 만들어 준다. 마지막으로 init_weights option에 따라 _initialize_wieghts() 함수를 호출한다. 이는 다음과 같이 구현되어 있다.

이 option은 기본적으로 모두 weight initialization을 하지만, pretrained된 모델을 불러올 때는 하지 않도록 하기 위함이다. 이에 관해서는 뒤에서 좀 더 자세히 살펴보자.
그리고, forward 함수에서 각 layer들을 이어 붙임으로써 VGG model design을 완성하게 된다. 여기서 torch.flatten() 이라는 함수는 tensor의 shape 중 (start_dim) index부터 (end_dim) index 까지의 부분을 1 dimension으로 만들겠다는 뜻이다. 위 코드는 start_dim이 1이고, end_dim은 default 값이 -1이므로, shape의 첫번째 Index에 해당하는 부분만 그대로 두고, 나머지는 1 dimension으로 만든다는 뜻이다. 따라서 이는 x.view(x.shape[0], -1)과 정확히 같은 표현이다.

다음으로 지정해준 type에 맞게 모델을 만들어주는데 이는 다음과 같다. 앞에서 말했던 4종류의 VGG model과 각각에 대해 Batch Normalization을 추가한 총 8개의 model을 반환하는 함수들이다.

다음은 그 중 한 예인 vgg11이다. 이는 _vgg 함수의 return 값을 return하는데, _vgg 함수는 아래와 같다.

PyTorch의 VGG 패키지는 ImageNet을 통해 trained된 model들을 함께 제공해준다. 만약 pretrained option을 True로 넘겨주면, 아래의 각 링크에서 pretrained된 model들의 parameter를 불러올 수 있다.

만약 pretrainedTrue면 weight initialization을 해줄 필요가 없으므로 False로 설정하고 모델을 만든다.

3. PyTorch 구현

3.1 Bigger that 224x224 - ImageFolder

이전의 custom image python 예제와 동일하게 구현하되, model design 부분만 아래와 같이 바꾼다.

이미 만들어져 있는 함수이므로 바로 가져오면 된다. 이때 size가 크더라도 nn.AdaptiveAvgPool2d((7, 7))에 의해 FC1에 들어갈 수 있도록 Resize 되지만, size가 너무 크면 계산량에 문제가 생길 수 있으므로 아래와 같이 dataset을 불러올 때부터 Resize 해주는 것이 좋다. 이때 224x224 보다 작아지지 않도록 주의한다.

3.2 Smaller that 224x224 - CIFAR10

model design 부분을 위와 같이 설계한다. 우선 기존 방법인 maxpooling을 5번 진행하면 32x32 size가 1x1이 되므로, CNN architecture를 직접 설계해야 한다. 이는 2. VGG PyTorch Package에서의 코드를 그대로 모방하면 된다. 이때 되도록 지켜야하는 두가지 조건이 있다.

  • size가 같다면, 즉 다음 maxpooling까지는 같은 output channel을 유지해야 한다.
  • maxpooling을 통해 size가 $1/N$배 감소하면 output channel의 개수는 $N$배 해야 한다.
    그러나 이번 예의 경우, 단순히 구현방식을 설명하기 위함이므로 위의 조건은 지키지 않았다. custom_cfg를 통해 CNN architecture를 설계한 후, make_layers 함수에서 이 list를 대입하면 된다. 만약 기존의 architecture를 사용하고자 한다면 make_layersvgg.cfgs['D']와 같이 대입하면 된다.

그 다음으로 앞서 설명했듯이 size가 작을 때 VGG lass를 수정해줘야 하므로 이를 상속받아 sub class를 만들어준다. 그 후, vgg package에서 해당 부분을 복사 붙여넣기한 후, avgpool과 관련한 코드를 제거한다. 마지막으로 FC1의 linear mudule size를 바꿔준다. 여기서는 32x32 size가 maxpooling을 3번 하므로, 4x4 size이고, CNN의 마지막 output channel이 512 이므로 input size는 512x4x4 이다. _initialize_weights 함수는 그대로 사용하므로, 별도의 overriding을 필요없다.

3.3 Input channel $\neq$ 3 - MNIST

이번에는 channel이 1이고, 28×28 size인 MNIST data를 VGG로 구현해본다. 우선, CNN architecture를 max pooling 2개로 설계하면 $28\div2^2=7$ 이다. 또한 cfg의 마지막 output channel도 512로 두었으므로, FC1의 input size와 동일하다. 따라서 별도의 VGG class 수정 필요 없이 그대로 가져와서 사용한다.
반면 input channel이 1이므로, 앞서 설명한바와 같이 make_layers 함수를 바꿔야 한다. 이때는 vgg 패키지에서 해당 함수를 그대로 가져온 후, in_channels만 1로 바꿔주면 된다. 이때 이는 함수 overriding이 아닌 직접 새로 만든 것임에 유의한다. 나머지는 CIFAR10 예제와 동일하므로 생략한다.

'강의 & 책 > PyTorchZeroToAll' 카테고리의 다른 글

[PytorchZeroToAll] Deep Learning Introduction  (0) 2023.03.04
Comments