카테고리 없음
Pytorch
ynzify
2023. 7. 19. 16:21
>>> target = train["survived"].to_numpy()
>>> target
array([0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0,
0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1,
0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0,
1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0,
0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0,
0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0,
0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1,
0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1,
0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0,
1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0,
0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0,
1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0,
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1,
1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1,
0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1,
0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0,
1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1,
0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1,
0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1,
1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1,
0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1,
0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0,
0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0,
1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0,
1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0,
1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0,
0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0,
0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1,
1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0,
0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0,
1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0])
# 학습데이터
train = pd.read_csv(f"{DATA_PATH}titanic_train.csv")
# 테스트 데이터
test = pd.read_csv(f"{DATA_PATH}titanic_test.csv")
train.shape , test.shape
# 학습데이터
train = pd.read_csv(f"{DATA_PATH}titanic_train.csv")
# 테스트 데이터
test = pd.read_csv(f"{DATA_PATH}titanic_test.csv")
train.shape , test.shape
Pytorch
- 구글의 tenserflow와 유사한 딥러닝 라이브러리
- 페이스북 인공지능 연구팀에 의해 주로 개발
- https://pytorch.org
torch | 텐서 변환 및 다양한 수학 함수와 클래스 포함 |
torch.nn | 신경망을 구축하기 위한 레이어(층), 활성화 함수, 손실 함수 등 에 대한 함수와 클래스 포함 |
torch.utils.data | 미니 배치 학습을 위한 데이터셋 구성관련 함수, 클래스 포함 |
torch.optim | optimizer 관련 함수와 클래스가 포함 |
타이타닉 데이터셋으로 딥러닝 학습
- 데이터 전처리
- 미니배치 단위 학습을 위해 데이터셋 클래스 구현
- 딥러닝 모델 및 인공신경망 구현
- 하이퍼파라미터 정의 (손실함수 및 옵티마이저 선택)
- 학습 및 테스트 loop 구현
* 학습 데이터와 테스트 데이터 따로 따로 나누어 처리하기
데이터 전처리
>>> import torch
>>> import numpy as np
>>> import pandas as pd
>>> from google.colab import drive
>>> drive.mount('/content/drive')
>>> DATA_PATH = "/content/drive/MyDrive/05_deep_learning/data/"
>>> DATA_PATH
# 학습데이터
>>> train = pd.read_csv(f"{DATA_PATH}titanic_train.csv")
# 테스트 데이터
>>> test = pd.read_csv(f"{DATA_PATH}titanic_test.csv")
>>> train.shape , test.shape
((916, 12), (393, 11))
- 결측치 확인하기
# 학습 데이터셋
>>> train.isnull().sum()
passengerid 0
survived 0
pclass 0
name 0
gender 0
age 180
sibsp 0
parch 0
ticket 0
fare 0
cabin 706
embarked 0
dtype: int64
# 테스트 데이터셋
>>> test.isnull().sum()
passengerid 0
pclass 0
name 0
gender 0
age 83
sibsp 0
parch 0
ticket 0
fare 1
cabin 308
embarked 2
dtype: int64
- 학습 데이터에서 얻은 통계량을 이용해 결측치 채우기
>>> age_mean = train["age"].mean()
>>> fare_median = train["fare"].median()
>>> cabin_unk = "UNK"
>>> embarked_mode = train["embarked"].mode()[0]
>>> age_mean , fare_median ,cabin_unk , embarked_mode
(29.904891304347824, 14.5, 'UNK', 'S')
- 결측치 처리
# 학습데이터 결측치 처리
>>> train["age"] = train["age"].fillna(age_mean)
>>> train["cabin"] = train["cabin"].fillna(cabin_unk)
# 테스트데이터 결측치 처리
>>> test["age"] = test["age"].fillna(age_mean)
>>> test["fare"] = test["fare"].fillna(fare_median)
>>> test["cabin"] = test["cabin"].fillna(cabin_unk)
>>> test["embarked"] = test["embarked"].fillna(embarked_mode)
>>> train.isnull().sum().sum() , test.isnull().sum().sum()
(0, 0)
- 특성으로 사용할 변수 추가하기
>>> cols = ["age","sibsp","parch","fare","pclass","gender","embarked"]
>>> train_ft = train[cols].copy()
>>> test_ft = test[cols].copy()
>>> train_ft.shape, test_ft.shape
((916, 7), (393, 7))
- 범주형 변수를 원핫 인코딩하여 특성으로 추가하기
>>> from sklearn.preprocessing import OneHotEncoder
>>> cols = ['gender','embarked']
>>> enc = OneHotEncoder(handle_unknown = 'ignore')
>>> enc.fit(train_ft[cols])
OneHotEncoder
OneHotEncoder(handle_unknown='ignore')
# 학습 데이터
>>> tmp = pd.DataFrame(
>>> enc.transform(train_ft[cols]).toarray(),
>>> columns = enc.get_feature_names_out()
>>> )
>>> train_ft = pd.concat([train_ft,tmp],axis=1)
>>> train_ft.head()
# 테스트 데이터
>>> tmp = pd.DataFrame(
>>> enc.transform(test_ft[cols]).toarray(),
>>> columns = enc.get_feature_names_out()
>>> )
>>> test_ft = pd.concat([test_ft,tmp],axis=1)
>>> test_ft.head()
- 파생 변수 생성 과정에서 생긴 결측치 확인
>>> train_ft.isnull().sum().sum(), test_ft.isnull().sum().sum()
# 생긴 결측치 없음이 확인 된다
(0, 0)
# cols를 더이상 이용할 필요가 없음으로 드랍해주기
>>> cols = ["gender","embarked"]
>>> train_ft = train_ft.drop(columns=cols)
>>> test_ft = test_ft.drop(columns=cols)
- Min-Max scaling
>>> from sklearn.preprocessing import MinMaxScaler
>>> scaler = MinMaxScaler()
>>> scaler.fit(train_ft)
MinMaxScaler
MinMaxScaler()
# 학습 데이터
>>> train_ft = scaler.transform(train_ft)
>>> train_ft
array([[0.88726043, 0. , 0. , ..., 1. , 0. ,
0. ],
[0.42377552, 0. , 0. , ..., 0. , 0. ,
1. ],
[0.36114243, 0.375 , 0.11111111, ..., 0. , 0. ,
1. ],
...,
[0.44882876, 0. , 0. , ..., 0. , 0. ,
1. ],
[0.473882 , 0. , 0. , ..., 0. , 0. ,
1. ],
[0.23587624, 0.125 , 0.11111111, ..., 0. , 0. ,
1. ]])
# 테스트 데이터
>>> test_ft = scaler.transform(test_ft)
>>> test_ft
array([[0.77452086, 0. , 0. , ..., 0. , 0. ,
1. ],
[0.34861581, 0. , 0. , ..., 0. , 0. ,
1. ],
[0.29850933, 0. , 0. , ..., 0. , 0. ,
1. ],
...,
[0.26092948, 0. , 0. , ..., 0. , 0. ,
1. ],
[0.37247766, 0. , 0. , ..., 0. , 0. ,
1. ],
[0.33608919, 0. , 0. , ..., 0. , 0. ,
1. ]])
>>> target = train["survived"].to_numpy()
>>> target
array([0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0,
0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1,
0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0,
1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0,
0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0,
0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0,
0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1,
0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1,
0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0,
1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0,
0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0,
1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0,
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1,
1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1,
0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1,
0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0,
1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1,
0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1,
0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1,
1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1,
0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1,
0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0,
0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0,
1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0,
1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0,
1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0,
0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0,
0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1,
1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0,
0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0,
1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0])
>>> train_ft.shape, test_ft.shape, target.shape
((916, 10), (393, 10), (916,))
# 시드 고정을 위해
import random
import os
>>> def reset_seeds(seed):
>>> random.seed(seed)
>>> os.environ['PYTHONHASHSEED'] = str(seed)
>>> np.random.seed(seed)
>>> torch.manual_seed(seed)
>>> torch.cuda.manual_seed(seed)
Deterministic 한 알고리즘으로 수행 가능한 연산은 그대로 진행, 불가능한 경우에는 RuntimeError를 던짐
>>> torch.backends.cudnn.deterministic = True
seed 고정
난수 생성기의 seed를 고정하면, 매번 프로그램을 실행할 때마다 생성되는 난수들의 수열이 같게 할 수 있다.
아래 링크에서 더 자세한 사항 확인
torch.use_deterministic_algorithms — PyTorch 2.0 documentation
Shortcuts
pytorch.org
PYTHONHASHSEED
hashing 알고리즘은 random요소가 있다. 그리고 그 hash결과에 영향을 주는 요소를 PYTHONHASHSEED 라고 한다
데이터셋 클래스 구현
- DATASET과 DATALOADER
- pytorch에서는 미니배치 단위 학습을 위해 데이터셋을 좀 더 쉽게 다룰 수 있도록 유용한 도구로서 torch.utils.data.Dataset 과 torch.utils.data.Dataloader 제공
- Dataset은 학습데이터와 정답을 저장해서 인덱싱을 통해 반환할 수 있는 클래스를 의미
- DataLoader는 Dataset의 데이터를 쉽게 접근할 수 있도록 iterable 객체로 만들어준다
- DataLoader 사용시 미니 배치, 셔플 등 간단히 수행 가능
>>> target.reshape(-1,1).shape
(916, 1)
item["y"] = torch.Tensor(self.y[idx]) 에서 self.y[idx] 값이 스칼라 값일 경우에는 에러가 날 수도 있음
따라서 2차원으로 reshape 해주어야 한다
# 정답값 말고 예측 값이 들어올때의 코딩
>>> class TitanicDataset(torch.utils.data.Dataset):
>>> def __init__(self,x,y=None):
>>> self.x = x
>>> self.y = y
>>> if self.y is not None:
# 이진 분류 문제에서 2차원 형태로 변경해줘야한다
# (스칼라값을 2차원 형태로 변환 안그러면 애가 못 읽음)
>>> self.y = y.reshape(-1,1)
>>> def __len__(self): # 총 샘플 수를 반환해주는 부분
>>> return self.x.shape[0]
>>> def __getitem__(self,idx):
# 학습데이터와 정답데이터를 반환해줄 딕셔너리
>>> item = {}
# Tensor는 기본적으로 32bit 사용을 함 -> item을 Tensor의 class로 insert 한다는 것은 32bit로 바꿔준다는 뜻
# item["x"] = torch.tensor(self.x[idx])
# 이렇게 돌리면 64bit 데이터 형태 그대로 tensor로 돌린다는 뜻
>>> item["x"] = torch.Tensor(self.x[idx])
>>> if self.y is not None:
>>> item["y"] = torch.Tensor(self.y[idx])
>>> return item
# 코드 만들어주고 꼭 인덱스 확인 해주기
>>> dt = TitanicDataset(train_ft,target)
>>> dt[3]
{'x': tensor([0.2233, 0.1250, 0.1111, 0.0254, 0.5000, 1.0000, 0.0000, 0.0000, 0.0000,
1.0000]),
'y': tensor([1.])}
>>> dt = TitanicDataset(test_ft,target)
>>> dt[3]
{'x': tensor([0.3725, 0.0000, 0.0000, 0.0151, 1.0000, 1.0000, 0.0000, 0.0000, 1.0000,
0.0000]),
'y': tensor([1.])}
>>> train_ft[:2]
array([[0.88726043, 0. , 0. , 0.09662576, 0. ,
0. , 1. , 1. , 0. , 0. ],
[0.42377552, 0. , 0. , 0.01571255, 1. ,
0. , 1. , 0. , 0. , 1. ]])
>>> target[:2]
array([0, 0])
>>> dl = torch.utils.data.DataLoader(dt,batch_size=2,shuffle=False)
#iterable한 객체인 것을 확인 (for 문으로 반복문 가능)
>>> dl
- 예측할 때는 순서대로 예측해야 하므로 shuffle = False
- 실제로 학습할 때 (학습 데이터를 줄 때), shuffle = True로 해주면 다양한 객체 섞어서 사용 가능
# iterable한 객체를 iterater로 바꿔서 언제든지 꺼낼 수 있게 하기
>>> next(iter(dl))
{'x': tensor([[0.8873, 0.0000, 0.0000, 0.0966, 0.0000, 0.0000, 1.0000, 1.0000, 0.0000,
0.0000],
[0.4238, 0.0000, 0.0000, 0.0157, 1.0000, 0.0000, 1.0000, 0.0000, 0.0000,
1.0000]]),
'y': tensor([[0.],
[0.]])}
딥러닝 모델 인공신경망 구현
- pytorch에서 신경망 모델은 torch.nn.Module을 상속받는 클래스 (class)를 생성하여 정의
- __init__ 메소드에서 신경망의 계층(layer)들을 정의
- forward 메소드에서 신경망에 텐서를 어떻게 전달할지 지정
>>> class Net(torch.nn.Module):
>>> def __init__(self,in_features):
# 부모 클래스 init method으로 초기화 필수
>>> super().__init__()
# 다중 회귀분석의 layer (in_features,노드 갯수)
>>> self.hidden_layer1 = torch.nn.Linear(in_features,8)
>>> self.hidden_layer2 = torch.nn.Linear(8,4)
>>> self.output_layer = torch.nn.Linear(4,1)
# 비선형성을 대비하여 ReLU 추가 해주기
>>> self.relu = torch.nn.ReLU()
>>> def forward(self,x):
>>> x = self.hidden_layer1(x)
>>> x = self.relu(x)
>>> x = self.hidden_layer2(x)
>>> x = self.relu(x)
>>> return self.output_layer(x)
>>> data = next(iter(dl))
>>> data
{'x': tensor([[0.8873, 0.0000, 0.0000, 0.0966, 0.0000, 0.0000, 1.0000, 1.0000, 0.0000,
0.0000],
[0.4238, 0.0000, 0.0000, 0.0157, 1.0000, 0.0000, 1.0000, 0.0000, 0.0000,
1.0000]]),
'y': tensor([[0.],
[0.]])}
>>> data["x"]
tensor([[0.8873, 0.0000, 0.0000, 0.0966, 0.0000, 0.0000, 1.0000, 1.0000, 0.0000,
0.0000],
[0.4238, 0.0000, 0.0000, 0.0157, 1.0000, 0.0000, 1.0000, 0.0000, 0.0000,
1.0000]])
>>> model = Net(train_ft.shape[1])
>>> model(data["x"])
tensor([[-0.2394],
[-0.2394]], grad_fn=<AddmmBackward0>)
하이퍼파라미터 정의
# 모델 학습을 위해 텐서를 어디 장치에 할 것인지 지정
>>> device = "cuda" if torch.cuda.is_available() else "cpu"
>>> device
'cpu'
# 미니배치 사이즈
>>> batch_size = 32
# 손실함수 객체 생성
>>> loss_fn = torch.nn.BCEWithLogitsLoss()
>>> loss_fn
BCEWithLogitsLoss()
# 모델 객체 생성
>>> reset_seeds(42)
# 모델 객체 생성후 모델 파라미터 사용가능한 장치로 이동
>>> model = Net(train_ft.shape[1]).to(device)
# optimizer 객체 생성
>>> optimizer = torch.optim.Adam(model.parameters())
# 학습데이터 객체 생성
>>> train_dt = TitanicDataset(train_ft,target)
>>> train_dl = torch.utils.data.DataLoader(train_dt,batch_size=batch_size,shuffle=True)
학습 및 테스트 loop 구현
- 학습 loop
>>> for _ in range(10):
>>> model.train() # 학습모드
>>> epoch_loss = 0
>>> for batch in train_dl:
# 모델예측
>>> pred = model(batch["x"].to(device))
# 손실 구하기
>>> loss = loss_fn(pred,batch["y"].to(device))
>>> optimizer.zero_grad() # 경사를 누적하여 업데이트 하기 때문에 0으로 초기화 해준다.
>>> loss.backward() # 역전파
>>> optimizer.step() # 가중치 업데이트
# print(f"batch loss {loss.item()}")
>>> epoch_loss += loss.item()
>>> print(f"epoch loss {epoch_loss / len(train_dl)}")
epoch loss 0.7530954212977968
epoch loss 0.7322561494235335
epoch loss 0.7084929449804898
epoch loss 0.6778858920623516
epoch loss 0.6415135737123161
epoch loss 0.6022779468832344
epoch loss 0.5654908860551899
epoch loss 0.5333360937134973
epoch loss 0.5079377756036562
epoch loss 0.4864064136455799
- test loop
>>> test_dt = TitanicDataset(test_ft)
>>> test_dl = torch.utils.data.DataLoader(test_dt,batch_size=batch_size,shuffle=False)
# 평가모드
>>> model.eval()
>>> pred_list = []
>>> sig = torch.nn.Sigmoid() # 0~1사이 확률로 변환해주는 시그모이드 객체 생성
>>> with torch.no_grad(): # 예측 과정에서 경사를 추적 할 필요 없기에 경사추적 꺼놓기
>>> for batch in test_dl: # 데이터로더 객체에서 배치단위로 batch 변수에 전달됨
>>> pred = model(batch["x"].to(device))
>>> pred = sig(pred) # 예측값 0~1사이 확률로변환
# 텐서 cpu 장치로 이동후 ndarray 로 변환
>>> pred = pred.to("cpu").numpy()
>>> pred_list.append(pred)
>>> pred = np.concatenate(pred_list)
>>> pred
array([[0.2712706 ],
[0.27998695],
[0.20150279],
[0.5070917 ],
[0.51006705],
[0.5060269 ],
[0.23415138],
[0.50962216],
[0.51320624],
[0.5502231 ],
[0.23940608],
[0.50708985],
[0.5690488 ],
[0.5690488 ],
[0.49669638],
[0.1981485 ],
[0.17948557],
[0.19569755],
[0.5690488 ],
[0.19816145],
[0.19636 ],
...
>>> y_test = pd.read_csv(f"{DATA_PATH}titanic_test_target.csv")["survived"]
>>> y_test
0 0
1 0
2 0
3 1
4 1
..
388 0
389 1
390 0
391 0
392 0
Name: survived, Length: 393, dtype: int64
>>> from sklearn.metrics import roc_auc_score
>>> roc_auc_score(y_test,pred)
0.877426916712631