NLP QUESTION
For this task you will build a classifier for the sarcasm dataset
The classifier should have a final layer with 1 neuron activated by sigmoid as shown.
It will be tested against a number of sentences that the network hasn't previously seen
And you will be scored on whether sarcasm was correctly detected in those sentences
์์ฐ์ด ์ฒ๋ฆฌ
์ด ์์ ์์๋ sarcasm ๋ฐ์ดํฐ ์ธํธ์ ๋ํ ๋ถ๋ฅ๊ธฐ๋ฅผ ์์ฑํฉ๋๋ค.
๋ถ๋ฅ๊ธฐ๋ 1 ๊ฐ์ ๋ด๋ฐ์ผ๋ก ์ด๋ฃจ์ด์ง sigmoid ํ์ฑํจ์๋ก ๊ตฌ์ฑ๋ ์ต์ข ์ธต์ ๊ฐ์ ธ์ผํฉ๋๋ค.
์ ์ถ๋ ๋ชจ๋ธ์ ๋ฐ์ดํฐ์ ์ด ์๋ ์ฌ๋ฌ ๋ฌธ์ฅ์ ๋ํด ํ ์คํธ๋ฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ๋น์ ์ ๊ทธ ๋ฌธ์ฅ์์ sarcasm ํ๋ณ์ด ์ ๋๋ก ๊ฐ์ง๋์๋์ง์ ๋ฐ๋ผ ์ ์๋ฅผ ๋ฐ๊ฒ ๋ ๊ฒ์ ๋๋ค
ํ์ํ ๋ชจ๋์ 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 Embedding, LSTM, Dense, Bidirectional, Flatten
from tensorflow.keras.models import Sequential
from tensorflow.keras.callbacks import ModelCheckpoint
tensorflow-datasets๋ฅผ ํ์ฉํฉ๋๋ค.
ํ์ํ ๋ฐ์ดํฐ์ธํธ๋ฅผ ๋ค์ด๋ก๋ํฉ๋๋ค.
url = 'https://storage.googleapis.com/download.tensorflow.org/data/sarcasm.json'
urllib.request.urlretrieve(url, 'sarcasm.json')
## Json ํ์ผ ๋ก๋
with open('sarcasm.json') as f:
datas = json.load(f)
datas
5๊ฐ ์ถ๋ ฅํด๋ด
์๋ค.
article_link
: ๋ด์ค ๊ธฐ์ฌ URLheadline
: ๋ด์ค๊ธฐ์ฌ์ ์ ๋ชฉis_sarcastic
: ๋น๊ผฌ๋ ๊ธฐ์ฌ ์ฌ๋ถ (๋น๊ผผ: 1, ์ผ๋ฐ: 0)datas[:5]
๋น list๋ฅผ ์์ฑํฉ๋๋ค. (sentences, labels)
sentences = []
labels = []
for data in datas:
sentences.append(data['headline'])
labels.append(data['is_sarcastic'])
๋ฌธ์ฅ 5๊ฐ๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
sentences[:5]
labels[:5]
20,000๊ฐ๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ฐ์ดํฐ์ ์ ๋ถ๋ฆฌํฉ๋๋ค.
training_size = 20000
train_sentences = sentences[:training_size]
train_labels = labels[:training_size]
validation_sentences = sentences[training_size:]
validation_labels = labels[training_size:]
๋จ์ด์ ํ ํฐํ๋ฅผ ์งํํฉ๋๋ค.
num_words
: ๋จ์ด max ์ฌ์ด์ฆ๋ฅผ ์ง์ ํฉ๋๋ค. ๊ฐ์ฅ ๋น๋์๊ฐ ๋์ ๋จ์ด๋ถํฐ ์ ์ฅํฉ๋๋ค.oov_token
: ๋จ์ด ํ ํฐ์ ์๋ ๋จ์ด๋ฅผ ์ด๋ป๊ฒ ํ๊ธฐํ ๊ฒ์ธ์ง ์ง์ ํด์ค๋๋ค.vocab_size = 1000
oov_tok = "<OOV>"
tokenizer = Tokenizer(num_words=vocab_size, oov_token='<OOV>')
fit_on_texts
๋ก ํ์ตํ ๋ฌธ์ฅ์ ๋ํ์ฌ ํ ํฐํ๋ฅผ ์งํํฉ๋๋ค.
tokenizer.fit_on_texts(train_sentences)
for key, value in tokenizer.word_index.items():
print('{} \t======>\t {}'.format(key, value))
if value == 25:
break
ํ ํฐํ๋ ๋จ์ด ์ฌ์ ์ ๊ฐฏ์
len(tokenizer.word_index)
๋จ์ด์ฌ์ ์ dictionary ํํ๋ก ๋์ด ์์ต๋๋ค.
์ฆ, ๋จ์ด๋ฅผ key๋ก ์ ๋ ฅํ๋ฉด ๊ฐ์ return ํฉ๋๋ค.
word_index = tokenizer.word_index
word_index['trump']
word_index['hello']
texts_to_sequences
: ๋ฌธ์ฅ์ ์ซ์๋ก ์นํ ํฉ๋๋ค. Train Set, Valid Set ๋ชจ๋ ๋ณ๋๋ก ์ ์ฉํด์ฃผ์ด์ผ ํฉ๋๋ค.
train_sequences = tokenizer.texts_to_sequences(train_sentences)
validation_sequences = tokenizer.texts_to_sequences(validation_sentences)
๋ณํ๋ Sequences ํ์ธ
train_sequences[:5]
3๊ฐ์ง ์ต์ ์ ์ ๋ ฅํด ์ค๋๋ค.
maxlen
: ์ต๋ ๋ฌธ์ฅ ๊ธธ์ด๋ฅผ ์ ์ํฉ๋๋ค. ์ต๋ ๋ฌธ์ฅ๊ธธ์ด๋ณด๋ค ๊ธธ๋ฉด, ์๋ผ๋
๋๋ค.truncating
: ๋ฌธ์ฅ์ ๊ธธ์ด๊ฐ maxlen
๋ณด๋ค ๊ธธ ๋ ์์ ์๋ฅผ์ง ๋ค๋ฅผ ์๋ฅผ์ง ์ ์ํฉ๋๋ค.padding
: ๋ฌธ์ฅ์ ๊ธธ์ด๊ฐ maxlen
๋ณด๋ค ์งง์ ๋ ์ฑ์์ค ๊ฐ์ ์์ ์ฑ์ธ์ง, ๋ค๋ฅผ ์ฑ์ธ์ง ์ ์ํฉ๋๋ค.# ํ ๋ฌธ์ฅ์ ์ต๋ ๋จ์ด ์ซ์
max_length = 120
# ์๋ผ๋ผ ๋ฌธ์ฅ์ ์์น
trunc_type='post'
# ์ฑ์์ค ๋ฌธ์ฅ์ ์์น
padding_type='post'
train_padded = pad_sequences(train_sequences, maxlen=max_length, truncating=trunc_type, padding=padding_type)
validation_padded = pad_sequences(validation_sequences, maxlen=max_length, padding=padding_type, truncating=trunc_type)
๋ณํ๋ Sequences ํ์ธ
train_padded.shape
model์ด list
type์ ๋ฐ์๋ค์ด์ง ๋ชปํ๋ฏ๋ก, numpy array๋ก ๋ณํํฉ๋๋ค.
train_labels = np.array(train_labels)
validation_labels = np.array(validation_labels)
๊ณ ์ฐจ์์ ์ ์ฐจ์์ผ๋ก ์ถ์์์ผ์ฃผ๋ ์ญํ ์ ํฉ๋๋ค.
one-hot encoding์ ์งํํ์ ๋, 1000์ฐจ์์ผ๋ก ํํ๋๋ ๋จ์ด๋ค์ 16์ฐจ์์ผ๋ก ์ค์ฌ์ฃผ๋ ๊ฒ๋๋ค. ๊ทธ๋ ๊ฒ ํด์ sparsity
๋ฌธ์ ๋ฅผ ํด์ํ๋๋ก ์ ๋ํฉ๋๋ค.
embedding_dim = 16
sample = np.array(train_padded[0])
sample
x = Embedding(vocab_size, embedding_dim, input_length=max_length)
x(sample)[0]
์ด์ Modeling์ ํ ์ฐจ๋ก์ ๋๋ค.
model = Sequential([
Embedding(vocab_size, embedding_dim, input_length=max_length),
Bidirectional(LSTM(64, return_sequences=True)),
Bidirectional(LSTM(64)),
Dense(32, activation='relu'),
Dense(16, activation='relu'),
Dense(1, activation='sigmoid')
])
model.summary()
optimizer
๋ ๊ฐ์ฅ ์ต์ ํ๊ฐ ์๋๋ ์๊ณ ๋ฆฌ์ฆ์ธ 'adam'์ ์ฌ์ฉํฉ๋๋ค.loss
๋ ์ด์ง ๋ถ๋ฅ์ด๊ธฐ ๋๋ฌธ์ binary_crossentropy
๋ฅผ ์ฌ์ฉํฉ๋๋ค.model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['acc'])
val_loss
๊ธฐ์ค์ผ๋ก epoch ๋ง๋ค ์ต์ ์ ๋ชจ๋ธ์ ์ ์ฅํ๊ธฐ ์ํ์ฌ, ModelCheckpoint๋ฅผ ๋ง๋ญ๋๋ค.
checkpoint_path
๋ ๋ชจ๋ธ์ด ์ ์ฅ๋ ํ์ผ ๋ช
์ ์ค์ ํฉ๋๋ค.ModelCheckpoint
์ ์ ์ธํ๊ณ , ์ ์ ํ ์ต์
๊ฐ์ ์ง์ ํฉ๋๋ค.checkpoint_path = 'my_checkpoint.ckpt'
checkpoint = ModelCheckpoint(checkpoint_path,
save_weights_only=True,
save_best_only=True,
monitor='val_loss',
verbose=1)
epochs=10
history = model.fit(train_padded, train_labels,
validation_data=(validation_padded, validation_labels),
callbacks=[checkpoint],
epochs=epochs)
ํ์ต์ด ์๋ฃ๋ ํ์๋ ๋ฐ๋์ load_weights
๋ฅผ ํด์ฃผ์ด์ผ ํฉ๋๋ค.
๊ทธ๋ ์ง ์์ผ๋ฉด, ์ด์ฌํ ModelCheckpoint๋ฅผ ๋ง๋ ์๋ฏธ๊ฐ ์์ต๋๋ค.
# checkpoint ๋ฅผ ์ ์ฅํ ํ์ผ๋ช
์ ์
๋ ฅํฉ๋๋ค.
model.load_weights(checkpoint_path)
import matplotlib.pyplot as plt
plt.figure(figsize=(12, 9))
plt.plot(np.arange(1, epochs+1), history.history['loss'])
plt.plot(np.arange(1, epochs+1), history.history['val_loss'])
plt.title('Loss / Val Loss', fontsize=20)
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend(['loss', 'val_loss'], fontsize=15)
plt.show()
plt.figure(figsize=(12, 9))
plt.plot(np.arange(1, epochs+1), history.history['acc'])
plt.plot(np.arange(1, epochs+1), history.history['val_acc'])
plt.title('Acc / Val Acc', fontsize=20)
plt.xlabel('Epochs')
plt.ylabel('Acc')
plt.legend(['acc', 'val_acc'], fontsize=15)
plt.show()