10. Seq2Seq Encoder로 뉴스기사 토픽 예측
데이터 소개
- reuters 뉴스 기사 Dataset 사용
- reuters dataset은 11,228개의 뉴스기사와 46개의 주제를 가지고 있다.
- 모든 단어는 빈도에 따른 정수로 교체 되어있다.
- 관례적으로 정수 0은 특정 단어를 나타내는 것으로 사용하지 않는다.
- 학습 데이터와 정답 데이터는, 각각 아래와 같다.
- train_text
1 2 3 4 5
[ [1, 20, 432, 12, 312, ...], [42, 21, 111, 1213, ...], ... ]
- train_answer
1 2 3
[ 3, 4, 3, ..., 25, 3 ]
최종 목표
- Seq2Seq 기반 모델의 이해
- word embedding 이해
- 시계열 데이터 학습 이해
전처리
1
2
3
4
5
6
"""
데이터 불러오기
"""
reuters = keras.datasets.reuters
(train_text, train_topic), (test_text, test_topic) = reuters.load_data()
1
2
3
4
5
6
7
8
9
"""
train_textm test_text에 등장한 정수 확인
"""
all_words = set([word for text in train_text for word in text])
| set([word for text in test_text for word in text])
print(sorted(all_words)[:5]) # [1, 2, 4, 5, 6]
print(sorted(all_words)[-5:]) # [30977, 30978, 30979, 30980, 30981]
1
2
3
4
5
6
7
8
9
10
11
"""
train_text와 test_text를 bow형태로 변경
"""
train_bow_text = tf.keras.preprocessing.sequence.pad_sequences(train_text,
value = 0)
text_bow_text = tf.keras.preprocessing.sequence.pad_sequences(test_text,
value = 0)
print(train_bow_text.shape, text_bow_text.shape)
# ((8982, 2376), (2246, 1032))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
"""
train 과 test에 나온 word들의 count 측정
"""
import collections
# 딕셔너리의 확장으로, 해시 가능한 객체의 개수를 세는 것을 도와준다. 여기서는 단어의 출현 횟수를 세기 휘해 사용
word_count = collections.Counter()
for text in train_text:
word_count.update(text)
for text in test_text:
word_count.update(text)
word_count.most_common(10)
"""
[(4, 82723),
(5, 42393),
(6, 40350),
(7, 33157),
(8, 29978),
(9, 29956),
(10, 29581),
(11, 20141),
(12, 16668),
(13, 15224)]
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
"""
word_count를 이용해 n번 이하로 나온 word를 삭제
"""
def cut_by_count(texts, n):
return np.array([[word for word in text if word_count[word] >= n]
for text in texts], dtype = object)
train_cut_text = cut_by_count(train_text, 20)
test_cut_text = cut_by_count(test_text, 20)
print(train_cut_text.shape) # (8982,)
print(test_cut_text.shape) # (2246,)
1
2
3
4
5
6
7
8
9
10
11
12
"""
train/test_cut_text 를 bow형태로 반환
"""
train_cut_bow_text =
tf.keras.preprocessing.sequence.pad_sequences(train_cut_text, value = 0)
test_cut_bow_text =
tf.keras.preprocessing.sequence.pad_sequence(test_cut_text, value = 0)
print(train_cut_bow_text.shape, test_cut_bow_text.shape)
# ((8982, 2266), (2246, 995))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
"""
train/test_text에 길이 제한을 줘서 bow 생성
"""
train_cut_bow_text2 = tf.keras.preprocessing.sequence.pad_sequences(train_text,
value = 0,
maxlen = 200)
test_cut_bow_text2 = tf.keras.preprocessing.sequence.pad_sequences(test_text,
value = 0,
maxlen = 200)
print(train_cut_bow_text2.shape, test_cut_bow_text2.shape)
# ((8982, 200), (2246, 200))
1
2
3
4
5
6
7
8
"""
topic을 onehot encoding으로 변경
"""
train_onehot_topic = keras.utils.to_categorical(train_topic)
test_onehot_topic = keras.utils.to_categorical(test_topic)
print(train_onehot_topic.shape, test_onehot_topic.shape)
# (8982, 46) (2246, 46)
1
2
3
4
5
6
7
8
9
10
11
"""
topic 인덱스를 text label로 변환
"""
raw_labels = ['cocoa','grain','vegoil','earn','acq','wheat','copper','housing','money-supply',
'coffee','sugar','trade','reserves','ship','cotton','carcass','crude','nat-gas',
'cpi','money-fx','interest','gnp','meal-feed','alum','oilseed','gold','tin', 'strategic-metal','livestock','retail','ipi','iron-steel','rubber','heat','jobs',
'lei','bop','zinc','orange','pet-chem','dlr','gas','silver','wpi','hog','lead']
def topic2label(idx):
return raw_labels[idx]
1
2
3
4
5
6
7
8
"""
reuters.get_word_index()를 이용해 text decoding
"""
index_word = { y : x for x, y in reuters.get_word_index().items()}
def bow2text(bow):
return " ".join([index_word[idx] for idx in bow])
모델링
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
"""
Encoder를 이용해 classification 모델 구축
"""
from keras.layers import Input, GRU, Embedding, Denses
from keras.models improt Model
def seq2seq():
inputs_x_bow = Input(shape = (200, ))
x = Embedding(len(index_word) + 1, 120)(inputs_x_bow)
context_vector = GRU(units = 64)(x)
y = Dense(units = 46, activation = 'softmax')(context_vector)
model = Model(inputs_x_bow, y)
model.compile(loss = 'categorical_crossentropy',
optimizer = 'adam',
metrics = ['accuracy'])
return model
1
2
3
4
5
6
7
8
9
10
11
12
13
"""
모델 학습
"""
hist = model.fit(
train_cut_bow_text2, train_onehot_topic,
validation_data = (
test_cut_bow_text2,
test_onehot_topicm
),
epochs = 20,
verbose = 1
)
This post is licensed under CC BY 4.0 by the author.