🔥알림🔥
① 테디노트 유튜브 -
구경하러 가기!
② LangChain 한국어 튜토리얼
바로가기 👀
③ 랭체인 노트 무료 전자책(wikidocs)
바로가기 🙌
④ RAG 비법노트 LangChain 강의오픈
바로가기 🙌
⑤ 서울대 PyTorch 딥러닝 강의
바로가기 🙌
[tensorflow] 단어 토큰화, Embedding, LSTM layer를 활용한 뉴스 데이터 sarcasm 판단
캐글의 뉴스의 Sarcasm 에 대한 판단을 해주는 딥러닝 모델을 tensorflow 2.0을 활용하여 만들어 보겠습니다.
sarcastic (sarcasm)
- 미국식 [sɑːrˈk-] 영국식 [sɑːˈkæstɪk]
- 뜻: 빈정대는, 비꼬는
출처: 네이버사전
개요
뉴스 기사의 헤드라인(영문장)을 통하여 sarcasm (비꼬는 기사) 인지 아닌지 여부를 판단하는 classification
문제입니다.
0. 필요한 라이브러리 import
import json
import tensorflow as tf
import numpy as np
import urllib
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.layers import Dense, Embedding, LSTM, Bidirectional
from tensorflow.keras.models import Sequential
1. sarcasm 데이터 로드
url = 'https://storage.googleapis.com/download.tensorflow.org/data/sarcasm.json'
urllib.request.urlretrieve(url, 'sarcasm.json')
json.load()를 활용하여 sarcasm 데이터를 로드합니다.
with open('sarcasm.json', 'r') as f:
data = json.load(f)
data[:5]
article_link
에는 신문기사의 링크가, headline
에는 신문 기사의 헤드라인이, is_sarcastic
에는 sarcasm 여부를 판단하는 label이 표기되어 있습니다.
2. feature, label 정의
sentences = []
labels = []
for d in data:
sentences.append(d['headline'])
labels.append(d['is_sarcastic'])
3. train, validation dataset 분할
# train dataset을 사용할 ratio를 정의합니다.
train_ratio = 0.8
train_size = int(len(data) * train_ratio)
train_size, len(data)
# train 분할
train_sentences = sentences[:train_size]
valid_sentences = sentences[train_size:]
# label 분할
train_labels = labels[:train_size]
valid_labels = labels[train_size:]
4. 토근화 (Tokenize)
vocab_size 는 Token화 진행시 최대 빈도숫자가 높은 1000개의 단어만을 활용하고 나머지는
vocab_size = 1000
token = Tokenizer(num_words=vocab_size, oov_token='<OOV>')
token.fit_on_texts(sentences)
word_index = token.word_index
word_index
단어: index로 맵핑된 dict 가 완성되었음을 확인할 수 있습니다.
word_index['party']
5. Sequence로 변환
train_sequences = token.texts_to_sequences(train_sentences)
valid_sequences = token.texts_to_sequences(valid_sentences)
단어로 이루어진 sentences를 Tokenizer
를 통해 기계가 알아들을 수 있는 numerical value로 변환하였습니다.
train_sentences[:5]
train_sequences[:5]
6. 문장의 길이 맞추기 (pad_sequences)
학습을 위해서는 input의 길이가 동일 해야합니다.
지금의 sequences는 길이가 들쭉날쭉합니다.
pad_sequences를 통해 길이를 맞춰주고, 길이가 긴 문장을 자르거나, 길이가 짧은 문장은 padding 처리를 해줄 수 있습니다.
padding 처리를 한다는 말은 0이나 특정 constant로 채워 준다는 의미 이기도 합니다.
pad_sequences
옵션 값
- truncating: 'post' / 'pre'- 문장의 길이가
maxlen
보다 길 때, 뒷 / 앞 부분을 잘라줍니다. - padding: 'post' / 'pre' - 문장의 길이가
maxlen
보다 길 때, 뒷 / 앞 부분을 잘라줍니다. - maxlen: 최대 문장 길이를 정의합니다.
_truncating = 'post'
_padding = 'post'
_maxlen = 120
train_padded = pad_sequences(train_sequences, truncating=_truncating, padding=_padding, maxlen=_maxlen)
valid_padded = pad_sequences(valid_sequences, truncating=_truncating, padding=_padding, maxlen=_maxlen)
7. label을 np.array로 변환
list 타입은 허용하지 않기 때문에, labels를 np.array
로 변환합니다.
train_labels = np.asarray(train_labels)
valid_labels = np.asarray(valid_labels)
train_labels, valid_labels
8. 모델링 (Modeling)
현재 vocab_size = 1000으로 정의되어 있기때문에 우리의 단어들은 1000차원 공간안에 정의되어 있다고 볼 수 있습니다.
우리는 이를 16차원으로 내려 Data Sparsity를 해결하고 효율적으로 학습할 수 있도록 합니다.
embedding_dim = 16
model = Sequential([
Embedding(vocab_size, embedding_dim, input_length=_maxlen),
Bidirectional(LSTM(32)),
Dense(24, activation='relu'),
Dense(1, activation='sigmoid')
])
model.summary()
9. Callback 정의 - validation best weight를 저장하기 위함
validation performance가 갱신이 될 때마다 저장합니다. (나중에 이를 load 하여 prediction할 예정입니다)
checkpoint_path = 'best_performed_model.ckpt'
checkpoint = tf.keras.callbacks.ModelCheckpoint(checkpoint_path,
save_weights_only=True,
save_best_only=True,
monitor='val_loss',
verbose=1)
adam
optimizer를 사용하며, 0, 1을 맞추는 것이므로 binary_crossentropy
를 사용합니다.
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
history = model.fit(train_padded, train_labels,
validation_data=(valid_padded, valid_labels),
callbacks=[checkpoint],
epochs=20,
verbose=2)
10. best model의 weight load
model.load_weights(checkpoint_path)
이제 새로운 데이터에 대하여 똑같이 토큰화 - 텍스트를 시퀀스 변환 - pad_sequence 스텝으로 처리한 후
우리가 정의한 model로 prediction을 할 수 있습니다.
11. 시각화
import matplotlib.pyplot as plt
%matplotlib inline
Loss
plt.figure(figsize=(12, 6))
plt.plot(np.arange(20)+1, history.history['loss'], label='Loss')
plt.plot(np.arange(20)+1, history.history['val_loss'], label='Validation Loss')
plt.title('losses over training', fontsize=20)
plt.xlabel('epochs', fontsize=15)
plt.ylabel('loss', fontsize=15)
plt.legend()
plt.show()
Accuracy
plt.figure(figsize=(12, 6))
plt.plot(np.arange(20)+1, history.history['accuracy'], label='Accuracy')
plt.plot(np.arange(20)+1, history.history['val_accuracy'], label='Validation Accuracy')
plt.title('Accuracy over training', fontsize=20)
plt.xlabel('epochs', fontsize=15)
plt.ylabel('Accuracy', fontsize=15)
plt.legend()
plt.show()
정리
- epoch=2 이후로는 validation loss가 증가하는 모습입니다. (overfitting 문제가 있을 수 있습니다)
- accuracy는 82%대에서 epoch이 늘어나도 크게 변동이 없어보입니다.
- Dense Layer를 깊게 쌓아 보거나, Conv1D, 혹은 LSTM을 두겹으로 쌓는 등 모델 개선의 여지는 충분히 있습니다.
댓글남기기