수업 복습/머신러닝과 딥러닝
전이 학습
김복칠
2024. 3. 26. 21:37
optimizer = optim.Adam(model.fc.parameters(), lr = 0.001)
epochs = 10
for epoch in range(epochs + 1):
sum_loss = 0
sum_acc = 0
for x_batch, y_batch in dataloaders['train']:
x_batch, y_batch = x_batch.to(device), y_batch.to(device)
y_pred = model(x_batch)
loss = nn.BCELoss()(y_pred, y_batch)
optimizer.zero_grad()
loss.backward()
optimizer.step()
sum_loss = sum_loss + loss.item()
y_bool = (y_pred >= 0.5).float()
acc = (y_batch == y_bool).float().sum() / len(y_batch) * 100
sum_acc = sum_acc + acc.item()
avg_loss = sum_loss / len(dataloaders['train'])
avg_acc = sum_acc / len(dataloaders['train'])
print(f'Epoch {epoch:4d}/{epochs} Loss: {avg_loss:.6f} Accuracy: {avg_acc:.2f}%')
# 결과
Epoch 0/10 Loss: 0.461126 Accuracy: 76.54%
Epoch 1/10 Loss: 0.289575 Accuracy: 86.23%
Epoch 2/10 Loss: 0.243776 Accuracy: 90.22%
Epoch 3/10 Loss: 0.192780 Accuracy: 92.20%
Epoch 4/10 Loss: 0.184669 Accuracy: 93.04%
Epoch 5/10 Loss: 0.145799 Accuracy: 95.03%
Epoch 6/10 Loss: 0.184113 Accuracy: 92.57%
Epoch 7/10 Loss: 0.168040 Accuracy: 92.90%
Epoch 8/10 Loss: 0.135855 Accuracy: 95.03%
Epoch 9/10 Loss: 0.147568 Accuracy: 94.25%
Epoch 10/10 Loss: 0.121778 Accuracy: 95.74%
1. 에일리언 vs 프레데터 데이터셋
Alien vs. Predator images
Small image classification - for transfer learning
www.kaggle.com
- 케글 로그인 -> 우측 상단의 계정을 클릭 -> Your Profile -> 중앙에 Account를 클릭 -> API 항목에 Create New API Token -> kaggle.json이 다운로드 됨
- {"username":"sakongmyoungheun","key":"eebb8c6baa890a589e08e51889cc3832"}
- 이번에는 기존에 존재하는 모델에 전이 학습을 진행하기 위해 kaggle에서 데이터를 불러와서 진행해보겠습니다
import os
os.environ['KAGGLE_USERNAME'] = 'sakongmyoungheun'
os.environ['KAGGLE_KEY'] = 'eebb8c6baa890a589e08e51889cc3832'
!kaggle datasets download -d pmigdal/alien-vs-predator-images
!unzip -q alien-vs-predator-images.zip
import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
from torchvision import datasets, models,transforms
from torch.utils.data import DataLoader
device = 'cuda' if torch.cuda.is_available() else 'cpu'
- kaggle에서 데이터를 불러오기 위해 kaggle_key를 발급받아 명령어로 데이터를 불러오기 위한 호출을 해줍니다
- 이후 학습에 필요한 모듈(?)을 import 해줍니다
2. 이미지 증강 기법(Image Augmentation)
- 원본 이미지(데이터)를 조작하여 원본과는 크고 작은 변화를 가진 이미지를 생성
- 일반적으로 모델의 성능이 좋아짐
- 오버피팅을 방지
- https://pytorch.org/vision/master/transforms.html
# 이미지 긍강 기법
data_transforms = {
'train': transforms.Compose([
# 크기 재조정
transforms.Resize((224, 224)),
# 각도, 찌그러뜨림, 크기,
transforms.RandomAffine(0, shear = 10, scale = (0.8, 1.2)),
# RandomHorizontalFlip: 수평으로 뒤집기
transforms.RandomHorizontalFlip(),
# tensor로 전환
transforms.ToTensor()
]),
'validation': transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor()
])
}
- 먼저 데이터를 동일한 조건으로 변경하는 transforms를 만들어 줍니다
- 이 data_transforms 딕셔너리는 데이터의 크기, 각도, 기울어짐 정도를 동일하게 하는 역할을 합니다
def target_transforms(target):
return torch.FloatTensor([target])
image_datasets = {
'train': datasets.ImageFolder('data/train', data_transforms['train'], target_transform=target_transforms),
'validation': datasets.ImageFolder('data/validation', data_transforms['validation'], target_transform=target_transforms)
}
dataloaders = {
'train':DataLoader(
image_datasets['train'],
batch_size=32,
shuffle=True
),
'validation':DataLoader(
image_datasets['validation'],
batch_size=32,
shuffle=True
)
}
- 그리고 transforms에 맞는 데이터를 적용시켜줍니다
- 마찬가지로 딕셔너리로 구성을 해서 train과 test를 나누어 torch 형태로 바꾸어 줍니다
- 그리고 나누어진 데이터를 dataloader를 만들어서 학습시킬 batch_size를 설정해 줍니다
3. 전이 학습(Transfer Learning)
- 하나의 작업을 위해 훈련된 모델을 유사 작업 수행 모델의 시작점으로 활용하는 딥러닝 접근법
- 신경망은 처음부터 새로 학습하는 것보다 전이 학습을 통해 업데이트하고 재학습하는 편이 더 빠르고 간편함
- 전이 학습은 여러 응용 분야(검출, 영상 인식, 음성 인식, 검색 분야)에서 많이 사용됨
3-1. 전이 학습의 고려할 점
- 크기 : 모델 크기는 배포할 위치와 방법에 따라 달라짐
- 속도 및 정확도 : 하드웨어, 배치 크기와 같은 요소를 고려
3-2. 사전 학습된 ResNet50 모델 사용하기
4. Freeze Layers
- 특징을 뽑아내는 CNN의 앞쪽 컨볼루션 레이어들은 학습을 하지 않도록 설정
- 출력 부분의 레이어(fc)를 다시 설정하여 분류에 맞게 변경
model = models.resnet50(weights='IMAGENET1K_V1').to(device)
for param in model.parameters():
param.requires_grad = False # 가져온 파라미터 (W,b)를 업데이트하지 않음
# 기존의 모델을 우리의 입맞에 맞게 바꾸는 과정
model.fc = nn.Sequential(
nn.Linear(2048, 128),
nn.ReLU(),
nn.Linear(128,1),
nn.Sigmoid()
).to(device)
- 먼저 resent50을 불러옵니다
- 이후 학습하는 과정에서 모델이 최신화 될 수 있기 때문에 파라미터는 업데이트 되지 않도록 해줍니다
- 그리고 출력되는 과정을 ReLU와 Sigmoid 함수를 이용해 레이어를 추가해서 완성해 줍니다
# train
optimizer = optim.Adam(model.fc.parameters(), lr = 0.001)
epochs = 10
for epoch in range(epochs + 1):
sum_loss = 0
sum_acc = 0
for x_batch, y_batch in dataloaders['train']:
x_batch, y_batch = x_batch.to(device), y_batch.to(device)
y_pred = model(x_batch)
loss = nn.BCELoss()(y_pred, y_batch)
optimizer.zero_grad()
loss.backward()
optimizer.step()
sum_loss = sum_loss + loss.item()
y_bool = (y_pred >= 0.5).float()
acc = (y_batch == y_bool).float().sum() / len(y_batch) * 100
sum_acc = sum_acc + acc.item()
avg_loss = sum_loss / len(dataloaders['train'])
avg_acc = sum_acc / len(dataloaders['train'])
# test
model.eval()
optimizer = optim.Adam(model.fc.parameters(), lr = 0.001)
epochs = 10
for epoch in range(epochs + 1):
sum_loss = 0
sum_acc = 0
for x,y in dataloaders['validation']:
x = x.to(device)
y = y.to(device)
y_pred = model(x)
loss = nn.BCELoss()(y_pred, y)
sum_loss = sum_loss + loss.item()
y_bool = (y_pred >= 0.5).float()
acc = (y_bool == y).float().sum() / len(y) * 100
sum_acc = sum_acc + acc.item()
avg_loss = sum_loss / len(dataloaders['validation'])
avg_acc = sum_acc / len(dataloaders['validation'])
- 이제 만들어진 모델을 가지고 train과 test를 진행해 줍니다
- loss와 accuracy 수치를 확인하고자 optimizer와 loss를 설정해 줍니다
- 이렇게 학습까지 완료한 모델을 예측 분류작업을 해줍니다
# 테스트할 이미지
img1 = Image.open('./data/validation/alien/19.jpg')
img2 = Image.open('./data/validation/predator/20.jpg')
# transforms 진행
img1_input = data_transforms['validation'](img1)
img2_input = data_transforms['validation'](img2)
# 이미지를 분류하기 위한 설정 및 모델에 주입
test_batch = torch.stack([img1_input, img2_input])
test_batch = test_batch.to(device)
y_pred = model(test_batch)
y_pred
# 이미지 결과 출력
fig ,axes = plt.subplots(1,2,figsize=(12,6))
axes[0].set_title(f'{(1-y_pred[0,0])*100:.2f}% Alien, {(y_pred[0,0])*100:.2f}% Predator')
axes[0].imshow(img1)
axes[0].axis('off')
axes[1].set_title(f'{(1-y_pred[1,0])*100:.2f}% Alien, {(y_pred[1,0])*100:.2f}% Predator')
axes[1].imshow(img2)
axes[1].axis('off')
plt.show()