Step 9 MLP: 원핫 인코딩으로 시작

기초 베이스라인 - 단어를 숫자로 변환하는 첫걸음

1. 텍스트 분류란?

뉴스 기사를 읽고 "이건 스포츠 뉴스야" 또는 "이건 정치 뉴스야"라고 판단하는 작업입니다. 이미지 분류(MNIST)와 똑같은 원리인데, 입력이 이미지가 아니라 텍스트라는 것만 다르죠!

📰 AG News 데이터셋

우리가 사용할 데이터셋은 AG News입니다. 뉴스 기사를 4개 카테고리로 분류하는 문제예요.

예시:

제목: "Wall St. Bears Claw Back Into the Black"
본문: "Reuters - Short-sellers, Wall Street's dwindling band of ultra-cynics..."
레이블: Business (2번)

2. 원핫 인코딩 (One-Hot Encoding)

컴퓨터가 단어를 이해하려면 숫자로 바꿔야 합니다. 가장 간단한 방법이 바로 원핫 인코딩이에요!

🔢 원핫 인코딩 원리

원핫 인코딩 과정 1. 어휘 사전 0: cat 1: dog 2: bird 3: fish 4: hamster 총 5개 단어 2. 원핫 벡터 cat → 1 0 0 0 0 dog → 0 1 0 0 0 bird → 0 0 1 0 0 idx 0 idx 1 idx 2 idx 3 idx 4 각 단어는 길이 5인 벡터 자기 위치만 1, 나머지는 0
import numpy as np

# 어휘 사전
vocab = {'cat': 0, 'dog': 1, 'bird': 2, 'fish': 3, 'hamster': 4}
vocab_size = len(vocab)

def one_hot_encode(word):
    vec = np.zeros(vocab_size)
    vec[vocab[word]] = 1
    return vec

print(one_hot_encode('cat'))   # [1, 0, 0, 0, 0]
print(one_hot_encode('dog'))   # [0, 1, 0, 0, 0]
print(one_hot_encode('bird'))  # [0, 0, 1, 0, 0]

❌ 원핫 인코딩의 한계

💡 그래서 이후 Step에서는?
Word2Vec, GloVe 같은 밀집(Dense) 임베딩을 배워요.
벡터 길이 100~300 정도로 줄이면서, 단어 의미도 표현!

3. 문장을 벡터로 변환하기

한 단어가 아니라 문장 전체를 벡터로 만들려면 어떻게 할까요?

📦 Bag of Words (BoW)

문장에 각 단어가 몇 번 등장했는지만 세는 방법입니다. 순서는 무시해요!

Bag of Words 예시 "The cat sat on the mat" ↓ 토큰화 & 카운팅 어휘 사전 0: the 1: cat 2: sat 3: on 4: mat BoW 벡터 2 1 1 1 1 the cat sat on mat "the"가 2번 나왔으니 2
from collections import Counter
import numpy as np

# 어휘 사전
vocab = {'the': 0, 'cat': 1, 'sat': 2, 'on': 3, 'mat': 4}

def bag_of_words(sentence, vocab):
    words = sentence.lower().split()
    vec = np.zeros(len(vocab))
    
    for word in words:
        if word in vocab:
            vec[vocab[word]] += 1
    
    return vec

sentence = "The cat sat on the mat"
bow = bag_of_words(sentence, vocab)
print(bow)  # [2. 1. 1. 1. 1.]

4. MLP로 뉴스 분류하기

이제 Bag of Words 벡터를 입력으로 받아서 뉴스 카테고리를 예측하는 MLP를 만들어봅시다!

🏗️ 모델 아키텍처

MLP 텍스트 분류기 Input BoW 벡터 20,000 차원 Hidden 1 512 units ReLU Dropout Hidden 2 256 units ReLU Dropout Output 4 classes Softmax World / Sports / Business / Sci-Tech 입력: 희소 벡터 (대부분 0) → 출력: 4개 확률
import torch
import torch.nn as nn

class MLPTextClassifier(nn.Module):
    def __init__(self, vocab_size, num_classes=4):
        super().__init__()
        
        self.fc1 = nn.Linear(vocab_size, 512)
        self.fc2 = nn.Linear(512, 256)
        self.fc3 = nn.Linear(256, num_classes)
        
        self.dropout = nn.Dropout(0.5)
        self.relu = nn.ReLU()
    
    def forward(self, x):
        # x: [batch_size, vocab_size] - BoW 벡터
        x = self.relu(self.fc1(x))
        x = self.dropout(x)
        
        x = self.relu(self.fc2(x))
        x = self.dropout(x)
        
        x = self.fc3(x)  # Softmax는 CrossEntropyLoss가 알아서 처리
        return x

# 모델 생성
model = MLPTextClassifier(vocab_size=20000, num_classes=4)
print(f"파라미터 수: {sum(p.numel() for p in model.parameters()):,}")

⚠️ 예상 성능

MLP + 원핫 인코딩은 가장 간단한 베이스라인입니다.

예상 정확도: 약 85-88%

이유:
• Bag of Words는 단어 순서를 무시함 ("dog bites man" = "man bites dog")
• 원핫 인코딩은 단어 의미를 표현 못 함
• 희소 벡터라 학습이 비효율적

하지만 놀랍게도 88%는 나쁘지 않은 시작입니다!
다음 Step들에서 점점 개선해나갈게요 🚀

🎯 다음 단계는?

MLP로 베이스라인을 만들었습니다! 하지만 개선할 점이 많죠.

문제점:
• 단어 순서 무시 → 문맥 이해 불가
• 희소 벡터 → 메모리 낭비
• 모든 단어가 동등 → 중요한 단어 강조 못 함

다음 Step 10에서 TF-IDF + CNN으로 단어 중요도를 반영해봅시다! 🚀