Загружаем каталог…
Загружаем каталог…
4.5 LSTM을 이용한 네이버 영화 리뷰 분류 이번에는 LSTM(Long Short-Term Memory) 을 이용해 네이버 영화 리뷰가 긍정인지 부정인지 분류해보았다. 사용할 데이터 : 네이버 영화 리뷰 데이터(NSMC) 전체 데이터 : 200,000개 Train : 150,000개 Test : 50,000개 Label : 긍정 1 , 부정 0 전체 과정은 다음과 같다. 영화 리뷰 ↓ 데이터 정제 ↓ 형태소 분석 ↓ 정수 인코딩 ↓ Padding ↓ Embedding ↓ LSTM ↓ 긍정 / 부정 분류 1. 데이터 이해와 전처리 1-1. 라이브러리 설정 import pandas as pd import numpy as np import matplotlib.pyplot as plt import urllib.request from konlpy.tag import Mecab from tqdm import tqdm from sklearn.model_selection import train_test_split from collections import Counter 이번 실습에서는 특히 Mecab : 한국어 형태소 분석 Counter : 단어 등장 빈도 계산 train_test_split : Train / Validation 데이터 분리 를 사용한다. 1-2. 데이터 로드 urllib.request.urlretrieve( "https://raw.githubusercontent.com/e9t/nsmc/master/ratings_train.txt", filename="ratings_train.txt" ) urllib.request.urlretrieve( "https://raw.githubusercontent.com/e9t/nsmc/master/ratings_test.txt", filename="ratings_test.txt" ) train_data = pd.read_table('ratings_train.txt') test_data = pd.read_table('ratings_test.txt') 데이터 개수를 확인하면 Train : 150,000 Test : 50,000 이고 데이터는 id / document / label 세 개의 컬럼으로 구성되어 있다. 여기서 document → 모델의 입력 label → 모델이 맞혀야 할 정답 이라고 이해하면 된다. 2. 데이터 정제 먼저 중복된 리뷰를 확인한다. train_data['document'].nunique() 결과 146182 150,000개의 데이터 중 중복된 리뷰가 존재하기 때문에 제거한다. train_data.drop_duplicates( subset=['document'], inplace=True ) Null 데이터도 제거한다. train_data = train_data.dropna(how='any') 그리고 한글과 공백을 제외한 문자를 제거한다. train_data['document'] = train_data['document'].str.replace( "[^ᄀ-하-ᅵ가-힣 ]", "", regex=True ) 특수문자를 제거하면서 아무 내용도 남지 않은 리뷰가 새롭게 생길 수 있으므로 빈 문자열도 제거한다. train_data['document'].replace('', np.nan, inplace=True) train_data = train_data.dropna(how='any') 전처리 후 Train 데이터 145,393개 처음에는 150,000개였지만 중복, Null, 의미 없는 데이터를 제거하면서 데이터가 줄어들었다. 3. 형태소 분석과 토큰화 한국어는 영어처럼 단순히 띄어쓰기만으로 단어를 나누기 어렵다. 예를 들어 나는 영화를 봤다 에서 나는 , 영화를 , 봤다 에는 조사와 어미가 붙어 있다. 그래서 Mecab 형태소 분석기 를 이용한다. mecab = Mecab() mecab.morphs( '와 이런 것도 영화라고 차라리 뮤직비디오를 만드는 게 나을 뻔' ) 결과 ['와', '이런', '것', '도', '영화', '라고', '차라리', '뮤직', '비디오', '를', '만드', '는', '게', '나을', '뻔'] 문장이 형태소 단위로 분리되는 것을 확인할 수 있다. 불용어 제거 분류에 큰 의미가 없다고 판단되는 조사 등의 단어는 제거한다. stopwords = [ '도', '는', '다', '의', '가', '이', '은', '한', '에', '하', '고', '을', '를', '인', '듯', '과', '와', '네', '들', '지', '임', '게' ] 전체 리뷰에 형태소 분석과 불용어 제거를 적용한다. X_train = [] for sentence in tqdm(train_data['document']): tokenized_sentence = mecab.morphs(sentence) stopwords_removed_sentence = [ word for word in tokenized_sentence if word not in stopwords ] X_train.append(stopwords_removed_sentence) 결과적으로 문장 ↓ 형태소들의 리스트 형태로 변환된다. 4. 단어 집합 만들기 컴퓨터는 영화 , 재밌다 같은 문자열을 그대로 계산할 수 없다. 따라서 먼저 학습 데이터에 어떤 단어들이 존재하는지 확인한다. word_list = [] for sent in X_train: for word in sent: word_list.append(word) word_counts = Counter(word_list) print(len(word_counts)) 결과 45,296 약 45,000개의 서로 다른 형태소가 존재했다. 하지만 이 중에는 한두 번밖에 등장하지 않는 단어도 많았다. 2회 이하 등장한 희귀 단어를 확인한 결과 희귀 단어 비율 : 약 57.63% 전체 등장 빈도에서 차지하는 비율 : 약 2.28% 였다. 즉 단어 종류에서는 절반 이상이지만 실제 문장에서는 거의 등장하지 않는다. 그래서 희귀 단어를 제외하고 단어 집합을 만들었다. Vocabulary : 19,191개 여기에 <PAD> = 0 <UNK> = 1 을 추가한다. 최종 Vocabulary 19,193개 <UNK> 는 학습할 때 보지 못한 단어, <PAD> 는 문장 길이를 맞추는 데 사용한다. 5. 정수 인코딩 이제 단어를 숫자로 바꾼다. 예를 들어 영화 → 2 좋 → 6 너무 → 11 와 같은 방식이다. def texts_to_sequences(tokenized_data, word_to_index): encoded_data = [] for sent in tokenized_data: encoded_sent = [] for word in sent: encoded_sent.append( word_to_index.get( word, word_to_index['<UNK>'] ) ) encoded_data.append(encoded_sent) return encoded_data 이를 통해 ['영화', '정말', '재밌'] 같은 문장은 [2, 53, 142] 와 같은 숫자의 나열로 바뀐다. 중요한 것은 숫자의 크기 자체에 의미가 있는 것이 아니라 단어를 구별하기 위한 번호 라는 것이다. 6. Padding 문제는 리뷰마다 길이가 다르다는 것이다. 리뷰 A → 7개 단어 리뷰 B → 15개 단어 리뷰 C → 30개 단어 신경망에서 Batch 단위로 처리하기 위해서는 길이를 동일하게 맞출 필요가 있다. Train 데이터의 길이를 확인해보면 최대 길이 : 74 평균 길이 : 약 12.3 이었다. 길이를 30 으로 설정하면 약 92.5%의 리뷰를 포함 할 수 있기 때문에 max_len = 30 으로 설정하였다. Padding 이후 데이터 크기는 Train : (116314, 30) Validation : (29079, 30) Test : (48852, 30) 이 된다. 예를 들어 [924, 1866, 128, 7, 80, 48, 34] 라는 리뷰는 [924, 1866, 128, 7, 80, 48, 34, 0, 0, 0, 0, ...] 처럼 길이 30까지 PAD = 0 으로 채워진다. 7. LSTM 모델 이제 실제 감성 분류 모델을 만든다. 모델 구조는 생각보다 간단하다. Integer Encoding ↓ Embedding ↓ LSTM ↓ Linear ↓ 긍정 / 부정 코드는 다음과 같다. class TextClassifier(nn.Module): def __init__( self, vocab_size, embedding_dim, hidden_dim, output_dim ): super().__init__() self.embedding = nn.Embedding( vocab_size, embedding_dim ) self.lstm = nn.LSTM( embedding_dim, hidden_dim, batch_first=True ) self.fc = nn.Linear( hidden_dim, output_dim ) def forward(self, x): embedded = self.embedding(x) lstm_out, (hidden, cell) = self.lstm( embedded ) last_hidden = hidden.squeeze(0) return self.fc(last_hidden) 사용한 주요 설정은 Vocabulary Size : 19,193 Embedding Dimension : 100 Hidden Dimension : 128 Output Dimension : 2 Batch Size : 32 Epoch : 5 Learning Rate : 0.001 이다. 모델 내부 데이터 변화 이 부분이 개인적으로 가장 중요했다. Batch Size가 32라면 Input (32, 30) ↓ Embedding (32, 30, 100) ↓ LSTM (32, 128) ↓ Linear (32, 2) 가 된다. 즉 Embedding Layer에서는 각각의 단어를 100차원의 벡터 로 표현한다. LSTM은 문장의 순서를 따라 정보를 읽고 마지막에 128차원의 Hidden State 로 문장의 정보를 요약한다. 마지막 Linear Layer는 부정 점수 / 긍정 점수 두 값을 출력한다. 8. 모델 학습 Loss Function은 criterion = nn.CrossEntropyLoss() Optimizer는 optimizer = torch.optim.Adam( model.parameters(), lr=0.001 ) 을 사용한다. 하나의 Batch가 학습되는 흐름은 Forward ↓ Loss 계산 ↓ Gradient 초기화 ↓ Backward ↓ Parameter Update 이다. 코드로 보면 logits = model(batch_X) loss = criterion( logits, batch_y ) optimizer.zero_grad() loss.backward() optimizer.step() 이 과정이 반복되면서 LSTM의 Parameter가 업데이트된다. 9. Validation과 Test 결과 학습 과정에서는 Train 데이터만 보는 것이 아니라 Validation 데이터의 Loss를 확인해서 가장 좋은 모델을 저장한다. if val_loss < best_val_loss: best_val_loss = val_loss torch.save( model.state_dict(), 'best_model_checkpoint.pth' ) 최종적으로 가장 좋은 모델을 불러와 평가한 결과 데이터 Loss Accuracy Validation 0.3392 84.90% Test 0.3435 84.92% Test Accuracy는 약 84.92% 가 나왔다. Validation과 Test Accuracy가 거의 비슷하게 나왔다는 것도 확인할 수 있었다. 10. 실제 문장 예측 학습한 모델에 직접 문장을 입력해보았다. test_input = "이 영화 개꿀잼 ᄏᄏᄏ" 결과 긍정 반대로 test_input = "이딴게 영화냐 ᄍᄍ" 결과 부정 실제 인터넷에서 사용할 법한 표현도 어느 정도 긍정과 부정을 구분하는 것을 확인할 수 있었다. 11. 공부하면서 이해한 부분 LSTM 모델 자체만 보는 것이 아니라 자연어가 모델에 입력되기까지의 과정 문장 ↓ 형태소 분석 ↓ 불용어 제거 ↓ Vocabulary 생성 ↓ 정수 인코딩 ↓ Padding ↓ Embedding ↓ LSTM ↓ Linear ↓ 긍정 / 부정 한국어는 조사와 어미 때문에 형태소 분석이 중요하다. 단어는 그대로 신경망에 들어가는 것이 아니라 정수 → Embedding Vector 로 변환된다. 서로 다른 문장 길이를 맞추기 위해 Padding 을 사용한다. LSTM은 단어를 순서대로 읽으면서 문장의 정보를 Hidden State에 저장한다. 이번 모델에서는 마지막 Hidden State를 이용해 긍정/부정을 분류하였다.
То, что RADAR обнаружил и классифицировал для этой возможности. Это опубликованный источником текст, а не подтверждение, что предложение ещё действует.
## 4.5 LSTM을 이용한 네이버 영화 리뷰 분류. 4.5 LSTM을 이용한 네이버 영화 리뷰 분류 이번에는 LSTM(Long Short-Term Memory) 을 이용해 네이버 영화 리뷰가 긍정인지 부정인지 분류해보았다. 사용할 데이터 : 네이버 영화 리뷰 데이터(NSMC) 전체 데이터 : 200,000개 Train : 150,000개 Test : 50,000개 Label : 긍정 1 , 부정 0 전체 과정은 다음과 같다. 영화 리뷰 ↓ 데이터 정제 ↓ 형태소 분석 ↓ 정수 인코딩 ↓ Padding ↓ Embedding ↓ LSTM ↓ 긍정 / 부정 분류 1. 데이터 이해와 전처리 1-1. 라이브러리 설정 import pandas as pd import numpy as np import…
Открыть источник