본문 바로가기
Computer Science/Deep Learning

하이퍼파라미터 튜닝 ② [CIFAR-10]

by BaekDaBang 2024. 4. 17.

 

Baseline 정보

GPU : T4x2
모델
- resnet50 사용
- IMAGENET1K_V1 으로 가중치 초기화
- 최종 분류기의 output 차원을 class 수에 맞게 변경

from torchvision.models import resnet50, ResNet50_Weights

# ImageNet 데이터로 사전학습시킨 가중치를 불러오기.
model = resnet50(weights=ResNet50_Weights.IMAGENET1K_V1)
epochs = 3
batch_size = 128
lr=1e-3
optimizer: SGD

 

데이터 증강 기법

우선 255로 나눠서 0~1 범위로 만들기
아래 Data Augmentation 기법을 사용하였으며, pytorch 공식 documentation을 참고
https://pytorch.org/vision/stable/transforms.html

 

<학습>
i) Resize(224x224) & Random Crop
ii) Horizontal Flip (p=0.5)
iii) Dtype torch.float32로 변경
iv) mean=[0.485,0.456,0.406], std=[0.229,0.224,0.225]


<평가>
i) Resize(224x224)
ii) Dtype torch.float32로 변경
iii) mean=[0.485,0.456,0.406], std=[0.229,0.224,0.225]

 

유의사항

기존 32x32 의 이미지를 224x224로 interpolation 후 학습을 진행하다 보니 학습 시간이 3epoch 기준 약 30분정도 소요
data의 차원 순서를 고려
- 기존 3072 차원의 1D data는 (Width, Height, Channel) - (32,32,3) 을 펼친 형태
- 이를 torch의 이미지 형태인 (Channel, Height, Width) - (3,32,32) 꼴로 변경해야 함

 

 

0. 필요한 함수 Import

import numpy as np
import pandas as pd
import torch

from tqdm import tqdm
import random
import os

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

# 램덤시드 고정
random_seed= 42
random.seed(random_seed)
np.random.seed(random_seed)
os.environ["PYTHONHASHSEED"] = str(random_seed)
torch.manual_seed(random_seed)
torch.cuda.manual_seed(random_seed)
torch.cuda.manual_seed_all(random_seed)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
torch.use_deterministic_algorithms(False)

 

1. Dataset

# Load Dataset
train = pd.read_csv('')
test = pd.read_csv('')

# Preprocessing
x_train = train.iloc[:,:-1]
y_train = train['label']
x_test = test

x_train = torch.FloatTensor(np.array(x_train))
y_train = torch.LongTensor(np.array(y_train))
x_test = torch.FloatTensor(np.array(x_test))

x_train = x_train.reshape(-1,3,32,32)  # (50000,3,32,32)
x_test = x_test.reshape(-1,3,32,32)    # (10000,3,32,32)

 

2. Model

%pip install torchsummary
import torch.nn as nn
from torchvision.models import resnet50, ResNet50_Weights
from torchsummary import summary as summary_

model = resnet50(weights=ResNet50_Weights.IMAGENET1K_V1)
model.fc = nn.Linear(2048,10)
model = model.to(device)

summary_(model,(3,224,224))
# 하이퍼파라미터
import torch.optim as optim
from torch.nn import CrossEntropyLoss

epochs = 1
batch_size = 128
lr = 1e-3

optimizer = optim.SGD(model.parameters(), lr=lr)
loss_fn = CrossEntropyLoss().to(device)

 

3. Train

# Transformation
from torchvision.transforms import v2

train_transform = v2.Compose([
    v2.RandomResizedCrop(size=(224, 224), antialias=True),
    v2.RandomHorizontalFlip(p=0.5),
    v2.ToDtype(torch.float32, scale=True),
    v2.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])

test_transform = v2.Compose([
    v2.Resize(size=(224, 224)),
    v2.ToDtype(torch.float32, scale=True),
    v2.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])
# 데이터를 배치 단위로 불러오기 위한 dataset과 dataloader 정의
from torchvision.transforms import transforms
from torchvision import utils
from torch.utils.data import TensorDataset, DataLoader

train_dataset = TensorDataset(x_train, y_train)
test_dataset = TensorDataset(x_test)

train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_dataloader = DataLoader(test_dataset, batch_size=1, shuffle=False)
# Train
model.train()
display_freq = 100

for epoch in range(epochs):
    train_loss = 0
    correct = 0
    avg_loss = 0
    
    for x,y in tqdm(train_dataloader):
        x = train_transform(x)
        x = x.to(device)
        y = y.to(device)
        
        pred = model(x)
        
        loss = loss_fn(pred, y.squeeze(-1))
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        pred = pred.data.max(1, keepdim=True)[1]
        correct += pred.cpu().eq(label.data.view_as(pred)).sum()
        
        if i % display_freq == 0:
            print(f'iter:{i}, loss:%.3f' %(loss))
            avg_loss += loss
            
    train_loss /= len(train_dataloader)
    train_accuracy = correct / len(train_dataloader.dataset)
        
    print(f'epoch:{epoch+1}, train_loss:{}, avg_loss:{avg_loss/len(train_dataloader)}')
    print(f'loss: {train_loss: .5f} - acc: {train_accuracy: .5f}')

 

4. Eval

 

# Eval
preds = list()

with torch.no_grad():
    model.eval()
    for x in tqdm(test_dataloader):
        x = preprocess(x[0])
        x = x.to(device)
        
        pred = ((model(x).softmax(dim=-1)).argmax(dim=-1))[0]
        preds.append(pred.cpu())

 

5. Submit

submit = pd.read_csv('')
submit['label'] = np.array(preds)
submit.to_csv('submission.csv', index=False)