6. Alien vs. Predator 데이터셋

2025. 1. 21. 14:47LLM(Large Language Model)의 기초/딥러닝

6. Alien vs. Predator 데이터셋
* Alien vs Predator 데이터셋은 컴퓨터 비전과 이미지 분류 모델을 학습시키기 위해 제공되는 소규모 데이터셋입니다. 
* 이 데이터셋은 영화 속 캐릭터인 에일리언(Alien)과 프레데터(Predator)의 이미지로 구성되어 있습니다. 
* 이 데이터를 통해 이 두 클래스를 분류하는 이미지 분류 모델을 학습시킬 수 있습니다.

링크 주소 : https://www.kaggle.com/datasets/pmigdal/alien-vs-predator-images

 

Alien vs. Predator images

Small image classification - for transfer learning

www.kaggle.com

 

예시 1)

#폴더 다운로드
!kaggle datasets download pmigdal/alien-vs-predator-images

 

예시 2)

#폴더 압축 풀기
!unzip -q alien-vs-predator-images.zip

 

2. Alexnet 모델을 활용한 Alien vs Predator 분류

 

예시 1)

device = 'cuda' if torch.cuda.is_available() else 'cpu' #현재 사용하고 있는 장치
print(device)
-->
cpu

 

 

예시 2)

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

# 데이터 전처리 정의
data_transforms = {
    'train': transforms.Compose([
        transforms.Resize((224, 224)),  # 이미지를 224x224 크기로 조정
        # 각도 변환, 찌그러뜨림, 크기 조정 (데이터 증강)
        transforms.RandomAffine(0, shear=10, scale=(0.8, 1.2)),
        # 수평으로 이미지를 뒤집기 (확률적으로 적용)
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor()  # 이미지를 텐서로 변환
    ]),
    'validation': transforms.Compose([
        transforms.Resize((224, 224)),  # 이미지를 224x224 크기로 조정
        transforms.ToTensor()  # 이미지를 텐서로 변환
    ])
}

 

예시 3)

def target_transforms(target):
    # 주어진 타겟 값을 FloatTensor 형태로 변환하여 반환
    return torch.FloatTensor([target])

 

예시 4)

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)  # 검증 데이터셋 로드 및 전처리 적용
}

 

예시 5)

dataloaders = {
    'train': DataLoader(
        image_datasets['train'],  # 학습 데이터셋 로드
        batch_size=32,  # 배치 크기 설정 (한 번에 처리할 데이터 개수)
        shuffle=True  # 데이터를 무작위로 섞어서 로드
    ),
    'validation': DataLoader(
        image_datasets['validation'],  # 검증 데이터셋 로드
        batch_size=32,  # 배치 크기 설정 (한 번에 처리할 데이터 개수)
        shuffle=False  # 데이터를 순차적으로 로드 (섞지 않음)
    )
}

 

예시 6)

print(len(image_datasets['train']), len(image_datasets['validation']))  # 학습 데이터셋과 검증 데이터셋의 샘플 개수를 출력

 

예시 7)

imgs, labels = next(iter(dataloaders['train']))  # 학습 데이터로부터 첫 번째 배치(이미지와 라벨)를 가져옴

fig, axes = plt.subplots(4, 8, figsize=(16, 8))  # 4행 8열의 서브플롯 생성, 전체 크기 설정

for ax, img, label in zip(axes.flatten(), imgs, labels):  # 이미지와 라벨을 각각 플롯에 매핑
    ax.imshow(img.permute(1, 2, 0))  # 이미지의 채널 순서 변경 (3, 224, 224) -> (224, 224, 3)
    ax.set_title(label.item())  # 라벨 값을 제목으로 설정
    ax.axis('off')  # 플롯의 축 제거

---->

 

3. 전이 학습
* 전이 학습(Transfer Learning)은 이미 학습된 모델(주로 대규모 데이터셋에서 사전 학습된 딥러닝 모델)을 새로운 문제에 적용하여 학습 시간을 단축하고 성능을 향상시키는 방법입니다. 
* 기존 모델이 학습한 특징(Feature)을 활용해, 새로운 데이터셋에서 모델의 일부(주로 마지막 레이어)만 다시 학습하거나 추가 학습(Fine-tuning)을 진행합니다. 
* 이는 특히 데이터가 적거나 학습 리소스가 제한된 상황에서 효과적이며, 이미지 분류(예: ResNet, VGG), 자연어 처리(예: BERT, GPT) 등 다양한 분야에서 널리 사용됩니다.

 

 

예시 1)

model = models.alexnet(weights='IMAGENET1K_V1').to(device)  # 사전 학습된 AlexNet 모델을 로드하고 장치(CPU/GPU)로 이동
print(model)  # 모델 구조 출력
--->
AlexNet(
  (features): Sequential(
    (0): Conv2d(3, 64, kernel_size=(11, 11), stride=(4, 4), padding=(2, 2))
    (1): ReLU(inplace=True)
    (2): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
    (3): Conv2d(64, 192, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
    (4): ReLU(inplace=True)
    (5): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
    (6): Conv2d(192, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (7): ReLU(inplace=True)
    (8): Conv2d(384, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (9): ReLU(inplace=True)
    (10): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (11): ReLU(inplace=True)
    (12): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (avgpool): AdaptiveAvgPool2d(output_size=(6, 6))
  (classifier): Sequential(
    (0): Dropout(p=0.5, inplace=False)
    (1): Linear(in_features=9216, out_features=4096, bias=True)
    (2): ReLU(inplace=True)
    (3): Dropout(p=0.5, inplace=False)
    (4): Linear(in_features=4096, out_features=4096, bias=True)
    (5): ReLU(inplace=True)
    (6): Linear(in_features=4096, out_features=1000, bias=True)
  )
)

 

### 이미지넷
* 이미지넷(ImageNet)은 대규모 이미지 데이터셋으로, 컴퓨터 비전 연구와 딥러닝 모델 학습에 널리 사용됩니다. 
* 2009년 스탠포드 대학의 페이페이 리(Fei-Fei Li) 교수팀이 구축했으며, 약 1,400만 장의 이미지와 22,000개 이상의 카테고리로 구성되어 있습니다. 
* 이 중, 가장 널리 사용되는 ILSVRC(Imagenet Large Scale Visual Recognition Challenge) 버전은 약 1,000개의 클래스와 120만 장의 이미지를 포함합니다. 
* 이미지넷은 모델이 객체를 분류하고 특징을 학습하는 데 필요한 풍부한 데이터와 레이블을 제공하며, ResNet, VGG, Inception 등 여러 혁신적인 모델이 이미지넷 대회를 통해 개발되었습니다. 
* 이 데이터셋은 특히 사전 학습(Transfer Learning)에서 중요한 역할을 하며, 딥러닝 연구의 표준 벤치마크로 자리 잡았습니다.

 

 

예시 1)

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

 

### Model Freezing
* Model Freezing은 전이 학습(Transfer Learning)에서 사전 학습된 모델의 일부 또는 전체 계층의 가중치를 고정하여 학습되지 않도록 설정하는 기법입니다. 
* 주로 사전 학습된 모델의 초기 계층(Convolutional Layers 등)은 일반적인 특징(예: 가장자리, 패턴)을 학습했으므로 고정하고, 새로운 데이터셋에 특화된 특징을 학습하기 위해 최상위 계층(분류 헤드 등)만 학습합니다. 
* 이 방법은 학습할 가중치의 수를 줄여 계산 비용을 절감하고, 과적합을 방지하며, 데이터가 부족한 상황에서 특히 유용합니다. 
* 필요에 따라, 초기 학습이 끝난 후 일부 계층을 고정 해제(Fine-Tuning)하여 모델을 더 정교하게 조정할 수도 있습니다.

 

예시 1)

 

model
-->
AlexNet(
  (features): Sequential(  # 특징 추출을 담당하는 합성곱 계층 시퀀스
    (0): Conv2d(3, 64, kernel_size=(11, 11), stride=(4, 4), padding=(2, 2))  # 입력 채널 3개(RGB), 출력 채널 64개, 커널 크기 11x11, 스트라이드 4, 패딩 2
    (1): ReLU(inplace=True)  # 활성화 함수 ReLU
    (2): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)  # 맥스풀링, 커널 크기 3x3, 스트라이드 2
    (3): Conv2d(64, 192, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))  # 출력 채널 192개, 커널 크기 5x5, 스트라이드 1, 패딩 2
    (4): ReLU(inplace=True)  # 활성화 함수 ReLU
    (5): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)  # 맥스풀링
    (6): Conv2d(192, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))  # 출력 채널 384개, 커널 크기 3x3, 스트라이드 1, 패딩 1
    (7): ReLU(inplace=True)  # 활성화 함수 ReLU
    (8): Conv2d(384, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))  # 출력 채널 256개
    (9): ReLU(inplace=True)  # 활성화 함수 ReLU
    (10): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))  # 출력 채널 256개
    (11): ReLU(inplace=True)  # 활성화 함수 ReLU
    (12): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)  # 맥스풀링
  )
  (avgpool): AdaptiveAvgPool2d(output_size=(6, 6))  # Adaptive Average Pooling, 출력 크기 6x6으로 조정
  (classifier): Sequential(  # 분류를 담당하는 완전연결 계층 시퀀스
    (0): Dropout(p=0.5, inplace=False)  # 드롭아웃, 50% 확률로 노드 제거
    (1): Linear(in_features=9216, out_features=4096, bias=True)  # 입력 노드 9216개, 출력 노드 4096개
    (2): ReLU(inplace=True)  # 활성화 함수 ReLU
    (3): Dropout(p=0.5, inplace=False)  # 드롭아웃
    (4): Linear(in_features=4096, out_features=4096, bias=True)  # 완전연결 계층, 출력 노드 4096개
    (5): ReLU(inplace=True)  # 활성화 함수 ReLU
    (6): Linear(in_features=4096, out_features=1000, bias=True)  # 출력 클래스 1000개 (ImageNet 분류 기준)
  )
)

 

예시 2)

# 학습
optimizer = optim.Adam(model.classifier.parameters(), lr=0.001)  # 분류기 부분의 가중치를 업데이트하기 위해 Adam 옵티마이저 사용

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)  # 입력 데이터를 장치(CPU/GPU)로 이동
            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  # 손실 값 누적

            # 예측값을 0.5를 기준으로 0과 1로 변환하여 정확도 계산
            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}%')
        -->
train     : Epoch    9/10 Loss: 0.1152 Accuracy: 94.33%
validation: Epoch    9/10 Loss: 0.1815 Accuracy: 94.20%
train     : Epoch   10/10 Loss: 0.0728 Accuracy: 97.73%
validation: Epoch   10/10 Loss: 0.1778 Accuracy: 94.64%

 

예시 3)

from PIL import Image

# 두 개의 이미지를 로드
img1 = Image.open('/content/data/validation/alien/30.jpg')  # 첫 번째 이미지 로드
img2 = Image.open('/content/data/validation/alien/42.jpg')  # 두 번째 이미지 로드

# 두 이미지를 한 줄에 나란히 출력
fig, axes = plt.subplots(1, 2, figsize=(12, 6))  # 1행 2열의 서브플롯 생성, 전체 크기 설정
axes[0].imshow(img1)  # 첫 번째 이미지를 첫 번째 플롯에 표시
axes[0].axis('off')  # 축 제거
axes[1].imshow(img2)  # 두 번째 이미지를 두 번째 플롯에 표시
axes[1].axis('off')  # 축 제거
plt.show()  # 플롯 표시

 

 

 

예시 4)

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

 

예시 5)

test_batch = torch.stack([img1_input, img2_input])  # 전처리된 두 이미지를 하나의 배치로 스택

test_batch = test_batch.to(device)  # 배치를 장치(CPU/GPU)로 이동

test_batch.shape  # 배치의 텐서 크기를 확인
--->
orch.Size([2, 3, 224, 224])

 

예시 6)

y_pred = model(test_batch)  # 배치를 모델에 입력하여 예측값 생성
y_pred  # 예측값 확인
--->
tensor([[7.4817e-07],
        [9.8960e-01]], grad_fn=<SigmoidBackward0>)

 

예시 7)

fig, axes = plt.subplots(1, 2, figsize=(12, 6))  # 1행 2열의 서브플롯 생성, 전체 크기 설정

# 첫 번째 이미지에 대한 예측 결과를 제목으로 설정
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')  # 축 제거
--->
(-0.5, 299.5, 167.5, -0.5)

--->

 

 

예시 8)

img1 = Image.open('/content/data/validation/alien/22.jpg')  # 첫 번째 이미지 로드
img2 = Image.open('/content/data/validation/alien/24.jpg')  # 두 번째 이미지 로드

fig, axes = plt.subplots(1, 2, figsize=(12, 6))  # 1행 2열의 서브플롯 생성, 전체 크기 설정
axes[0].imshow(img1)  # 첫 번째 이미지를 첫 번째 플롯에 표시
axes[0].axis('off')  # 축 제거
axes[1].imshow(img2)  # 두 번째 이미지를 두 번째 플롯에 표시
axes[1].axis('off')  # 축 제거
plt.show()  # 플롯 표시

# 두 이미지를 전처리하여 배치로 변환
test_batch = torch.stack([img1_input, img2_input])  # 전처리된 두 이미지를 하나의 배치로 스택

test_batch = test_batch.to(device)  # 배치를 장치(CPU/GPU)로 이동
test_batch.shape  # 배치의 텐서 크기 확인

# 모델을 사용하여 예측 수행
y_pred = model(test_batch)  # 배치를 모델에 입력하여 예측값 생성
y_pred  # 예측값 확인

fig, axes = plt.subplots(1, 2, figsize=(12, 6))  # 1행 2열의 서브플롯 생성

# 첫 번째 이미지에 대한 예측 결과를 제목으로 설정
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')  # 축 제거

--->

728x90
LIST