반응형

안녕하세요. 

 

Plain Network(단순히 Layer을 깊게 쌓음)에서 발생하는 Vanishing Gradient(기울기 소실), Overfitting(과적합) 등의 문제를 해결하기 위해 ReLU, Batch Nomalization 등 많은 기법이 있습니다. 

 

ILSVRC Challenge
2021년 3월 24일 기준 인용

ILSVRC 대회에서 2015년, 처음으로 Human Recognition보다 높은 성능을 보인 것이 ResNet입니다.

그 위용은 무지막지한 논문 인용 수로 확인할 수 있습니다. 

 

그렇기 때문에 ResNet은 딥러닝 이미지 분야에서 바이블로 통하고 있습니다. 

 

Plain Netwrok Vs ResNet

Plain Network는 단순히 Convolution 연산을 단순히 쌓는다면, ResNet은 Block단위로 Parameter을 전달하기 전에 이전의 값을 더하는 방식입니다. 

 

Residual Block

F(x) : weight layer => relu => weight layer 

x : identity

 

weight layer들을 통과한 F(x)와 weight layer들을 통과하지 않은 x의 합을 논문에서는 Residual Mapping 이라 하고, 그림의 구조를 Residual Block이라 하고, Residual Block이 쌓이면 Residual  Network(ResNet)이라고 합니다.

Residual Mapping은 간단하지만, Overfitting, Vanishing Gradient 문제가 해결되어 성능이 향상됐습니다.

그리고 다양한 네트워크 구조에서 사용되며, 2017년 ILSVRC을 우승한 SeNet에서 사용됩니다. ( 이 글을 쓴 이유이기도 합니다. ) 

 

Plain Network VS ResNet (Error)

 

Residual Block

class Residual_Block(nn.Module):
    def __init__(self, in_dim, mid_dim, out_dim):
        super(Residual_Block,self).__init__()
        # Residual Block
        self.residual_block = nn.Sequential(
                nn.Conv2d(in_dim, mid_dim, kernel_size=3, padding=1),
                nn.ReLU,
                nn.Conv2d(mid_dim, out_dim, kernel_size=3, padding=1),
            )            
        self.relu = nn.ReLU()
                  
    def forward(self, x):
       out = self. residual_block(x)  # F(x)
        out = out + x  # F(x) + x
        out = self.relu(out)
        return out
    

 

그리고 Residual Block 소개 후 BottleNeck이 나옵니다. 아래 글을 참고하시면 좋을 것 같습니다. 

coding-yoon.tistory.com/116?category=825914

 

[딥러닝] DeepLearning CNN BottleNeck 원리(Pytorch 구현)

안녕하세요. 오늘은 Deep Learning 분야에서 CNN의 BottleNeck구조에 대해 알아보겠습니다. 대표적으로 ResNet에서 BottleNeck을 사용했습니다. ResNet에서 왼쪽은 BottleNeck 구조를 사용하지 않았고, 오른쪽은..

coding-yoon.tistory.com

ResNet 원문

arxiv.org/abs/1512.03385

 

Deep Residual Learning for Image Recognition

Deeper neural networks are more difficult to train. We present a residual learning framework to ease the training of networks that are substantially deeper than those used previously. We explicitly reformulate the layers as learning residual functions with

arxiv.org

 

728x90
반응형
반응형

안녕하세요. WB LOS/NLOS Classification Using Deep Learning Method(1)에서 UWB CIR Dataset을 생성하였다면, 

2편으로 논문에서 제시한 CNN_LSTM 네트워크를 약간 변형하여 구성하겠습니다. 

 

coding-yoon.tistory.com/138

 

[무선 통신] UWB LOS/NLOS Classification Using Deep Learning Method (1)

안녕하세요. 오늘은 Indoor Positioning에서 [cm]단위의 오차를 내는 UWB 관련 논문에 이야기하겠습니다. coding-yoon.tistory.com/136?category=910542 [무선 통신] Bluetooth Low Energy(BLE) 1. Physical Layer..

coding-yoon.tistory.com

1편을 보고 오시는 것을 추천드립니다. 이는 1편처럼 Dataset이 준비됐다는 가정 하에 진행됩니다.

 

Dataset

Columns : 1016 (Sampling CIR)

Label : 42000(LOS : 21000, NLOS : 21000)  

 

먼저 위 논문은 CNN-LSTM 구조로 LOS/NLOS를 학습하는 모델입니다.

(epoch : 10, learning rate : 0.001, dropout : 0.5, Train Sample : 35000, Test Sample : 7000)

CNN에서 CIR Featur을 추출, Redundant information을 제거하고, LSTM을 이용하여 분류합니다.

( CNN+stacked-LSTM Accuracy : 82.14% )

 

Model Structure
CNN Structure
LSTM Structure
Result

Implemnet ( Dataset : df_uwb_data 준비 )

 

1. Import

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
from torch.utils.tensorboard import SummaryWriter

from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt 

import time
import random

import uwb_dataset

print("Pytorch Version :", torch.__version__)  # Pytorch Version : 1.7.1+cu110
writer = SummaryWriter('runs/UWB_CIR_Classfication')

%matplotlib inline

 

2. Hyper-Parameters

# random seed
random_seed = 42

num_epoch = 10
batch_size = 64
in_channels = 1
num_classes = 2
num_layers = 2
fully_connected = 128

lr = 0.001
weight_decay = 0.0

# Parameters
view_train_iter = 50
view_val_iter = 5
save_point = 0.90

3. Random Seed

def torch_random_seed(on_seed=False, random_seed=1):
    if on_seed:
        torch.manual_seed(random_seed)
        torch.backends.cudnn.deterministic = True
        torch.backends.cudnn.benchmark = False

        np.random.seed(random_seed)
        random.seed(random_seed)
        
torch_random_seed(on_seed=True, random_seed=random_seed)

4. Model Evaluation Function

def get_clf_eval(y_true, y_pred, average='weighted'):
    accuracy = accuracy_score(y_true, y_pred)
    precision = precision_score(y_true, y_pred, average=average)
    recall = recall_score(y_true, y_pred, average=average)
    f1 = f1_score(y_true, y_pred, average=average)

    return accuracy, precision, recall, f1

5. Split (Train, Validation, Test) X, label Data

# sklearn의 train_test_split은 stratify 파라미터를 통해 Label의 비율을 유지하면서 Split
x_train, x_test, y_train, y_test = train_test_split(df_uwb_data.values, df_uwb['NLOS'].values, test_size=0.1, random_state=42, stratify=df_uwb['NLOS'].values)
x_train, x_val, y_train, y_val = train_test_split(x_train, y_train, test_size=0.1, random_state=random_seed, stratify=y_train)

print("x_train shape :", x_train.shape, y_train.shape)
print("x_val shape :", x_val.shape, y_val.shape)
print("x_test shape :", x_test.shape, y_test.shape)
print("Train NLOS 0 count :", len(y_train[y_train==0]))
print("Train NLOS 1 count :", len(y_train[y_train==1]))
print("Validation NLOS 0 count :", len(y_val[y_val==0]))
print("Validation NLOS 1 count :", len(y_val[y_val==1]))
print("Test NLOS 0 count :", len(y_test[y_test==0]))
print("Test NLOS 0 count :", len(y_test[y_test==1]))

7. Dataset & DataLoader

def generating_loader(x_data, y_data, batch_size=batch_size, shuffle=True, drop_last=True):
    # preprocessing x_data
    x_data = np.expand_dims(x_data, axis=1)
    x_tensor = torch.tensor(x_data, dtype=torch.float32)
    # preprocessing y_data
    y_tensor = torch.tensor(y_data, dtype=torch.long).view(-1)

    return DataLoader(TensorDataset(x_tensor, y_tensor), batch_size=batch_size, shuffle=shuffle, drop_last=drop_last)
trainloader = generating_loader(x_train, y_train, batch_size=batch_size, shuffle=True, drop_last=True)
validationloader = generating_loader(x_val, y_val, batch_size=batch_size, shuffle=False, drop_last=True)
testloader = generating_loader(x_val, y_val, batch_size=batch_size, shuffle=False, drop_last=True)
for x, label in trainloader:
    print(x.shape, label.shape)
    break

8. Create Model

class CNN_LSTM(nn.Module):
    def __init__(self, in_channels, out_channels, batch_size, num_layers, fully_connected, device):
        super(CNN_LSTM, self).__init__()
        self.batch_size = batch_size
        self.conv1d_layer = nn.Sequential(
            nn.Conv1d(in_channels=in_channels, out_channels=10, kernel_size=4, stride=1, padding=0),
            nn.ReLU(),
            nn.Conv1d(in_channels=10, out_channels=20, kernel_size=5, stride=1, padding=0),
            nn.ReLU(),
            nn.MaxPool1d(kernel_size=2, stride=2),
        ) 
        self.lstm = nn.LSTM(input_size = 504, 
                            hidden_size = 32, 
                            num_layers = num_layers,
                            bias = False,
                            dropout = 0.5,
                            bidirectional = True,
                            batch_first=True)

        self.hidden_state, self.cell_state = self.init_hidden()
        
        self.bn2 = nn.BatchNorm1d(20)
        self.bn0 = nn.BatchNorm1d(64)
        self.bn1 = nn.BatchNorm1d(128)

        self.fc_layer = nn.Linear(64, 128)
        self.relu = nn.ReLU()
        self.fc_layer_class = nn.Linear(128, out_channels)


    def init_hidden(self):
        hidden_state = torch.zeros(num_layers*2, self.batch_size, 32).to(device)
        cell_state = torch.zeros(num_layers*2, self.batch_size, 32).to(device)

        return hidden_state, cell_state
        
    def forward(self, x):
        x = self.conv1d_layer(x)
        x, _ = self.lstm(x,(self.hidden_state, self.cell_state))
        x = x[:, -1 :].view(x.size(0), -1)
        x = self.bn0(x)
        x = self.fc_layer(x)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.fc_layer_class(x)
        x = self.relu(x)

        return x

9. Loss Function, Optimizer

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model = CNN_LSTM(
    in_channels=in_channels,\
    device=device,\
    out_channels=num_classes,\
    batch_size=batch_size,\
    fully_connected=fully_connected,\
    num_layers=num_layers).to(device)
loss_function = nn.CrossEntropyLoss()  
optimizer = optim.Adam(model.parameters(), lr=lr, weight_decay=weight_decay)  # optimizer

# tensorboard
images, labels = next(iter(trainloader))
writer.add_graph(model, images.to(device))

# lr_scheduler = optim.lr_scheduler.MultiStepLR(optimizer=optimizer, milestones=[int(num_epoch * 0.5), int(num_epoch * 0.75)], gamma=0.1, last_epoch=-1)

10. Train, Validation 

start = time.time()

correct = 0
total = 0
train_acc = []
tmp_acc = 0
loss_arr = []

print("*Train Start!!*")
if torch.cuda.device_count() == True:
    print("epoch : {}, learing rate : {}, device : {}".format(num_epoch, lr, torch.cuda.get_device_name(0)))
    print("Model : {}".format(model._get_name()))
    print("Loss function : {}".format(loss_function._get_name()))
    print("Optimizer : {}".format(str(optimizer).replace("\n", " ").replace("     ", ", ")))
else:
    print("epoch : {}, learing rate : {}, device : {}".format(num_epoch, lr, device))
    print("Model : {}".format(model._get_name()))
    print("Loss function : {}".format(loss_function._get_name()))
    print("Optimizer : {}".format(str(optimizer).replace("\n", " ").replace("     ", ", ")))
print("*"*100)

# train
for epoch in range(num_epoch):
    epoch += 1
    for train_iter, (train_x, train_y_true) in enumerate(trainloader):
        model.train()  # Train mode
        model.zero_grad()  # model zero initialize
        optimizer.zero_grad()  # optimizer zero initialize
        

        train_x, train_y_true = train_x.to(device), train_y_true.to(device)  # device(gpu)
        train_y_pred = model.forward(train_x)  # forward
        loss = loss_function(train_y_pred, train_y_true)  # loss function
        loss.backward()  # backward
        optimizer.step()  # optimizer
        _, pred_index = torch.max(train_y_pred, 1)
        
        if train_iter % view_train_iter == 0:
            loss_arr.append(loss.item())
            total += train_y_true.size(0)  # y.size(0)
            correct += (pred_index == train_y_true).sum().float()  # correct
            tmp_acc = correct / total  # accuracy
            train_acc.append(tmp_acc)

            writer.add_scalar("Loss/train", loss, epoch)
            writer.add_scalar("Accuracy/train",tmp_acc, epoch)

            print("[Train] ({}, {}) Time={:.2f}[s], loss = {:.5f}, Accuracy = {:.4f}, lr={:.6f}".format(epoch, train_iter, time.time()-start, loss.item(), tmp_acc, optimizer.param_groups[0]['lr']))
    # lr_scheduler.step()
    # validation 
    if epoch % view_val_iter == 0: 
        val_acc_tmp, val_precision_tmp, val_recall_tmp, val_f1_tmp = [], [], [], []
        val_acc_result, val_precision_result, val_recall_result, val_f1_result = [], [], [], []
        val_time = time.time()
        for val_iter, (val_x, val_y_true) in enumerate(validationloader):
            model.eval()
            val_x, val_y_true = val_x.to(device), val_y_true.to(device)  # device(gpu)
            val_y_pred = model.forward(val_x)  # forward
            _, val_pred_index = torch.max(val_y_pred, 1)

            val_pred_index_cpu = val_pred_index.cpu().detach().numpy()
            val_y_true_cpu = val_y_true.cpu().detach().numpy()
            
            val_acc, val_precision, val_recall, val_f1 = get_clf_eval(val_y_true_cpu, val_pred_index_cpu)

            val_acc_tmp.append(val_acc), val_acc_result.append(val_acc)
            val_precision_tmp.append(val_precision), val_precision_result.append(val_precision)
            val_recall_tmp.append(val_recall), val_recall_result.append(val_recall)
            val_f1_tmp.append(val_f1), val_f1_result.append(val_f1)

        val_acc_mean = sum(val_acc_tmp, 0.0)/len(val_acc_tmp)
        val_precision_mean = sum(val_precision_tmp, 0.0)/len(val_precision_tmp)
        val_recall_mean = sum(val_recall_tmp, 0.0)/len(val_recall_tmp)
        val_f1_mean = sum(val_f1_tmp, 0.0)/len(val_f1_tmp)

        print("-"*100)
        print("|  Validation {:.2f}[s], Accuracy : {:.4f}, Precision : {:.4f}, Recall : {:.4f}, F1 Score : {:.4f}   |".format(
            time.time()-val_time, val_acc_mean, val_precision_mean, val_recall_mean, val_f1_mean))
        print("-"*100)
        if val_acc_mean >= save_point:
            epoch_str = str(epoch)
            lr_str = str(lr)
            batch_str= str(batch_size)
            acc_str= str((int(val_acc_mean*100)))
            model_name = "["+model._get_name()+"](epoch-"+epoch_str+")-"+"(init_lr-"+lr_str+")-"+"(batch-"+batch_str+")-"+"(acc-"+acc_str+").pt"
            save_path = os.path.join(path, dir_ ,model_name)
            parameters = {'epoch' : epoch, 'model_state_dict' : model.state_dict(), 'optimizer_state_dict' : optimizer.state_dict(), 'loss' : loss}
            torch.save(parameters, save_path)
            print('[INFO] Model Saved : '+ save_path)
writer.flush()
writer.close()

fig = plt.figure(figsize=[16, 8])
loss_plt = plt.subplot(2,1,1)
acc_plt = plt.subplot(2,1,2)

loss_plt.plot(loss_arr, color='red', marker="*")
loss_plt.set_title("Train - Loss", fontsize=15)
loss_plt.legend(['Train-Loss'])
loss_plt.grid(True, axis='y')

acc_plt.plot(train_acc, color='green', marker="*")
acc_plt.set_title("Train - Accuracy", fontsize=15)
acc_plt.legend(['Train-Accuracy'])
acc_plt.set_ylim((0.0, 1.05))
acc_plt.grid(True, axis='y')

plt.show()

11. Model Evaluation

test_start = time.time()

model.eval()
with torch.no_grad():
    test_acc_tmp, test_precision_tmp, test_recall_tmp, test_f1_tmp = [], [], [], []
    for test_iter, (test_x, test_y_true) in enumerate(testloader):
        test_x, test_y_true = test_x.to(device), test_y_true.to(device)
        test_y_pred = model.forward(test_x)  # forward

        _, test_pred_index = torch.max(test_y_pred, 1)

        test_pred_index_cpu = test_pred_index.cpu().detach().numpy()
        test_y_true_cpu = test_y_true.cpu().detach().numpy()
            
        test_acc, test_precision, test_recall, test_f1 = get_clf_eval(test_y_true_cpu, test_pred_index_cpu)

        test_acc_tmp.append(test_acc), test_precision_tmp.append(test_precision), test_recall_tmp.append(test_recall), test_f1_tmp.append(test_f1)

    test_acc_mean = sum(test_acc_tmp, 0.0)/len(test_acc_tmp)
    test_precision_mean = sum(test_precision_tmp, 0.0)/len(test_precision_tmp)
    test_recall_mean = sum(test_recall_tmp, 0.0)/len(test_recall_tmp)
    test_f1_mean = sum(test_f1_tmp, 0.0)/len(test_f1_tmp)
    print("[Evaluation] {:.2f}[s], Test Accuracy : {:.4f}, Precision : {:.4f}, Recall : {:.4f}, F1 Score : {:.4f}".format(
        time.time()-test_start, test_acc_mean, test_precision_mean, test_recall_mean, test_f1_mean))
    print("[Model Performance] Model Performance : {:.5f}".format(test_acc_mean))

Model Performance : 89.83%
Tensorboard

 

모델에 제시된 파라미터는 그대로 사용하고, 약간 변형하여 모델을 구축하였는데 높은 Accuracy를 보여줍니다. 

 

하지만 LOS/NLOS의 분류를 통해 UWB 성능을 올리는 방법을 제시하였지만, 논문의 Limitations으로 실제로 이 분류기를 통해 UWB 성능을 검증하지 못했습니다. 

 

그리고 제가 생각하는 또 다른 문제는 오픈소스의 데이터라고 생각합니다. 

이 데이터를 보았을 때, 굳이 딥러닝, 머신러닝을 사용할 필요가 있을까? 의문이 듭니다. 

1차원적으로 생각하였을 때 Threshold를 10000에서 잘라버리면, NLOS를 쉽게 지워버릴 수 있습니다. 

 

현 데이터는 허수(방향) 부분을 제외한 오직 크기의 성질만을 가지고 학습하였기 때문에, 과연 실제 환경 속에서 제대로 작동할지 의문이 듭니다. 

 

UWB 특성상 Nanosecond로 시간을 재는 방식이기 때문에 데이터 추출하는 것이 굉장히 굉장히 어려움이 있어 구현하는 것은 어려움이 있습니다. 그렇기 때문에 5년 전 오픈소스이지만, 2020년에도 이를 이용해 논문을 작성했을 것이라고 생각합니다.

 

728x90
반응형
반응형

pip install pandas

 

현재 폴더 경로 

각 폴더에는 아래와 같이 전처리 되지 않은 CSV가 존재한다.

JS01

 

JS02

 

JS03

[JS01-210210_222834_p9_고정, JS02-210210_222841_p9고정, JS03-210210_222859_p9_고정]과 같이 데이터 프레임을 병합하고, 분석에 알맞게 전처리를 하는 과정을 보여준다.  

 

아래는 실험 데이터로 중간에 빈 데이터가 보이고, 전처리 과정이 필요한 원본 데이터이다.  

 

raw data
preprocessing data


이제부터 Pandas를 통해 데이터 분석에 알맞게 전처리를 할 것이다.  (위 preprocessing data가 최종 목표 데이터)

 

 

 

* Section 1 *

 

0. 모든 CSV를 불러온다. 

1. Null/NaN(결손) 데이터를 제거한다. 

   ex) (df : dataframe) df.isna.sum() 를 통해서 결손데이터를 파악할 수 있다. ( df.info()도 확인가능하다. )

2. 필요없는 열(bootms)을 삭제한다. 

3. Column 이름을 변경한다. (" aCnt" ▶"aCnt", " RSSI" "RSSI") 

   ( " aCnt"와 "aCnt"의 차이는 띄어쓰기이다. df.columns 를 통해 정확한 column name을 작성한다. 띄어쓰기 구별 )

4. 1001 이상 aCnt 행을 삭제한다. 

5. aCnt를 Group 내어 평균한다. 

6. CSV 데이터로 저장한다. 

 

import pandas as pd
import os


# 모든 CSV 경로를 변수에 저장한다..
list_folder_name = ['JS01', 'JS02', 'JS03']
list_csv_folder = [os.path.join(os.getcwd(), file_name) for file_name in list_folder_name]
list_p = []
list_path = []

for i in list_csv_folder:
    _, _, file_names = next(os.walk(i))
    for n, j  in enumerate(file_names):
        list_path.append(os.path.join(i,j))
        print(list_path[n])
        
# result 
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_222834_p9_고정.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_224020.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_225507.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_225821.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230150.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230314.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230540.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230845.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_222834_p9_고정.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_224020.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_225507.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_225821.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230150.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230314.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230540.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230845.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_222834_p9_고정.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_224020.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_225507.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_225821.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230150.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230314.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230540.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230845.csv

 

# 파일 별로 1번 ~ 6번 과정을 반복한다.
# 0. 모든 CSV를 불러온다. 
for i in range(len(list_path)):
    print(list_path[i])
    # 0_1. CSV를 불러온다.
    csv_data = pd.read_csv(list_path[i])
    
    # 1. Null/NaN(결손) 데이터를 제거한다. 
    csv_data.dropna(inplace=True)
    
    # 2. 필요없는 열(bootms)을 삭제한다. 
    csv_data.rename(columns={" aCnt":"aCnt", " RSSI":"RSSI"}, inplace=True)
    
    # 3. Column 이름을 변경한다. (" aCnt" ▶"aCnt", " RSSI" ▶ "RSSI") 
    csv_data.drop(columns=['bootms'], inplace=True)
    
    # 4. 1001 이상 aCnt 행을 삭제한다.
    csv_data.query('aCnt<=1000', inplace=True)

    # 5. aCnt를 Group 내어 평균한다. 
    csv_data_group = csv_data.groupby(['aCnt']).mean().round(1)
    
    # 6. CSV 데이터로 저장한다. 
    csv_data_group.to_csv(list_path[i], mode='w', index=True)

head(5)
tail(5)

1차적으로 필요없는 열 제거, 결손 데이터 제거 등 필수 작업은 끝이 났다. 

 

이제 분석을 하기 위해 Dataframe 병합, 분석에 필요한 열 추가를 할 것이다. 

 

 

 

* Section 2 *

 

import pandas as pd
import numpy as np
import os


list_folder_name = ['JS01', 'JS02', 'JS03']
list_csv_folder = [os.path.join(os.getcwd(), file_name) for file_name in list_folder_name]
list_path = []

for i in list_csv_folder:
    _, _, file_names = next(os.walk(i))
    for j in file_names:
        list_path.append(os.path.join(i,j))
        
# result 
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_222834_p9_고정.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_224020.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_225507.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_225821.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230150.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230314.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230540.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230845.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_222834_p9_고정.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_224020.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_225507.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_225821.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230150.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230314.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230540.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230845.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_222834_p9_고정.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_224020.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_225507.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_225821.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230150.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230314.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230540.csv
c:\Users\mangnani\Desktop\Develop\VS Code\Python37\[티스토리]__Pandas전처리\JS01\210210_230845.csv        

 

np_path = np.array(list_path) # (24)
np_path = np_path.reshape(len(list_folder_name), -1) # (3, 8)
np_path_trans = np_path.T  # Transpose (8, 3)  
print(np_path_trans)

# result 
"""
[['c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS01\\210210_222834_p9_고정.csv'
  'c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS02\\210210_222841_p9고정.csv'
  'c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS03\\210210_222859_p9_고정.csv']
 ['c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS01\\210210_224020.csv'
  'c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS02\\210210_224045.csv'
  'c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS03\\210210_224041.csv']
 ['c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS01\\210210_225507.csv'
  'c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS02\\210210_225511.csv'
  'c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS03\\210210_225519.csv']
 ['c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS01\\210210_225821.csv'
  'c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS02\\210210_225828.csv'
  'c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS03\\210210_225837.csv']
 ['c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS01\\210210_230150.csv'
  'c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS02\\210210_230159.csv'
  'c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS03\\210210_230155.csv']
 ['c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS01\\210210_230314.csv'
  'c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS02\\210210_230325.csv'
  'c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS03\\210210_230329.csv']
 ['c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS01\\210210_230540.csv'
  'c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS02\\210210_230607.csv'
  'c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS03\\210210_230601.csv']
 ['c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS01\\210210_230845.csv'
  'c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS02\\210210_230850.csv'
  'c:\\Users\\mangnani\\Desktop\\Develop\\VS Code\\Python37\\[티스토리]__Pandas전처리\\JS03\\210210_230903.csv']]
  """

 

df_1 = pd.read_csv(np_path_trans[file_index][0])
df_2 = pd.read_csv(np_path_trans[file_index][1])
df_3 = pd.read_csv(np_path_trans[file_index][2])

print(df_1, df_2, df_3, sep="\n")

# result
       aCnt  RSSI
0       0.0 -73.2
1       1.0 -71.5
2       2.0 -72.5
3       3.0 -72.0
4       4.0 -73.0
..      ...   ...
988   996.0 -73.3
989   997.0 -73.3
990   998.0 -74.0
991   999.0 -72.7
992  1000.0 -73.0

[993 rows x 2 columns]
       aCnt  RSSI
0       0.0 -85.0
1       1.0 -84.0
2       2.0 -85.0
3       4.0 -81.0
4       5.0 -82.0
..      ...   ...
741   996.0 -84.0
742   997.0 -83.0
743   998.0 -81.5
744   999.0 -80.0
745  1000.0 -81.5

[746 rows x 2 columns]
      aCnt  RSSI
0      0.0 -80.5
1      1.0 -82.0
2      2.0 -81.0
3      3.0 -85.0
4      4.0 -81.0
..     ...   ...
759  982.0 -83.0
760  984.0 -83.0
761  990.0 -87.0
762  992.0 -86.0
763  999.0 -85.0

[764 rows x 2 columns]

데이터 프레임을 자세히 보면 세 개의 df 행의 갯수가 다름을 알 수 있다. ( 이는 데이터 특성상 aCnt가 없는 것을 의미한다.) 

 

각각 데이터 프레임 aCnt의 교집합을 찾아 병합할 것이다. 

df_tmp = pd.merge(df_1, df_2, on='aCnt', how='inner')
df_rssi = pd.merge(df_tmp, df_3, on='aCnt', how='inner')

df_rssi

# result
aCnt	RSSI_x	RSSI_y	RSSI
0	0.0	-73.2	-85.0	-80.5
1	1.0	-71.5	-84.0	-82.0
2	2.0	-72.5	-85.0	-81.0
3	4.0	-73.0	-81.0	-81.0
4	5.0	-73.0	-82.0	-83.5
...	...	...	...	...
586	982.0	-73.3	-83.3	-83.0
587	984.0	-73.3	-81.0	-83.0
588	990.0	-73.0	-83.0	-87.0
589	992.0	-73.7	-82.5	-86.0
590	999.0	-72.7	-80.0	-85.0
591 rows × 4 columns

 

Colum name을 알맞게 변경한다. 

 

df_rssi.rename(columns={"RSSI_x":"RSSI_1", "RSSI_y":"RSSI_2", "RSSI":"RSSI_3"}, inplace=True)

df_rssi

# result

aCnt	RSSI_1	RSSI_2	RSSI_3
0	0.0	-73.2	-85.0	-80.5
1	1.0	-71.5	-84.0	-82.0
2	2.0	-72.5	-85.0	-81.0
3	4.0	-73.0	-81.0	-81.0
4	5.0	-73.0	-82.0	-83.5
...	...	...	...	...
586	982.0	-73.3	-83.3	-83.0
587	984.0	-73.3	-81.0	-83.0
588	990.0	-73.0	-83.0	-87.0
589	992.0	-73.7	-82.5	-86.0
590	999.0	-72.7	-80.0	-85.0
591 rows × 4 columns

RSSI를 통한 Distance를 추가할 것이다. ( lambda 함수 사용 )

def lambda_distance(rssi, tp=-64):
    ratio = rssi*1.0/tp
    if ratio < 1.0:
        return pow(ratio, 10)
    else:
        distance = (0.89976)*pow(ratio,7.7095) + 0.111
        return distance

 

df_rssi['distance_1'] = df_rssi['RSSI_1'].apply(lambda rssi:lambda_distance(rssi))
df_rssi['distance_2'] = df_rssi['RSSI_2'].apply(lambda rssi:lambda_distance(rssi))
df_rssi['distance_3'] = df_rssi['RSSI_3'].apply(lambda rssi:lambda_distance(rssi))

df_rssi

# result
	aCnt	RSSI_1	RSSI_2	RSSI_3	distance_1	distance_2	distance_3
0	0.0	-73.2	-85.0	-80.5	2.645139	8.132164	5.384701
1	1.0	-71.5	-84.0	-82.0	2.225242	7.432724	6.191371
2	2.0	-72.5	-85.0	-81.0	2.464196	8.132164	5.642557
3	4.0	-73.0	-81.0	-81.0	2.592246	5.642557	5.642557
4	5.0	-73.0	-82.0	-83.5	2.592246	6.191371	7.103364
...	...	...	...	...	...	...	...
586	982.0	-73.3	-83.3	-83.0	2.671951	6.975277	6.786975
587	984.0	-73.3	-81.0	-83.0	2.671951	5.642557	6.786975
588	990.0	-73.0	-83.0	-87.0	2.592246	6.786975	9.707345
589	992.0	-73.7	-82.5	-86.0	2.781686	6.483119	8.889049
590	999.0	-72.7	-80.0	-85.0	2.514708	5.137370	8.132164
591 rows × 7 columns

df_rssi.to_csv(csv_name, mode='w', index=False)

 

728x90
반응형
반응형

안녕하세요. 오늘은 RNN을 Pytorch로 직접 구현해보고, Tanh(hyperbolic tangent) 대신, Sigmoid나 ReLU를 사용하면 어떻게 되는지 실험을 한 번 해보겠습니다. 

 

www.youtube.com/watch?v=tlyzfIYvMWE&list=PLSAJwo7mw8jn8iaXwT4MqLbZnS-LJwnBd&index=26

제가 Pytorch를 처음 공부할 때 위 영상을 많이 참고 했습니다. 

 

Pytorch를 처음 공부하시는 분이시라면, 위 딥러닝 홀로서기 Pytorch Kist 영상을 보시는 걸 추천드립니다. 

 

자료도 아낌없이 GIt에 올라와 있고, 라이브 코딩을 하면서 수업이 진행되기 때문에 접근하는 노하우를 기를 수 있다고 생각합니다. 

 

코드는 위 영상 GIthub의 자료를 수정한 내용입니다. 

 

우선 RNN(Recurrent Neural Network)에 구조 대해 이야기 해보겠습니다. 

 

RNN은 Input과 Output을 Sequence 단위로 처리하는 네트워크 구조입니다. 

 

일반 신경망과 달리 순환 신경망은 Cell 부분이 순환하게 됩니다.

Hidden Layer는 바로 이전 Hidden Layer의 입력을 현재 입력으로 사용하는 것이 가장 큰 특징입니다.

 

이런 RNN의 순환 구조 때문에 시계열 데이터에 가장 많이 사용되고 있습니다. 

 

위 구조는 간단한 식으로 표현할 수 있습니다.

 

그렇다면 activation function인 tanh 말고, 지금 가장 많이 사용한다는 ReLU를 사용하면 안될까 라는 궁금증이 생겼습니다. 

 

Sigmoid의 미분의 최대값이 0.25이기 때문에, Deep해질수록 Vanishing Gradient 가 발생합니다. 

 

Vanishing 문제를 해결하기 위해 만든 것이 Tanh 입니다. 

 

Tanh는 0~1인 Sigmoid 확장판이며, 미분의 최대값이 1로 Vanishing Graidient를 해결합니다. 

 

ReLU는 -1~1을 반환하는 Tanh 대신, x가 0보다 크면 그대로 값을 보내게 되어, 속도와 학습률이 향상됐습니다.  

 

하지만, RNN의 내부는 계속 순환하는 구조로 값이 1보다 크게 되면, ReLU 특성상 값이 발산할 수 있기 때문에 적합하지 않다고 합니다.   

 

그렇다면, 간단한 데이터에서 발산하지 않는 환경에서 ReLU를 사용하게 된다면 어떻게 될지 궁금했습니다. 

 

위 영상의 Git 코드를 사용했으며, 학습이 실패한 영상입니다. 

 

수정을 하진 않고, 코드를 그대로 사용했으며, 활성화 함수만 바꿔가면서 학습 결과를 확인했습니다. 

 

import torch
import torch.nn as nn


class RNN(nn.Module):
    def __init__(self, input_dim, output_dim, hid_dim, batch_size): 
        super(RNN, self).__init__()
        
        self.input_dim = input_dim
        self.output_dim = output_dim
        self.hid_dim = hid_dim
        self.batch_size = batch_size
        
        self.wx = nn.Linear(self.input_dim, self.hid_dim, bias=False)
        self.wh = nn.Linear(self.hid_dim, self.hid_dim, bias=False)
        self.wy = nn.Linear(self.hid_dim, self.output_dim, bias=False)
        self.act_fn = nn.Tanh()  # nn.Sigmoid() nn.ReLU() nn.LeakyReLU() 
        
        self.hidden = self.init_hidden()
        
    def init_hidden(self, batch_size=None):
        if batch_size is None:
            batch_size = self.batch_size
        return torch.zeros(batch_size, self.hid_dim)
    
    def forward(self, x):
        h = self.act_fn(self.wx(x) + self.wh(self.hidden))
        y = self.wy(h)
        return y, h

대략 이런 그런 그림이 그려집니다. 분명 Loss 전부 떨어졌으나 모델 성능은 별로 인 것 같습니다. 

 

ReLU가 조금이나마 따라가는 듯하나 값을 예측을 하지 못했습니다. 

 

그래서 LeakyReLU를 사용해 또 결과를 확인 했습니다. 

 

Sinc함수???

LeakyReLU를 사용했을 땐, Sinc 함수가 그려졌습니다. 

 

궁금증을 해결하고자 활성화함수를 바꿔가면서 학습을 시켰으나 오히려 궁금증이 더 커졌습니다.

 

이 부분은 좀 더 공부를 해봐야 할 것 같습니다... 딥러닝 고수분들 피드백 부탁드립니다. 

728x90
반응형
반응형

안녕하세요. 

 

오늘은 LSTM을 이용해서 삼성전자 주가를 예측해보겠습니다. 

 

큰 Dataset은 따로 필요하지 않으니 부담 갖지 않고 하시면 될 것 같습니다. 

 

 

아래는 본문 글입니다.

cnvrg.io/pytorch-lstm/?gclid=Cj0KCQiA6t6ABhDMARIsAONIYyxsIXn6G6EcMLhGnPDxnsKiv3zLU49TRMxsyTPXZmOV3E-Hh4xeI2EaAugLEALw_wcB

 

LSTM이 어떻게 동작을 하는지 자세히 아시고 싶으시면 아래 블로그를 추천드립니다.

dgkim5360.tistory.com/entry/understanding-long-short-term-memory-lstm-kr

 

Long Short-Term Memory (LSTM) 이해하기

이 글은 Christopher Olah가 2015년 8월에 쓴 글을 우리 말로 번역한 것이다. Recurrent neural network의 개념을 쉽게 설명했고, 그 중 획기적인 모델인 LSTM을 이론적으로 이해할 수 있도록 좋은 그림과 함께

dgkim5360.tistory.com

 

 

1. 라이브러리

import numpy as np
import pandas as pd
import pandas_datareader.data as pdr
import matplotlib.pyplot as plt

import datetime

import torch
import torch.nn as nn
from torch.autograd import Variable 

import torch.optim as optim
from torch.utils.data import Dataset, DataLoader

 

no module pandas_datareaderno module named 'pandas_datareader'

pandas가 깔려 있는데, 위 문구가 뜬다면 pip install pandas_datareader로 다운로드합니다. 

 

coding-yoon.tistory.com/56

 

[파이썬 응용] pandas_datareader의 error문 : FutureWarning: pandas.util.testing is deprecated. Use the functions in the pu

안녕하세요. pandas_datareader을 이용해서 데이터 처리를 하기 위해 아래 문구처럼 에러문이 뜨는 경우가 있습니다. FutureWarning: pandas.util.testing is deprecated. Use the functions in the public API at..

coding-yoon.tistory.com

옛날에는 Pandas를 깔면 자동으로 깔렸었는데, 이번에 아예 분리가 된 것 같습니다. 

 

 

2. 삼성 전자 주식 불러오기 

start = (2000, 1, 1)  # 2020년 01년 01월 
start = datetime.datetime(*start)  
end = datetime.date.today()  # 현재 

# yahoo 에서 삼성 전자 불러오기 
df = pdr.DataReader('005930.KS', 'yahoo', start, end)
df.head(5)
df.tail(5)
df.Close.plot(grid=True)

 

head(5) : 맨 앞 5개

 

tail(5) : 맨 뒤 5 개
삼성 전자 2000 ~ 2020년

삼성 전자 종가를 2000년부터 2020년으로 한 번에 보니 미쳐 날 뛰네요. 지금이라도 이 흐름을 타야 하지 않을까요.

십 만전자 가자!!

 

혹시 다른 주식도 하고 싶으시면  야후 파이낸시에서 찾아보시는 것도 추천드립니다.

finance.yahoo.com/

 

Yahoo Finance - Stock Market Live, Quotes, Business & Finance News

At Yahoo Finance, you get free stock quotes, up-to-date news, portfolio management resources, international market data, social interaction and mortgage rates that help you manage your financial life.

finance.yahoo.com

그리고 학습된 모델이 성능을 확인하기 위해서 위 데이터(현재 약 5296개)를 Train(학습하고자 하는 데이터)를 0부터 4499까지, Test(성능 테스트하는 데이터)는 4500부터 5295개 까지 데이터로 분류합니다.

 

오늘자 대략, 노란색 선 정도까지 데이터를 가지고 학습을 하고, 노란색 선 이후부터 예측을 할 것입니다. 

과연 내려가고 올라가는 포인트를 잘 예측할 수 있을지 궁금합니다.

 

3. 데이터셋 준비하기

"""
저도 주식을 잘 모르기 때문에 참고해주시면 좋을 것 같습니다. 
open 시가
high 고가
low 저가
close 종가
volume 거래량
Adj Close 주식의 분할, 배당, 배분 등을 고려해 조정한 종가

확실한건 거래량(Volume)은 데이터에서 제하는 것이 중요하고, 
Y 데이터를 Adj Close로 정합니다. (종가로 해도 된다고 생각합니다.)

"""
X = df.drop(columns='Volume')
y = df.iloc[:, 5:6]

print(X)
print(y)

X
y

"""
학습이 잘되기 위해 데이터 정규화 
StandardScaler	각 특징의 평균을 0, 분산을 1이 되도록 변경
MinMaxScaler	최대/최소값이 각각 1, 0이 되도록 변경
"""

from sklearn.preprocessing import StandardScaler, MinMaxScaler
mm = MinMaxScaler()
ss = StandardScaler()

X_ss = ss.fit_transform(X)
y_mm = mm.fit_transform(y) 

# Train Data
X_train = X_ss[:4500, :]
X_test = X_ss[4500:, :]

# Test Data 
"""
( 굳이 없어도 된다. 하지만 얼마나 예측데이터와 실제 데이터의 정확도를 확인하기 위해 
from sklearn.metrics import accuracy_score 를 통해 정확한 값으로 확인할 수 있다. )
"""
y_train = y_mm[:4500, :]
y_test = y_mm[4500:, :] 

print("Training Shape", X_train.shape, y_train.shape)
print("Testing Shape", X_test.shape, y_test.shape) 

numpy 형태 : 이 상태에서는 학습이 불가능. 

"""
torch Variable에는 3개의 형태가 있다. 
data, grad, grad_fn 한 번 구글에 찾아서 공부해보길 바랍니다. 
"""
X_train_tensors = Variable(torch.Tensor(X_train))
X_test_tensors = Variable(torch.Tensor(X_test))

y_train_tensors = Variable(torch.Tensor(y_train))
y_test_tensors = Variable(torch.Tensor(y_test))

X_train_tensors_final = torch.reshape(X_train_tensors,   (X_train_tensors.shape[0], 1, X_train_tensors.shape[1]))
X_test_tensors_final = torch.reshape(X_test_tensors,  (X_test_tensors.shape[0], 1, X_test_tensors.shape[1])) 

print("Training Shape", X_train_tensors_final.shape, y_train_tensors.shape)
print("Testing Shape", X_test_tensors_final.shape, y_test_tensors.shape) 

학습할 수 있는 형태로 변환하기 위해 Torch로 변환

 

 

4. GPU 준비하기 (없으면 CPU로 돌리면 됩니다.)

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")  # device
print(torch.cuda.get_device_name(0))

 

 

5. LSTM 네트워크 구성하기

class LSTM1(nn.Module):
  def __init__(self, num_classes, input_size, hidden_size, num_layers, seq_length):
    super(LSTM1, self).__init__()
    self.num_classes = num_classes #number of classes
    self.num_layers = num_layers #number of layers
    self.input_size = input_size #input size
    self.hidden_size = hidden_size #hidden state
    self.seq_length = seq_length #sequence length
 
    self.lstm = nn.LSTM(input_size=input_size, hidden_size=hidden_size,
                      num_layers=num_layers, batch_first=True) #lstm
    self.fc_1 =  nn.Linear(hidden_size, 128) #fully connected 1
    self.fc = nn.Linear(128, num_classes) #fully connected last layer

    self.relu = nn.ReLU() 

  def forward(self,x):
    h_0 = Variable(torch.zeros(self.num_layers, x.size(0), self.hidden_size)).to(device) #hidden state
    c_0 = Variable(torch.zeros(self.num_layers, x.size(0), self.hidden_size)).to(device) #internal state   
    # Propagate input through LSTM

    output, (hn, cn) = self.lstm(x, (h_0, c_0)) #lstm with input, hidden, and internal state
   
    hn = hn.view(-1, self.hidden_size) #reshaping the data for Dense layer next
    out = self.relu(hn)
    out = self.fc_1(out) #first Dense
    out = self.relu(out) #relu
    out = self.fc(out) #Final Output
   
    return out 

 

 

위 코드는 복잡해 보이지만, 실상 하나씩 확인해보면 굉장히 연산이 적은 네트워크입니다. 

시계열 데이터이지만, 간단한 구성을 위해 Sequence Length도 1이고, LSTM Layer도 1이기 때문에 굉장히 빨리 끝납니다. 아마 본문 작성자가 CPU환경에서도 쉽게 따라 할 수 있게 간단하게 작성한 것 같습니다. 

 

아래는 Pytorch로 RNN을 사용하는 방법을 적었지만, LSTM과 동일합니다. 

기본 동작 원리만 이해하시면, 쉽게 따라 하실 수 있습니다.

coding-yoon.tistory.com/55

 

[딥러닝] RNN with PyTorch ( RNN 기본 구조, 사용 방법 )

오늘은 Pytorch를 통해 RNN을 알아보겠습니다. https://www.youtube.com/watch?v=bPRfnlG6dtU&t=2674s RNN의 기본구조를 모르시면 위 링크를 보시는걸 추천드립니다. Pytorch document에 RNN을 확인하겠습니다. ht..

coding-yoon.tistory.com

 

 

5. 네트워크 파라미터 구성하기 

num_epochs = 30000 #1000 epochs
learning_rate = 0.00001 #0.001 lr

input_size = 5 #number of features
hidden_size = 2 #number of features in hidden state
num_layers = 1 #number of stacked lstm layers

num_classes = 1 #number of output classes 
lstm1 = LSTM1(num_classes, input_size, hidden_size, num_layers, X_train_tensors_final.shape[1]).to(device)

loss_function = torch.nn.MSELoss()    # mean-squared error for regression
optimizer = torch.optim.Adam(lstm1.parameters(), lr=learning_rate)  # adam optimizer

 

6. 학습하기

for epoch in range(num_epochs):
  outputs = lstm1.forward(X_train_tensors_final.to(device)) #forward pass
  optimizer.zero_grad() #caluclate the gradient, manually setting to 0
 
  # obtain the loss function
  loss = loss_function(outputs, y_train_tensors.to(device))

  loss.backward() #calculates the loss of the loss function
 
  optimizer.step() #improve from loss, i.e backprop
  if epoch % 100 == 0:
    print("Epoch: %d, loss: %1.5f" % (epoch, loss.item())) 

 

7. 예측하기

df_X_ss = ss.transform(df.drop(columns='Volume'))
df_y_mm = mm.transform(df.iloc[:, 5:6])

df_X_ss = Variable(torch.Tensor(df_X_ss)) #converting to Tensors
df_y_mm = Variable(torch.Tensor(df_y_mm))
#reshaping the dataset
df_X_ss = torch.reshape(df_X_ss, (df_X_ss.shape[0], 1, df_X_ss.shape[1]))
train_predict = lstm1(df_X_ss.to(device))#forward pass
data_predict = train_predict.data.detach().cpu().numpy() #numpy conversion
dataY_plot = df_y_mm.data.numpy()

data_predict = mm.inverse_transform(data_predict) #reverse transformation
dataY_plot = mm.inverse_transform(dataY_plot)
plt.figure(figsize=(10,6)) #plotting
plt.axvline(x=4500, c='r', linestyle='--') #size of the training set

plt.plot(dataY_plot, label='Actuall Data') #actual plot
plt.plot(data_predict, label='Predicted Data') #predicted plot
plt.title('Time-Series Prediction')
plt.legend()
plt.show() 

 

 

빨간색 선 이후부터 모델이 예측을 한 것인데 나름 비슷하게 나온 것 같습니다.

 

하지만 인공지능이라도 팔만 전자는 예상하지 못했나 봅니다. 

728x90
반응형

+ Recent posts