다음 코드는 텍스트 분류에 대한 예제 코드이다. 데이터 전처리, 모델 구성, 학습, 예측 단계로 진행된다.
import tensorflow as tf
from tensorflow import keras
import numpy as np
import matplotlib.pyplot as plt
#==================== load data ====================
data = keras.datasets.imdb #이진 분류 데이터, 리뷰의 단어 배열은 정수 형태로 변환 되어 있음
#verify error 해결 코드 in mac
import ssl
try:
_create_unverified_https_context = ssl._create_unverified_context
except AttributeError:
# Legacy Python that doesn't verify HTTPS certificates by default
pass
else:
# Handle target environment that doesn't support HTTPS verification
ssl._create_default_https_context = _create_unverified_https_context
#빈도수가 높은 단어만 선택
(train_data, train_labels), (test_data, test_labels) = data.load_data(num_words=10000)
#print(train_data[0])
#==================== set vocabulary, pre-processing ====================
word_index = data.get_word_index() #return dictionary
word_index = {k:(v+3) for k, v in word_index.items()} #key: word, value: integer
word_index["<PAD>"] = 0
word_index["<START>"] = 1
word_index["<UNK>"] = 2
word_index["<UNUSED>"] = 3
reverse_word_index = dict([(value, key) for (key, value) in word_index.items()])
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)
def decode_review(text):
return ' '.join([reverse_word_index.get(i, "?") for i in text])
#print(decode_review(test_data[0]))
print(len(test_data[0]), len(test_data[1]), type(test_data[0]))
#==================== create model and fit ====================
model = keras.Sequential()
#embedding를 사용해서 dense vector로 변환, 첫 번째 층에서만 사용.
model.add(keras.layers.Embedding(10000, 16, input_shape=(None,)))
model.add(keras.layers.GlobalAveragePooling1D()) #average vector
model.add(keras.layers.Dense(16, activation='relu')) #classify
model.add(keras.layers.Dense(1, activation='sigmoid'))
#output 0~1사이의 값, sigmoid는 단순한 2진 분류, softmax는 확률 또는 신뢰도
model.compile(optimizer="adam", loss="binary_crossentropy", metrics=["accuracy"])
x_val = train_data[:10000]
x_train = train_data[10000:]
y_val = train_labels[:10000]
y_train = train_labels[10000:]
fit_model = model.fit(x_train, y_train, epochs=40, batch_size=512, validation_data=(x_val,y_val), verbose=1)
results = model.evaluate(test_data, test_labels)
print(results)
model.save("model.h5")
#==================== predict ====================
def review_encode(s):
encoded = [1]
for word in s:
if word.lower() in word_index:
encoded.append(word_index[word.lower()])
else:
encoded.append(2)
return encoded
new_model = keras.models.load_model("model.h5")
with open("/Users/Documents/SimpleProject/SimpleML/test.txt", encoding="utf-8") as f:
for line in f.readlines():
nline = line.replace(",", "").replace(".", "").replace("(","").replace(")","").replace(":","").strip().split()
encode = review_encode(nline)
encode = keras.preprocessing.sequence.pad_sequences([encode], value=word_index["<PAD>"], padding="post", maxlen=256)
predict = new_model.predict(encode)
print(predict)
전처리 단계에서 imdb의 영화 리뷰 데이터를 받아올 때 빈도수가 높은 상위 10,000개의 단어만 받는다. 각각의 리뷰에 사용되는 단어는 vocabulary에 mapping 된 정수로 변환되어 있다. 그리고 이 vocabulary의 key와 value를 조금 수정해서 decode 함수와 encode 함수를 만든다. 각 리뷰의 정수 리스트는 모델에 입력하기 위해 padding으로 리스트의 최대 크기가 같은 tensor로 변환해야 한다.
모델 구성 단계에서 첫 번째 layer로 사용되는 embedding vector는 dense vector의 일종으로 실수값을 element로 갖는 저차원 벡터이다. embedding의 첫 번째 인자는 전체 데이터에 사용되는 단어의 개수이다. 두 번째 인자는 embedding 후에 각각의 word index에 대응하는 벡터들의 크기이다. embedding을 한 후에는 GlobalAveragePooling1D 메서드로 embedding vector를 average vector로 축소시킨다. 이 층에서 학습은 하지 않는다. 다음 층은 relu activation function를 사용하여 실제로 classify를 진행하는 층이다. average vector에 있는 10,000개의 단어를 16차원 벡터 공간에서 비슷한 단어들끼리 분류를 한다. 모델이 학습을 하면서 분류 정확도가 상승하고 비슷한 단어들끼리 가까워지게 될 것이다. 마지막 층에서는 sigmoid activation function를 사용하기 때문에 이전 층의 16개의 뉴런의 가중치에 따라 0에서 1 사이의 값을 반환하게 된다. 이 값은 긍정과 부정에 대한 추정치이다.
학습 단계에서는 compile로 optimizer와 loss function, metrics를 설정하고 fit으로 모델을 학습시킨다. 학습을 할 때 fit에 더 많은 인자를 주어 training에 사용되는 데이터와 validation을 위한 데이터로 구분하여 학습할 수 있다. 위의 예제에서는 10,000개의 데이터를 검증 데이터로 사용하고 나머지 데이터는 train data로 사용했다. 이 방법 대신 모든 data를 fit의 인자로 전달하고 validation_split으로 train과 validation 비율을 정해서 구분할 수 있다. 검증 데이터의 loss가 낮아지다가 증가한다는 것은 과적합화 문제가 발생했다는 뜻이다. batch size는 512이며 fitting을 40회 반복한다. verbose는 학습 중 출력되는 문구를 설정하는 속성이다. 예측 단계로 넘어가기 전에 모델을 save와 load_model로 저장하고 불러올 수 있다. 이때 확장자는 .h5로 설정한다.
2020/05/21 - [공부/비즈니스를위한데이터과학] - 과적합화 문제 해결
예측 단계에서는 텍스트 파일로 저장된 리뷰 하나를 토큰화하고 인코딩을 한 뒤에 padding한다. 이렇게 모델에 입력할 준비를 한 뒤에 predict 메서드로 결과를 출력한다. 결과는 다음과 같다.
결과:
학습 전 초기 모델의 훈련 데이터와 검증 데이터의 손실도는 0.7, 정확도는 0.55 정도로 매우 형편없다. 그리고 훈련을 진행하면서 손실도는 낮아지고 정확도가 올라가다가 Epoch이 33일때 검증 데이터의 손실도가 다시 상승하는 것을 볼 수 있다. 이는 과적합화가 일어났다는 것이며 학습 횟수를 줄여야 한다는 것을 의미한다. 최종적으로 이 모델의 손실도는 0.32, 정확도는 0.87가 되었다.
간단하게 bad nothing terrible disappointment boring 이라는 부정 문장과 good nice touching moved fun perfect 이라는 긍정 문장을 넣고 결과값을 예측해 보았다. 첫 번째 문장은 결과가 0.06이고 두 번째 문장은 0.9로 문장이 부정 리뷰인지 긍정 리뷰인지 잘 분류했다. test.txt 파일에 실제 리뷰를 넣으면 InvalidArgumentError: indices[0,7] = 27451 is not in [0, 10000) 이런 에러가 발생한다. 이 에러는 vocabulary size를 늘리면 해결할 수 있다. data.load_data(num_words=10000)에서 num_words 값을 늘리고 embedding layer의 input size 값을 사전의 크기와 같도록 하면 된다.
관련 에러:
https://github.com/tensorflow/tensorflow/issues/23698
참고:
https://www.youtube.com/watch?v=6g4O5UOH304&list=PLn6_vibrJjiFKdR1pMxBX2DtDI0yA-C_I&index=2&t=1540s
https://www.tensorflow.org/tutorials/keras/text_classification?hl=ko
영화 리뷰를 사용한 텍스트 분류 | TensorFlow Core
Note: 이 문서는 텐서플로 커뮤니티에서 번역했습니다. 커뮤니티 번역 활동의 특성상 정확한 번역과 최신 내용을 반영하기 위해 노력함에도 불구하고 공식 영문 문서의 내용과 일치하지 않을 수
www.tensorflow.org
위키독스
온라인 책을 제작 공유하는 플랫폼 서비스
wikidocs.net
'데이터 사이언스 공부 > 딥러닝' 카테고리의 다른 글
CNN, RNN (0) | 2020.07.03 |
---|---|
ML Tip - Learning Rate, Overfitting, Regularization, Normalization, Standardization, Drop Out, Tensor Board (0) | 2020.06.26 |
Multinominal Logistic Regression, Softmax (0) | 2020.06.24 |
Logistic Regression, Binary Classification, Sigmoid (0) | 2020.06.16 |
TensorFlow 2.0 basic practice 1 (0) | 2020.06.04 |