일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- DP
- ssafy 7기 교수님
- SSAFY
- 전이학습
- pytorch
- ssafy 7기 합격
- 백준
- git
- 코딩교육
- React
- 삼성 청년 SW 아카데미
- DenseNet
- 프로그래머스
- 알고리즘
- 웹 표준 사이트 만들기
- SSAFY 입학식
- SWEA
- 코딩 교육
- SSAFY 8기
- 유니온 파인드
- SSAFYcial
- dfs
- 프로그래머스 고득점 kit
- Learning
- 백준7576 bfs
- 이코테
- 싸피 7기 입학식
- 삼성청년sw아카데미
- bfs
- ssafy 7기
- Today
- Total
개미의 개열시미 프로그래밍
[4주차] 전이학습(Transfer Learning) <실습 정리편> 본문
전이 학습(Transfer learning)은 직접 코드를 보면서 이해하는 것이 이해하는데 도움이 많이 되었습니다.
실습은 PyTorch.org 사이트에서 전이 학습에 대한 코드를 Colab, Jupyter notebook, GitHub으로 공유하고 있고 이 공유된 코드를 통해 정리를 하려고 합니다.
tutorials.pytorch.kr/beginner/transfer_learning_tutorial.html
전에 <이론 정리편>을 이해했다면 아래와 같은 말을 이해할 수 있습니다.
reliablecho-programming.tistory.com/1?category=921344
실제로 충분한 크기의 데이터셋을 갖추기는 상대적으로 드물기 때문에, (무작위 초기화를 통해) 맨 처음부터 합성곱 신경망(Convolutional Network) 전체를 학습하는 사람은 매우 적습니다. 대신, 매우 큰 데이터셋(예. 100가지 분류에 대해 120만 개의 이미지가 포함된 ImageNet)에서 합성곱 신경망(ConvNet)을 미리 학습한 후, 이 합성곱 신경망을 관심 있는 작업을 위한 초기 설정 또는 고정된 특징 추출기(fixed feature extractor)로 사용합니다.
먼저, 학습을 하는 과정을 순서대로 나열해보자면
- 데이터 불러오기(정규화)
- 모델 정의
- 손실함수 및 Optimizer 정의
- Train dataset을 통해 학습 & Test dataset을 통해 평가
1. 데이터 불러오기(정규화)
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']}
# path['train']는 train set의 경로
# path['test']는 val set의 경로
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
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
데이터는 공공데이터인 hymenopetra dataset을 사용했으며 벌과 개미 두 개의 클래스를 가집니다.
*일부 이미지(batch size=4) 시각화해보기
def imshow(inp, title=None):
"""Imshow for Tensor."""
inp = inp.numpy().transpose((1, 2, 0))
mean = np.array([0.485, 0.456, 0.406])
std = np.array([0.229, 0.224, 0.225])
inp = std * inp + mean
inp = np.clip(inp, 0, 1)
plt.imshow(inp)
if title is not None:
plt.title(title)
plt.pause(0.001) # 갱신이 될 때까지 잠시 기다립니다.
# 한개의 Bathc만큼 이미지를 불러온다. 배치사이를 4로 헀으니 4장이 로드된다.
inputs, classes = next(iter(dataloaders['train']))
# 배치로부터 격자 형태의 이미지를 만듭니다.
out = torchvision.utils.make_grid(inputs)
# 이미지를 출력한다.
imshow(out, title=[class_names[x] for x in classes])
데이터셋 다운로드가 잘되었는지 판단?하기 위한 과정인 것 같습니다. batch size를 4로 설정했기 때문에 총 4개의 이미지를 출력합니다.
2. 모델 정의
model_ft = models.resnet18(pretrained=True) #pretrained model을 가져온다.
for param in model_ft.parameters(): # False로 설정함으로써 마지막 classifier를 제외한 모든 부분을 고정하여 backward()중에 경사도 계산이 되지 않도록 합니다.
param.requires_grad = False
num_ftrs = model_ft.fc.in_features # ResNet18모델의 마지막 단에서, 출력 노드의 갯수를 구해주는 함수이다.
model_ft.fc = nn.Linear(num_ftrs, 2)
# 이렇듯 Pretrained-model의 끝단에 Fully connected layer를 추가로 삽입하고 노드를 연결시켜 주는 것이 우리가 사용할 모델
# 본 예제에서는 Fully connected layer 즉 Linear layer의 출력 노드 갯수는 Class의 갯수와 같다.(개미와 벌 == 2)
model_ft = model_ft.to(device)
첫번째 줄에서 pretrained를 True로 설정함으로써 학습된 모델을 불러올 때 자동으로 Weights 값을 불러올 수 있습니다.
(주의) param.requires_grad 를 True로 설정하는 경우 모델 전체에 대해 backward계산을 진행합니다.
3. 손실함수 및 Optimizer 정의
criterion = nn.CrossEntropyLoss()
optimizer_ft = optim.SGD(model_ft.parameters(), lr=0.001, momentum=0.9)
exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)
# Learning Rate Scheduler를 사용하면 좀 더 효율적으로 Global Minimam에 수렴할 수 있다.
# 예를 들면 특정 Epoch마다 Learning Rate를 다르게 해서 좀 더 효율 적으로 Global minima
# 에 수렴할 수 있도록 도와준다.
4. Train dataset을 통해 학습 & Test dataset을 통해 평가
def train_model(model, criterion, optimizer, scheduler, num_epochs=25):
since = time.time() # 시작 시간을 기록(총 소요 시간 계산을 위해)
# fc를 초기화한 model의 parameter를 저장
best_model_wts = copy.deepcopy(model.state_dict())
best_acc = 0.0
#지정한 epoch을 돌며 training
for epoch in range(num_epochs):
print('Epoch {}/{}'.format(epoch, num_epochs - 1)) #epoch를 카운트
print('-' * 10)
# 각 에폭(epoch)은 학습 단계와 검증 단계를 갖습니다.
for phase in ['train', 'val']: # train mode와 validation mode순으로 진행
if phase == 'train':
model.train() # 모델을 train 모드로 설정
else:
model.eval() # 모델을 eval(=val) 모드로 설정
running_loss = 0.0
running_corrects = 0
# 데이터를 반복
for inputs, labels in dataloaders[phase]:
inputs = inputs.to(device)
labels = labels.to(device)
# 매개변수 Gradiant를 0으로 초기화
optimizer.zero_grad()
# 순전파(foward)
# 학습 시(train)에만 연산 기록을 추적
# train의 경우 끝 fc부분만 진행이된다.
with torch.set_grad_enabled(phase == 'train'):
outputs = model(inputs)
_, preds = torch.max(outputs, 1)
loss = criterion(outputs, labels)
# 학습 단계인 경우 역전파 + 최적화
if phase == 'train':
loss.backward()
optimizer.step()
# 통계
running_loss += loss.item() * inputs.size(0)
running_corrects += torch.sum(preds == labels.data)
if phase == 'train':
scheduler.step()
epoch_loss = running_loss / dataset_sizes[phase]
epoch_acc = running_corrects.double() / dataset_sizes[phase]
print('{} Loss: {:.4f} Acc: {:.4f}'.format(
phase, epoch_loss, epoch_acc))
# 모델을 깊은 복사(deep copy)함
# val을 수행하고
if phase == 'val' and epoch_acc > best_acc:
best_acc = epoch_acc
best_model_wts = copy.deepcopy(model.state_dict())
print()
time_elapsed = time.time() - since
print('Training complete in {:.0f}m {:.0f}s'.format(
time_elapsed // 60, time_elapsed % 60))
print('Best val Acc: {:4f}'.format(best_acc))
# 가장 나은 모델 가중치를 불러옴
model.load_state_dict(best_model_wts)
return model
#코드에서 보면 확인할 수 있듯이 학습과 검사를 동시에 진행을 하여 epoch마다 Training acc와 Test acc를 확인할 수 있습니다. 최적의 epoch값을 찾기에 좋은 것 같습니다.
코드에서 보면 확인할 수 있듯이 학습과 검사를 동시에 진행을 하여 epoch마다 Training acc와 Test acc를 확인할 수 있
습니다. 최적의 epoch값을 찾기에 좋은 것 같습니다.
model_ft = train_model(model_ft, criterion, optimizer_ft,
exp_lr_scheduler, num_epochs=25)
이제 위의 코드를 통해 train, test의 정확도를 확인해봅니다.
이전에 학습이 잘된 모델의 weights를 통해서 새 모델을 생성해주는 전이 학습기법을 통해 95% 이상의 높은 결과가 나온 것을 확인할 수 있었습니다.
이번 인턴과제인 '유사이미지 분류' 또한 전이 학습을 이용하기에 실습으로 정리를 해보았습니다. 다음은 지금까지 정리한 전이 학습(Transfer learning)과 Densnet을 통해 구현한 과제를 정리해보도록 하겠습니다.
'인턴쉽 > 동계백마인턴쉽(2021)' 카테고리의 다른 글
[6~7주차] '유사 이미지 분류기' 구현완성 (1) | 2021.02.08 |
---|---|
[5주차] '유사 이미지 분류' Trainer코드 제작 (0) | 2021.02.08 |
[4주차] 전이학습(Transfer Learning) <이론 정리편> (0) | 2021.02.08 |
[2~3주차] DenseNet <이론 정리편> (0) | 2021.02.08 |
[1주차] 환경세팅하기 (Anaconda + PyTorch) (1) | 2021.02.08 |