co-code 님의 블로그

RNN(순환 신경망 : Recurrent Neural Network), LSTM 본문

python

RNN(순환 신경망 : Recurrent Neural Network), LSTM

co-code 2026. 5. 27. 20:00
  • RNN (순환 신경망)
    • 이전 시점의 정보를 현재 시점의 계산에 반영하는 구조
      • 첫번쨰 입력 : 초기 상태(h_0 = 0)와 입력에 대한 상태(h_1)로 계산
      • 두번째 입력 : 이전의 상태(h_1)와 결합해서 계산 (h_2)
      • 세번재 입력 : 이전의 입력상태(h_2)와 현재의 입력상태를 결합해서 계산(h_3)
      • ...
      • 마지막 입력(반복 작업이 완료되었을 때) : 마지막 상태 (h_t) 생성 -> 모든 과거의 정보를 결합해놓은 상태
    • parameter(매개변수)
      • input_size : 각 시점(레이어)에서 입력 feature의 수
      • hidden_size : 은닉층(출력)의 크기
      • num_layers
        • 기본값 : 1
        • RNN 은닉층의 개수 (층이 깊어질수록 복잡한 패턴을 발생)
        • 층의 개수가 늘어날수록 시간은 증가하고 과적합의 위험성이 존재
        • 1 ~3 정도 사용을 하고 1부터 개수를 1씩 증가시키면서 사용
      • nonlinearity
        • 기본값 : 'tanh'
        • 비선형 활성화 함수를 선택
      • batch_first
        • 기본값 : False
        • 입력 tensor에서 첫번째 차원이 배치인지 여부
      • bias
        • 기본값 : True
        • 각 가중치의 편향을 추가할지 여부
      • dropout
        • 기본값 : 0.0
        • 층 사이에 Dropout의 적용 비율 : 층이 2개 이상인 경우에만 사용
      • bidirectional
        • 기본값 : False
        • 양방향 RNN을 사용할지 여부 (순방향은 기본, 역방향을 사용할 것인가?)
    • parameter 설정 시 유의할 점
      • hidden_size
        • 크기가 너무 작은 경우라면 정보가 부족, 너무 큰 경우라면 과적합
        • 일반적으로 32, 64, 128
      • num_layers
        • 시간의 복잡도에 따라서 1 ~ 3 정도 이용
        • 1부터 테스트를 돌려서 교차 검증
      • nonlinearity
        • 일반적으로 'tanh'을 사용
        • relu를 사용하면 시간이 감소하지만 발산의 위험성이 증가
      • dropout
        • 층이 2개 이상인 경우에만 사용
        • 과적합 방지를 위해 사용
        • 0.2 ~ 0.5 사이의 값을 사용 (권장사항)
import math
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, Dataset
from sklearn.preprocessing import StandardScaler
class RNN_Model(nn.Module):
    def __init__(self):
        super(RNN_Model, self).__init__()
        self.rnn=nn.RNN(
            input_size=1,
            hidden_size=64,
            num_layers=1,
            batch_first=True,
            dropout=0.0,
            nonlinearity='tanh',
            bidirectional=False
        )
        self.linear=nn.Linear(64, 1)
    def forward(self,x):
        #RNN 모델에서 되돌려주는 데이터는 2개를 되돌려 줌
            #첫번쨰 데이터 : 모든 시점에서의 은닉층의 값 
            # 두번쩨 데이터 : 마지막 시점에서의 은닉층의 값 (층이 존재하는 경우 마지막 층의 값을 추출)
            out, h_n = self.rnn(x)
            result = self.linear(h_n[-1])
            return result

  • LSTM (장기 의존성 학습 모델)
    • RNN의 구조에서 발생하는 문제를 해결하기 위해 구조를 변경한 모델
    • 기존의 RNN은 학습회수가 증가하면 과거의 기억을 잊음
      • 반복 학습을 하면서 가중치의 변화량이 0에 가까워진다.
      •  손실함수 -> tanh -> 반복적으로 -1 ~ 1 사이의 가중치 변화량이 곱해지면서 0에 수렴 (기억 손실)
    • LSTM 모델은 반복학습을 하면서 과거의 기억 중 장기 기억으로 나눠주는 역할
      • 반복 학습을 하면서 tanh()를 중복적으로 실행하면서 0에 가까워짐
      • 장기기억 tanh() 함수를 실행하지 않으면 가중치의 변화를 유지
      • cell 공간에 장기기억으로 정보 전달'
      • 게이트로 정보를 선택적으로 보관, 삭제, 출력
import pandas as pd
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
class windowDS(Dataset):
    def __init__(self, _x, _y, _window):
        self.x=_x
        self.y=_y
        self.window=_window
        self.n=len(_x)-_window

    def __len__(self):
        return max(self.n, 1)
    
    def __getitem__(self,idx):
        x=self.x[idx:idx+self.window]
        y=self.y[idx+self.window]
        #깊은 복사로 tensor 생성
        #일반적으로 얕은 복사를 사용하는 경우가 많음 : 메모리의 사용량 줄이기
        x_tensor=torch.tensor(x, dtype=torch.float32)
        y_tensor=torch.tensor(y, dtype=torch.float32)
        return x_tensor, y_tensor
#LSTM 모델 정의
class LSTMModel(nn.Module):
    def __init__(self, 
                input_size, 
                hidden_size=64, 
                num_layers=1, 
                dropout=0.0, 
                bidirectional=False, 
                batch_first=True, 
                head_type='c'
        ):
        super(LSTMModel, self).__init__()

        #LSTM 기본 설정
        self.lstm=nn.LSTM(
            input_size=input_size,
            hidden_size=hidden_size,
            num_layers=num_layers,
            dropout=dropout,
            bidirectional=bidirectional,
            batch_first=batch_first
        )

        #bidirectional이 True인 out feature의 개수가 2배
        hidden_size=hidden_size * (2 if bidirectional else 1)

        #head type에 땨라서 출력의 feature 개수가 달라진다.
        if head_type in ['h','c']:
        # if (head_type == 'f') | (head_type =='c')
            pass
        elif head_type == 'h_c':
            hidden_size=hidden_size*2
        else:
            print("head_type의 인자의 값을 잘못 입력하였습니다. ('h', 'c', 'h_c')을 써주세요")

        #선형 모델 생성
        self.model=nn.Linear(hidden_size, 1)
        #객체 안의 독립적인 데이터를 저장
        self.head_type=head_type
    
    #순전파 함수 정의
    def forward(self, x):
        #순전파의 예측 값 (RNN 모델에서는 2개, LSTM 모델에서는 3개)
        out, (h_n, c_n) = self.lstm(x)
        #은닉층의 가장 마지막 값 저장
        h_last=h_n[-1]
        c_last=c_n[-1]

        if self.head_type == 'h':
            feat=h_last
        elif self.head_type == 'c':
            feat=c_last
        elif self.head_type == 'h_c':
            feat=torch.cat( [h_last, c_last], dim=-1 )
        
        return self.model(feat)

'python' 카테고리의 다른 글

LSA(Latent Semantic Analysis)  (0) 2026.06.04
TF-IDF(Term Frequency-Inverse Document Frequency)  (0) 2026.06.02
군집 분석  (0) 2026.05.19
차원 축소  (0) 2026.05.19
랜덤 포레스트(Random Forest)  (0) 2026.05.15