2025. 1. 21. 14:47ㆍLLM(Large Language Model)의 기초/딥러닝
6. Alien vs. Predator 데이터셋
* Alien vs Predator 데이터셋은 컴퓨터 비전과 이미지 분류 모델을 학습시키기 위해 제공되는 소규모 데이터셋입니다.
* 이 데이터셋은 영화 속 캐릭터인 에일리언(Alien)과 프레데터(Predator)의 이미지로 구성되어 있습니다.
* 이 데이터를 통해 이 두 클래스를 분류하는 이미지 분류 모델을 학습시킬 수 있습니다.
링크 주소 : https://www.kaggle.com/datasets/pmigdal/alien-vs-predator-images
예시 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') # 축 제거
--->
'LLM(Large Language Model)의 기초 > 딥러닝' 카테고리의 다른 글
5. 손글씨 도형 분류 FastAPI로 서빙 (2) | 2025.01.20 |
---|---|
4. Alexnet 구현하기 (4) | 2025.01.20 |
4. 손글씨 도형 분류하기 (2) | 2025.01.16 |
3. CNN(Convolutional Neural Network, 합성곱 신경망) (2) | 2025.01.15 |
2. Multi-class Weather Dataset (2) | 2025.01.14 |