Step 11 RNN: Word2Vec으로 순서 처리

사전학습 임베딩 (freeze) - 시퀀스 데이터의 시작

1. 이전 Step의 한계

TF-IDF + CNN은 단어 중요도를 반영했지만, 여전히 단어의 의미는 표현하지 못했습니다. "cat"과 "dog"이 둘 다 동물이라는 걸 모르죠. 그리고 단어 순서도 제대로 활용하지 못했어요.

❌ 이전 방식의 문제

단어 순서의 중요성 "The movie is not bad" → 긍정 "The movie is bad not" → ??? BoW/TF-IDF: 둘 다 같은 단어 → 같은 벡터! 하지만 의미는 완전히 다르죠 😢

필요한 것:
1. 단어의 의미를 표현하는 밀집 벡터
2. 단어 순서를 고려하는 모델

2. Word2Vec: 단어의 의미를 벡터로

Word2Vec은 단어를 밀집 벡터(Dense Vector)로 변환합니다. 비슷한 의미의 단어는 비슷한 벡터로 표현되죠!

🧠 Word2Vec의 핵심 아이디어

"비슷한 문맥에 나타나는 단어는 비슷한 의미를 가진다"
- John Rupert Firth

예시:
• "The cat is sleeping on the sofa"
• "The dog is sleeping on the sofa"
• "The hamster is sleeping on the sofa"

→ cat, dog, hamster는 비슷한 위치에 나타남
→ Word2Vec은 이들을 비슷한 벡터로 표현!

원핫 인코딩 vs Word2Vec 원핫 인코딩 cat: [1, 0, 0, ..., 0] dog: [0, 1, 0, ..., 0] 길이: 20,000 ❌ 희소, 의미 X Word2Vec cat: [0.2, -0.5, 0.8, ...] dog: [0.3, -0.4, 0.7, ...] 길이: 100~300 ✅ 밀집, 의미 O 벡터 공간에서 의미 표현 cat dog hamster car bus 동물 클러스터 탈것 클러스터

📦 사전학습된 Word2Vec 사용하기

Word2Vec을 직접 학습하려면 엄청난 데이터가 필요합니다. 대신 Google이 학습한 모델을 가져와서 쓸 수 있어요!

# Gensim으로 Word2Vec 불러오기
from gensim.models import KeyedVectors

# Google News 사전학습 모델 (300차원)
# 다운로드: https://code.google.com/archive/p/word2vec/
wv = KeyedVectors.load_word2vec_format(
    'GoogleNews-vectors-negative300.bin', 
    binary=True
)

# 단어 벡터 확인
print(wv['cat'].shape)  # (300,)

# 유사 단어 찾기
print(wv.most_similar('cat', topk=5))
# [('cats', 0.76), ('dog', 0.76), ('kitten', 0.71), ...]

# 단어 연산!
print(wv.most_similar(positive=['king', 'woman'], negative=['man']))
# [('queen', 0.71), ...]
# king - man + woman = queen!

3. RNN: 순서를 기억하는 신경망

이제 단어의 의미를 표현할 수 있게 됐습니다! 다음은 순서를 처리할 차례예요. RNN (Recurrent Neural Network)이 바로 그 주인공입니다.

🔄 RNN의 핵심 아이디어

RNN의 동작 원리 "The cat sat" RNN t=0 The h₀ hidden RNN t=1 cat h₁ hidden RNN t=2 sat h₂ Hidden State (은닉 상태) 이전 단어들의 정보를 기억! h₂는 "The", "cat", "sat" 모두의 정보를 담고 있음

RNN의 수식:

$$ h_t = \tanh(W_{hh} h_{t-1} + W_{xh} x_t + b_h) $$
$$ y_t = W_{hy} h_t + b_y $$

• $h_t$: 현재 시점의 hidden state
• $x_t$: 현재 시점의 입력 (단어 임베딩)
• $h_{t-1}$: 이전 시점의 hidden state (이전 단어들의 정보!)

4. RNN + Word2Vec 모델

이제 Word2Vec 임베딩과 RNN을 결합해봅시다!

🏗️ 모델 아키텍처

RNN Text Classifier Input 토큰 인덱스 [42, 108, ...] Word2Vec 300차원 사전학습 🔒 Frozen RNN 128 units 순서 처리 hidden state FC 4 classes Softmax Word2Vec (freeze) → RNN → 분류 예상 성능: 약 90-92% (CNN 대비 +1-2%p)
import torch
import torch.nn as nn

class RNNClassifier(nn.Module):
    def __init__(self, vocab_size, embedding_dim, hidden_dim, num_classes, pretrained_embeddings=None):
        super().__init__()
        
        # Word2Vec 임베딩 (freeze)
        self.embedding = nn.Embedding(vocab_size, embedding_dim)
        
        if pretrained_embeddings is not None:
            self.embedding.weight.data.copy_(pretrained_embeddings)
            self.embedding.weight.requires_grad = False  # 🔒 Freeze!
        
        # RNN
        self.rnn = nn.RNN(
            input_size=embedding_dim,
            hidden_size=hidden_dim,
            batch_first=True  # [batch, seq, feature]
        )
        
        # 분류기
        self.fc = nn.Linear(hidden_dim, num_classes)
    
    def forward(self, x):
        # x: [batch, seq_len]
        embedded = self.embedding(x)  # [batch, seq_len, embedding_dim]
        
        # RNN
        output, hidden = self.rnn(embedded)  
        # output: [batch, seq_len, hidden_dim]
        # hidden: [1, batch, hidden_dim]
        
        # 마지막 hidden state 사용
        final_hidden = hidden.squeeze(0)  # [batch, hidden_dim]
        
        return self.fc(final_hidden)

# 모델 생성
model = RNNClassifier(
    vocab_size=20000,
    embedding_dim=300,  # Word2Vec 차원
    hidden_dim=128,
    num_classes=4,
    pretrained_embeddings=word2vec_weights  # Word2Vec 가중치
)

✅ RNN + Word2Vec의 장점

⚠️ RNN의 한계

RNN은 순서를 처리하지만, 장기 의존성(Long-term Dependency) 문제가 있습니다:

문제:
"The cat, which was sitting on the mat, was cute"
→ "cat"과 "was"가 멀리 떨어져 있으면 관계를 잊어버림 😢

다음 Step 12에서 LSTM + GloVe로 장기기억을 추가해봅시다! 🚀