import torch
import torch.nn as nn
import torchvision
from torchvision import transforms
from torch.utils.data import DataLoader, Subset
from torch.utils.tensorboard import SummaryWriter
# Device 설정
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# 데이터 전처리
def get_smile(attr):
return attr[31] # 웃음 레이블 추출
transform_train = transforms.Compose([
transforms.RandomCrop([178, 178]),
transforms.RandomHorizontalFlip(),
transforms.Resize([64, 64]),
transforms.ToTensor(),
])
transform = transforms.Compose([
transforms.CenterCrop([178, 178]),
transforms.Resize([64, 64]),
transforms.ToTensor(),
])
# 데이터셋 로드
image_path = './'
celeba_train_dataset = torchvision.datasets.CelebA(
image_path, split='train',
target_type='attr', download=False,
transform=transform_train, target_transform=get_smile
)
celeba_valid_dataset = torchvision.datasets.CelebA(
image_path, split='valid',
target_type='attr', download=False,
transform=transform, target_transform=get_smile
)
celeba_test_dataset = torchvision.datasets.CelebA(
image_path, split='test',
target_type='attr', download=False,
transform=transform, target_transform=get_smile
)
# 데이터셋 서브셋 가져오기
celeba_train_dataset = Subset(celeba_train_dataset, torch.arange(16000))
celeba_valid_dataset = Subset(celeba_valid_dataset, torch.arange(1000))
# 데이터로더 작성
batch_size = 32
train_dl = DataLoader(celeba_train_dataset, batch_size, shuffle=True)
valid_dl = DataLoader(celeba_valid_dataset, batch_size, shuffle=False)
test_dl = DataLoader(celeba_test_dataset, batch_size, shuffle=False)
# CNN 모델 정의
model = nn.Sequential(
nn.Conv2d(3, 32, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2),
nn.Dropout(p=0.5),
nn.Conv2d(32, 64, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2),
nn.Dropout(p=0.5),
nn.Conv2d(64, 128, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2),
nn.Conv2d(128, 256, kernel_size=3, padding=1),
nn.ReLU(),
nn.AvgPool2d(kernel_size=8),
nn.Flatten(),
nn.Linear(256, 1),
nn.Sigmoid()
)
model.to(device) # 모델을 GPU로 이동
import numpy as np
import matplotlib.pyplot as plt
def train(model, num_epochs, train_dl, valid_dl):
loss_fn = nn.BCELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
loss_hist_train = []
accuracy_hist_train = []
loss_hist_valid = []
accuracy_hist_valid = []
x_arr = []
# plt.ion() 호출 추가 (인터랙티브 모드 활성화)
plt.ion()
fig = plt.figure(figsize=(12, 4))
ax1 = fig.add_subplot(1, 2, 1)
ax2 = fig.add_subplot(1, 2, 2)
for epoch in range(num_epochs):
model.train()
loss_tmp = 0
accuracy_tmp=0
for x_batch, y_batch in train_dl:
x_batch, y_batch = x_batch.to(device), y_batch.to(device) # 데이터 GPU로 이동
optimizer.zero_grad() # gradient 초기화
pred = model(x_batch)[:, 0] # 모델 예측
loss = loss_fn(pred, y_batch.float()) # 손실 계산
loss.backward() # 기울기 계산
optimizer.step() # 파라미터 업데이트
loss_tmp += loss.item()*y_batch.size(0)
is_correct = ((pred>=0.5).float() == y_batch).float() # 정확도 계산
accuracy_tmp += is_correct.sum()
loss_hist_train.append(loss_tmp / len(train_dl.dataset))
accuracy_hist_train.append(accuracy_tmp / len(train_dl.dataset))
# 검증 루프
model.eval()
with torch.no_grad():
loss_tmp = 0
accuracy_tmp=0
for x_batch, y_batch in valid_dl:
x_batch, y_batch = x_batch.to(device), y_batch.to(device) # 데이터 GPU로 이동
pred = model(x_batch)[:, 0]
loss = loss_fn(pred, y_batch.float())
loss_tmp += loss.item()*y_batch.size(0)
is_correct = ((pred>=0.5).float() == y_batch).float()
accuracy_tmp += is_correct.sum()
loss_hist_valid.append(loss_tmp / len(valid_dl.dataset))
accuracy_hist_valid.append(accuracy_tmp / len(valid_dl.dataset))
ax1.clear()
ax2.clear()
x_arr.append(epoch)
# Loss 그래프
ax1.plot(x_arr, loss_hist_train, '-o', label='Train loss')
ax1.plot(x_arr, loss_hist_valid, '--<', label='Validation loss')
ax1.set_xlabel('Epoch', size=15)
ax1.set_ylabel('Loss', size=15)
ax1.legend(fontsize=15)
# Accuracy 그래프
ax2.plot(x_arr, accuracy_hist_train, '-o', label='Train acc.')
ax2.plot(x_arr, accuracy_hist_valid, '--<', label='Validation acc.')
ax2.set_xlabel('Epoch', size=15)
ax2.set_ylabel('Accuracy', size=15)
ax2.legend(fontsize=15)
plt.draw() # 그래프 갱신
plt.pause(0.1) # 0.1초 대기
print(f'에포크 {epoch+1} 정확도: {accuracy_hist_train[epoch]:.4f} 검증 정확도: {accuracy_hist_valid[epoch]:.4f}')
plt.show() # 마지막 그래프 출력
return loss_hist_train, loss_hist_valid, accuracy_hist_train, accuracy_hist_valid
torch.manual_seed(1)
num_epochs = 30
hist = train(model, num_epochs, train_dl, valid_dl)
첫댓글 매우 좋은 정보입니다. 모두들 읽어보세요