Pytorch_10_Dataset_save

전사영·2024년 11월 4일

이번 시간에는 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
  • __init은 Class를 생성할 때 사용하는 함수, init 함수의 내용에 train_csv를 가져옵니다.
  • self.x는 전체 중에서 1에서 3번째 컬럼을 사용해줍니다.
  • self.x를 np.min을 열별로 최소 값으로 빼고 열별 최대값에 최소값을 빼서 나눠줍니다. 이는 즉 minmax scaling과 같습니다.
  • self.y를 Close 열을 y 컬럼으로 사용해줍니다.
  • .values를 통해 넘파이 형태로 변환해줍니다.
  • __len 스스로 Class의 길이는 얼마인지 확인하는 함수입니다.
  • __getitem은 Class에 대하여 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
  • 기존에 RNN 모델을 구성했던 것과 같이 init함수와 forward함수를 구성해줍니다.
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()는 각 계층의 가중치와 편향을 딕셔너리 형태로 키와 값 쌍으로 저장하는 메서드 입니다.

profile
매일 조금씩!

0개의 댓글