: Recurrent Neural Network
: BackPropagation Through Time (BPTT)
1️⃣ tf.keras.Sequential
2️⃣ 첫 번째 층은 encoder 토큰 인덱스의 시퀀스에 텍스트를 반환
3️⃣ 인코더 후 임베딩 레이어
4️⃣ RNN은 요소를 반복하여 시퀀스 입력을 처리한다. RNN은 한 타임 스텝의 출력을 다음 타입 스텝의 입력으로 전달
5️⃣ RNN 단일 벡터에 순서를 전환한 후, 두 layers.Dense 분류 출력으로 단일 로짓이 벡터 표현에서 일부 최종 처리 및 변환 함.
model = tf.keras.Sequential([
encoder,
tf.keras.layers.Embedding(
input_dim=len(encoder.get_vocabulary()),
output_dim=64,
# Use masking to handle the variable sequence lengths
mask_zero=True),
tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(64)),
tf.keras.layers.Dense(64, activation='relu'),
tf.keras.layers.Dense(1)
])
: 유사한 단어가 유사한 인코딩을 갖는 효율적이고 조밀한 표현을 사용하는 방법을 제공
➡️ 단어를 특정 차원의 벡터로 바꿔 주는 것
# Embed a 1,000 word vocabulary into 5 dimentions
embedding_layer = tf.keras.layers.Embedding(1000, 5)
✅ 임베딩 레이어를 생성할 때 임베딩의 가중치는 다른 레이어와 마찬가지로 무작위로 초기화 된다.
훈련하는 동안 역전파를 통해 점진적으로 조정된다.
일단 훈련되면 학습된 단어 임베딩은 단어 간의 유사성을 대략적으로 인코딩한다.
📍 해당 TextVectorization은 단어의 맥락을 고려하는 것이 아니라 빈도수에 따른 단어 사전의 위치만 알려준다. 따라서 TextVectorization으로 학습하는 것은 큰 의미가 없다.
✅ 따라서 TextVectorization을 Embedding을 시켜주고 좌표로 표시할 수 있다.
맥락이 비슷하면 좌표에서 거리를 가깝게 옮겨주고 맥락이 반대면 좌표에서 거리를 멀게 설정해준다.
이 거리를 설정하는 과정은 LSTM에서 학습 후 조정해주게 된다.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
df = pd.read_csv("https://bit.ly/seoul-120-text-csv")
df.shape
>>>>
(2645, 5)
df.head(2)
df['문서'] = df['제목'] + " " + df['내용']
df['분류'].value_counts()
>>>>
행정 1098
경제 823
복지 217
환경 124
주택도시계획 110
문화관광 96
교통 90
안전 51
건강 23
여성가족 13
Name: 분류, dtype: int64
df = df[df['분류'].isin(['행정', '경제', '복지'])]
df.shape
>>>>
(2138, 6)
label_name = '분류'
X = df['문서']
y = df[label_name]
X.shape, y.shape
>>>>
((2138,), (2138,))
y_onehot = pd.get_dummies(y)
y_onehot.head(2)
>>>>
경제 복지 행정
0 0 1 0
1 1 0 0
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y_onehot, test_size=0.2, stratify=y_onehot, random_state=42)
X_train.shape, X_test.shape, y_train.shape, y_test.shape
>>>>
((1710,), (428,), (1710, 3), (428, 3))
display(y_train.value_counts(normalize=True))
display(y_test.value_counts(normalize=True))
>>>>
경제 복지 행정
0 0 1 0.513450
1 0 0 0.384795
0 1 0 0.101754
dtype: float64
경제 복지 행정
0 0 1 0.514019
1 0 0 0.385514
0 1 0 0.100467
: 병렬 연산을 위해 여러 문장의 길이를 임의로 동일하게 맞춰주는 작업이 필요
from tensorflow.keras.preprocessing.sequence import pad_sequence
max_length = 500
padding_type = 'post'
X_train_sp = pad_sequences(train_sequence, maxlen=max_length, padding=padding_type)
X_test_sp = pad_sequences(test_sequence, maxlen=max_length, padding=padding_type)
X_train_sp.shape, X_test_sp.shape
>>>>
((1710, 500), (428, 500))
display(X_train_sp[0, :100])
display(X_test_sp[0, :100])
>>>>
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense, Embedding, SimpleRNN, GRU, Bidirectional, LSTM, Dropout, BatchNormalization
# embedding_dim : 임베딩 할 벡터의 차원
# vocab_size : 텍스트 데이터의 전체 단어 집합의 크기
# max_length : 패딩의 기준
embadding_dim = 64
n_class = y_train.shape[1]
model = Sequential()
# 입력-임베드 층
model.add(Embedding(input_dim=vocab_size,
output_dim=embadding_dim,
input_length=max_length))
model.add(Bidirectional(SimpleRNN(units=64, return_sequences=True))
model.add(Bidirectional(SimpleRNN(units=64, return_sequences=True))
model.add(SimpleRNN(units=64))
# 출력층
model.add(Dense(units=n_class, activation='softmax'))
model.summary()
>>>>
Model: "sequential_19"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding_2 (Embedding) (None, 500, 64) 64000
bidirectional_12 (Bidirecti (None, 500, 128) 16512
onal)
bidirectional_13 (Bidirecti (None, 500, 128) 24704
onal)
simple_rnn_34 (SimpleRNN) (None, 64) 12352
dense_28 (Dense) (None, 3) 195
=================================================================
Total params: 117,763
Trainable params: 117,763
Non-trainable params: 0
model.compile(optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy'])
from tensorflow.keras.callbacks import EarlyStopping
early_stop = EarlyStopping(monitor='val_loss', patience=5)
X_train_val, X_valid, y_train_val, y_valid = train_test_split(
X_train_sp, y_train, test_size=0.2, random_state=42, stratify=y_train)
X_train_val.shape, X_valid.shape, y_train_val.shape, y_valid.shape
>>>>
((1368, 500), (342, 500), (1368, 3), (342, 3))
history = model.fit(X_train_val, y_train_val, validation_data=(X_valid, y_valid),
epochs=100, callbacks=[early_stop])
history
df_hist = pd.DataFrame(history.history)
df_hist
>>>>
loss accuracy val_loss val_accuracy
0 0.941182 0.505117 0.945245 0.497076
1 0.942451 0.512427 0.946420 0.497076
2 0.944342 0.517544 0.949780 0.497076
3 0.944913 0.502924 0.945130 0.497076
4 0.949079 0.491228 0.995339 0.479532
5 0.950846 0.505848 0.948766 0.447368
6 0.944535 0.505117 0.967566 0.497076
7 0.949653 0.475877 0.960229 0.497076
8 0.946728 0.497807 0.953476 0.497076
y_pred = model.predict(X_test_sp)
# np.argmax를 이용해 가장 큰 값의 인덱스들을 반환한 값(클래스 예측)을 y_predict에 할당
y_predict = np.argmax(y_pred, axis=1)
# np.argmax를 이용해 가장 큰 값의 인덱스들을 반환한 값을 y_test_val에 할당
y_test_val = np.argmax(y_test.values, axis=1)
# 맞춘 값의 평균
(y_test_val == y_predict).mean()
>>>>
0.514018691588785
loss, accuracy = model.evaluate(X_test_sp, y_test)
loss, accuracy
>>>>
(0.945652961730957, 0.514018714427948)
model = Sequential()
# 입력-임베딩 층
model.add(Embedding(input_dim=vocab_size,
output_dim=embedding_dim,
input_length=max_length))
model.add(Bidirectional(LSTM(units=64, return_sequences=True)))
model.add(Bidirectional(LSTM(units=64, return_sequences=True)))
model.add(Bidirectional(LSTM(units=64)))
model.add(Dense(units=16))
# 출력층
model.add(Dense(units=n_class, activation='softmax'))
model.summary()
>>>>
Model: "sequential_22"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding_5 (Embedding) (None, 500, 64) 64000
bidirectional_19 (Bidirecti (None, 500, 128) 66048
onal)
bidirectional_20 (Bidirecti (None, 500, 128) 98816
onal)
bidirectional_21 (Bidirecti (None, 128) 98816
onal)
dense_33 (Dense) (None, 16) 2064
dense_34 (Dense) (None, 3) 51
=================================================================
Total params: 329,795
Trainable params: 329,795
Non-trainable params: 0
_________________________________________________________________
model.compile(optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy'])
history = model.fit(X_train_val, y_train_val, validation_data=(X_valid, y_valid),
epochs=100, callbacks=[early_stop])
model = Sequential()
# 입력-임베딩 층
model.add(Embedding(input_dim=vocab_size,
output_dim=embedding_dim,
input_length=max_length))
model.add(Bidirectional(GRU(units=64, return_sequences=True)))
model.add(Bidirectional(GRU(units=64)))
model.add(Dense(units=16))
# 출력층
model.add(Dense(units=n_class, activation='softmax'))
model.summary()
>>>>
Model: "sequential_24"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding_7 (Embedding) (None, 500, 64) 64000
bidirectional_24 (Bidirecti (None, 500, 128) 49920
onal)
bidirectional_25 (Bidirecti (None, 128) 74496
onal)
dense_37 (Dense) (None, 16) 2064
dense_38 (Dense) (None, 3) 51
=================================================================
Total params: 190,531
Trainable params: 190,531
Non-trainable params: 0
_________________________________________________________________
model.compile(optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy'])
history = model.fit(X_train_val, y_train_val, validation_data=(X_valid, y_valid),
epochs=100, callbacks=[early_stop])
df_hist = pd.DataFrame(history.history)
df_hist
>>>>
loss accuracy val_loss val_accuracy
0 0.958088 0.494883 0.942238 0.549708
1 0.922429 0.527047 0.876623 0.590643
2 0.751728 0.690058 0.790169 0.663743
3 0.581616 0.766082 0.786014 0.666667
4 0.480338 0.809211 0.860106 0.652047
5 0.381432 0.853070 0.929460 0.634503
6 0.343799 0.866959 0.922687 0.637427
7 0.302327 0.875731 1.120898 0.660819
8 0.288006 0.891813 1.132852 0.657895
fig, axes = plt.subplots(ncols=2, figsize=(10, 5))
df_hist[['loss', 'val_loss']].plot(ax=axes[0])
df_hist[['accuracy', 'val_accuracy']].plot(ax=axes[1])
y_pred = model.predict(X_test_sp)
y_predict = np.argmax(y_pred, axis=1)
y_test_val = np.argmax(y_test.values, axis=1)
(y_test_val == y_predict).mean()
>>>>
0.6658878504672897
✅ SimpleRNN - accuracy : 0.514018691588785
✅ GRU - accuracy : 0.6658878504672897
➡️ 확실히 성능이 좋아졌다.
📌 텍스트 데이터 벡터화 하는 방법 ??
📌 텍스트 데이터 전처리 방법??
📌 RNN