개발 창고/AI

순환 신경망(RNN, Recurrent Neural Network) 기초

Royzero 2025. 8. 20. 22:00
반응형

1) RNN이란 무엇인가?

기존의 **Feedforward Neural Network(순전파 신경망)**는 입력을 독립적으로 처리합니다. 하지만 언어, 시계열 데이터처럼 **순서(순차성)**가 중요한 데이터는 이런 구조로 충분히 학습할 수 없습니다.

RNN은 과거의 출력을 현재 입력과 함께 고려하여 **“기억”**을 반영할 수 있습니다.
즉, **이전 단계(hidden state)**를 다음 단계로 전달하는 구조로, 순차적인 맥락을 이해하는 데 강점을 가집니다.


2) RNN의 핵심 구조

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

  • Hidden state 갱신

    h_t = tanh(W_hh * h_(t-1) + W_xh * x_t + b_h)
  • 출력 계산

    y_t = W_hy * h_t + b_y

여기서

  • x_t: 시점 t의 입력
  • h_t: 시점 t의 hidden state
  • y_t: 시점 t의 출력

즉, RNN은 이전 시점의 상태 + 현재 입력을 합쳐 다음 출력을 생성합니다.


3) RNN의 직관적 이해

실생활 예시로 보면,

  • 누군가 “오늘 날씨는…”이라고 말할 때,
  • 뇌는 이미 앞 문장에서 오늘날씨라는 맥락을 기억합니다.
  • 따라서 뒤에 오는 단어 “맑다”를 이해할 때, 이전 단어들이 영향을 줍니다.

이처럼 문맥(Context)을 반영할 수 있는 것이 RNN의 강점입니다.


4) Python 실습: 간단한 RNN 구현

여기서는 PyTorch를 이용해 간단한 RNN 모델을 만들어봅니다.

import torch
import torch.nn as nn

# 샘플 입력 (batch=1, sequence=3, feature=5)
x = torch.randn(1, 3, 5)

# RNN 레이어 정의 (input_size=5, hidden_size=4, num_layers=1)
rnn = nn.RNN(input_size=5, hidden_size=4, num_layers=1, batch_first=True)

# 초기 hidden state (num_layers, batch, hidden_size)
h0 = torch.zeros(1, 1, 4)

# 순전파
output, hn = rnn(x, h0)

print("입력 크기:", x.shape)
print("출력 크기:", output.shape)
print("마지막 hidden state:", hn.shape)

예상 출력

입력 크기: torch.Size([1, 3, 5])
출력 크기: torch.Size([1, 3, 4])
마지막 hidden state: torch.Size([1, 1, 4])

여기서 볼 수 있듯이, RNN은 **시퀀스 길이(3)**만큼 순차적으로 처리하면서 hidden state를 전달합니다.


5) RNN의 한계

  • 장기 의존성(Long-Term Dependency) 문제
    → 문맥이 길어질수록 앞부분의 정보가 사라지는 현상
  • 기울기 소실/폭발(Gradient Vanishing/Exploding) 문제
    → 학습이 잘 되지 않음
  • 이를 보완하기 위해 LSTM(Long Short-Term Memory), GRU(Gated Recurrent Unit) 구조가 등장

6) 실습 아이디어

  • 문자 단위 언어 모델: "hello" 다음 글자를 예측하기
  • 시계열 데이터 예측: 주가나 기온의 다음 값 예측하기

예시 코드 (문자 인덱스 예측):

import torch
import torch.nn as nn

# 예제 단어
chars = "hello"
char_to_idx = {ch: i for i, ch in enumerate(set(chars))}
idx_to_char = {i: ch for ch, i in char_to_idx.items()}

# 입력 (h, e, l) -> 출력 (e, l, l)
x_data = [char_to_idx[ch] for ch in "hel"]
y_data = [char_to_idx[ch] for ch in "ell"]

x = torch.tensor([x_data], dtype=torch.long)
y = torch.tensor([y_data], dtype=torch.long)

# 임베딩 + RNN
embedding = nn.Embedding(len(char_to_idx), 10)
rnn = nn.RNN(10, 20, batch_first=True)
fc = nn.Linear(20, len(char_to_idx))

out, _ = rnn(embedding(x))
out = fc(out)

print(out.shape)  # [1, sequence_length, vocab_size]

7) 핵심 요약

  • RNN은 순차 데이터를 다루기 위한 기본 신경망 구조
  • 이전 시점의 상태(hidden state)를 다음 시점에 전달
  • 문맥을 이해할 수 있지만 장기 의존성 문제가 있음
  • 이를 개선한 구조가 LSTM, GRU

8) 다음 차시 예고

다음 12차시에서는 LSTM(Long Short-Term Memory) 구조를 학습합니다.
→ 장기 의존성 문제를 해결하는 핵심 기법입니다.


🔗 추천 학습 링크

반응형