[딥러닝] NLP : 자연어 처리 기본 (+ 영화 리뷰글 긍정/부정 판단해보기)
이번 포스팅에서는 자연어 처리(NLP)에 대해서 알아보고 Transformer 출연 이전 자연어 처리에서 널리 사용되었던 지난 포스팅에서 다루어 보았던 RNN 기반 모델을 활용한 NLP 기술들에 대해서 살펴보려고 한다.
해당 포스팅에서는 아래와 같은 내용들을 다룰 것이다.
- NLP(자연어 처리)의 개념
- NLP의 발전 과정
- 모델 입력 형태 : Character Embedding과 Word Embedding, 그리고 Embedding Vector
- RNN 기반의 NLP
- 영화 리뷰 데이터를 학습 -> 문장의 긍정 및 부정을 예측하는 모델 만들어보기
NLP (자연어 처리, Natural Language Processing)
컴퓨터가 인간의 언어를 이해하고 처리하며 생성할 수 있도록 하는 인공지능의 한 분야이다. 언어의 구조와 의미를 분석하고 이를 통해서 다양한 작업을 수행하는 것을 목표로 한다.
- 자연어 (Natural Language) :사람들의 사회생활에서 자연스럽게 발생하여 쓰이는 언어
- 자연어 처리 :자연어를 그대로 컴퓨터로 처리하는 학문 분야
- 언어학적 측면 :언어의 규칙성이나 변화 양상 등을 파악
- 전산학적 측면 :자연어를 입출력으로 사용하는 컴퓨터 프로그램에 사용되는 처리과정
자연어 처리의 분류
- 자연어 이해 (NLU, Natural language understanding) : 사람이 이해하는 자연어를 컴퓨터가 이해할 수 있는 값으로 바꾸는 과정
- 자연어 생성 (NLG, Natural language generation) : 컴퓨터가 이해할수 있는 값을 사람이 이해하도록 바꾸는 과정
자연어 처리 및 언어 지능을 이용해서 할 수 있는 일
- 개체명 인식 : 텍스트에서 사람, 장소, 날짜 등과 같은 명명된 개체를 식별
- 감정 분석 : 텍스트의 긍정, 부정, 중립적 의견 파악
- 질문 응답 : 특정 질문에 대해서 문맥에 맞는 답변 생성
- 텍스트 분류 : 텍스트를 사전에 정의된 범주로 분류
- 정보 추출 : 텍스트에서 특정 정보를 추출
- 기계 번역 : 한 언어로 작성된 문장을 다른 언어로 번역
- 정보 검색 : 대량의 텍스트 데이터에서 사용자의 질의에 맞는 정보를 검색
- 문서 요약 : 긴 문서나 긴 대화를 간결하게 요약
언어 지능의 어려움
1. 언어의 중의성 : 완벽히 같은 글자의 조합이 여러 의미를 가짐 -> 처리의 복잡도 상승
2. 규칙의 예외 : 규칙을 모든 단어에 그대로 적용할 수 없음
- 형태론(Mopology) : 언어의 규칙을 연구하는 분야
3. 언어의 유연성과 확장성 : 언어는 항상 변하며, 시간의 흐름에 따라 없어지거나 새로 탄생하는 용어가 있음.
4. 바꾸어 말하기 : Paraphrase 문제. 문장 표현 방식은 다양하고, 비슷한 의미의 단어들이 존재.
5. 단어 간 유사도 : 자연어는 기계 입장에서 매우 어려움, One-hot 인코딩으로 표현된 값은 유사도나 모호성을 표현할 수 없음
- 희소 벡터(Sparse Vector) : 자연어는 높은 차원으로 표현되고 0으로 표현되는 비어있는 요소가 많음
- 딥러닝에서는 단어 임베딩(Word Embedding)을 통해 해결
자연어 처리의 발전
1. 규칙 기반 (50년대)
- 토큰화 : 입력 문장을 작은 단위로 쪼개 처리하기 위해 단어, 구두점 등 토큰으로 분리.
- 형태소 분석 : 토큰을 작은 의미로 분할하고, 형태소 정보를 추출(대명사, 명사, 동사..)
- 구문 분석 : 문장의 구문 구조를 분석하여 단어들 사이의 관계 파악
- 의미 분석 : 언어 지식을 활용하여 단어의 의미를 이해
- 규칙 매칭 : 사람이 정의한 규칙으로 특정 언어의 패턴을 찾아냄
- 규칙 실행 : 일치하는 규칙에 따라 답변 생성, 텍스트 분류 등 정해진 동작 실행
- 모호성 해소 : 여러 규칙/패턴일 경우 우선순위, 문맥분석, 통계모델 등을 사용
2. 통계 기반(80년대)
- 규칙 기반 사전 정의를 통계적으로 처리.
- 조건부 확률 : 통계적 처리의 핵심 수학 개념
- N-gram 모델 : 문장의 연속된 N개의 단어나 문자단위로 묶어 확률적 모델링을 수행
3. 기계 학습 (ML) 기반(90년대 이후)
- SVM : 지도학습. 텍스트 분류, 개체명 인식, 문장 감정 분류
- Naïve Bayes : 지도학습. 베이즈 정리에 기반한 확률적 분류. 텍스트 분류, 문장 감정 분류..
- 군집화 : 비지도학습. 문서 군집화(유사주제), 단어 군집화(유사어), 의도 군집화(사용자 의도 파악)
- LDA: : 비지도학습. 대규모 텍스트 데이터에서 토픽을 추출
- 강화학습 : 대화 시스템, 기계 번역, 자동 요약. State, Action, Value, Policy
4. RNN 기반(2010년대)
- 시계열 데이터를 처리하기 위해 설계된 인공 신경망.
- 출력을 다시 입력으로 처리하는 모델
- 심층 학습 기반의 자연어 처리 기술의 시작
5. Transformer 기반(2010년대 후반 이후)
- 2017년 Google에서 발표한 자연어 처리 모델.
- Self-Attention : 문장의 모든 단어에 동시 적용 -> RNN의 병렬 처리 부족 해소
- Long-range Dependency 해소 : 문장 내에서 거리가 떨어져 있는 단어간의 관계 파악
모델 입력 형태 : 자연어는 어떻게 입력해야할까?
자연어, 이미지, 오디오 등과 같은 비정형 데이터를 모델에 학습시키기 위해서는 정형 데이터로 변환하는 과정이 필요하다.
CNN 모델에서 사용되는 이미지와 같은 형태는 0~255의 화소의 벡터로 이미지에 대한 입력을 표현하였다.
그렇다면 자연어는 컴퓨터가 이해할 수 있도록 어떤 식으로 변환해야 할까?
Character Embedding (문자 임베딩)
문자 단위로 텍스트를 임베딩하는 방법이다. 위의 그림은 각 문자를 가장 단순한 1차원 벡터의 형태로 매핑한 예시이다.
즉 Character Embedding은 각 문자를 고유한 벡터로 표현한다.
그렇지만 계산 복잡도가 증가하고 문맥을 파악하기 어렵다는 문제가 있어서 Word Embedding의 개념이 도입되었다.
Word Embedding (단어 임베딩)
Word Embedding은 이제 단어 단위로 매핑한다.
그런데 위와 같이 단일 숫자로 표현한다면 비슷한 의미의 단어는 비슷하게 표현되고 단어의 다양한 의미의 내포가 어려워진다.
임베딩 벡터(Embedding Vector)
이를 극복하기 위해서 여러가지 의미를 가지는 고차원 형태의 벡터를 사용하게 된다. 임베딩 벡터는 각 차원이 복합적으로 다양한 의미를 나타내므로 단어 간의 관계와 의미를 잘 파악할 수 있도록 한다.
위의 예시에서 벡터의 각 차원은 긍정률, 행동을 나타내는지, 사물을 나타내는 지 등을 각각 표현할 수 있을 것이다.
만약 "Baby is cute"와 "Panda is cute" 두 문장을 학습시킨다고 생각해보자.
Word embeddings은 단어를 공간상의 점으로 나타내는 기법으로 단어 간의 의미적인 유사성을 파악하려고 한다.
벡터 각각은 Weight를 가지고 이것이 학습되어 다양한 의미를 내포한 형태로 임베딩된다. 임베딩 벡터의 차원이 높아질수록 다양한 맥락의 유사도를 파악할 수 있다.
어떻게 Embedding Vector로 만드는가?
자연어 처리를 위해 입력 데이터를 임베딩 벡터로 변환하기 위해서는 Word2Vec, GloVe, FastText 등의 사전 훈련이 완료된 임베딩 모델을 사용한다.
이러한 임베딩 모델들 또한 신경망 모델을 기반으로 학습되었다. Word2Vec은 CBOW, Skip-gram이라는 신경망 구조를 사용하여 단어 임베딩을 학습한다.
이 임베딩 벡터는 이후의 RNN, LSTM 등 모델의 입력으로 사용된다.
비교
Character Embedding
장점
- 미등록 단어(Out-of-Vocabulary, OOV) 문제 해결: 새로운 단어 또는 희귀한 단어에 대해 더 잘 대응할 수 있음, 단어의 철자 정보까지 활용하기 때문에 사전에 없는 단어라도 처리 가능
- 언어의 유연성: 다양한 언어적 변형과 오타에 대해 견고함
- 소규모 데이터셋에서 유리: 단어 단위보다 더 작은 단위에서 학습하기 때문에 상대적으로 작은 데이터셋에서도 학습이 가능
단점
- 계산 복잡도 증가: 단어를 구성하는 모든 문자를 처리해야 하므로 계산 비용이 높아짐
- 문맥 정보의 손실: 단어 단위의 문맥을 바로 파악하기 어려움, 긴 문장에서는 문맥 정보를 잡아내기 어려울 수 있음
Character Embedding이 더 좋은 경우
- 새로운 단어와 희귀한 단어가 자주 등장하는 경우
- 오타가 빈번히 발생하는 사용자 생성 콘텐츠를 처리할 때
- 다양한 형태로 변형되는 언어적 특성을 다룰 때(예: 소셜 미디어 텍스트, 방언 등)
Word Embedding
장점
- 문맥 이해: 단어의 의미를 문맥적으로 파악하여 단어 간의 유사성을 반영
- Word2Vec, GloVe, FastText 등의 모델을 통해 단어의 의미를 벡터 공간에 효율적으로 표현
- 계산 효율성: 단어 단위로 처리 → 연산이 상대적으로 빠르고 효율적. 사전 학습된 벡터를 사용할 경우 빠르게 적용 가능
- 전이 학습(Transfer Learning): 대규모 말뭉치에서 미리 학습된 임베딩 벡터를 다양한 작업에 활용할 수 있음 → 특정 도메인에 맞춰 미세 조정이 가능
단점
- 미등록 단어(OOV) 문제: 학습된 사전에 없는 새로운 단어에 대해 처리하지 못함 → 성능 저하 발생 가능
- 언어의 유연성 문제: 오탈자 처리에 어려움
Word Embedding이 더 좋은 경우
- 대규모의 사전 학습된 말뭉치를 사용할 수 있는 경우
- 문맥 정보가 중요하고, 문맥을 통해 단어의 의미를 잘 파악해야 하는 경우(예: 문서 분류, 감정 분석 등)
- 빠르고 효율적인 처리가 요구되는 경우
RNN(순환 신경망, Recurrent Neural Network)
과거의 정보를 사용해서 현재 및 미래의 입력에 대한 신경망의 예측 성능을 개선하는 인공 신경망 구조이다. 즉 순차적인 문맥을 파악하는 신경망이다.
순차적 구성 요소가 복잡한 의미와 구문 규칙에 따라 상호 연관되는 단어, 문장 또는 시계열 데이터 등의 순차적 데이터의 처리에 강점을 가지고 있다.
만약 RNN, LSTM, GRU 등의 RNN에 대해서 잘 모른다면 아래의 포스팅을 참고하면 좋을 것 같다.
https://sjh9708.tistory.com/226
RNN 기반 자연어 처리 : 문장 긍정/부정 판단하기
이제 RNN을 기반 모델로 자연어 처리를 학습시켜보자. 모델로는 LSTM을 사용할 예정이다.
우리는 영문 영화 리뷰 데이터를 모델에 학습시킨 후, 문장의 긍정 및 부정을 판단해 볼 것이고, 네이버 영화 리뷰 데이터를 학습시켜서 한글 문장의 긍정 및 부정도 판단해보자.
from IPython.core.display import display, HTML
display(HTML("<style>.container {width:90% !important;}</style>"))
from google.colab import drive
drive.mount('/content/drive')
Mounted at /content/drive
import os
os.chdir('drive/MyDrive/DL2024_201810776/week11/')
%load_ext autoreload
%autoreload 2
import numpy as np
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import SimpleRNN, LSTM, GRU, Dense
import matplotlib.pyplot as plt
A. 영화 리뷰 학습 후 문장 긍정/부정 구분하기¶
from tensorflow.keras.datasets import imdb
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.layers import Embedding
1. 데이터셋 로드¶
IMDB(Internet Movie Database)는 영화 정보와 리뷰 등을 포함하는 온라인 데이터베이스이다
max_features = 10000 # 단어 사전 : 사용할 단어의 최대 개수 (Baby, Panda..)
max_len = 500 # 패딩할 시퀀스의 최대 길이 (비어있는 부분을 0으로 채워줌)
(X_train, y_train), (X_test, y_test) = imdb.load_data(num_words=max_features)
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/imdb.npz 17464789/17464789 [==============================] - 0s 0us/step [1, 249, 1323, 7, 61, 113, 10, 10, 13, 1637, 14, 20, 56, 33, 2401, 18, 457, 88, 13, 2626, 1400, 45, 3171, 13, 70, 79, 49, 706, 919, 13, 16, 355, 340, 355, 1696, 96, 143, 4, 22, 32, 289, 7, 61, 369, 71, 2359, 5, 13, 16, 131, 2073, 249, 114, 249, 229, 249, 20, 13, 28, 126, 110, 13, 473, 8, 569, 61, 419, 56, 429, 6, 1513, 18, 35, 534, 95, 474, 570, 5, 25, 124, 138, 88, 12, 421, 1543, 52, 725, 6397, 61, 419, 11, 13, 1571, 15, 1543, 20, 11, 4, 2, 5, 296, 12, 3524, 5, 15, 421, 128, 74, 233, 334, 207, 126, 224, 12, 562, 298, 2167, 1272, 7, 2601, 5, 516, 988, 43, 8, 79, 120, 15, 595, 13, 784, 25, 3171, 18, 165, 170, 143, 19, 14, 5, 7224, 6, 226, 251, 7, 61, 113]
from utils import decode_imdb, sentence_to_vector
# 4번째 리뷰 확인
print(X_train[4]) # 숫자 하나하나가 단어, 숫자가 높을수록 빈도가 높음
print(len(X_train[4])) #147개의 단어
decoded_review = decode_imdb(X_train[4])
print(decoded_review) # 번역된 리뷰
[1, 249, 1323, 7, 61, 113, 10, 10, 13, 1637, 14, 20, 56, 33, 2401, 18, 457, 88, 13, 2626, 1400, 45, 3171, 13, 70, 79, 49, 706, 919, 13, 16, 355, 340, 355, 1696, 96, 143, 4, 22, 32, 289, 7, 61, 369, 71, 2359, 5, 13, 16, 131, 2073, 249, 114, 249, 229, 249, 20, 13, 28, 126, 110, 13, 473, 8, 569, 61, 419, 56, 429, 6, 1513, 18, 35, 534, 95, 474, 570, 5, 25, 124, 138, 88, 12, 421, 1543, 52, 725, 6397, 61, 419, 11, 13, 1571, 15, 1543, 20, 11, 4, 2, 5, 296, 12, 3524, 5, 15, 421, 128, 74, 233, 334, 207, 126, 224, 12, 562, 298, 2167, 1272, 7, 2601, 5, 516, 988, 43, 8, 79, 120, 15, 595, 13, 784, 25, 3171, 18, 165, 170, 143, 19, 14, 5, 7224, 6, 226, 251, 7, 61, 113] 147 the sure themes br only acting i i was favourite as on she they hat but already most was scares minor if flash was well also good 8 older was with enjoy used enjoy phone too i'm of you an job br only women than robot to was with these unexpected sure little sure guy sure on was one your life was children in particularly only yes she sort is jerry but so stories them final known to have does such most that supposed imagination very moving antonioni only yes this was seconds for imagination on this of and to plays that nights to for supposed still been last fan always your bit that strong said clean knowing br theory to car masterpiece out in also show for film's was tale have flash but look part i'm film as to penelope is script hard br only acting
2. 데이터 전처리¶
- 학습시킬 벡터의 길이(max_len)은 500이다. 따라서 벡터의 길이를 맞춰주어야 한다.
- 시퀀스 패딩 : 만약 147개의 Word vector가 있다면 353개의 Padding을 추가해준다.
- 뒷부분이 영향력이 크므로 앞부분에 패딩처리를 한다.
X_train = pad_sequences(X_train, maxlen=max_len)
X_test = pad_sequences(X_test, maxlen=max_len)
X_train[4]
array([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 249, 1323, 7, 61, 113, 10, 10, 13, 1637, 14, 20, 56, 33, 2401, 18, 457, 88, 13, 2626, 1400, 45, 3171, 13, 70, 79, 49, 706, 919, 13, 16, 355, 340, 355, 1696, 96, 143, 4, 22, 32, 289, 7, 61, 369, 71, 2359, 5, 13, 16, 131, 2073, 249, 114, 249, 229, 249, 20, 13, 28, 126, 110, 13, 473, 8, 569, 61, 419, 56, 429, 6, 1513, 18, 35, 534, 95, 474, 570, 5, 25, 124, 138, 88, 12, 421, 1543, 52, 725, 6397, 61, 419, 11, 13, 1571, 15, 1543, 20, 11, 4, 2, 5, 296, 12, 3524, 5, 15, 421, 128, 74, 233, 334, 207, 126, 224, 12, 562, 298, 2167, 1272, 7, 2601, 5, 516, 988, 43, 8, 79, 120, 15, 595, 13, 784, 25, 3171, 18, 165, 170, 143, 19, 14, 5, 7224, 6, 226, 251, 7, 61, 113], dtype=int32)
3. 모델 생성¶
- 임베딩 벡터 input_dim=max_features, output_dim = 128, input_length=max_len
- LSTM hidden layer 64개
- Dense 출력 1개, activation은 sigmoid
nlp_model = Sequential([
Embedding(input_dim=max_features, output_dim=128, input_length=max_len),
LSTM(64, return_sequences=False),
Dense(1, activation='sigmoid')
])
nlp_model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
nlp_model.summary()
Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= embedding (Embedding) (None, 500, 128) 1280000 lstm (LSTM) (None, 64) 49408 dense (Dense) (None, 1) 65 ================================================================= Total params: 1329473 (5.07 MB) Trainable params: 1329473 (5.07 MB) Non-trainable params: 0 (0.00 Byte) _________________________________________________________________
4. 모델 학습¶
nlp_history = nlp_model.fit(X_train, y_train, epochs=5, batch_size=64, validation_split=0.2)
Epoch 1/5 313/313 [==============================] - 232s 731ms/step - loss: 0.5293 - accuracy: 0.7524 - val_loss: 0.4243 - val_accuracy: 0.8102 Epoch 2/5 313/313 [==============================] - 236s 753ms/step - loss: 0.3150 - accuracy: 0.8734 - val_loss: 0.3350 - val_accuracy: 0.8684 Epoch 3/5 313/313 [==============================] - 234s 747ms/step - loss: 0.2127 - accuracy: 0.9208 - val_loss: 0.3281 - val_accuracy: 0.8588 Epoch 4/5 313/313 [==============================] - 226s 720ms/step - loss: 0.1503 - accuracy: 0.9477 - val_loss: 0.3486 - val_accuracy: 0.8562 Epoch 5/5 313/313 [==============================] - 226s 722ms/step - loss: 0.1109 - accuracy: 0.9620 - val_loss: 0.3797 - val_accuracy: 0.8656
5. 모델 평가 및 예측¶
test_loss, test_acc = nlp_model.evaluate(X_test, y_test)
print(f'Test Accuracy: {test_acc:.4f}')
782/782 [==============================] - 67s 86ms/step - loss: 0.4082 - accuracy: 0.8573 Test Accuracy: 0.8573
encode_test_sentence = sentence_to_vector('like this actor')
encode_test_sentence = pad_sequences(encode_test_sentence, maxlen=max_len)
nlp_model.predict(encode_test_sentence) #긍정/부정 판단하기 (수치가 낮을수록 부정)
[37, 11, 281] 1/1 [==============================] - 0s 51ms/step
array([[0.5339742]], dtype=float32)
encode_test_sentence = sentence_to_vector('hate the movie')
encode_test_sentence = pad_sequences(encode_test_sentence, maxlen=max_len)
nlp_model.predict(encode_test_sentence) #긍정/부정 판단하기 (수치가 낮을수록 부정)
[781, 1, 17] 1/1 [==============================] - 0s 48ms/step
array([[0.22174719]], dtype=float32)
1. 데이터 로드¶
해당 데이터는 네이버의 영화 리뷰 데이터를 모아놓은 것이다.
import pandas as pd
from tensorflow.keras.preprocessing.text import Tokenizer
path_to_train_file = tf.keras.utils.get_file('train_txt', 'https://raw.githubusercontent.com/hmkim312/datas/main/navermoviereview/ratings_train.txt')
path_to_test_file = tf.keras.utils.get_file('test_txt', 'https://raw.githubusercontent.com/hmkim312/datas/main/navermoviereview/ratings_test.txt')
train_data = pd.read_csv(path_to_train_file, sep='\t')
test_data = pd.read_csv(path_to_test_file, sep='\t')
# 데이터 확인
train_data.head()
id | document | label | |
---|---|---|---|
0 | 9976970 | 아 더빙.. 진짜 짜증나네요 목소리 | 0 |
1 | 3819312 | 흠...포스터보고 초딩영화줄....오버연기조차 가볍지 않구나 | 1 |
2 | 10265843 | 너무재밓었다그래서보는것을추천한다 | 0 |
3 | 9045019 | 교도소 이야기구먼 ..솔직히 재미는 없다..평점 조정 | 0 |
4 | 6483659 | 사이몬페그의 익살스런 연기가 돋보였던 영화!스파이더맨에서 늙어보이기만 했던 커스틴 ... | 1 |
2. 데이터 전처리¶
# Null 값 제거
train_data = train_data.dropna(how='any')
test_data = test_data.dropna(how='any')
# 특수 문자 제거 및 단어로 쪼개기
train_data['document'] = train_data['document'].str.replace("[^ㄱ-ㅎㅏ-ㅣ가-힣 ]","")
train_data['document'] = [sentence.split(' ') for sentence in train_data['document']]
test_data['document'] = test_data['document'].str.replace("[^ㄱ-ㅎㅏ-ㅣ가-힣 ]","")
test_data['document'] = [sentence.split(' ') for sentence in test_data['document']]
# 토큰화 (Text -> Sequence)
tokenizer = Tokenizer(num_words=20000)
tokenizer.fit_on_texts(train_data['document'])
X_train = tokenizer.texts_to_sequences(train_data['document'])
X_test = tokenizer.texts_to_sequences(test_data['document'])
y_train = np.array(train_data['label'])
y_test = np.array(test_data['label'])
마찬가지로 시퀀스 패딩 추가해주기
# 패딩
max_len = 25
X_train = pad_sequences(X_train,padding='post', maxlen=max_len)
X_test = pad_sequences(X_test,padding='post', maxlen=max_len)
3. 모델 생성¶
- 임베딩 벡터 input_dim=20000, output_dim = 300, input_length=max_len
- LSTM hidden layer 64개
- Dense 출력 1개, activation은 sigmoid
nlp_model = Sequential([
Embedding(input_dim=20000, output_dim=300, input_length=max_len),
LSTM(64, return_sequences=False),
Dense(1, activation='sigmoid')
])
nlp_model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
nlp_model.summary()
Model: "sequential_1" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= embedding_1 (Embedding) (None, 25, 300) 6000000 lstm_1 (LSTM) (None, 64) 93440 dense_1 (Dense) (None, 1) 65 ================================================================= Total params: 6093505 (23.24 MB) Trainable params: 6093505 (23.24 MB) Non-trainable params: 0 (0.00 Byte) _________________________________________________________________
4. 모델 학습¶
nlp_history = nlp_model.fit(X_train, y_train, epochs=5, batch_size=64, validation_split=0.2)
Epoch 1/5 1875/1875 [==============================] - 256s 135ms/step - loss: 0.4802 - accuracy: 0.7466 - val_loss: 0.4301 - val_accuracy: 0.7860 Epoch 2/5 1875/1875 [==============================] - 250s 133ms/step - loss: 0.3728 - accuracy: 0.8103 - val_loss: 0.4378 - val_accuracy: 0.7831 Epoch 3/5 1875/1875 [==============================] - 254s 135ms/step - loss: 0.3182 - accuracy: 0.8335 - val_loss: 0.4987 - val_accuracy: 0.7772 Epoch 4/5 1875/1875 [==============================] - 251s 134ms/step - loss: 0.2771 - accuracy: 0.8511 - val_loss: 0.5231 - val_accuracy: 0.7740 Epoch 5/5 458/1875 [======>.......................] - ETA: 3:06 - loss: 0.2312 - accuracy: 0.8747
5. 모델 평가 및 예측¶
test_loss, test_acc = nlp_model.evaluate(X_test, y_test)
print(f'Test Accuracy: {test_acc:.4f}')
1563/1563 [==============================] - 31s 20ms/step - loss: 0.5949 - accuracy: 0.7584 Test Accuracy: 0.7584
test_sentence = '지루할 줄 알았는데 너무 재밌었다'
test_sentence = test_sentence.split(' ')
test_sentences =[]
now_sentence = []
for word in test_sentence:
now_sentence.append(word)
test_sentences.append(now_sentence[:])
test_X_1 = tokenizer.texts_to_sequences(test_sentences)
test_X_1 = pad_sequences(test_X_1, padding = 'post', maxlen=max_len)
prediction = nlp_model.predict(test_X_1)
for idx, sentence in enumerate(test_sentences):
print(sentence)
print(prediction[idx])
1/1 [==============================] - 0s 475ms/step ['지루할'] [0.49168205] ['지루할', '줄'] [0.48779213] ['지루할', '줄', '알았는데'] [0.40793136] ['지루할', '줄', '알았는데', '너무'] [0.45090854] ['지루할', '줄', '알았는데', '너무', '재밌었다'] [0.9056931]
test_sentence = '괜찮을 줄 알았는데 지루하고 재미없었다.'
test_sentence = test_sentence.split(' ')
test_sentences =[]
now_sentence = []
for word in test_sentence:
now_sentence.append(word)
test_sentences.append(now_sentence[:])
test_X_1 = tokenizer.texts_to_sequences(test_sentences)
test_X_1 = pad_sequences(test_X_1, padding = 'post', maxlen=max_len)
prediction = nlp_model.predict(test_X_1)
for idx, sentence in enumerate(test_sentences):
print(sentence)
print(prediction[idx])
1/1 [==============================] - 0s 41ms/step ['괜찮을'] [0.7870225] ['괜찮을', '줄'] [0.6561334] ['괜찮을', '줄', '알았는데'] [0.38337335] ['괜찮을', '줄', '알았는데', '지루하고'] [0.15542373] ['괜찮을', '줄', '알았는데', '지루하고', '재미없었다.'] [0.00052879]
<자연어 처리> 다음으로
기계 번역 : Seq2Seq와 Attention
https://sjh9708.tistory.com/230
Transformer : 간단한 챗봇 만들기
https://sjh9708.tistory.com/231
해당 포스팅의 내용은 "상명대학교 민경하 교수님 "인공지능" 수업, 상명대학교 김승현 교수님 "딥러닝"수업을 기반으로 작성하였으며, 포스팅 자료는 해당 내용을 기반으로 재구성하여 만들어 사용하였습니다.
'Data Science > 머신러닝 & 딥러닝' 카테고리의 다른 글
[딥러닝] Transformer : 소개와 동작 원리 (+ 간단한 챗봇 만들기) (0) | 2024.06.11 |
---|---|
[딥러닝] 기계 번역 : Seq2Seq와 Attention (+ 모델 학습시켜 다국어 번역해보기) (0) | 2024.06.11 |
[딥러닝] 기억하는 신경망 : RNN, 그리고 개선 모델 (LSTM, GRU) (0) | 2024.06.08 |
[딥러닝] CNN : ResNet 모델로 동물 이미지 분류하기(CIFAR 이미지셋) (0) | 2024.06.08 |
[딥러닝] CNN : 이미지 학습을 위한 신경망 (+ MNIST 손글씨 분류해보기) (1) | 2024.06.08 |