Python DeepLearning

RNN(Recurrent Neural Network) 개념 및 구현

PyExplorer 2025. 4. 19. 15:50
728x90

RNN(Recurrent Neural Network) 개념 및 구현

1. RNN이란?

순환 신경망(Recurrent Neural Network, RNN)은 시퀀스 데이터를 다룰 때 유용한 신경망 구조입니다. 기존의 인공신경망(ANN)이나 합성곱 신경망(CNN)은 독립적인 입력을 처리하지만, RNN은 이전 상태를 기억하고 이를 활용하여 현재 입력을 처리하는 특성을 가집니다. 이러한 특성 덕분에 자연어 처리(NLP), 시계열 분석, 음성 인식 등의 분야에서 활발히 사용됩니다.

1.1 RNN의 핵심 개념

RNN의 가장 큰 특징은 순환 구조입니다. 일반적인 신경망은 입력을 받아 출력을 내보내는 방식이지만, RNN은 이전 상태(hidden state)를 기억하여 다음 계산에 활용합니다. 이를 통해 시간에 따라 변화하는 데이터를 효과적으로 모델링할 수 있습니다.

1.2 RNN의 수식 표현

RNN의 기본적인 수식은 다음과 같습니다.

$$
h_t = \tanh(W_h h_{t-1} + W_x x_t + b)
$$
$$
y_t = W_y h_t + c
$$

여기서,

  • $ h_t $ : t 시점의 은닉 상태(hidden state)
  • $ x_t $ : t 시점의 입력
  • $ y_t $ : t 시점의 출력
  • $ W_h, W_x, W_y $ : 학습해야 할 가중치 행렬
  • $ b, c $ : 편향 값
  • $ \tanh $ : 활성화 함수 (하이퍼볼릭 탄젠트)

2. RNN의 문제점과 해결 방법

2.1 기울기 소실(Vanishing Gradient) 문제

RNN은 긴 시퀀스를 학습할 때 기울기 소실 문제가 발생할 수 있습니다. 이는 역전파 과정에서 기울기 값이 점점 작아져 가중치 업데이트가 효과적으로 이루어지지 않는 현상입니다.

해결 방법

  • LSTM(Long Short-Term Memory) : 장기 의존성을 학습할 수 있도록 설계된 구조
  • GRU(Gated Recurrent Unit) : LSTM보다 간결한 구조를 가지며 비슷한 성능을 보이는 방식
  • Residual Connection : 기울기 소실을 완화하는 방법
  • Batch Normalization : 내부 공변량 변화(Internal Covariate Shift)를 줄이기 위한 방법

3. RNN 구현하기 (PyTorch 기반)

RNN을 직접 구현하여 간단한 시계열 예측을 수행하는 예제를 소개합니다. 여기서는 PyTorch를 사용하여 기본적인 RNN 모델을 구축합니다.

3.1 라이브러리 불러오기

import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
from sklearn.preprocessing import MinMaxScaler
import matplotlib.pyplot as plt

3.2 데이터 준비

간단한 사인(sine) 함수를 기반으로 시계열 데이터를 생성합니다.

# 데이터 생성
np.random.seed(42)
t = np.linspace(0, 50, 500)
data = np.sin(t) + np.random.normal(0, 0.1, 500)

# 데이터 정규화
scaler = MinMaxScaler()
data = scaler.fit_transform(data.reshape(-1, 1))

def create_sequence(data, seq_length):
    sequences, targets = [], []
    for i in range(len(data) - seq_length):
        sequences.append(data[i:i+seq_length])
        targets.append(data[i+seq_length])
    return np.array(sequences), np.array(targets)

seq_length = 20
X, y = create_sequence(data, seq_length)

3.3 RNN 모델 정의

class RNNModel(nn.Module):
    def __init__(self, input_size, hidden_size, output_size, num_layers=1):
        super(RNNModel, self).__init__()
        self.hidden_size = hidden_size
        self.num_layers = num_layers
        self.rnn = nn.RNN(input_size, hidden_size, num_layers, batch_first=True)
        self.fc = nn.Linear(hidden_size, output_size)

    def forward(self, x):
        h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size)
        out, _ = self.rnn(x, h0)
        out = self.fc(out[:, -1, :])
        return out

3.4 모델 학습

# 데이터 변환
X_train = torch.tensor(X, dtype=torch.float32)
y_train = torch.tensor(y, dtype=torch.float32)

# 모델 초기화
model = RNNModel(input_size=1, hidden_size=16, output_size=1, num_layers=1)
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)

# 학습 과정
epochs = 100
for epoch in range(epochs):
    optimizer.zero_grad()
    outputs = model(X_train.unsqueeze(-1))
    loss = criterion(outputs, y_train)
    loss.backward()
    optimizer.step()
    if (epoch+1) % 10 == 0:
        print(f'Epoch [{epoch+1}/{epochs}], Loss: {loss.item():.4f}')

3.5 예측 및 시각화

# 예측 수행
with torch.no_grad():
    predictions = model(X_train.unsqueeze(-1)).numpy()

# 결과 시각화
plt.figure(figsize=(10, 4))
plt.plot(data, label='True Data')
plt.plot(range(seq_length, len(predictions) + seq_length), predictions, label='Predicted', linestyle='dashed')
plt.legend()
plt.show()

4. 결론

이번 포스팅에서는 RNN의 개념과 작동 원리를 살펴보고, PyTorch를 이용하여 간단한 RNN 모델을 구현하는 과정을 다루었습니다. RNN은 시퀀스 데이터를 다룰 때 유용하지만, 기울기 소실 문제를 해결하기 위해 LSTM과 GRU 같은 개선된 모델이 자주 사용됩니다.

728x90