안녕하세요. 문범우입니다.
이번 포스팅에서는 TensorFlow tutorial의 두번째인, Text classification에 대해서 진행해보았습니다.
1. Text Classification¶
https://www.tensorflow.org/tutorials/keras/basic_text_classification?hl=ko
by doorbw (https://doorbw.tistory.com)
# TensorFlow and tf.keras
# 텐서플로우와 keras를 import한다. 이떄 tensorflow는 tf라는 별칭으로 사용할 것임.
import tensorflow as tf
from tensorflow import keras
# Helper libraries
# numpy와 matplotlib을 사용한다.
import numpy as np
import matplotlib.pyplot as plt
# jupyter notebook에서 matplotlib을 사용하기 위한 매직커맨드
%matplotlib inline
print("사용되는 tensorflow의 버전:",tf.__version__)
ㄱ. 데이터준비¶
이번 text classification 실습을 위한 데이터는 keras dataset에 있는 imdb를 사용한다.
(해당 데이터는 영화에 대한 review 내용이다.)
아래에서 확인해볼 수 있겠지만 train과 test 데이터 셋은 각각 25,000개 이며 데이터는 review자체로 구성되어 있다.
또한 labels는 0또는 1값으로 해당 review가 긍정적인 것인지 부정적인 것인지를 나타낸다.
따라서 우리는 test데이터를 이용하여 해당 Review가 영화에 대해 긍정적인 것인지, 부정적인 것인지를 예측해본다.
데이터의 자세한 내용은 아래에서 확인해본다.
imdb = keras.datasets.imdb
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)
# training data 확인
print("Training entries: {}, labels: {}".format(len(train_data), len(train_labels)))
training data는 위와 같다.
하지만, 실제로 데이터를 하나 찍어보면 string이 아닌 integer 값이 리스트로 들어있다.
print(train_data[0])
이렇게 되어 있는 이유는, 추가적인 dictionary에 각 숫자와 단어가 매칭되어 있기 때문이다.
또한 아래와 같이 각각의 데이터의 길이도 다른 것을 확인할 수 있다.
len(train_data[0]), len(train_data[1])
하지만 실제로 우리가 ML모델에 넣어줄때, 입력의 길이는 모두 같아야 한다.
따라서 우리는 추후에 입력의 길이가 다른 것에 대한 컨트롤을 진행한다.
먼저 데이터를 보다 자세히 확인해보기 위해 각 데이터의 숫자를 단어로 치환해본다.
# 숫자로 된 값을 단어로 바꾸기 위한 dictionary를 가져온다
word_index = imdb.get_word_index()
#word_index #블로그 길이때문에 주석처리함
#word_index.items() #블로그 길이때문에 주석처리함.
word_index라는 dictionary는 단어가 key, 숫자가 value로 되어있다.
추가적으로, pad, start, unknown, unused 값을 나타내기 위해 각 value에 3을 더하고 비어있게 되는 0~3에 각각을 할당한다.
# The first indices are reserved
word_index = {k:(v+3) for k,v in word_index.items()}
word_index["<PAD>"] = 0
word_index["<START>"] = 1
word_index["<UNK>"] = 2 # unknown
word_index["<UNUSED>"] = 3
또한 실제로 우리가 필요한 dictionary는 숫자가 key이고, 단어가 value인 dictionary이기 때문에,
reverse_word_index 라는 dictionary를 구성하고 숫자로 이루어진 입력데이터를 단어로 치환해주며 문장으로 출력하는는 decode_review함수를 만든다.
reverse_word_index = dict([(value, key) for (key, value) in word_index.items()])
def decode_review(text):
return ' '.join([reverse_word_index.get(i, '?') for i in text])
# 하나의 입력데이터를 문장으로 확인해보자
decode_review(train_data[0])
앞에서 추가해주었던 start, unk 등이 추가되어 보여지는 것을 확인할 수 있다.
ㄴ. 데이터 전처리¶
실제로 우리의 데이터를 ML모델에 입력하기 위해 데이터 전처리를 진행한다.
먼저 위에서 언급했던 각 데이터의 길이가 상이한 것을 처리한다.
keras에서 제공하는 preprocessing 함수를 이용하여 모든 데이터를 최대길이로 늘려주면서 빈공간에는 위에서 dictionary에 추가적으로 넣어주었던 pad값을 이용한다.
train_data = keras.preprocessing.sequence.pad_sequences(train_data,
value=word_index["<PAD>"],
padding='post',
maxlen=256)
test_data = keras.preprocessing.sequence.pad_sequences(test_data,
value=word_index["<PAD>"],
padding='post',
maxlen=256)
train데이터와 test데이터를 같이 작업하였고, 이를 통한 입력데이터를 확인해본다.
print("길이가 동일한가? => 0번째 데이터 길이:",len(train_data[0]),"1번째 데이터 길이",len(train_data[1]))
tmp_len_check = 0
tmp_len = 256
for data in train_data:
if(tmp_len == len(data)): tmp_len_check += 1
if(tmp_len_check == len(train_data)):
print("모든 데이터의 길이가 256으로 동일합니다!")
else:
print("데이터의 길이가 동일하지 않습니다!")
print("데이터 형태는?\n",train_data[0])
위와 같이 데이터 길이가 서로 동일한 것을 확인할 수 있고, 실제로 0번째 데이터를 확인해보았을때 맨 뒤에 0값, 즉 pad값이 포함된 것을 확인할 수 있다.
ㄷ. 모델 구성하기¶
이제 text classification을 수행할 ML모델을 만들어보자.
먼저 vocab_size 는 영화리뷰에 사용되는 단어의 개수이다.
실제로 위에서의 단어와 숫자를 매칭하는 dictionary의 사이즈는 보다 크지만, 해당 데이터에서는 10000개의 단어 이내에로 리뷰가 작성되었다.
각 레이어에 대한 설명은 다음과 같다.
- embedding 해당 레이어는 숫자로 인코딩 되어있는 각 단어를 사용하며 각 단어 인덱스에 대한 벡터를 찾는다.
이러한 벡터는 추후 model이 학습하는데 사용된다.
- GlobalAveragePooling1D 해당 레이어에서는 각 예시에 대해 sequence 차원을 평균하여 고정된 길이의 벡터를 출력한다.
이를 통해 가변적인 길이의 입력을 간단하게 처리할 수 있다.
- Dense_1, Dense_2 첫번째 Dense 레이어를 통해서, 고정길이로 출력된 vector 값을 통해 16개의 hidden unit을 가진 fully-connected layer를 통과시킨다.
이후 두번째 Dense 레이어는 단일 출력 노드를 가짐고 시그모이드 활성화 함수를 사용함으로써 결과에 대해 0 ~ 1 사이의 값을 가지도록 한다.
# input shape is the vocabulary count used for the movie reviews (10,000 words)
vocab_size = 10000
model = keras.Sequential()
model.add(keras.layers.Embedding(vocab_size, 16))
model.add(keras.layers.GlobalAveragePooling1D())
model.add(keras.layers.Dense(16, activation=tf.nn.relu))
model.add(keras.layers.Dense(1, activation=tf.nn.sigmoid))
model.summary()
모델 구성에 대한 마지막으로 loss function과 optimizer를 설정한다.
model.compile(optimizer=tf.train.AdamOptimizer(),
loss='binary_crossentropy',
metrics=['accuracy'])
ㄹ. 모델 훈련하기¶
모델을 훈련하기에 앞서 우리는 10,000개의 데이터를 따로 떼어 validation set을 만든다.
이렇게 하는 이유는 모델이 새롭게 접하는 데이터에 대한 accuracy와 loss 등을 확인해보기 위해서이다.
x_val = train_data[:10000]
partial_x_train = train_data[10000:]
y_val = train_labels[:10000]
partial_y_train = train_labels[10000:]
history = model.fit(partial_x_train,
partial_y_train,
epochs=40,
batch_size=512,
validation_data=(x_val, y_val),
verbose=1)
results = model.evaluate(test_data, test_labels)
print(results)
위를 통해 우리의 모델은 test데이터 기반, 약 87%의 정확도를 가짐을 볼 수 있다.
실제로 더 진보된 모델이라고 하기 위해서는 약 95%이상의 정확도를 필요로 한다.
일단 이정도로 하고, 위에서 결과로 확인한 정확도와 오차 등을 그래프로 확인해보고 마무리한다.
history_dict = history.history
history_dict.keys()
acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(1, len(acc) + 1)
# "bo" is for "blue dot"
plt.plot(epochs, loss, 'bo', label='Training loss')
# b is for "solid blue line"
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()
plt.clf() # clear figure
acc_values = history_dict['acc']
val_acc_values = history_dict['val_acc']
plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.show()
'AI & BigData > TensorFlow' 카테고리의 다른 글
텐서플로우(tensor flow) 튜토리얼 #4_Overfitting and Underfitting (0) | 2018.08.30 |
---|---|
텐서플로우(tensor flow) 튜토리얼 #3_Regression (0) | 2018.08.13 |
텐서플로우(tensor flow) 튜토리얼 #1_Basic Classification (0) | 2018.08.04 |