본문 바로가기
의학 연구

[비전공자의 머신러닝 의학연구 #9] RNN과 LSTM — 시간 순서를 학습하는 신경망

by Dr CK 2026. 7. 3.

MLP는 딥러닝의 가장 기본적인 구조로 딥러닝에는 이 뿐만 아니라 CNN, RNN 등 다른 모형들이 존재한다. MLP는 각 변수가 독립적 인 표 형식 데이터. 환자의 나이·병기·종양크기 등 — 변수 간 공간적·시간적 관계가 없는 데이터에 적합하며, 이를 생존분석에 확장한것이 DeepSurv 였다. 이 같은 모형은 각 환자에게 한 번만 측정되는 변수 (시간-고정 변수) 를 다뤘다. 하지만 의학연구에는 시간에 따라 변하는 변수도 흔하다. 이런 시간 순서가 있는 데이터를 다루는 딥러닝이 Recurrent Neural Network, RNN이고, 그 개선버전이 Long-Short term memory, LSTM이다.

 

1. 왜 RNN이 필요한가?

의학연구에서 시간 순서가 있는 데이터는 흔하다. 이런 데이터는 각 시점의 값도 중요하지만 그 순서와 변화 패턴도 중요하다.

MLP는 입력을 모두 한꺼번에 받는 구조였다. 시간 순서가 있는 데이터를 MLP에 넣으면 순서 정보가 사라진다.

환자 A: 혈압 측정 12회 (12개월간 매월)
       → MLP에 12개를 한꺼번에 입력 → 순서 무관하게 학습

 

이게 적절하지 않다. 환자가 점점 좋아지고 있는지, 점점 나빠지고 있는지 의 정보가 사라진다.

→ 시간 순서를 학습하는 별도의 구조, 그게 RNN 이다.

2. RNN의 기본 구조

RNN = Recurrent Neural Network = 순환 신경망

이름의 Recurrent (순환) 가 핵심이다. 같은 신경망을 시점마다 반복 적용 하면서, 이전 시점의 정보를 다음으로 전달 한다.

RNN의 핵심은 hidden state (h) 이다.

각 시점 t에서:
  h_t = f(x_t, h_{t-1})

  → 새 hidden state = 함수(현재 입력, 이전 hidden state)

 

RNN의 가장 큰 특징은 시간(t)에 따라 같은 연산을 반복한다는 점이다. 이를 이해하기 가장 좋은 방법은 동그란 루프 형태의 RNN을 시간 순서대로 길게 펼쳐보는(Unrolling) 것입니다.

  • 입력(x_t): 현재 시점의 데이터 (예: 문장의 각 단어)
  • 은닉 상태(h_t): '기억' 혹은 '상태'. 과거의 정보가 압축되어 담겨 있으며, 다음 시점으로 전단됨.
  • 출력(y_t): 현재 시점의 예측값.

 

RNN은 데이터를 읽는 '순전파'와 실수로부터 배우는 '역전파' 과정을 거친다.

  • 1단계: 순전파 (Forward Pass) - "예측하기"
    데이터가 시점 t=1부터 순차적으로 흐르며 각 단계의 은닉 상태를 갱신하고 최종 예측을 내놓는다.
    * 예: "I Love Deep" -> "Learning" 예측
  • 2단계: 손실 계산 (Loss Calculation)
    모델이 내놓은 예측값과 실제 정답 사이의 오차를 계산한다.
  • 3단계: BPTT (Backpropagation Through Time) - "시간을 거슬러 배우기"
    오차가 시간을 역행하며 전달되는 RNN만의 역전파 방식.
    1.  마지막 시점의 오차를 줄이기 위해 가중치를 수정한다.
    2.  이 영향력은 체인 룰(Chain Rule)을 통해 이전 시점으로 계속 전달된다.
    3.  모든 시점의 데이터를 바탕으로 가중치(W)를 조금씩 조정한다.

마지막 출력으로 예측

보통 마지막 시점의 hidden state h_T 가 전체 시퀀스의 요약 으로 쓰인다. 이걸 출력층에 넣어 최종 예측을 만든다.

환자의 12개월 혈압 → RNN → h_T → 예측 (재발 위험 등)

 

예시 — 위암 환자 CEA 추적

이해를 돕기 위해 의학연구 예시로 살펴보자. 위암 수술 후 환자가 6개월간 매월 종양 마커 (CEA) 를 측정했다.


매 시점마다 RNN은 현재 CEA 값 + 이전까지 누적된 기억(h) 을 합쳐 새 기억 을 만든다. 6개월 후의 h_6 는 전체 6개월간의 상승 패턴을 압축한 결과이고, 이를 출력층에 넣어 재발 위험 예측 을 만든다.

3. RNN의 한계 — 장기 의존성 문제

RNN의 치명적 한계 가 있다 — 시퀀스가 길어지면 초기 정보가 흐려진다.

BPTT 과정에서 오차 신호가 과거로 전달될 때, 동일한 가중치가 반복적으로 곱해집니다. 초기 시점의 중요한 정보 (x₁) 가 — 시점이 진행될수록 hidden state에서 점점 희미해지며, 결국 후반부로 가면 거의 사라진다. 이를 장기 의존성 (Long-Term Dependency) 문제 라고 한다. 수학적으로는 기울기 소실 (vanishing gradient) 문제와 연결된다.

의학연구에서의 예

  • 진단 시점의 병기 정보 가 1년 후 위험 예측에 결정적인데 — 중간의 여러 측정에 묻혀 약해짐
  • 수술 직후의 합병증 발생 여부 가 5년 후에도 영향을 주는데 — 긴 추적 기간 동안 흐려짐

→ 오래된 정보를 잃지 않고 보존하는 구조 가 필요 — 그게 LSTM 이다.

4. LSTM — 게이트로 기억을 관리

LSTM = Long Short-Term Memory (Hochreiter & Schmidhuber, 1997)

LSTM은 RNN의 장기 의존성 문제를 해결하기 위해 — 3개의 게이트(gate) 를 추가한 셀 구조이다.

4-1. Cell State — 장기 기억의 고속도로

LSTM의 가장 중요한 새 요소는 Cell State (C) 이다.

기존 RNN의 hidden state(h)는 매 시점마다 완전히 새로 계산 되었다. 그래서 정보가 쉽게 사라졌다.

Cell State는 시점마다 큰 변화 없이 흘러가는 별도의 통로 이다 — 장기 기억 고속도로 같은 역할. 정보가 손상 없이 멀리까지 전달 될 수 있다.

4-2. 3개의 게이트

Cell State를 어떻게 관리할지 결정하는 3개의 게이트가 있다.

게이트 역할
Forget Gate 이전 기억 중 무엇을 잊을지 결정
Input Gate 새 입력에서 무엇을 추가할지 결정
Output Gate 현재 기억 중 무엇을 출력할지 결정

각 게이트는 Sigmoid 활성화 함수 로 0~1 사이 값을 출력한다 :

  • 0에 가까우면 완전히 막음 (잊음 / 추가 안함 / 출력 안함)
  • 1에 가까우면 완전히 통과 (모두 기억 / 모두 추가 / 모두 출력)

이 게이트들의 값 자체가 학습되는 가중치 이다 — 언제 무엇을 잊고 기억할지 를 데이터에서 자동 학습한다.

이 선택적 관리 덕분에 — 중요한 정보는 길게 보존 하고 불필요한 정보는 빠르게 잊는다. 그래서 장기 의존성 문제 해결.

5. 입력 데이터 형태

PyTorch Tensor 형태의 연장선상으로, RNN/LSTM은 3차원 Tensor 를 받는다.

shape: (batch_size, seq_length, feature_dim)
       (배치 크기,   시간 시점 수,  변수 개수)

의학연구 예 :

# 환자 100명, 시간 12시점 (12개월), 변수 5개 (혈압·혈당·...)
X.shape   # (100, 12, 5)

각 환자마다 12개월 × 5변수의 시계열 이 입력이고, 출력은 예측값 1개 (재발 여부, 사망 위험 등).

6. 파이썬 코드 — PyTorch

6-1. 모델 정의

import torch
import torch.nn as nn

class SimpleLSTM(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim, num_layers=1):
        super().__init__()
        self.lstm = nn.LSTM(
            input_size=input_dim,       # 변수 개수
            hidden_size=hidden_dim,     # hidden state 차원
            num_layers=num_layers,      # LSTM 층 수
            batch_first=True,           # (batch, seq, feature) 순서
            dropout=0.3
        )
        self.fc = nn.Linear(hidden_dim, output_dim)

    def forward(self, x):
        # x.shape: (batch, seq_length, input_dim)
        out, (h_n, c_n) = self.lstm(x)
        # out: 모든 시점의 출력, h_n: 마지막 hidden state, c_n: 마지막 cell state

        # 마지막 시점의 출력만 사용 (시퀀스 요약)
        out = out[:, -1, :]              # shape: (batch, hidden_dim)
        out = self.fc(out)
        return out

model = SimpleLSTM(input_dim=5, hidden_dim=64, output_dim=2)
  • nn.LSTM(...) — PyTorch의 표준 LSTM 모듈. 이거 한 줄에 3개 게이트가 모두 포함 되어 있음
  • batch_first=True — 입력 shape를 (batch, seq, feature) 순서로 받음 (자연스러운 순서)
  • out, (h_n, c_n) = self.lstm(x) — 출력 3개 :
    • out : 모든 시점의 출력 (batch, seq, hidden_dim)
    • h_n : 마지막 hidden state
    • c_n : 마지막 cell state
  • out[:, -1, :] — 마지막 시점만 추출 — 보통 전체 시퀀스의 요약 으로 사용
  • self.fc(out) — 마지막 분류층 (이전 MLP와 같은 패턴)

6-2. 학습

학습 루프는 MLP와 거의 동일 하다. 입력 shape만 3차원이라는 점만 다름.

import torch.optim as optim

criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

for epoch in range(100):
    optimizer.zero_grad()
    output = model(X_train)              # X_train.shape = (N, T, F)
    loss = criterion(output, y_train)
    loss.backward()
    optimizer.step()

7. RNN/LSTM의 장단점

장점

  • 시간 순서를 학습 — 변화 패턴 자동 인식
  • 임의 길이의 시퀀스 — 짧든 길든 같은 모델로
  • 다양한 응용 — 시계열 예측, 텍스트, 음성, 비디오
  • 생존분석 확장 — LSTM-Cox, Dynamic-DeepHit 등

한계

  • 순차 학습 — 병렬 처리 어려움 → 학습 느림
  • 매우 긴 시퀀스에서는 LSTM도 한계 — 1000+ 시점이면 Transformer 가 우위
  • 해석성 — hidden state 내부 의미 파악 어려움
  • 데이터 요구량 — 시퀀스 학습엔 더 많은 데이터 필요

 

반응형