728x90
  • 이미지넷 pretrained model을 사용해서 전이학습과 하이퍼파라미터 튜닝을 진행하는 과제

-> 구체적으로는 ImageNet에서 학습된(pretrained) ResNet 18 딥러닝 모델을 사용해서 MNIST 모델, Fashion-MNIST 모델을 만들었다.

  1. ImageNet에서 학습된 ResNet 18 딥러닝 모델을 불러온다.
  2. MNIST 데이터셋(train, test dataset)을 불러온다.
  3. pretrained 되지 않은 resnet18모델(이하 mnist_resnet18)을 불러온다. 코드는 아래와 같다.(실습에서는 mnist_resnet18이라는 이름으로 불러옴. 여기에 mnist데이터셋을 전이학습시킬 예정이므로!)
mnist_resnet18 = torchvision.models.resnet18(pretrained=False)

4. conv1.weight.shape[1], fc.weight.shape[0]을 통해 모델의 입출력 채널 개수를 각각 확인한다.

print("네트워크 필요 입력 채널 개수", mnist_resnet18.conv1.weight.shape[1])
print("네트워크 출력 채널 개수 (예측 class type 개수)", mnist_resnet18.fc.weight.shape[0])
# 네트워크 필요 입력 채널 개수 3
# 네트워크 출력 채널 개수 (예측 class type 개수) 1000

5. 서로 다른 타입의 데이터를 사용했기 때문에 mnist데이터셋을 mnist_resnet18에 학습 시키기 위해서는, mnist데이터의 차원을 변경할 필요가 있다.

- mnist 원본 데이터(지금 전이학습시키려는 mnist데이터셋)는 흑백(grayscale)인데에 반해, 학습시키려는 모델인 mnist_resnet18은 컬러이다.

- 따라서 mnist는 28*28픽셀 이미지라서 데이터의 차원은 (28, 28)

- mnist_resnet18은 28*28(픽셀)*3(rgb의 3개 채널)의 (3, 28, 28)이다.

mnist_resnet18에 맞추어 mnist 데이터셋의 차원을 (3, 28, 28)으로 만들어주는 과정이 필요하다.

이는 torchvision.transforms.Compose라는 함수를 통해 가능하다.

그 코드는 아래와 같다.

# torchvision.datasets.mnist의 데이터 타입은 PIL Image이고, 학습 때는 torch로 type 변경이 필요함
# + 원본은 grayscale이라서 채널이 한개뿐인 입력이지만 모델은 3채널이기 때문에 grayscale을 RGB로 변경해주어야함
# (참고) grayscale의 입력을 모델에 넣고 싶으면, 모델 입력을 channel 1개만 받도록 변경할 수도 있다!
common_transform = torchvision.transforms.Compose(
  [
    torchvision.transforms.Grayscale(num_output_channels=3), # grayscale의 1채널 영상을 3채널로 동일한 값으로 확장함
    torchvision.transforms.ToTensor() # PIL Image를 Tensor type로 변경함
  ]
)
# 앞서 선언한 데이터셋에 transform 인자를 넘겨주자
mnist_train_transformed = torchvision.datasets.MNIST(root='./mnist', train=True, download=True, transform=common_transform)
mnist_test_transformed = torchvision.datasets.MNIST(root='./mnist', train=False, download=True, transform=common_transform)

6. resnet18모델에 맞게 변경된 mnist데이터에 대해 데이터로더를 만들어준다.(이때 데이터 shuffle=True 필수!)

7. mnist_resnet18모델의 fully connected layer(mnist_resnet18.fc)의 output features를 mnist데이터의 레이블 개수인 10으로 변경

8. mnist_resnet18.fc의 가중치와 편향을 초기화

6~8번 과정에 대한 코드는 아래와 같다.

import math

# Mnist Dataset을 DataLoader에 붙이기
BATCH_SIZE = 64
mnist_train_dataloader = torch.utils.data.DataLoader(mnist_train_transformed, batch_size=BATCH_SIZE, shuffle=True, num_workers=2)
mnist_test_dataloader = torch.utils.data.DataLoader(mnist_test_transformed, batch_size=BATCH_SIZE, shuffle=False, num_workers=2)

# mnist_resnet18 분류 모델을 학습하기
## 1. 분류 모델의 output 크기가 1000개로 되어 있음으로 mnist data class 개수로 나올 수 있도록 Fully Connected Layer를 변경하고 xavier uniform으로 weight 초기화
MNIST_CLASS_NUM = 10
mnist_resnet18.fc = torch.nn.Linear(in_features=512, out_features=MNIST_CLASS_NUM, bias=True)
torch.nn.init.xavier_uniform_(mnist_resnet18.fc.weight)

# 이해 안가는 부분
# fully connected layer의 bias를 resnet18.fc in_feature의 크기의 1/root(n) 크기의 uniform 분산 값 중 하나로 설정
stdv = 1. / math.sqrt(mnist_resnet18.fc.weight.size(1))
mnist_resnet18.fc.bias.data.uniform_(-stdv, stdv)

print("네트워크 필요 입력 채널 개수", mnist_resnet18.conv1.weight.shape[1])
print("네트워크 출력 채널 개수 (예측 class type 개수)", mnist_resnet18.fc.weight.shape[0])

9. 이후 한 번의 에폭마다 학습과 테스트를 진행하며 전이학습을 마친다. fashion mnist데이터셋에 대해서도 같은 과정을 반복한다.

 

과제에서는 resnet18모델 각각에 mnist, fashion mnist를 전이학습시켜보았다. 모두 성능이 좋았지만 resnet18에 mnist데이터를 전이학습 시킨 mnist_resnet18모델을 source task로 두고 fashion mnist를 전이학습시켜 보는 것도 성능이 좋을 것 같다.

728x90