AI 개발 공부 공간

AI, 머신러닝, 딥러닝, Python & PyTorch, 실전 프로젝트

딥러닝/딥러닝: 자연어 처리

자연어 처리 모델

qordnswnd123 2025. 2. 26. 16:52

1. 데이터셋 불러오기

※ 데이터셋 설명
데이터 출처: Internet Movie Database (IMDB)
데이터 구성
text: 리뷰 텍스트. 영화에 대한 텍스트 리뷰
target: 리뷰가 긍정적인지 (1) 부정적인지(0)를 나타내는 이진 레이블

 

'target'피처의 데이터는 'positive'와 'negative'로 구성되어 있습니다.
positive는 1, negative는 0으로 변경합니다.

import numpy as np
import pandas as pd
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
from sklearn.model_selection import train_test_split
import gensim.downloader as api

# 데이터 불러오기
df = pd.read_csv('train.csv')

# 타겟값 0, 1로 변경
df['target'] = df['target'].apply(lambda x: 1 if x =='positive' else 0)

# 데이터셋을 훈련 데이터와 테스트 데이터로 분리
train_df, test_df = train_test_split(df, test_size=0.2, random_state=42)

train_df.head()

 

2. 데이터 전처리

2.1 토크나이저

# 간단한 토크나이저 정의 (공백 기준으로 단어 분리, 소문자로 변환)
def simple_tokenizer(text):
    return text.lower().split()

 

2.2 텍스트를 인덱스로 변환

# 텍스트를 인덱스로 변환
def encode_text(text, vocab, max_len):
    tokens = simple_tokenizer(text)
    token_ids = [vocab.get(token, 0) for token in tokens]
    token_ids = token_ids[:max_len]
    padding = [0] * (max_len - len(token_ids))
    return token_ids + padding

 

2.3 커스텀 데이터셋

class CustomDataset(Dataset):
    def __init__(self, dataframe, vocab, max_len):
        self.data = dataframe
        self.text = dataframe.text
        self.targets = dataframe.target
        self.vocab = vocab
        self.max_len = max_len

    def __len__(self):
        return len(self.data)

    def __getitem__(self, index):
        text = self.text.iloc[index]
        target = self.targets.iloc[index]
        input_ids = encode_text(text, self.vocab, self.max_len)

        return {
            'text': text,
            'input_ids': torch.tensor(input_ids, dtype=torch.long),
            'targets': torch.tensor(target, dtype=torch.long)
        }

print(CustomDataset)

 

3. 모델 정의

class TextClassifier(nn.Module):
    def __init__(self, embedding_matrix, num_classes, hidden_dim, max_len):
        super(TextClassifier, self).__init__()
        self.embedding = nn.Embedding.from_pretrained(embedding_matrix, freeze=False)
        self.lstm = nn.LSTM(embedding_matrix.size(1), hidden_dim, batch_first=True)
        self.fc = nn.Linear(hidden_dim, num_classes)

    def forward(self, x):
        x = self.embedding(x)
        x, (hn, cn) = self.lstm(x)
        out = self.fc(hn[-1])
        return out
    
print(TextClassifier)
# 모델 학습 함수 정의
def train_model(model, train_loader, criterion, optimizer, num_epochs):
    model.train()
    for epoch in range(num_epochs):
        total_loss = 0
        for batch in train_loader:
            input_ids = batch['input_ids']
            targets = batch['targets']

            optimizer.zero_grad()
            outputs = model(input_ids)
            loss = criterion(outputs, targets)
            loss.backward()
            optimizer.step()

            total_loss += loss.item()
        print(f"Epoch {epoch+1}/{num_epochs}, Loss: {total_loss/len(train_loader)}")

# 모델 평가 함수 정의
def evaluate_model(model, test_loader):
    model.eval()
    correct_predictions = 0
    total_predictions = 0

    with torch.no_grad():
        for batch in test_loader:
            input_ids = batch['input_ids']
            targets = batch['targets']
            
            outputs = model(input_ids)
            _, predicted = torch.max(outputs, 1)
            correct_predictions += (predicted == targets).sum().item()
            total_predictions += targets.size(0)

    accuracy = correct_predictions / total_predictions
    print(f"Test Accuracy: {accuracy * 100:.2f}%")
# 예측 메소드 정의
def predict(model, text, vocab, max_len):
    model.eval()
    input_ids = encode_text(text, vocab, max_len)
    input_tensor = torch.tensor(input_ids, dtype=torch.long).unsqueeze(0)  # 배치 차원 추가

    with torch.no_grad():
        outputs = model(input_tensor)
        _, predicted = torch.max(outputs, 1)
    
    return predicted.item()

 

4. 사전 학습된 임베딩 층

# GloVe 사전학습 모델을 가져옵니다.
glove_model = api.load('glove-wiki-gigaword-50')

# 어휘 사전 생성 및 임베딩 매트릭스 초기화
vocab = {word: idx + 1 for idx, word in enumerate(glove_model.index_to_key)}
vocab['<PAD>'] = 0

embedding_matrix = np.zeros((len(vocab) + 1, glove_model.vector_size)) # 0번째는 padding
embedding_matrix[1:len(glove_model.index_to_key) + 1] = glove_model.vectors # 1부터 채워넣기
embedding_matrix = torch.tensor(embedding_matrix, dtype=torch.float32)

 

5. 모델 학습과 실행

# 모델 하이퍼파라미터
num_classes = 2
hidden_dim = 128
max_len = 10

# 데이터셋 및 데이터로더 생성
train_dataset = CustomDataset(train_df, vocab, max_len)
test_dataset = CustomDataset(test_df, vocab, max_len)

train_loader = DataLoader(train_dataset, batch_size=2, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=2, shuffle=False)

# 모델 인스턴스 생성
model = TextClassifier(embedding_matrix, num_classes, hidden_dim, max_len)
print(model)

# 손실 함수 및 옵티마이저 생성
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
TextClassifier(
  (embedding): Embedding(400002, 50)
  (lstm): LSTM(50, 128, batch_first=True)
  (fc): Linear(in_features=128, out_features=2, bias=True)
)
num_epochs = 3

# 모델 학습
train_model(model, train_loader, criterion, optimizer, num_epochs)

# 모델 검증
evaluate_model(model, test_loader)
Epoch 1/3, Loss: 0.7068629860877991
Epoch 2/3, Loss: 0.665664978325367
Epoch 3/3, Loss: 0.6492479220032692
Test Accuracy: 40.00%

 

6. 학습한 모델 사용 예시

# 예측 예시 1
sample_text = "I'am very happy"
predicted_class = predict(model, sample_text, vocab, max_len)
print(f"Input text: '{sample_text}' is predicted to be in class {predicted_class}")
Input text: 'I'am very happy' is predicted to be in class 1
# 예측 예시 2
sample_text = "That's too bad. And I'am so sad. not good"
predicted_class = predict(model, sample_text, vocab, max_len)
print(f"Input text: '{sample_text}' is predicted to be in class {predicted_class}")
Input text: 'That's too bad. And I'am so sad. not good' is predicted to be in class 1

 

'딥러닝 > 딥러닝: 자연어 처리' 카테고리의 다른 글

Seq2Seq 실습1  (0) 2025.02.28
Seq2Seq 개념  (1) 2025.02.28
임베딩(Embedding)  (0) 2025.02.25
AlexNet (2012)  (0) 2025.02.25
LeNet-5 (1998)  (0) 2025.02.24