본문 바로가기
Natural Language Processing

[Goorm] 딥러닝을 이용한 자연어 처리 2 (IMDB 이용)

by 자몽먹은토끼 2024. 7. 5.
728x90
반응형

IMDB 셋을 가져와 텍스트 데이터 다루기

; Internet Movie DataBase 영화에 대한 리뷰가 담긴 텍스트 데이터

 

 

심화 실습

 

1. 데이터준비

import os
ac_dir= '/content/aclImdb'
train_dir = os.path.join(ac_dir,'train')
test_dir = os.path.join(ac_dir,'test')

texts = []
labels = []

for label in ['neg','pos']:
    txts_dir= os.path.join(train_dir,label)
    for fname in os.listdir(txts_dir):
        if fname[-4:] == '.txt':
            with open(os.path.join(txts_dir,fname),encoding='utf-8') as f:
                texts.append(f.read())
            labels.append(0 if label == 'neg' else 1)

print(texts[0])
print(labels[0])
print(texts[12500])
print(labels[12500])
# neg:0, pos:1

> texts리스트와 labels리스트에 각각 데이터 담기 

> 각 25,000개

 

 

2. 데이터 전처리

import numpy as np
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences

maxlen= 200
training_samples= 10000
validation_samples= 10000
max_words= 10000            # 최다빈도 단어 10000개

# 토큰화 및 패딩
token= Tokenizer(num_words=max_words)
token.fit_on_texts(texts)
sequences= token.texts_to_sequences(texts)
pad_seq= pad_sequences(sequences,maxlen=maxlen)

# 데이터 셔플 및 분할
indices= np.arange(pad_seq.shape[0])
np.random.shuffle(indices)
data= pad_seq[indices]
labels= labels[indices]

x_train= data[:training_samples]
y_train= labels[:training_samples]
x_val= data[training_samples:training_samples+validation_samples]
y_val= labels[training_samples:training_samples+validation_samples]

> 특징과 레이블을 두 개의 넘파이 배열에 따로 저장한 경우 다음처럼 인덱스를 무작위로 뒤섞는 방법을 사용하여 

두개의 배열을 같은 순서로 뒤섞을 수 있다.

> ex) data = [5, 2, 4, 3, 1, 0]
         labels = [5, 2, 4, 3, 1, 0]

 

※ 만약 texts나 labels의 shape문제가 발생한다면, 아래와 같은 numpy배열로 바꿔주는 코드를 넣을 것! 

labels= np.asarray(labels)

 

 

 

3. 모델 정의 및 학습

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Embedding, Bidirectional, LSTM, Dense, Dropout
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint

# 모델 정의
model= Sequential()
model.add(Embedding(max_words,64,input_length=maxlen))
model.add(Bidirectional(LSTM(64, return_sequences= True)))
model.add(Dropout(0.5))
model.add(Bidirectional(LSTM(64, return_sequences= True)))
model.add(Dense(1,activation='sigmoid'))

model.compile(optimizer='adam',loss='binary_crossentropy',metrics=['acc'])    # rmsprop vs adam

early_stopping= EarlyStopping(monitor='val_loss',patience= 5, restore_best_weights= True)
model_checkpoint= ModelCheckpoint('best_model.keras',monitor='val_loss',save_best_only= True)

history= model.fit(x_train,y_train,epochs=10,batch_size=64,validation_data=(x_val,y_val),callbacks=[early_stopping,model_checkpoint])
  • Embedding( ) : 각 토큰을 특정 차원의 벡터로 변환시킨다.
    • 첫번째 인자 : 고유 토큰의 개수, 데이터 셋에서 최다 빈도 상위 n개의 토큰
    • 두번째 인자 : 각 토큰을 몇차원의 벡터로 변환시킬 것인가
    • input_length : 패딩 시 패딩의 길이, 각 문장마다의 길이 (패딩하여 같게 맞춰줄 것!)
  • Bidirectional  (LSTM ( ) ) : 일반적인 LSTM은 순방향으로 정보를 추출하지만 역방향으로도 정보를 추출해서 이용할 수 있는데, 이를 양방향 LSTM 이라고 한다.
    양방향 LSTM의 경우, 양방향의 정보를 결합하기 때문에 시퀀스 데이터에서 더 많은 정보를 추출할 수 있어 좋은 성능을 나타낸다.
    • 64 : 64개의 차원으로 출력
    • return_sequences : 시퀀스 마다 출력을 추출할 것인가, 모든 타임스텝마다 출력을 반환할 것인가
  • Dropout ( ) : 학습 시마다 0-1 사이 비율의 뉴런을 무작위로 사용하지 않고 버린다. 과적합 방지를 위함이며, 일반화 능력을 향상시킨다. 
  • Dense ( ) : 이진 분류(?)를 수행하는 출력 레이어
    • 출력 뉴런의 수 : 이진분류의 경우, 단일 뉴런을 사용
    • activation : 활성화 함수
  • EarlyStopping ( ) : 조기 중단 함수, 학습 중 과적합을 방지하기 위해 중간에 학습을 중단시킨다
    • monitor : 해당 값을 기준으로 조기중단의 실행을 결정
    • patience : 이 횟수 이상으로 값이 나아지지 않을 경우, 조기중단이 발생
    • restore_best_weights : monitor값이 가장 나았던 에포크의 가중치로 모델을 복원한다. (loss의 경우 작을때, acc의 경우 클때)
  • ModelCheckpoint ( ) : 모델의 체크포인트를 저장, 나중에 저장된 체크포인트를 불러와 사용 가능
    • 첫번째 인자 : 모델 저장 경로 및 이름 ex) ' /Desktop/best_model.keras '
    • monitor : 해당 값을 기준으로 모델 가중치를 저장할건지 결정
    • save_best_only : monitor에 해당하는 메트릭이 개선될 때만 모델을 저장

 

 

4. 테스트

# 모델을 사용하여 예측 단문/장문
test_texts = [
    "I hated this movie. It was terrible and the acting was horrible.",
    "This was the worst film I have ever seen. Not worth the time.",
    "I loved this movie. It was fantastic and the acting was great.",
    "This was the best film I have seen in a long time. Totally worth it.",
    "I had high hopes for this movie, but it was a complete letdown. The storyline was incredibly dull, and the pacing was excruciatingly slow. The characters lacked depth, making it hard to care about their fates. Overall, a waste of time.",
    "This film was a disaster from start to finish. The dialogue was cringe-worthy, and the special effects looked outdated. I couldn't believe how poorly executed the entire production was. Definitely one to avoid.",
    "What an amazing film! The plot was deeply engaging, keeping me on the edge of my seat throughout. The actors delivered powerful performances that brought the story to life. This movie is a must-watch for everyone.",
    "I was thoroughly impressed by this film. The cinematography was stunning, capturing the beauty of every scene. The story was heartwarming and inspiring, and the music perfectly complemented the mood. An outstanding cinematic experience."
]

test_sequences= token.texts_to_sequences(test_texts)
test_data= pad_sequences(test_sequences,maxlen=maxlen)

# 저장된 모델 로드
from tensorflow.keras.models import load_model
best_model= load_model('best_model.keras', custom_objects= None, compile= True)

predictions= model.predict(test_data)

for i, test_data in enumerate(test_texts):
    print('text: ',test_data[:20],'...')
    print('prediction: ','positive' if predictions[i][0] > 0.5 else 'negative','(확률',predictions[i][0],')')

> 테스트 시에는 테스트 텍스트를 시퀀스데이터로 바꿔주고 패딩 시킨다. ( 학습전처리와 동일하게)

text:  I hated this movie.  ...
prediction:  negative (확률 [0.11365569] )
text:  This was the worst f ...
prediction:  negative (확률 [0.14768119] )
text:  I loved this movie.  ...
prediction:  positive (확률 [0.8399998] )
text:  This was the best fi ...
prediction:  positive (확률 [0.8393788] )
text:  I had high hopes for ...
prediction:  negative (확률 [0.11349824] )
text:  This film was a disa ...
prediction:  negative (확률 [0.11352557] )
text:  What an amazing film ...
prediction:  positive (확률 [0.84009147] )
text:  I was thoroughly imp ...
prediction:  positive (확률 [0.8400203] )

 

 

 

728x90
반응형