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

https://www.kaggle.com/datasets/pmigdal/alien-vs-predator-images

 

Alien vs. Predator images

Small image classification - for transfer learning

www.kaggle.com

  • 캐글 로그인 -> 우측 상단 계정 클릭 -> Your Profile -> 중앙Account 클릭 -> API 항목에 Create New API Token 클릭 -> kaggle.json이 자동으로 다운로드 됩니다.

실습 시작


1. 필요 모듈 임포트

import os
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

 

2. datasets 다운로드 및 압축풀기

os.environ['KAGGLE_USERNAME'] = 'username'
os.environ['KAGGLE_KEY'] = '토큰키값'

다운로드 된 kaggle.json파일을 열어보시면 해당 값들이 적혀 있습니다. 값을 넣어서 다운로드 받으면 됩니다.

 

2-1. 다운로드

!kaggle datasets download -d pmigdal/alien-vs-predator-images

 

2-2. 압축풀기

!unzip -q alien-vs-predator-images.zip

 

3. gpu 변경

device = 'cuda' if torch.cuda.is_available() else 'cpu'
print(device)

# 결과값 => cuda

 

2. 이미지 증강 기법을 이용하여 예측하기

  • 원본 이미지(데이터)를 조작하여 워본과는 크고 작은 변화를 가진 이미지를 생성
  • 일반적으로  모델 성능이 좋아짐
  • 오버피팅을 방지함

https://pytorch.org/vision/master/transforms.html

 

Transforming and augmenting images — Torchvision main documentation

Shortcuts

pytorch.org

 

4. data_tranforms 생성

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.Resize() = 이미지의 크기를 조절 (224 * 224)
  • transforms.RandomAffine() = 무작위로 이미지에 아핀 변환을 적용
    • 0 : 회전각도를 설정
    • shear = 10 : 이미지를 최대 10도까지 기울여 변형(shear)
    • scale = (0.8, 1.2) : 이미지의 크기를 0.8배 ~ 1.2배 사이로 무작위로 조정
  • transforms.RandomHorizontalFlip() : 이미지를 수평 방향으로 무작위로 뒤집습니다.
    • 이미지의 좌우 대칭성을 활용하여 데이터의 다양성을 증가시키기 위함.
  • transforms.ToTensor() : PIL 이미지 또는 NumPy ndarray를 PyTorch 텐서로 변환하며 픽셀의 강도 값을 0 ~ 1 범위로 정규화

5. target_transforms의 함수 생성

def target_transforms(target):
    return torch.FloatTensor([target])

 

6. image 데이터셋 준비

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

 

7. 데이터로드 준비

dataloaders = {
    'train': DataLoader(
        image_datasets['train'],
        batch_size = 32,
        shuffle = True
    ),
    'validation': DataLoader(
        image_datasets['validation'],
        batch_size = 32,
        shuffle = True
    )
}
print(len(image_datasets['train']), len(image_datasets['validation']))

# 결과값 => 694, 200

 

8. 학습

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

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

for ax, img, label in zip(axes.flatten(), imgs, labels):
    ax.imshow(img.permute(1, 2, 0))
    ax.set_title(label.item())
    ax.axis('off')


3. 전이 학습(Transform Learning)

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

 

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

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

4. 사전 학습된 RestNet50 모델 사용하기

  • 파이토치에서 제공하는 사전 학습 모델들

https://pytorch.org/vision/stable/models.html

 

Models and pre-trained weights — Torchvision 0.16 documentation

Shortcuts

pytorch.org

 

5. 이미지넷(ImageNet)

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


RestNet50 모델 사용하기

9. 모델 생성하기

model = models.resnet50(weights = 'IMAGENET1K_V1').to(device)
print(model)

더 많은 내용이 있지만 생략함.

10. Freeze Layers 사용하기

for param in model.parameters():
    # 가져온 파라미터(W, b)를 업데이트 하지 않음
    param.requires_grad = False

model.fc = nn.Sequential(
    nn.Linear(2048, 128),
    nn.ReLU(),

    nn.Linear(128, 1),
    nn.Sigmoid()
).to(device)

 

11. 학습하기

# 학습
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 :
            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}%')

 

12. 학습 후 이미지 테스트

from PIL import Image

img1 = Image.open('./data/validation/alien/19.jpg)
img2 = Image.open('./data/validaition/predator/20.jpg')

_, 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()

이미지는 정상적으로 출력이 되는걸 볼 수 있습니다.

 

13. 이미지를 텐서형으로 바꾸기

# 이미지를 텐서형으로 바꾸기
img1_input = data_transforms['validation'](img1)
img2_input = data_transforms['validation'](img2)
print(img1_input.shape)
print(img2_input.shape)

# 결과값 => 
# torch.Size([3, 224, 224])
# torch.Size([3, 224, 224])

 

14. 2개를 batch로 묶어서 넣기

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

# 결과값 => torch.Size([2, 3, 224, 224])

※ stack() : 차원을 쌓아줌

 

15. 예측하기

y_pred = model(test_batch)

_, 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()