이번 시간에는 Dataset을 통하여 Pytorch에서 가중치를 저장하는 방법에 대하여 알아보도록 하겠습니다.
사용 데이터는 Kaggle에서 받은 netflix 주가 데이터입니다.
import pandas as pd
import numpy as np
from sklearn.metrics import accuracy_score
import torch
import torch.nn as nn
import torch.optim as optim
import random
random.seed(333)
np.random.seed(333)
torch.manual_seed(333) #토치 고정
torch.cuda.manual_seed(333) #gpu 고정
# USE_CUDA = torch.cuda.is_available()
# DEVICE = torch.device('cuda:0'if USE_CUDA else 'cpu')
# print('torch' , torch.__version__, '사용DEVICE : ', DEVICE)
DEVICE = 'cuda:0' if torch.cuda.is_available else 'cpu'
print(DEVICE)
path = '_data/kaggle/netflix-stock-prediction/'
train_csv = pd.read_csv(path + 'train.csv')
print(train_csv)
print(train_csv.info())
print(train_csv.describe())
import matplotlib.pyplot as plt
data = train_csv.iloc[:, 1:4] # 판다스 열행인데 판다스를 행렬 형태로 쓸 수 있는 것이 loc iloc이다
# iloc 에서 i는 index loc는 location # 사용하면 열행 형태로 끌어오게 되는 판다스를 행렬로 끌어와 작업하게 된다.
data['종가'] = train_csv['Close']
print(data)
# hist = data.hist()
# plt.show()
##### 컬럼별로 최소 최대가 아닌 전체 데이터셋의 최소 최대가 적용되는 문제 #####
# data = train_csv.iloc[:, 1:4]
# data = (data - np.min(data)) / (np.max(data) - np.min(data))
# data = pd.DataFrame(data)
# print(data.describe())
##### 컬럼별로 최소 최대가 아닌 전체 데이터셋의 최소 최대가 적용되는 문제해결, axis=0을 넣어주면 된다 #####
# data = train_csv.iloc[:, 1:4]
# data = (data - np.min(data, axis=0)) / (np.max(data, axis=0) - np.min(data, axis=0))
# data = pd.DataFrame(data)
# print(data.describe())
from torch.utils.data.dataset import Dataset, TensorDataset
from torch.utils.data import DataLoader
class Custom_Dataset(Dataset):
def __init__(self):
self.csv = train_csv # self에 train_csv를 가져오겠다.
self.x = self.csv.iloc[:, 1:4].values #시가, 고가, 저가 컬럼이 된다.
# 정규화
self.x = (self.x - np.min(self.x, axis=0)) / (np.max(self.x, axis=0) - np.min(self.x, axis=0)) #minmax scaler
# y데이터
self.y = self.csv['Close'].values
def __len__(self):
return len(self.x) - 30
def __getitem__(self, i):
x = self.x[i:i+30]
y = self.y[i+30]
return x,y
aaa = Custom_Dataset()
# print(aaa)
# print(type(aaa))
# print(aaa[0])
# print(aaa[0][0].shape) #(30, 3)
# print(aaa[0][1]) #94
# print(len(aaa)) #937
# print(aaa[936])
train_loader = DataLoader(aaa, batch_size=32)
# aaa = iter(train_loader)
# bbb= next(aaa)
# print(bbb)
#2. 모델
class RNN(nn.Module):
def __init__(self):
super(RNN, self).__init__()
self.rnn = nn.RNN(input_size=3, #피쳐의 개수
hidden_size = 64, #output node의 개수, tensorflow에선 unit
num_layers=5, # rnn의 계층을 쌓는 파라미터
batch_first = True, # 적용 시 torch에서 rnn연산시 바뀌는 순서를 정상적인 순서로 배치함
)
self.fc1 = nn.Linear(in_features=30*64, out_features=32)
self.fc2 = nn.Linear(in_features=32, out_features=1)
self.relu = nn.ReLU()
def forward(self, x, h0):
x, h0 = self.rnn(x)
x = torch.reshape(x, (x.shape[0], -1))
x = self.fc1(x)
x = self.relu(x)
x = self.fc2(x)
return x
model = RNN().to(DEVICE)
#3. 컴파일 훈련
from torch.optim import Adam
optim = Adam(params=model.parameters(), lr=0.001)
import tqdm
for epoch in range(1, 201):
iterator = tqdm.tqdm(train_loader)
for x, y in iterator:
optim.zero_grad()
h0 = torch.zeros(5, x.shape[0], 64 ).to(DEVICE) #(num_layers, batch_size, hidden size) = (5, 32, 64)
hypothesis = model(x.type(torch.FloatTensor).to(DEVICE), h0)
# type함수로 형태 변형 가능
loss = nn.MSELoss()(hypothesis, y.type(torch.FloatTensor).to(DEVICE))
loss.backward()
optim.step()
iterator.set_description(f'epoch:{epoch} loss:{loss.item()}')
save_path = './/_save//torch//'
torch.save(model.state_dict(), save_path + 't22.pth')
from torch.utils.data.dataset import Dataset, TensorDataset from torch.utils.data import DataLoader
Dataset을 import해줍니다.
class Custom_Dataset(Dataset): def __init__(self): self.csv = train_csv # self에 train_csv를 가져오겠다. self.x = self.csv.iloc[:, 1:4].values #시가, 고가, 저가 컬럼이 된다. # 정규화 self.x = (self.x - np.min(self.x, axis=0)) / (np.max(self.x, axis=0) - np.min(self.x, axis=0)) #minmax scaler # y데이터 self.y = self.csv['Close'].values def __len__(self): return len(self.x) - 30 def __getitem__(self, i): x = self.x[i:i+30] y = self.y[i+30] return x,y
aaa = Custom_Dataset() train_loader = DataLoader(aaa, batch_size=32)
aaa란 인스턴스에 Custom_Dataset()을 선언해줍니다.
train_loader는 DataLoader에 aaa를 batch_size 32로 나눠준 것입니다.
#2. 모델 class RNN(nn.Module): def __init__(self): super(RNN, self).__init__() self.rnn = nn.RNN(input_size=3, #피쳐의 개수 hidden_size = 64, #output node의 개수, tensorflow에선 unit num_layers=5, # rnn의 계층을 쌓는 파라미터 batch_first = True, # 적용 시 torch에서 rnn연산시 바뀌는 순서를 정상적인 순서로 배치함 ) self.fc1 = nn.Linear(in_features=30*64, out_features=32) self.fc2 = nn.Linear(in_features=32, out_features=1) self.relu = nn.ReLU() def forward(self, x, h0): x, h0 = self.rnn(x) x = torch.reshape(x, (x.shape[0], -1)) x = self.fc1(x) x = self.relu(x) x = self.fc2(x) return x
model = RNN().to(DEVICE) #3. 컴파일 훈련 from torch.optim import Adam optim = Adam(params=model.parameters(), lr=0.001)
model은 RNN()을 DEVICE로 사용해줍니다.
optim 인스턴스는 Adam을 사용해줍니다. Adam에 들어가는 변수는 params와 lr이 있습니다.
import tqdm for epoch in range(1, 201): iterator = tqdm.tqdm(train_loader) for x, y in iterator: optim.zero_grad() h0 = torch.zeros(5, x.shape[0], 64 ).to(DEVICE) #(num_layers, batch_size, hidden size) = (5, 32, 64) hypothesis = model(x.type(torch.FloatTensor).to(DEVICE), h0) # type함수로 형태 변형 가능 loss = nn.MSELoss()(hypothesis, y.type(torch.FloatTensor).to(DEVICE)) loss.backward() optim.step() iterator.set_description(f'epoch:{epoch} loss:{loss.item()}')
for문 2개 사용하는 이유 epoch당 batch단위로 훈련되는 것을 확인하기 위한 것입니다.
tqdm은 프로그래스 바를 확인하기 위한 것입니다. tqdm.tqdm으로 데이터를 감싸줍니다.
set_description은 tqdm에 내장된 메서드입니다. set_description는 tqdm 라이브러리에서 진행 상황(progress) 표시줄의 설명을 설정하는 메서드입니다.
save_path = './/_save//torch//' torch.save(model.state_dict(), save_path + 't24.pth')
경로를 지정해줍니다.
지정된 경로에 원하는 파일 명으로 모델을 저장해줍니다.
model.state_dict()는 각 계층의 가중치와 편향을 딕셔너리 형태로 키와 값 쌍으로 저장하는 메서드 입니다.