Python/딥러닝(DL)

Python(35)- 전이학습

두설날 2024. 6. 21. 09:34

*이 글을 읽기전에 작성자 개인의견이 있으니, 다른 블로그와 교차로 읽는것을 권장합니다.*

1. 에일리언 vs 프레데터 데이터셋

  • 데이터셋
  • 캐글 로그인 -> 우측 상단의 계정을 클릭 -> Settings -> Account -> API의 Create New Token 클릭 -> kaggle.json 파일이 다운로드 됨
  • kaggle.json 파일 오픈
import os
os.environ['KAGGLE_USERNAME'] = 'himdo123'
os.environ['KAGGLE_KEY'] = '8f359ef1099d4ff2a07d5fa2cece36a2'
  • 점 3개 -> copy API command -> !kaggle datasets download 입력
# 점 3개 -> copy API command -> !kaggle datasets download 입력
!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 # models는 pytorch에서 제공하는 학습된 모델 제공
from torch.utils.data import DataLoader
# cpu -> gpu 런타임 유형 변경
device = 'cuda' if torch.cuda.is_available() else 'cpu'
print(device)


2. 이미지 증강 기법(Image Augmentation)

  • 원본 이미지(데이터)를 조작하여 원본과는 크고 작은 변화를 가진 이미지를 생성하여 학습하는 기법
  • 일반적으로 모델 성능이 좋아짐
  • 데이터가 좋아봐야 계속 학습해봤자 과적합 발생, 과적합 방지하는 목적
  • https://pytorch.org/vision/master/transforms.html
 

Transforming and augmenting images — Torchvision main documentation

Shortcuts

pytorch.org

data_transforms = {
    'train': transforms.Compose([
        transforms.Resize((224, 224)),
        # 각도, 찌그러뜨림, 크기
        transforms.RandomAffine(0, shear=10, scale=(0.8, 1.2)),
        # 수평으로 뒤집기
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor()
    ]),
    'validation': transforms.Compose([
        transforms.Resize((224, 224)),
        transforms.ToTensor()
    ])
}
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=False
    )
}
print(len(image_datasets['train']), len(image_datasets['validation']))

imgs, labels = next(iter(dataloaders['train']))

fig, axes = plt.subplots(4, 8, figsize=(16, 8))

for ax, img, label in zip(axes.flatten(), imgs, labels):
    # permute(): index로 차원 바꿔주기
    ax.imshow(img.permute(1, 2, 0)) # (3, 224, 224) -> (224, 224, 3)
    ax.set_title(label.item())
    ax.axis('off')

 


3. 전이 학습(Transfer Learning)

  • 하나의 작업을 위해 훈련된 모델을 유사 작업 수행 모델의 시작점으로 활용할 수 있는 딥러닝 접근법
  • 신경망은 처음부터 새로 학습하는 것보다 전이 학습을 통해 업데이트하고 재학습하는 편이 더 빠르고 간편함
  • 전이 학습은 여러 응용분야(검출, 영상인식, 자연어처리, 검색분야)에서 많이 사용됨

3-1. 전이 학습의 고려할 점

  • 크기: 모델의 코기는 배포할 위치와 방법, 규모에 따라 달라짐
  • 속도 및 정확도: 하드웨어, 배치 크기, 모델과 같은 요소를 고려

3-2. 사전 학습된 ResNet50 모델 사용하기

 

Models and pre-trained weights — Torchvision 0.18 documentation

Shortcuts

pytorch.org

3-3. RestNet50(Residual Network)의 특징

  • 네트워크가 이전 레이어의 출력을 다음 레이어로 직접 전달하는 '스킵 연결'을 통해 학습을 진행하는 방식
    합성곱 신경망으로 '잔차연결', '스킵연결' 도입하여, 기울기 소실 문제를 해결하고 훨씬 더 깊은 네트워크를 효과적으로 학습시킬 수 있음
    잔차(Residual) : 모델이 학습해야 할 오차(예측값 - 실제값)
    50개의 레이어로 구성되어 있으며 주로 Conv(컨볼루션)레이어와 Batch Normalization, ReLU 활성화 함수, 풀링 레이어 등으로 이루어져 있음
    이미지 분류, 객체 탐지 등 다양한 컴퓨터 비전 작업에서 높은 성능을 보임

4. 이미지넷(ImageNet)

이미지 데이터베이스
1000개의 클래스로 동물과 사물 이미지를 포함

model = models.resnet50(weights='IMAGENET1K_V1').to(device) # model을 GPU로 보냄
print(model)


5. Freeze Layer

  • 특징을 뽑아내는 CNN의 앞쪽 컨볼루션 레이어들은 수정하지 않도록 설정
  • 출력 부분의 레이어(FC)를 다시 설정하여 분류에 맞게 설정
for param in model.parameters():
    param.requires_grad = False # 가져온 파라미터를 업데이트 하지 않음
model.fc = nn.Sequential(
    nn.Linear(2048, 128),
    nn.ReLU(),
    nn.Linear(128, 1),
    nn.Sigmoid()
).to(device)

print(model)

# 학습
optimizer = optim.Adam(model.fc.parameters(), lr=0.001)

epochs = 10

for epoch in range(epochs):
    for phase in ['train', 'validation']:
        if phase == 'train':
            model.train()
        else: # 'validation'
            model.eval()

        sum_losses = 0
        sum_accs = 0

        for x_batch, y_batch in dataloaders[phase]:
            x_batch = x_batch.to(device)
            y_batch = y_batch.to(device)

            y_pred = model(x_batch)
            loss = nn.BCELoss()(y_pred, y_batch)

            if phase == 'train':
                optimizer.zero_grad()
                loss.backward()
                optimizer.step()

            sum_losses = sum_losses + loss

            y_bool = (y_pred >= 0.5).float()
            acc = (y_batch == y_bool).float().sum() / len(y_batch) * 100
            sum_accs = sum_accs + acc

        avg_loss = sum_losses / len(dataloaders[phase])
        avg_acc = sum_accs / len(dataloaders[phase])
        print(f'{phase:10s}: Epoch {epoch+1:4d}/{epochs} Loss: {avg_loss:.4f} Accuracy: {avg_acc:.2f}%')

from PIL import Image
img1 = Image.open('/content/data/validation/alien/21.jpg')
img2 = Image.open('/content/data/validation/predator/30.jpg')

fig, axes = plt.subplots(1, 2, figsize=(12,6))
axes[0].imshow(img1)
axes[0].axis('off')
axes[1].imshow(img2)
axes[1].axis('off')
plt.show

img1_input = data_transforms['validation'](img1)
img2_input = data_transforms['validation'](img2)
print(img1_input.shape)
print(img2_input.shape)

test_batch = torch.stack([img1_input, img2_input])
test_batch = test_batch.to(device)
test_batch.shape

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')