-
Transfer Learning Tutorial(전이학습)AI Basic 2023. 3. 12. 01:04
전이학습이 어떤 방식으로 이루어 지는지 궁금해서
아래 예제로 공부하면서 코드를 작성해봤다. 재사용을 위해서 리팩토링을 했므으로 같은 함수이다.
출저 : https://9bow.github.io/PyTorch-tutorials-kr-0.3.1/beginner/transfer_learning_tutorial.html
전이학습(Transfer Learning) 튜토리얼 — PyTorch Tutorials 0.3.1 documentation
이 튜토리얼에서는 전이학습(Transfer Learning)을 이용하여 신경망을 어떻게 학습시키는지 배워보겠습니다. 전이학습에 대해서 더 알아보시려면 CS231n 노트 를 읽어보시면 좋습니다. 실제로 충분한
9bow.github.io
나는 위 예제가 가장 좋은것 같다. 그래서 위 예제를 따라하면 전의 학습이 어떻게 이루어 지는지 알아보자!
사전 준비 지식
위 예제에서는 resnet 이라는 network를 사용한다. 자세한것은 인터넷에 찾아보면 되고 핵심적인 내용은
이미지를 분류하는 네트워크이고 1000개로 이미지를 분류한다.
네트워크 복잡도에 따라서 resnet18, resnet50,resnet101,resnet152로 나뉜다.
여기서 내 경우는 resnet18, resent152를 사용해서 얼마나 성능향상이 있는지 알아본다.
아래 글에 resnet에대해서 간단하게 잘 적어져 있으니 참조하면 좋을것 같다.
[CNN 알고리즘들] ResNet의 구조
LeNet-5 => https://bskyvision.com/418 AlexNet => https://bskyvision.com/421 VGG-F, VGG-M, VGG-S => https://bskyvision.com/420 VGG-16, VGG-19 => https://bskyvision.com/504 GoogLeNet(inception v1) => https://bskyvision.com/539 ResNet => https://bskyvision.co
bskyvision.com
1. 사전 준비
데이터를 다운 받는다. pytorch tutorial에
~~~
메모
데이터를 여기 에서 다운로드 받아 현재 받고 압축을 해주세요.
~~~
내 경우는 코드 기준 ../data/hymenoptera_data 위치에 데이터를 저장했음.
그러면 아래와 같은 구조를 가짐.
data
|-- hymenoptera_data
|-- train
|-- val
|-- learning-ai-knowledge
https://github.com/freddiekimN/learning-ai-knowledge/tree/study/transfer_learning_tutorial
GitHub - freddiekimN/learning-ai-knowledge
Contribute to freddiekimN/learning-ai-knowledge development by creating an account on GitHub.
github.com
코드는 여기 있다.
브랜치를 transfer_learning_tutorial로 수정후 다운 받으면됨.
그리고 네트워크의 입출력에대해서 알아한다.
기존 resnet 의 입력은 3x244x244 이고 출력은 1000개 이다.
그러나 예제에서는 3x244x244 을 받아서 출력은 2개(벌, 개미) 만 분류하는 예이다.
그리고 샘플 데이터는
train 데이터의 크기는 개미는 124개 이미지 이고 벌은 121개 이미지 이다.
validation 데이터 크기는 개미는 70개 벌은 83개이다.
batch 사이즈는 4개단위로 학습한다.
위 정도 사전지식을 알면 코드를 분석하기 훨씬 편하다.
우선 내가 볼때 transfer learning은 3가지 방법이 있는것 같다.
1. 모든 파라미터를 학습시킨다. 2. 가져온 파라미터는 고정시키고 뒷단만 학습시킨다.3. 둘다 한번씩한다.
즉 이번 전이 학습은 1000개의 클래스로 학습된 모델을 2개로 다시 학습하는 예이다.
from __future__ import print_function, division import torch import torchvision from torchvision import datasets, models, transforms import matplotlib.pyplot as plt import os from torchsummary import summary as summary from imshow import imshow from visualize_model import visualize_model from train_model import train_model from train_model_main import train_model_main plt.ion() # interactive mode # 학습을 위한 데이터 증가(Augmentation)와 일반화하기 # 단지 검증을 위한 일반화하기 data_transforms = { 'train': transforms.Compose([ transforms.RandomResizedCrop(224), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]), 'val': transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]), } data_dir = '../data/hymenoptera_data' image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x]) for x in ['train', 'val']} dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=4, shuffle=True, num_workers=4) for x in ['train', 'val']} dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']} class_names = image_datasets['train'].classes use_gpu = torch.cuda.is_available() # Get a batch of training data inputs, classes = next(iter(dataloaders['train'])) # Make a grid from batch out = torchvision.utils.make_grid(inputs) imshow(out, title=[class_names[x] for x in classes]) # 모델 학습하기 model_ft = models.resnet18(pretrained=True) model_ft = train_model_main(model_ft,True,use_gpu,dataloaders,class_names,dataset_sizes) model_conv = models.resnet18(pretrained=True) model_conv = train_model_main(model_conv,False,use_gpu,dataloaders,class_names,dataset_sizes) model_152_ft = models.resnet152(pretrained=True) model_152_ft = train_model_main(model_152_ft,True,use_gpu,dataloaders,class_names,dataset_sizes) model_152_conv = models.resnet152(pretrained=True) model_152_conv = train_model_main(model_152_conv,False,use_gpu,dataloaders,class_names,dataset_sizes)
#3번 을 했을때 결과이다.## resnet18 #모든 파라미터를 학습하므로 시간이 많이 걸린다.
Training complete in 1m 26s
Best epoch 5 and val Acc: 0.954248#뒷단만 하므로 시간이 적게 걸린다.
Training complete in 0m 49s
Best epoch 1 and val Acc: 0.947712## resnet152
Training complete in 8m 14s
Best epoch 19 and val Acc: 0.967320
Training complete in 3m 47s
Best epoch 4 and val Acc: 0.973856
# 1번 각각 다 학습함# resnet18
Training complete in 1m 19s
Best epoch 3 and val Acc: 0.967320# 2번 뒷단만 학습함
# resnet18
Training complete in 0m 44s
Best epoch 4 and val Acc: 0.960784# 1번 각각 다 학습함
# resnet152
Training complete in 7m 59s
Best epoch 24 and val Acc: 0.980392# 2번 뒷단만 학습함
# resnet152
Training complete in 4m 2s
Best epoch 2 and val Acc: 0.954248근데 위 결과를 다 믿을 수는 없다. 이유는 suffle=True이기때문에 어떻게 잘 썪이는지가 약간 중요했다.
횟수 늘리고 데이터 늘리면 되겠지만 시간도 없고 의지도 없다.
내가 볼때 여기서 주목할 것은
# 2번 뒷단만 학습함
# resnet18
Training complete in 0m 44s
Best epoch 4 and val Acc: 0.960784이 데이터 이다.
당연히
# 1번 각각 다 학습함
# resnet152
Training complete in 7m 59s
Best epoch 24 and val Acc: 0.980392이 조건이 결과가 제일 좋았지만
처음한것이 학습시간이 1/8이 었다. 즉 간단한 모델과 적은 데이타가 있어도 전이학습을 잘만하면 최상은 아니지만 괜찮은 결과를 얻을 수 있다. 반증 같다.
참고로 3번 처럼 시험하기 위해서는 아래 처럼 코드를 수정하면 된다.
이유는 train_model.py 를 보면 가장 좋은 모델을 저장하는 코드가 내장되어 있다.
그래서 생성부분을 주석 처리하고 출력을 다시 입력으로 넣어 주면된다.
best_model_wts = copy.deepcopy(model.state_dict())model.load_state_dict(best_model_wts)# 모델 학습하기 model_ft = models.resnet18(pretrained=True) model_ft = train_model_main(model_ft,True,use_gpu,dataloaders,class_names,dataset_sizes) #model_ft = models.resnet18(pretrained=True) model_ft = train_model_main(model_ft,False,use_gpu,dataloaders,class_names,dataset_sizes) model_152_ft = models.resnet152(pretrained=True) model_152_ft = train_model_main(model_152_ft,True,use_gpu,dataloaders,class_names,dataset_sizes) #model_152_ft = models.resnet152(pretrained=True) model_152_ft = train_model_main(model_152_ft,False,use_gpu,dataloaders,class_names,dataset_sizes)
구조 파악하기
1. 모델 가져오기.
model_ft = models.resnet18(pretrained=True)맨 마지막에 있는 fully connect layer를 변경함. 입력개수는 같고 출력개수가 1000개 에서 2개로 변경함.
num_ft = model_ft.fc.in_featuresmodel_ft.fc = nn.Linear(num_ft, 2)학습과 검증을 번갈아가변서 실행됨.
num_epochs = 25번 이므로 25번 실행되고
batch_size=4이므로 한번에 4개의 이미지를 비교함.
for epoch in range(num_epochs):print('Epoch {}/{}'.format(epoch, num_epochs - 1))print('-' * 10)
# Each epoch has a training and validation phasefor phase in ['train', 'val']:if phase == 'train':scheduler.step()model.train(True) # Set model to training modeelse:model.train(False) # Set model to evaluate mode모델을 실행하고 결과가 나옴.
batch_size = 4 이고 출력 개수는 2개이므로
output.data 는 4 x 2 의 행렬 크기를 가짐.
dim = 1이라는 의미으로 max 를 하면 4x1이 되고
preds 는 index 를 저장함.
outputs = model(inputs)_, preds = torch.max(outputs.data, 1)running_loss += loss.data.item() * inputs.size(0)running_corrects += torch.sum(preds == labels.data)검증 개수는 153개
훈련개수는 244개임.
epoch_loss = running_loss / dataset_sizes[phase]epoch_acc = running_corrects / dataset_sizes[phase]인덱스를 이용해서 같은 개수 누적해서 확률을 개산함.
훈련은 61번 실행되고
검증은 39번 실행됨
batch size 4 이므로
전체 개수에서 정수로 떨어지지 않을 경우 더 많이 실행되는것을 알 수있음.
39x4=156
61x4=244
train Loss: 0.4669 Acc: 0.8074 Cnt:61
val Loss: 0.2914 Acc: 0.8954 Cnt:39질문1.
위 코드에서 batch size는 성능에 영향을 미칠까?
YES
이유는 아래 코드 때문임.
4개에서 loss 를 계산하고 *4를함.
즉 너무 크거나 너무 작으면 학습이 잘 안 될것 같음.
loss = criterion(outputs, labels)loss.data.item() * inputs.size(0)반응형'AI Basic' 카테고리의 다른 글
yolov5 모델로 보행자 사람 자전거만 탐지하기/검증파일 실행해보기. (1) 2023.03.22 yolov5 실행하기 (0) 2023.03.18 Transformer가 transfer learning에 적합한 이유. (0) 2023.03.07 conda yml 만드는 법(feat. 많이 설치되어 있다고 쫄지 말자) (0) 2023.02.13 torch에서 parameters를 보는 법 (0) 2023.02.13