Recurrent Neural Networks

  • As you are reading the present sentence, you are processing it word by word while keeping memories of what came before.
  • A recurrent neural network (RNN) processes sequences by iterating through the sequence elements and maintaining a state containing information relative to what it has seen so far.
    • The network internally loops over sequence elements.

 
scaler = MinMaxScaler()
df[['Open','High','Low','Close','Volume']] = scaler.fit_transform(df[['Open','High','Low','Close','Volume']])
# CPU/GPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(f'{device} is available.')
# Dataset
X = df[['Open','High','Low','Volume']].values
y = df['Close'].values
# Sequence를 생성하는 함수
def
 seq_data(xysequence_length):
    
    x_seq = []
    y_seq = []
    for i in range(len(x)-sequence_length):
        x_seq.append(x[i:i+sequence_length]) # a[2:6] -> 2,3,4,5
        y_seq.append(y[i+sequence_length]) # 지난 5일을 통해서 다음날의 종가를 구한다.
    
    return torch.FloatTensor(x_seq).to(device), torch.FloatTensor(y_seq).to(device).view([-11]) 
split = 200
sequence_length = 5

x_seq, y_seq = seq_data(X, y, sequence_length)
x_train_seq = x_seq[:split]
y_train_seq = y_seq[:split]
x_test_seq = x_seq[split:]
y_test_seq = y_seq[split:]
print(x_train_seq.size(), y_train_seq.size())
print(x_test_seq.size(), y_test_seq.size())
train = torch.utils.data.TensorDataset(x_train_seq, y_train_seq)
test = torch.utils.data.TensorDataset(x_test_seq, y_test_seq)

batch_size = 20
train_loader = torch.utils.data.DataLoader(dataset=train, batch_size=batch_size, shuffle=False)
test_loader = torch.utils.data.DataLoader(dataset=test, batch_size=batch_size, shuffle=False)
 
# RNN hyper-parameter
input_size = x_seq.size(2)
num_layers = 2 # 크기가 과도하게 클경우 overfitting 가능성이 커짐
hidden_size = 8 # 크기가 과도하게 클경우 overfitting 가능성이 커짐
 
class VanillaRNN(nn.Module):    
    def __init__(selfinput_sizehidden_sizesequence_lengthnum_layersdevice):
        super(VanillaRNN, self).__init__()
        self.device =device
        self.hidden_size = hidden_size
        self.num_layers = num_layers
        self.rnn = nn.RNN(input_size, hidden_size, num_layers, batch_first=True) # pytorch에서 제공하는 RNN은 sequence length가 먼저 들어와야하는데, batch_size가 첫번째로 들어왔다. 따라서 순서를 바꾸어하므로, batch_first=True로 선언한다. 
        self.fc = nn.Sequential(nn.Linear(hidden_size*sequence_length, 1), nn.Sigmoid())
        
    def forward(selfx):
        h0 = torch.zeros(self.num_layers, x.size()[0], self.hidden_size).to(self.device) # 초기 hidden state 설정
        out, _ = self.rnn(x, h0) # out: RNN의 마지막 레이어로 부터 나온 output feature 반환, hn: hidden state 반환
        out = out.reshape(out.shape[0], -1# many to many 전략. 각각의 일자에 대해서 output도출한다.
        out = self.fc(out)
        return out
model = VanillaRNN(input_size=input_size, 
                   hidden_size=hidden_size, 
                   sequence_length=sequence_length, 
                   num_layers=num_layers, 
                   device=device).to(device)
criterion = nn.MSELoss()

lr = 1e-3
num_epochs = 200 
optimizer = optim.Adam(model.parameters(), lr=lr)
loss_graph = []
n = len(train_loader)

for epoch in range(num_epochs):
    running_loss = 0.0
    
    for data in train_loader:
        
        seq, target = data # 배치 데이터 
        out = model(seq)
        loss = criterion(out, target)
        
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        running_loss += loss.item()
    
    loss_graph.append(running_loss/n)
    if epoch % 100 == 0:
        print('[epoch: %d] loss: %.4f' %(epoch, running_loss/n))
# 실제값과 예측값 비교
def
 plotting(train_loadertest_loaderactual):
    with torch.no_grad():
        train_pred = []
        test_pred = []
   
        for data in train_loader:
            seq, target = data # 배치 데이터 
            #print(seq.size())
            out = model(seq)
            train_pred += out.cpu().numpy().tolist()
            
        for data in test_loader:
            seq, target = data # 배치 데이터 
            #print(seq.size())
            out = model(seq)
            test_pred += out.cpu().numpy().tolist()
    total = train_pred+test_pred       
    plt.figure(figsize=(20,10))
    plt.plot(np.ones(100)*len(train_pred),np.linspace(0,1,100),'--', linewidth=0.6)
    plt.plot(actual,'--')
    plt.plot(total,'b', linewidth=0.6)
    
    
    plt.legend(['train boundary','actual','prediction'])
    plt.show() 
    
plotting(train_loader, test_loader, df['Close'][sequence_length:].values)        

실제 주가와 예측 주가의 비교 그래프

'파이토치' 카테고리의 다른 글

[파이토치] Transfer Learning  (0) 2022.02.14
[파이토치] LSTM / GRU  (0) 2022.02.14
[파이토치] CNN  (0) 2022.02.14
[파이토치] Cross-Validation  (0) 2022.02.14
[파이토치] Optimizers and Scheduling  (0) 2022.02.14

Convolutional Neural Networks

CNN모델과 10개의 클래스를 가진 이미지 데이터인 CIFAR-10데이터를 이용하여 실습을 진행하였습니다.

 

transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.50.50.5), (0.50.50.5))])

trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
                                        download=True, transform=transform)

trainloader = torch.utils.data.DataLoader(trainset, batch_size=8, shuffle=True

testset = torchvision.datasets.CIFAR10(root='./data', train=False,
                                       download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=8, shuffle=False)
# CPU/GPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(f'{device} is available.')

1. 모델 선언

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(365# 합성곱 연산 (입력 채널수 3, 출력 채널수 6, 필터크기 5x5 , stride=1(defualt))
        self.pool1 = nn.MaxPool2d(22# 합성곱 연산 (필터크기 2, stride=2)
        self.conv2 = nn.Conv2d(6165# 합성곱 연산 (입력 채널수 6, 출력 채널수 16, 필터크기 5x5 , stride=1(defualt))
        self.pool2 = nn.MaxPool2d(22# 합성곱 연산 (필터크기 2, stride=2)
        self.fc1 = nn.Linear(16 * 5 * 5120# 5x5 피쳐맵 16개를 일렬로 피면 16*5*5개의 노드가 생성
        self.fc2 = nn.Linear(12010# 120개 노드에서 클래스의 개수인 10개의 노드로 연산

    def forward(selfx): # 실제 계산이 이루어진다.
        x = self.pool1(F.relu(self.conv1(x))) # conv1 -> ReLU -> pool1
        x = self.pool2(F.relu(self.conv2(x))) # conv2 -> ReLU -> pool2
        x = x.view(-116 * 5 * 5# 5x5 피쳐맵 16개를 일렬로 만든다.  # -1은 배치수 대신에 사용하였다.
        x = F.relu(self.fc1(x)) 
        x = self.fc2(x)

        return x

2. 모델 선언 (Preferable)

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        # sequential로 feature extraction layers를 하나로 묶을 수 있다.
        self.feature_extraction = nn.Sequential(nn.Conv2d(365), 
                                                nn.ReLU(),
                                                nn.MaxPool2d(22), 
                                                nn.Conv2d(6165),
                                                nn.ReLU(),
                                                nn.MaxPool2d(22))
        
        self.classifier = nn.Sequential(nn.Linear(16 * 5 * 5120),
                                        nn.ReLU(),
                                        nn.Linear(12010))
                                        
    def forward(selfx):
        x = self.feature_extraction(x)
        x = x.view(-116 * 5 * 5# 5x5 피쳐맵 16개를 일렬로 만든다.
        x = self.classifier(x)
 
        return x

net = Net().to(device) # 모델이 GPU연산을 가능하도록 한다.

 

criterion = nn.CrossEntropyLoss() # CrossEntropyLoss는 softmax 계산까지 포함되어 있으므로 모델의 마지막 output node에 별도의 활성화 함수를 사용하지 않아도 된다.
optimizer = optim.SGD(net.parameters(), lr=1e-3, momentum=0.9)
# 모델의 학습 과정인 4강에서 배운 인공 신경망과 동일하다.
loss_ = [] # 그래프를 그리기 위한 loss 저장용 리스트 
n = len(trainloader) # 배치 개수

for epoch in range(10):  # 10번 학습을 진행한다.

    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):

        inputs, labels = data[0].to(device), data[1].to(device) # GPU연산이 가능한 배치 데이터 
        
        optimizer.zero_grad()

        outputs = net(inputs) # 예측값 산출 
        loss = criterion(outputs, labels) # 손실함수 계산
        loss.backward() # 손실함수 기준으로 역전파 선언
        optimizer.step() # 가중치 최적화

        # print statistics
        running_loss += loss.item()

    loss_.append(running_loss / n)    
    print('[%d] loss: %.3f' %(epoch + 1, running_loss / len(trainloader)))

print('Finished Training')
plt.plot(loss_)
plt.title("Training Loss")
plt.xlabel("epoch")
plt.show()

 
PATH = './models/cifar_net.pth' # 모델 저장 경로 
torch.save(net.state_dict(), PATH) # 모델 저장
# 모델 불러오기는 엄밀히 말하자면 모델의 파라메타를 불러오는 것이다. 따라서 모델의 뼈대를 먼저 선언하고
# 모델의 파라메타를 불러와 pretrained model을 만든다.

net = Net().to(device) # 모델을 먼저 불러오고 그 위에 파라메타를 덮어씌운다. 이때, GPU 모델로 저장을 했기 때문에, 불러올때도 GPU로 받아야한다.
net.load_state_dict(torch.load(PATH)) # 모델 파라메타 불러오기
# 평가 데이터를 이용해 정확도 구하기.
# output은 미니배치의 결과가 산출되기 때문에 for문을 통해서 test 전체의 예측값을 구한다.

correct = 0
total = 0
with torch.no_grad():
    
    for data in testloader:
        images, labels = data[0].to(device), data[1].to(device)
        outputs = net(images)
        _, predicted = torch.max(outputs.data, 1) # 벡터값에서 argmax를 하기위해 max()를 취한다. 즉, 최댓값의 위치
        total += labels.size(0# 개수 누적(총 개수)
        correct += (predicted == labels).sum().item() # 누적(맞으면 1, 틀리면 0으로 합산)
        
print('Accuracy of the network on the 10000 test images: %d %%' % (100 * correct / total))

'파이토치' 카테고리의 다른 글

[파이토치] LSTM / GRU  (0) 2022.02.14
[파이토치] RNN  (0) 2022.02.14
[파이토치] Cross-Validation  (0) 2022.02.14
[파이토치] Optimizers and Scheduling  (0) 2022.02.14
[파이토치] Neural Networks  (0) 2022.02.14

In k-fold cross-validation, the original sample is randomly partitioned into k equal sized subsamples

  • Of the k subsamples, a single subsample is retained as the validation data
  • The remaining k-1 subsamples are used as training data
  • The cross-validation process is then repeated k times with each of the k samples used exactly once as the validation data
  • 학습을 위한 데이터가 적은 경우 유용한 방법론이다.

 

import pandas as pd # 데이터프레임 형태를 다룰 수 있는 라이브러리
import numpy as np
from sklearn.model_selection import train_test_split # 전체 데이터를 학습 데이터와 평가 데이터로 나눈다.

# ANN
import torch
from torch import nn, optim # torch 내의 세부적인 기능을 불러온다. (신경망 기술, 손실함수, 최적화 방법 등)
from torch.utils.data import DataLoader, Dataset # 데이터를 모델에 사용할 수 있도록 정리해 주는 라이브러리
import torch.nn.functional as F # torch 내의 세부적인 기능을 불러온다. (신경망 기술 등)
# Cross Validation
from sklearn.model_selection import KFold
# Loss
from sklearn.metrics import mean_squared_error # Regression 문제의 평가를 위해 MSE(Mean Squared Error)를 불러온다.
# Plot
import matplotlib.pyplot as plt # 시각화 도구
df = pd.read_csv('./data/reg.csv', index_col=[0])
# 데이터를 넘파이 배열로 만들기
X = df.drop('Price', axis=1).to_numpy() # 데이터프레임에서 타겟값(Price)을 제외하고 넘파이 배열로 만들기
Y = df['Price'].to_numpy().reshape((-1,1)) # 데이터프레임 형태의 타겟값을 넘파이 배열로 만들기
# 텐서 데이터로 변환하는 클래스(3강 참고)
class TensorData(Dataset):

    def __init__(selfx_datay_data):
        self.x_data = torch.FloatTensor(x_data)
        self.y_data = torch.FloatTensor(y_data)
        self.len = self.y_data.shape[0]

    def __getitem__(selfindex):

        return self.x_data[index], self.y_data[index] 

    def __len__(self):
        return self.len
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.7)
trainset = TensorData(X_train, Y_train) # trainDataLoader는 for문 내에서 선언한다.
testset = TensorData(X_test, Y_test)
testloader = torch.utils.data.DataLoader(testset, batch_size=32, shuffle=False)
class Regressor(nn.Module):
    def __init__(self):
        super().__init__() # 모델 연산 정의
        self.fc1 = nn.Linear(1350, bias=True# 입력층(13) -> 은닉층1(50)으로 가는 연산
        self.fc2 = nn.Linear(5030, bias=True# 은닉층1(50) -> 은닉층2(30)으로 가는 연산
        self.fc3 = nn.Linear(301, bias=True# 은닉층2(30) -> 출력층(1)으로 가는 연산
    
    def forward(selfx):
        x = self.fc1(x) 
        x = self.fc2(x) 
        x = self.fc3(x) 
      
        return x
kfold = KFold(n_splits=3, shuffle=True) # k는 3으로 설정
criterion = nn.MSELoss()
def evaluation(dataloader):
    
    predictions = torch.tensor([], dtype=torch.float# 예측값을 저장하는 텐서
    actual = torch.tensor([], dtype=torch.float# 실제값을 저장하는 텐서
        
    with torch.no_grad():
        model.eval() # 평가를 할 때에는 .eval() 반드시 사용해야 한다.
        for data in dataloader:
            inputs, values = data
            outputs = model(inputs)

            predictions = torch.cat((predictions, outputs), 0# cat을 통해 예측값을 누적
            actual = torch.cat((actual, values), 0# cat을 통해 실제값을 누적
    
    predictions = predictions.numpy() # 넘파이 배열로 변경
    actual = actual.numpy() # 넘파이 배열로 변경
    rmse = np.sqrt(mean_squared_error(predictions, actual)) # sklearn을 이용하여 RMSE 계산
    model.train() # 학습 중간에 평가를 했지때문에 모델을 eval()로 변환했다면 train()으로 재선언해야한다.
    return rmse  
 
# 이번 예시에서는 상관없으나 평가 시에는 정규화 기술을 배제하여 온전한 모델로 평가를 해야한다. 따라서 .eval()을 사용한다.
# 즉, 드랍아웃이나 배치 정규화 등과 같이 학습 시에만 사용하는 기술들이 적용 된 모델은 평가 시에는 비활성화 해야하며 학습 시 .train()을 사용한다.
validation_loss = []

for fold, (train_idx, val_idx) in enumerate(kfold.split(trainset)):
    # fold는 1,2,3의 값을 가질것이고, train_idx와 val_idx는 각각 인덱스 값을 가진다.
    train_subsampler = torch.utils.data.SubsetRandomSampler(train_idx) # index 생성
    val_subsampler = torch.utils.data.SubsetRandomSampler(val_idx) # index 생성
    
    # sampler를 이용한 DataLoader 정의
    trainloader = torch.utils.data.DataLoader(trainset, batch_size=32, sampler=train_subsampler) 
    valloader = torch.utils.data.DataLoader(trainset, batch_size=32, sampler=val_subsampler)
    
    # 모델 선언
    model = Regressor()
    optimizer = optim.Adam(model.parameters(), lr=0.001, weight_decay=1e-7)
    
    for epoch in range(400): # 400번 학습을 진행한다.

        for data in trainloader: # 무작위로 섞인 32개 데이터가 있는 배치가 하나 씩 들어온다.

            inputs, values = data # data에는 X, Y가 들어있다.

            optimizer.zero_grad() # 최적화 초기화

            outputs = model(inputs) # 모델에 입력값 대입 후 예측값 산출
            loss = criterion(outputs, values) # 손실 함수 계산
            loss.backward() # 손실 함수 기준으로 역전파 설정 
            optimizer.step() # 역전파를 진행하고 가중치 업데이트

    train_rmse = evaluation(trainloader) # 학습 데이터의 RMSE
    val_rmse = evaluation(valloader)
    print("k-fold", fold," Train Loss: %.4f, Validation Loss: %.4f" %(train_rmse, val_rmse)) 
    validation_loss.append(val_rmse)

validation_loss = np.array(validation_loss)
mean = np.mean(validation_loss)
std = np.std(validation_loss)
print("Validation Score: %.4f, ± %.4f" %(mean, std))    
trainloader = torch.utils.data.DataLoader(trainset, batch_size=32, shuffle=False)
train_rmse = evaluation(trainloader) # train 데이터의 RMSE
test_rmse = evaluation(testloader) # test 데이터의 RMSE

print("Train RMSE: %.4f" %train_rmse)
print("Test RMSE: %.4f" %test_rmse)

'파이토치' 카테고리의 다른 글

[파이토치] LSTM / GRU  (0) 2022.02.14
[파이토치] RNN  (0) 2022.02.14
[파이토치] CNN  (0) 2022.02.14
[파이토치] Optimizers and Scheduling  (0) 2022.02.14
[파이토치] Neural Networks  (0) 2022.02.14
import torch
import torchvision
model = torchvision.models.resnet18(pretrained=False)

1) Stochastic Gradient Descent

optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

2) Stochastic Gradient Descent with Momentum

optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

3) Stochastic gradient descent with Nesterov’s momentum

optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9, nesterov=true)

4) Adam (Algorithms with Adaptive Learning Rates)

• Adaptive moment estimation

• It uses the first moment and the second moment.

• A variant on the combination of RMSProp and momentum

optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
 
5) Scheduling
optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=30, gamma=0.1)
 
• Adaptive learning rates
• 첫번째 30개의 epoch에서는 0.1의 gradient를 사용하고 다음 30부터 60번째 epoch에서는 0.01의 gradient를 사용한다.
 
for epoch in range(400): 
    running_loss = 0.0
    for data in trainloader: 
        inputs, values = data 
        optimizer.zero_grad() 
        outputs = model(inputs) 
        loss = criterion(outputs, values) 
        loss.backward() 
        optimizer.step()  # 역전파를 진행하고 가중치 업데이트
        ...
 
    scheduler.step() # 스케줄링을 통한 학습률 조정 (outer for문에 선언해야 한다)
 
 

※ 참고자료 (https://www.slideshare.net/yongho/ss-79607172)

다양한 optimizer가 존재한다.

 

자세한 Offical document는 아래 링크에서 확인할 수 있습니다.

https://pytorch.org/docs/stable/generated/torch.optim.SGD.html

 

'파이토치' 카테고리의 다른 글

[파이토치] LSTM / GRU  (0) 2022.02.14
[파이토치] RNN  (0) 2022.02.14
[파이토치] CNN  (0) 2022.02.14
[파이토치] Cross-Validation  (0) 2022.02.14
[파이토치] Neural Networks  (0) 2022.02.14

+ Recent posts