[kaggle] 선인장 식별하기 - Baseline model

youznn·2023년 2월 26일
0

Must Have - 머신러닝, 딥러닝 문제해결 전략__(신백균 저)
11장 항공 사진 내 선인장 식별 경진대회에 대한 내용

시드값 고정

시드값 고정하는 이유: 여러번 실행해도 계속 같은 결과를 얻기 위함


import torch
import random
import numpy as np
import os

seed = 50
os.environ['PYTHONHASHSEED'] = str(seed)
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
torch.backends.cudnn.enabled = False

GPU 장비 설정

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

내 컴퓨터에서는 cuda 할당

데이터 준비

google colab에서 작업하였다. 경로 설정해준다. 이미 EDA 과정에서 압축은 해제했다.

import pandas as pd

data_path = '/content/drive/MyDrive/cactus/'
labels = pd.read_csv(data_path + 'train.csv')
submission = pd.read_csv(data_path+'sample_submission.csv')

훈련데이터와 검증데이터도 분리해 줘야 한다. sklearn의 train_test_split으로 하면 된다.

from sklearn.model_selection import train_test_split

train,valid = train_test_split(labels, test_size = 0.1, stratify= labels['has_cactus'], random_state = 50)

train과 valid set의 데이터 개수를 확인해주면

print(len(train))
print(len(valid))

15750 1750
이 출력된다.

데이터셋 클래스 정의/생성

import cv2
from torch.utils.data import Dataset

class ImageDataset(Dataset):
#생성자
  def __init__(self, df, img_dir = './', transform = None):
    super().__init__()
    self.df = df
    self.img_dir = img_dir
    self.transform = transform
    
  #데이터셋 크기 반환하는 메서드
  def __len__(self):
    return len(self.df)
  #해당 인덱스 데이터 반환 메서드
  def __getitem__(self,idx):
    img_id = self.df.iloc[idx,0]
    img_path = self.img_dir + img_id
    image= cv2.imread(img_path)
    image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB) #RGB로 바꿔줘야 한다.
    label = self.df.iloc[idx,1]

    if self.transform is not None:
      image = self.transfr(image)
    return image,label

데이터셋 클래스 정의가 완료되었으니, 데이터셋을 생성해준다.

from torchvision import transforms
transform = transforms.ToTensor()
dataset_train = ImageDataset(df=train, img_dir = '/content/drive/MyDrive/cactus/train/', transform = transform)
dataset_valid = ImageDataset(df=valid, img_dir = '/content/drive/MyDrive/cactus/valid/', transform = transform)

클래스에 df에는 데이터를 전달, img_dir는 이미지 디렉토리, transform에는 방금 만든 transform을 전달해서 인스턴스 생성

데이터로더 생성

from torch.utils.data import DataLoader
loader_train = DataLoader(dataset=dataset_train, batch_size=32 , shuffle=True)
loader_valid= DataLoader(dataset=dataset_valid, batch_size=32 , shuffle=False)

dataset에는 위에서 만든 데이터셋을 전달, batch_size는 2의 제곱수로 설정하면 좋고, shuffle은 데이터 섞는 건데 훈련 데이터는 섞으면 좋지만 검증 데이터는 섞을 필요가 없다.

  • batch size: 데이터셋을 얼마나 쪼갤 것인가
    • 작을수록 일반화 성능 좋아짐
    • 작을수록 많은 iteration

모델 생성하기 (CNN)

import torch.nn as nn
import torch.nn.functional as F

class Model(nn.Module):

  def __init__(self):
    super().__init__() #상속받은 nn.Module 메서드에서 init 호출하기

    self.conv1 = nn.Conv2d(in_channels = 3, out_channels = 32, kernel_size = 3, padding = 2)
    self.conv2 = nn.Conv2d(in_channels = 32, out_channels = 64, kernel_size = 3, padding = 2)
    self.max_pool = nn.MaxPool2d(kernel_size=2)
    self.avg_pool = nn.AvgPool2d(kernel_size=2)
    self.fc = nn.Linear(in_features = 64*4*4, out_features = 2)
  
  def forward(self,x):
    x = self.max_pool(F.relu(self.conv1(x)))
    x = self.max_pool(F.relu(self.conv2(x)))
    x = self.avg_pool(x)
    x = x.view(-1, 64*4*4)
    x = self.fc(x)
    return x

forward() 메서드: 순전파 출력을 계산한다.
x = self.max_pool(F.relu(self.conv1(x))) : 첫번째 합성곱 연산
x = self.max_pool(F.relu(self.conv2(x))) : 두번째 합성곱 연산
x = self.avg_pool(x) : 평균 풀링
x = x.view(-1, 64*4*4) : 평탄화 , view가 데이터 모양을 바꿈
x = self.fc(x) : 전결합

손실 함수, 옵티마이저

#손실함수
criterion = nn.CrossEntropyLoss() #교차엔트로피

#옵티마이저
optimizer = torch.optim.SGD(model.parameters(), lr = 0.01)

모델 훈련

epochs = 10

for epoch in range(epochs):
  epoch_loss = 0

  for images, lables in loader_train:
    image = images.to(device)
    labels = labels.to(device)

    optimizer.zero_grad()
    outputs = model(images)

    loss = criterion(outputs, labels)
    epoch_loss += loss.item()
    loss.backward()
    optimizer.step()
profile
https://github.com/youznn

0개의 댓글