데이터 준비
- 리뷰 텍스트와 라벨(긍정=1, 부정=0)을 가져옴
- 텍스트 전처리(소문자화/정규식 처리 등)
토큰화 + 정수 인코딩
- 단어 사전(VOCAB) 만들고 각 리뷰를 단어 -> 정수 시퀀스로 바꿈
"i loved this movie" → [10, 532, 21, 88]
길이 맞추기
- 리뷰 길이가 제각각이라 모델 입력이 불편
- 최대길이(max_len)으로 자르거나 0으로 채움(padding)
최종 입력 shape : (batch, seq_len)
Embedding 레이어
- 정수(단어 ID)를 바로 쓰지 않고 각 단어를 연속 벡터로 바꿈
입력: (batch, seq_len) → 출력: (batch, seq_len, emb_dim)
GRU 통과
- 왼쪽 → 오른쪽으로 읽으면서 “현재까지의 요약(은닉상태 h)”을 계속 업데이트함
- LSTM처럼 Cell state(Ct)는 없고, 은닉상태(h) 하나로 기억/요약을 같이 처리
이때 게이트 2개가 핵심
-
Update gate: 이전 요약을 유지할지, 새 정보로 바꿀지 결정
- 유지 비중↑ → 과거 정보가 더 남음
- 갱신 비중↑ → 현재 입력(새 정보)이 더 반영됨
-
Reset gate: 새 요약을 만들 때 과거를 얼마나 참고할지 결정
- reset 약함 → 과거를 덜 참고(문맥 끊고 새로 해석)
- reset 강함 → 과거를 계속 참고(문맥 이어서 해석)
최종적으로 각 시점마다 은닉상태 ℎ𝑡가 나오고, 마지막 은닉상태 ℎ𝑇를 문장 대표로 쓰는 경우가 많음
분류기
- GRU의 출력(보통 마지막 hidden)을 Dense로 보내서 시그모이드로 긍정확률 0~1 출력
학습
-
손실함수(BCE)
-
옵티마이저로 가중치 업데이트
-
검증셋으로 과적합 체크
추론
- 새 리뷰 → (토큰화 → 패딩 → 임베딩 → GRU → 시그모이드)
- 확률 ≥ 0.5면 긍정, 아니면 부정(임계값 조정)
부록
-
왜 GRU가 LSTM보다 단순한가?
- LSTM: “Cell state(C)” + “Hidden state(h)” 두 개를 관리 + 게이트 3개
- GRU: “Hidden state(h)” 하나만 관리 + 게이트 2개(Update/Reset)
그래서 파라미터/연산량이 줄어들어 학습이 빠름
-
UPDATE/RESET 쉽게 생각하기
- Update gate: “이번 단어가 중요하면 요약(h)을 새로 갱신한다(유지 vs 갱신).”
not, never, terrible, amazing 같이 감정에 직접 영향 큰 단어 나올때
- Reset gate: “문맥이 바뀌면 과거를 덜 참고하고 새 요약을 만든다(과거 참고량 조절).”
but, however, although같이 문맥 전환/반전 신호 나올때