카테고리 없음

스파르타 AI-8기 TIL(10/31) -> 도전 과제 전체 코드 학습

kimjunki-8 2024. 10. 31. 17:10

먼저 맨 위에 코드를 보겠습니다.

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import re
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, Dataset
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from torchtext.data.utils import get_tokenizer
from torchtext.vocab import build_vocab_from_iterator
from torch.nn.utils.rnn import pad_sequenc
pandas와 numpy:
pandas
는 주로 표 형식의 데이터 처리를 위한 라이브러리로, 데이터 프레임을 통해 데이터를 조작하고, 정리하고, 조작하는 기능을 제공합니다. 특히 데이터 분석과 전처리에 매우 유용하며, 엑셀이나 CSV와 같은 파일 형식으로 데이터를 로드하는 데 널리 사용됩니다.
numpy
는 수치 연산을 위한 라이브러리로, 다차원 배열을 생성하고 처리하는 기능을 제공합니다. 배열이나 행렬 연산을 수행하는 데 매우 효율적이며, 특히 신경망의 입력 데이터를 다루는 데 있어 필수적입니다. numpy는 대부분의 데이터 처리에서 pandas와 함께 사용되며, 텐서로 변환하기 전에 데이터 배열을 다루는 데 자주 쓰입니다.

seaborn과 matplotlib.pyplot:
seaborn은 matplotlib
를 기반으로 데이터 시각화에 특화된 라이브러리로, 데이터를 다양한 그래프로 표현하는 기능을 제공합니다. 주로 통계적 시각화에 강점이 있으며, 간단한 코드로 복잡한 데이터의 패턴을 시각화할 수 있습니다.
matplotlib.pyplot
은 파이썬의 기본적인 시각화 라이브러리로, 다양한 형태의 그래프와 차트를 생성할 수 있습니다. seaborn과 함께 사용하면 더욱 풍부한 시각화를 지원합니다.

re:
정규 표현식 모듈로, 텍스트 데이터에서 특정 패턴을 찾거나 대체하는 데 사용됩니다. 여기에서는 데이터 전처리 과정에서 불필요한 기호나 숫자를 제거하거나 필요한 단어만 남길 때 유용합니다. 정규 표현식은 특히 텍스트 전처리에서 필수적인 도구로, 데이터의 일관성을 확보하기 위해 문자열 조작 시 자주 사용됩니다.

torch, torch.nn, torch.optim, torch.utils.data:
torch: 
PyTorch 라이브러리의 메인 모듈로, 신경망 모델을 생성하고 학습하는 데 필요한 기본 기능을 제공합니다.
torch.nn: 
신경망을 구성하는 여러 가지 층(layer), 손실 함수(loss function), 그리고 다양한 유틸리티를 제공합니다. 여기서는 LSTM 모델을 구성하는 데 사용됩니다.
torch.optim: 
모델을 학습할 때 필요한 다양한 최적화 알고리즘(SGD, Adam 등)을 제공하는 모듈로, 손실을 최소화하기 위해 모델의 가중치를 업데이트하는 역할을 합니다.
torch.utils.data: 
데이터셋과 데이터로더(Dataset과 DataLoader 클래스)를 포함한 데이터 처리 관련 기능을 제공합니다. 이 모듈을 통해 데이터셋을 로드하고, 미니 배치 단위로 데이터를 모델에 전달합니다.

sklearn의 train_test_split과 LabelEncoder:
train_test_split: 데이터를 훈련 및 테스트 세트로 나누는 함수로, 모델 학습에 필요한 데이터와 성능 평가에 사용할 데이터를 분리하는 데 사용됩니다.
LabelEncoder: 문자열 형태의 레이블을 정수 인코딩으로 변환하여 모델이 처리하기 쉽게 합니다. 예를 들어, 레이블이 '긍정', '부정'으로 되어 있다면 각각을 숫자 0, 1로 변환하여 신경망이 처리할 수 있도록 합니다.

torchtext:
get_tokenizer: 문장을 단어로 분리하여 리스트로 변환하는 토큰화(tokenization)를 수행하는 함수입니다. 주로 텍스트 데이터를 모델에 전달하기 전, 텍스트에서 필요한 단어를 추출할 때 사용됩니다.
build_vocab_from_iterator: 텍스트 데이터를 단어 사전 형태의 인덱스 맵으로 변환하여 모델이 단어를 인식할 수 있게 합니다. 각 단어를 고유한 숫자로 인덱싱하여 텍스트 데이터를 수치 데이터로 변환합니다.
pad_sequence: 길이가 다른 텐서를 동일한 길이로 맞추는 데 사용되며, 신경망에 데이터를 일괄 처리할 때 필수적입니다. 이 함수는 미니 배치 형태의 데이터를 순차 모델에 맞게 조정해줍니다.

def preprocess_text(content):
    if isinstance(content, float):
        return ''
    content = content.lower()
    content = re.sub(r'[^/w/s]', '', content)
    content = re.sub(r'\d+', '', content)
    content = content.strip()
    return content or '<pad>'
1. if isinstance(content, float)::
이 조건문은 content가 float형으로 전달되었는지 확인하는 부분입니다. 일반적으로 리뷰 텍스트 데이터는 문자열이지만, 결측값이 있거나 숫자로 잘못 인식된 데이터가 있을 경우, float 형식으로 처리될 수 있습니다.
만약 float이라면 결측값으로 간주하여 빈 문자열 ''을 반환합니다. 이를 통해 데이터가 누락된 경우 빈 문자열을 처리할 수 있게 합니다.
2. content = content.lower():
모든 텍스트 데이터를 소문자로 변환하여 대소문자 구별을 제거합니다. 이를 통해 단어의 일관성을 유지하고 'The'와 'the'를 같은 단어로 인식할 수 있게 합니다.
3. content = re.sub(r'[^/w/s]', '', content):
정규 표현식을 사용하여 텍스트에서 숫자, 특수 문자, 그리고 공백을 제외한 모든 문자를 제거합니다.
r'[^/w/s]': 정규 표현식에서 /w는 문자, /s는 공백을 의미합니다. [^...]는 괄호 안의 문자들이 아닌 것만을 선택하라는 의미입니다.
4. content = re.sub(r'\d+', '', content):
숫자 제거. \d+는 연속된 숫자(1개 이상)를 의미합니다. 일반적으로 텍스트 데이터에서 숫자는 분석에 큰 의미가 없거나 불필요할 수 있어, 이를 제거함으로써 데이터의 순수한 텍스트 정보만 남깁니다.
5. content = content.strip():
텍스트 양 끝에 있는 불필요한 공백을 제거합니다. 텍스트 데이터는 데이터 입력 시의 공백 등으로 인해 불필요한 공백이 포함될 수 있는데, strip() 메서드를 통해 이러한 공백을 제거합니다.
6. return content or '<pad>':
만약 모든 처리가 끝난 content가 빈 문자열일 경우, <pad>라는 값을 반환하여 패딩 처리를 위한 기본 문자열로 설정합니다. 데이터가 공백으로만 이루어진 경우, 모델이 입력을 처리할 때 이를 인식할 수 있게 하는 기본 패딩 값으로 사용됩니다. '<pad>' 토큰은 모델이 학습하지 않으며, 배치의 모든 입력 데이터가 일정한 길이를 유지하도록 하는 역할을 합니다.

data[['userName', 'content']] = data[['userName', 'content']]
.apply(lambda col: col.apply(preprocess_text))
userName과 content 열에 대해 preprocess_text 함수를 적용합니다.
apply(lambda col: col.apply(preprocess_text)): 각 열의 값을 하나씩 preprocess_text 함수로 처리합니다.

여기서 각 함수가 어떻게 적용되는지 보면, (저기 저 col은 선언한 적이 없는데??!!)
1. apply(lambda col: col.apply(preprocess_text)): 각 열의 값을 하나씩 preprocess_text 함수로 처리합니다.
2. data[['userName', 'content']]는 userName과 content 두 개의 열로 이루어진 DataFrame의 일부입니다.
3. apply(lambda col: col.apply(preprocess_text))는 두 단계로 이루어져 있습니다.
4. 바깥쪽 apply는 각 열(userName, content)에 대해 lambda 함수를 호출합니다.
5. lambda 함수 안에서 col이라는 매개변수를 통해 전달된 각 열에 대해 다시apply(preprocess_text)를 호출합니다.
6. col.apply(preprocess_text)는 전달받은 열의 각 요소에 preprocess_text 함수를 적용하여 텍스트를 전처리합니다.
7. 따라서 col은 data[['userName', 'content']]의 각 열(Series 객체)이며, apply 함수가 lambda 함수 안으로 전달해 주기 때문에 별도로 선언하지 않아도 됩니다.

점수 전처리 함수
def preprocess_score():
    return int(score) -1
점수를 정수로 변환하고 -1을 빼서 0부터 시작하게 합니다. 예를 들어, 1부터 5점까지의 점수를 0부터 4로 변환하여 모델의 예측 범위를 맞춥니다. 머신러닝 모델의 레이블 인코딩에서는 일반적으로 0부터 시작하는 숫자를 사용하는 것이 편리하기 때문에 이러한 변환을 수행합니다.

예시: 원래 score가 3일 경우 int(score) - 1은 2가 되어, 0을 기준으로 맞춰집니다.

 


ReviewDataset 클래스 정의
class ReviewDataset(Dataset):
    def __init__(self, content, score, preprocess_text, preprocess_score):
        self.content = content.to_numpy()
        self.score = content.to_numpy()
        self.preprocess_text = preprocess_text
        self.preprocess_score = preprocess_score
이 클래스는 PyTorch의 Dataset 클래스를 상속하여 커스텀 데이터셋을 정의한 부분입니다. PyTorch에서 Dataset은 데이터와 레이블을 함께 관리하고 DataLoader를 통해 미니배치 형태로 데이터를 불러올 때 사용됩니다. ReviewDataset은 전처리된 리뷰 텍스트와 점수를 관리하여, 모델이 학습 및 평가에 사용할 수 있도록 데이터를 준비하는 데 중요한 역할을 합니다.

__init__ 메서드:

ReviewDataset 객체가 생성될 때 호출되는 메서드로, 객체의 초기화를 담당합니다.

self.content = content.to_numpy()
이 코드는 전달받은 content 열을 NumPy 배열로 변환하여 self.content에 저장합니다. to_numpy()는 Pandas의 Series 형식을 Numpy 배열로 바꾸는 메서드입니다. 데이터셋의 텍스트 내용을 NumPy 배열로 변환하면, Python 리스트보다 메모리 사용이 효율적이고 속도 면에서 빠르게 접근할 수 있습니다. 이를 통해 훈련 시 인덱싱이나 불러오는 속도가 개선됩니다.

self.score = score.to_numpy()
마찬가지로, score 열을 NumPy 배열로 변환하여 self.score에 저장합니다. 점수 데이터 또한 효율적으로 관리하기 위해 NumPy 배열로 변환합니다. 점수는 레이블로 사용되므로 이 과정을 통해 모델 학습 시 필요한 정수형 레이블이 준비됩니다.

self.preprocess_text와 self.preprocess_score
전달받은 전처리 함수들을 self.preprocess_text와 self.preprocess_score에 각각 저장합니다. 각 샘플을 호출할 때마다 이 함수들을 통해 텍스트와 점수 데이터를 사전 정의한 전처리 방식으로 처리할 수 있도록 합니다. 이렇게 함수 자체를 인스턴스 변수에 저장해두면 데이터셋을 호출할 때마다 전처리를 자동화할 수 있고, 코드의 재사용성과 가독성을 높입니다.
__len__ 메서드
def __len__(self):
    return len(self.content)
데이터셋의 크기를 반환하는 메서드로, Python의 len() 함수와 동일한 역할을 합니다. DataLoader가 배치(batch) 단위로 데이터를 로드할 때 이 메서드를 호출하여 데이터셋의 전체 길이를 알 수 있게 합니다. 이를 통해 DataLoader는 배치 개수를 결정할 수 있습니다.

여기서 반환하는 값은 self.content의 길이, 즉 리뷰 텍스트 데이터의 전체 개수입니다. 이는 데이터셋에 포함된 샘플 수와 동일하며, 모델이 학습할 때 반복하는 횟수(또는 에포크당 스텝 수)를 결정하는 데 중요한 요소입니다. 이 메서드는 모델이 데이터셋의 끝에 도달했는지를 판단하는 기준이 됩니다.
__getitem__ 메서드
def __getitem__(self, idx):
    content = self.preprocess_text(self.content[idx])
    score = self.preprocess_score(self.score[idx])

    indexed_content = torch.tensor([vocab[token] for token in content.split()])

    return indexed_content, torch.tensor(score)
데이터셋의 특정 인덱스 idx에 해당하는 데이터 샘플을 가져오는 메서드입니다. DataLoader에서 미니 배치로 데이터를 추출할 때 이 메서드를 사용하여 샘플들을 불러옵니다. 데이터의 전처리, 토큰화, 인덱싱 과정을 거쳐 신경망의 입력으로 사용할 준비를 마친 텐서를 반환합니다.

content = self.preprocess_text(self.content[idx])

self.content 배열에서 idx 위치에 있는 텍스트 데이터를 불러온 뒤, preprocess_text 함수로 전처리하여 content 변수에 저장합니다. 이는 전처리 함수가 텍스트 데이터를 정리하고 일관된 형식으로 변환하여, 이후 모델이 데이터를 쉽게 다룰 수 있도록 보장하는 과정입니다.

score = self.preprocess_score(self.score[idx])
self.score 배열에서 idx 위치에 있는 점수 데이터를 불러온 뒤, preprocess_score 함수를 통해 변환하여 score 변수에 저장합니다. 이를 통해 모델이 처리하기 쉬운 0 기반 정수로 인코딩된 레이블이 됩니다.

indexed_content = torch.tensor([vocab[token] for token in content.split()])
전처리된 content를 단어 단위로 나눈 후(content.split()), 각 단어를 vocab을 통해 인덱스로 변환합니다. 이 인덱스 리스트는 텍스트 데이터의 수치형 표현으로, 단어를 신경망이 이해할 수 있는 형태로 인코딩합니다. torch.tensor()를 통해 리스트를 텐서로 변환하여 신경망의 입력으로 바로 사용할 수 있게 준비합니다.

return indexed_content, torch.tensor(score)
최종적으로 인덱싱된 텍스트 텐서(indexed_content)와 정수형 레이블 텐서(torch.tensor(score))를 반환합니다. 이 값들은 DataLoader를 통해 배치 단위로 모델에 전달됩니다. indexed_content는 모델의 입력으로, score는 정답 레이블로 사용됩니다. 이 구조는 모델이 학습 시 단어 인덱스를 바탕으로 예측하고, 해당 예측이 실제 레이블과 비교되는 일관된 구조를 제공합니다.

 

train_content, test_content, train_score, test_score = 
    train_test_split(data['content'], data['score'], test_size = 0.2, random_state = 42)
데이터셋을 학습용과 테스트용으로 분할하여 모델 학습과 평가에 사용할 준비를 합니다. 이 코드는 train_test_split 함수에 의해 수행됩니다. 전체 데이터셋에서 80%는 학습 데이터로, 20%는 테스트 데이터로 나누어 모델의 성능을 일반화할 수 있게 합니다.


data['content'], data['score']
원본 데이터의 content 열(리뷰 텍스트)과 score 열(평가 점수)을 각각 추출하여 분할합니다. train_test_split 함수는 이 데이터를 학습과 테스트 셋으로 나눠주는데, 학습 셋은 모델 학습에 사용하고 테스트 셋은 모델의 성능을 평가하는 데 사용됩니다.

test_size=0.2
전체 데이터의 20%를 테스트 데이터로 사용하겠다는 설정입니다. 0.2는 테스트 셋의 비율을 의미하며, 나머지 80%는 학습 셋으로 사용됩니다. 이 비율은 모델의 일반화 성능을 평가하기에 충분한 데이터를 제공하며, 모델이 과적합하는지 여부를 확인하는 데 도움이 됩니다.

random_state=42
무작위 시드 값을 고정하는 설정으로, 같은 데이터를 매번 동일하게 나누어 재현 가능한 결과를 얻을 수 있게 합니다. random_state를 설정하지 않으면 데이터가 무작위로 나뉘어 코드 실행 시마다 다른 결과를 얻게 됩니다. 시드 값을 고정함으로써 실험의 일관성과 재현성을 확보할 수 있습니다.
batch_size = 64
DataLoader 생성
train_dataset = ReviewDataset(train_content, train_score, preprocess_text, preprocess_score)
train_dataload = DataLoader(train_dataset, batch_size = batch_size, shuffle = True)

test_dataset = ReviewDataset(test_content, test_score, preprocess_text, preprocess_score)
test_dataloader= DataLoader(test_dataset, batch_size = batch_size, shuffle = True)
이 부분은 PyTorch의 DataLoader를 통해 학습과 테스트에 사용할 데이터 로더를 설정하는 부분입니다. DataLoader는 주어진 Dataset을 기반으로 데이터를 배치 단위로 나누고, 모델 학습 시 매 배치마다 데이터를 불러오는 역할을 합니다.
batch_size = 64
한 번에 모델에 전달할 데이터 샘플의 수를 지정합니다. batch_size는 학습 성능과 메모리 사용량을 조정하는 중요한 하이퍼파라미터입니다.


train_dataset = ReviewDataset(train_content, train_score, preprocess_text, preprocess_score)
학습용 데이터셋 객체를 생성합니다. train_content와 train_score 데이터를 각각 리뷰와 레이블로 사용하며, 전처리 함수 preprocess_text와 preprocess_score를 함께 전달하여 데이터셋이 각 샘플을 불러올 때마다 전처리를 수행하도록 합니다.

ReviewDataset 클래스는 Dataset을 상속받아 PyTorch의 데이터 로딩 방식에 맞춰 구현되었으며, 이 데이터셋 객체를 통해 각 텍스트 데이터를 전처리하고 토큰화하여 신경망에 전달할 준비를 합니다.

train_dataload = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
DataLoader는 train_dataset을 미니 배치로 나누어 모델에 전달할 수 있도록 준비합니다.

batch_size=batch_size는 각 배치의 크기를 64로 설정하여, 학습 중에 매번 64개의 샘플을 한 번에 불러옵니다. 이를 통해 메모리 효율성을 확보하고, 매 배치마다 가중치를 업데이트할 수 있어 모델 학습 속도가 빨라집니다.
shuffle=True는 데이터셋을 랜덤하게 섞어 학습하는 옵션입니다. 데이터가 순차적으로 학습되지 않게 하여, 모델이 데이터의 특정 순서에 의존하거나 과적합하는 것을 방지하는 데 도움을 줍니다.

test_dataset = ReviewDataset(test_content, test_score, preprocess_text, preprocess_score)
테스트 데이터셋을 생성하며, 학습 데이터와 동일한 전처리 함수와 인코딩 방식을 사용하여 일관성을 유지합니다. test_content와 test_score는 각각 테스트 데이터셋의 텍스트와 레이블을 나타내며, 이는 모델 평가에 사용됩니다.


test_dataload = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)
테스트 데이터 로더를 생성하는 부분으로, 학습 데이터와 동일한 배치 크기 설정을 유지합니다.

shuffle=False는 테스트 데이터는 학습과 달리 순차적으로 불러와 평가하는 것을 의미합니다. 이는 성능 평가의 재현성과 일관성을 보장하기 위함입니다.

Vocabulary 생성
def content_text(content):
    for text in content:
        yield text.split()
vocab = build_vocab_from_iterator(content_text(data['content']), specials=['<unk>'])
vocab.set_default_index(vocab['<unk>'])
모델이 텍스트 데이터를 이해할 수 있도록 단어를 수치화하는 과정입니다. 텍스트를 각 단어별로 고유 인덱스로 변환하여 모델에 입력할 수 있는 형태로 바꾸는 중요한 작업입니다.
1. tokenizer = get_tokenizer("basic_english")

텍스트 데이터를 기본적인 영어 규칙에 따라 토큰화하는 tokenizer를 생성합니다. get_tokenizer("basic_english")은 공백이나 구두점을 기준으로 단어를 분리하며, 영어 텍스트에 맞춰 토큰화 규칙이 설정됩니다.
토큰화(tokenization)는 텍스트를 단어 단위로 분리하여 모델이 이해할 수 있도록 각 단어를 독립적인 요소로 다룰 수 있게 합니다. 이를 통해 자연어를 수치화하기 위한 기초 단계가 됩니다.

2. vocab = build_vocab_from_iterator(map(tokenizer, train_content), specials=["<unk>", "<pad>"])
어휘 사전을 생성하며, train_content의 각 텍스트 데이터를 tokenizer로 토큰화하고, 그 결과로 만들어진 토큰들을 기반으로 vocab을 구축합니다.
vocab은 단어와 인덱스를 매핑하여 각 단어를 고유한 숫자로 표현할 수 있게 하며, <unk>와 <pad>를 특수 토큰으로 지정합니다.
2.1 <unk>는 어휘 사전에 없는 단어를 나타내며, 모델이 훈련에서 본 적이 없는 단어가 주어졌을 때 대신 사용할 수 있는 토큰입니다.
2.2 <pad>는 데이터 길이를 맞출 때 사용하는 토큰으로, 가변 길이의 시퀀스를 동일한 길이로 맞추기 위해 사용됩니다.

3. vocab.set_default_index(vocab["<unk>"])
vocab 객체의 기본 인덱스를 <unk>의 인덱스로 설정합니다. 이를 통해 어휘 사전에 포함되지 않은 단어가 주어질 경우, 해당 단어를 <unk>로 자동 처리하도록 합니다.
이렇게 기본 인덱스를 설정하면 어휘 범위 외 단어가 등장했을 때 처리에 어려움이 생기는 것을 방지하고, 미지의 단어에 대해 일관된 방식으로 모델이 처리할 수 있게 됩니다.

LSTM 모델 정의
class LSTMModel(nn.Module):
    def __init__(self, vocab_size, embed_dim, hidden_dim, output_dim):
        super(LSTMModel, self).__init__()
        self.embedding = nn.EmbeddingBag(vocab_size, embed_dim, sparse=True)
        self.lstm = nn.LSTM(embed_dim, hidden_dim, batch_first=True)
        self.fc = nn.Linear(hidden_dim, output_dim)
    def forward(self, content):
        embedded = self.embedding(content)
        output, (hidden, cell) = self.lstm(embedded.unsqueeze(1))
        return self.fc(hidden[-1])

 

이 클래스는 LSTM 모델을 정의하며, 임베딩(embedding) 층, LSTM 층, 그리고 출력층을 구성합니다. 텍스트 데이터를 입력받아 최종적으로 분류 점수를 예측하는 모델로 설계되어 있습니다.
class LSTMModel(nn.Module):
PyTorch의 nn.Module을 상속받아, LSTM 기반의 모델 구조를 정의하는 클래스를 생성합니다. 이 클래스는 모델의 초기화 단계(__init__)와 순전파(forward) 단계를 포함하며, 모델이 입력 데이터를 받아 처리하는 방식을 정의합니다.
__init__ 메서드: 모델의 층 구성

def __init__(self, vocab_size, embed_dim, hidden_dim, output_dim):
모델 초기화 함수로, 모델의 여러 층의 크기와 파라미터를 설정합니다.
vocab_size: 전체 어휘의 크기를 나타내며, 임베딩 층의 입력 크기로 사용됩니다.
embed_dim: 각 단어를 임베딩할 차원의 크기입니다.
hidden_dim: LSTM의 은닉 상태 크기입니다. 이 크기는 모델이 단어 시퀀스에서 기억해야 할 정보의 양을 결정합니다.
output_dim: 모델이 출력해야 할 클래스 개수입니다. 예를 들어, 점수 예측에서는 5점 척도를 사용하기 때문에 이 값은 5가 됩니다.

super(LSTMModel, self).__init__()
nn.Module의 초기화 메서드를 호출하여 LSTMModel 클래스가 부모 클래스인 nn.Module의 속성과 메서드를 사용할 수 있도록 설정합니다.

self.embedding = nn.EmbeddingBag(vocab_size, embed_dim, sparse=True)
nn.EmbeddingBag은 주어진 단어의 인덱스를 사용해 임베딩을 생성하는 층입니다. 각 단어를 고정된 크기의 벡터로 변환합니다.
vocab_size: 어휘의 크기를 임베딩의 입력 크기로 사용하여, 각 단어가 해당 어휘 집합의 한 인덱스로 표현될 수 있습니다.
embed_dim: 임베딩 차원으로, 단어가 embed_dim 차원의 벡터로 변환됩니다.
sparse=True는 희소 매트릭스를 사용하여 메모리 효율성을 높입니다.

EmbeddingBag은 전체 문장에 대해 평균 또는 합계 방식을 통해 임베딩을 생성하므로, 임베딩 벡터가 시퀀스 전체를 대변하게 됩니다.

self.lstm = nn.LSTM(embed_dim, hidden_dim, batch_first=True)
LSTM 층을 정의하며, embed_dim을 입력 크기로, hidden_dim을 은닉 상태의 크기로 설정합니다.
embed_dim은 임베딩 벡터의 차원 크기로, LSTM이 처리할 각 입력의 차원입니다.
hidden_dim은 LSTM의 은닉 상태와 셀 상태의 크기이며, 모델이 데이터를 처리하면서 유지할 기억 용량을 나타냅니다.
batch_first=True는 입력의 첫 번째 차원이 배치 크기(batch size)가 되도록 설정하여, 입력 텐서의 크기를 [batch_size, seq_length, embed_dim] 형식으로 맞춥니다.

self.fc = nn.Linear(hidden_dim, output_dim)
완전 연결 층(Fully Connected Layer)으로, LSTM의 최종 은닉 상태에서 출력된 정보를 이용해 최종 예측을 수행합니다.
hidden_dim은 LSTM이 반환하는 은닉 상태의 크기입니다.
output_dim은 최종 출력 차원으로, 예측할 클래스의 개수를 의미합니다.

forward 메서드: 모델의 순전파 단계
def forward(self, content):
입력 데이터를 처리하여 모델의 예측값을 반환하는 순전파 단계입니다. 입력 텐서 content는 미리 배치로 준비된 텍스트 데이터를 나타냅니다.

embedded = self.embedding(content)
content에 포함된 각 단어 인덱스를 임베딩 벡터로 변환합니다. embedding 층을 통해 [batch_size, embed_dim] 형태의 임베딩 벡터로 변환되며, 이는 LSTM에 입력으로 사용됩니다.

output, (hidden, cell) = self.lstm(embedded.unsqueeze(1))
LSTM 층을 통해 입력된 임베딩 벡터를 순차적으로 처리합니다.
embedded.unsqueeze(1)은 임베딩 벡터의 차원을 조정하여 [batch_size, seq_length=1, embed_dim]으로 만들고, 이는 LSTM의 입력 차원 요구 사항에 맞춥니다.
output은 모든 시점에서의 은닉 상태를 포함하고, (hidden, cell)은 마지막 시점의 은닉 상태와 셀 상태를 반환합니다.
hidden[-1]은 LSTM이 최종적으로 기억하는 정보로, 문장 전체를 요약한 벡터를 의미합니다.

return self.fc(hidden[-1])
hidden[-1]을 완전 연결층에 입력하여 최종 예측을 수행합니다. 이는 문장을 기반으로 예측된 클래스의 로짓(logit)을 출력하며, 모델의 예측 결과로 사용됩니다.

하이퍼파라미터 및 모델 초기화
Vocab_size = len(vocab)
Embed_dim = 64
Hidden_dim = 128
Output_dim = len(set(data['score']))
model = LSTMModel(Vocab_size, Embed_dim, Hidden_dim, Output_dim)
이 부분에서는 모델의 구조와 학습에 필요한 주요 파라미터들을 설정하며, 각 파라미터는 모델 성능에 직접적인 영향을 미치는 중요한 요소입니다.

Vocab_size = len(vocab)
어휘 사전(vocab)의 크기를 Vocab_size로 지정하여, 임베딩 층의 입력 크기를 결정합니다. 모든 고유 단어 수에 맞춰 어휘의 크기를 설정합니다.

Embed_dim = 64
임베딩 차원을 64로 설정하여, 각 단어가 64차원의 벡터로 표현되도록 합니다. 이 차원 크기는 모델의 학습 성능에 영향을 미치며, 적절한 크기를 선택하여 학습 효율성을 높일 수 있습니다.

Hidden_dim = 128
LSTM의 은닉 상태 크기를 128로 설정하여, 모델이 문장의 정보를 요약하고 기억할 수 있는 용량을 조정합니다. 은닉 차원이 커질수록 모델이 학습할 수 있는 정보량이 늘어나지만, 학습 비용 또한 증가합니다.

Output_dim = len(set(data['score']))
출력 차원을 데이터에 포함된 레이블의 고유 개수로 설정합니다. 이 모델이 예측할 점수의 개수로, 출력층의 크기를 의미합니다.

model = LSTMModel(Vocab_size, Embed_dim, Hidden_dim, Output_dim)
설정된 파라미터를 사용하여 LSTMModel을 초기화합니다. 이 모델은 정의된 LSTM 기반의 신경망을 인스턴스화하여 학습 준비를 마칩니다.

손실 함수와 옵티마이저 정의
optimizer = optim.SGD(model.parameters(), lr=0.01)
criterion = nn.CrossEntropyLoss()

 

옵티마이저: 확률적 경사 하강법을 사용하여 모델의 가중치를 업데이트합니다.
손실 함수: CrossEntropyLoss는 예측과 실제 값의 차이를 계산하여 손실을 반환합니다.

optimizer = optim.SGD(model.parameters(), lr=0.01)
경사 하강법 기반의 최적화 알고리즘인 SGD를 사용해 모델의 학습 파라미터를 업데이트합니다.
model.parameters()
는 모델 내 모든 가중치를 의미하며, lr=0.01은 학습 속도를 조절하는 학습률입니다. 낮은 학습률은 안정적인 학습을 도와주지만, 너무 낮으면 학습 속도가 느려질 수 있습니다.

criterion = nn.CrossEntropyLoss()
분류 문제의 손실 함수로, CrossEntropyLoss를 사용하여 예측값과 실제 레이블 간의 차이를 측정합니다.
이 손실 함수는 예측한 각 클래스의 확률 분포와 실제 클래스 간의 차
nn.CrossEntropyLoss()는 일반적으로 다중 클래스 분류에 사용되며, 모델의 예측 분포와 실제 레이블 간의 차이를 측정해주는 함수입니다.
이 함수는 모델이 예측한 각 클래스의 확률값을 비교해 예측의 정확성을 계산합니다. 손실 함수의 결과는 모델의 성능을 개선하기 위해 옵티마이저가 모델의 파라미터를 업데이트할 때 기준이 됩니다.

 

예측 함수

 

def predict_review(model, review):
    processed_review = preprocess_text(review)
    tensor_review = torch.tensor([vocab[token] for token in processed_review.split()]).unsqueeze(0)
    with torch.no_grad():
        output = model(tensor_review)

    predicted_score = torch.argmax(output, dim=1).item() + 1
    return predicted_score
def predict_review(model, review):
모델과 텍스트 데이터를 입력받아, 해당 텍스트에 대한 예측 점수를 반환하는 함수입니다. 학습된 모델의 가중치를 이용해 예측을 수행하며, 리뷰 텍스트가 예측을 위한 전처리 과정을 거치게 됩니다.

processed_review = preprocess_text(review)
입력 리뷰 텍스트를 preprocess_text 함수를 통해 정규화하여, 분석 가능한 형식으로 변환합니다. 소문자화, 특수문자 제거 등을 통해 일관된 형태로 리뷰 텍스트를 만듭니다. 모델의 성능을 위해 텍스트를 표준화하는 단계로서 중요합니다.

tensor_review = torch.tensor([vocab[token] for token in processed_review.split()]).unsqueeze(0)
전처리된 텍스트를 모델이 처리할 수 있도록 텐서로 변환합니다.
[vocab[token] for token in processed_review.split()]는 리뷰 텍스트를 개별 토큰으로 나누고, 각 토큰을 어휘 사전을 통해 인덱스로 변환하여 시퀀스 데이터로 만듭니다.
torch.tensor()는 이 시퀀스를 텐서 형태로 변환합니다.
.unsqueeze(0)는 입력 차원을 [1, seq_length] 형식으로 만들어 배치 차원을 추가합니다. 이는 모델이 예측할 때 입력 데이터를 배치 단위로 처리하도록 합니다.

with torch.no_grad():
이 블록 안의 코드 실행 시, 모델의 그래디언트를 계산하지 않도록 설정하여 메모리와 연산 효율성을 높입니다. 예측 단계에서는 학습이 필요 없기 때문에 그래디언트를 계산하지 않습니다.

output = model(tensor_review)
전처리된 리뷰 텍스트를 모델에 입력하여 예측 결과를 얻습니다. output은 모델의 출력으로, 각 클래스에 대한 점수(logit)로 표현됩니다. 출력 형태는 [1, output_dim]으로 각 클래스별 점수를 나타냅니다.

predicted_score = torch.argmax(output, dim=1).item() + 1
torch.argmax(output, dim=1)는 output에서 가장 높은 값의 인덱스를 선택하여 예측된 클래스를 결정합니다.
dim=1은 각 행에서 가장 큰 값을 찾도록 지정하는 것이며, 여기서 행은 배치 내 각 샘플을 의미합니다.
.item()은 단일 스칼라 값을 반환하여, 텐서가 아닌 일반 정수 형태로 예측 결과를 다룰 수 있게 합니다.
+1은 원래 점수 범위(1-5)를 복구하기 위한 작업으로, 원본 점수 범위와 일치시켜 해석이 가능하도록 합니다.

return predicted_score
최종적으로 모델이 예측한 점수를 반환합니다. 이 점수는 주어진 리뷰가 몇 점일지를 나타내며, 새로운 리뷰 텍스트에 대해 모델이 추정한 평가 결과로 볼 수 있습니다.

new_review = "This app is terrible"
predicted_score = predict_review(model, new_review)
print(f'Predicted Score: {predicted_score}')

 

새로운 텍스트에 대해 모델의 예측 성능을 확인하기 위해, 예제 리뷰를 입력하여 점수를 예측하고 이를 출력합니다.

new_review = "This app is terrible"
new_review에 모델의 성능을 테스트하기 위한 예제 리뷰를 저장합니다. 이 텍스트는 모델이 어떻게 부정적인 리뷰를 해석하는지 확인하기 위한 샘플입니다.

predicted_score = predict_review(model, new_review)
predict_review 함수를 호출하여 new_review에 대한 예측 점수를 얻습니다. 이 과정에서 predict_review 함수는 리뷰를 전처리하고 모델에 입력하여 점수를 예측하게 됩니다.

print(f'Predicted Score: {predicted_score}')
예측된 점수를 출력하여, 모델이 부여한 점수를 확인할 수 있습니다. 모델이 학습한 내용을 기반으로 새로운 텍스트에 적절히 점수를 매겼는지 평가할 수 있습니다.

 

 

 

 

결국 종합적으로 전체 흐름을 정리하면,

전체 코드 흐름 정리
1. 라이브러리 임포트 및 초기 설정: 데이터 처리, 전처리, 텍스트 임베딩 및 모델 학습에 필요한 라이브러리들을 불러옵니다.

2. 데이터 전처리:
2.1 preprocess_text: 리뷰 텍스트에서 불필요한 특수 문자와 숫자를 제거하고 소문자로 변환하여 통일성을 유지합니다.
2.2 preprocess_score: 점수 데이터를 0에서 4 사이의 정수로 변환하여 클래스 레이블로 사용합니다.

3. ReviewDataset 클래스:
전처리된 리뷰 텍스트와 점수 데이터를 관리하며, 각 데이터 샘플에 접근할 수 있는 방법을 제공합니다.
__len__과 __getitem__ 메서드를 통해 데이터셋 크기와 각 샘플을 얻는 기능을 정의합니다.

4. 학습 및 테스트 데이터 분할:
데이터셋을 학습용과 테스트용으로 분할하여 모델 성능을 평가할 수 있도록 준비합니다.

5. DataLoader 생성:
train_dataload와 test_dataload를 생성하여 모델이 데이터를 배치 단위로 접근하고 학습할 수 있게 합니다.

6. Vocabulary 생성:
모든 텍스트 데이터에서 고유한 단어들로 구성된 vocab을 생성하여 단어-인덱스 매핑을 만듭니다. 이는 텍스트 데이터를 인덱스 형태로 변환하는 데 사용됩니다.

7. LSTM 모델 정의:
LSTMModel 클래스는 단어 임베딩, LSTM 레이어, 그리고 최종 선형 레이어로 구성된 모델 구조를 정의합니다.
forward 메서드에서는 텍스트 데이터를 임베딩하고 LSTM을 통해 예측 점수를 생성합니다.

8. 손실 함수와 옵티마이저 정의:
CrossEntropyLoss: 예측과 실제 점수 간의 손실을 계산하는 데 사용됩니다.
SGD 옵티마이저: 확률적 경사 하강법을 통해 가중치를 업데이트합니다.

9. 예측 함수 정의:
predict_review: 새로운 리뷰에 대해 예측 점수를 생성하는 함수입니다. 입력 리뷰를 전처리하고, 텍스트를 모델에 입력하여 예측 점수를 반환합니다.

10. 예측 결과 출력:
새로운 리뷰 텍스트에 대해 모델의 예측 결과를 출력하여 모델 성능을 테스트합니다.

오늘은 여기까지...