순환신경망(Vanilla RNN 및 LSTM 구현)

순환 신경망 구현 및 학습

Vanilla RNN

1
!pip install tensorflow==2.0.0-beta1
1
import tensorflow as tf

tensorflow version 확인

1
print(tf.__version__)

하이퍼 파라미터 설정

1
2
3
4
EPOCHS = 10

# 우리가 분석할 때 10000개의 단어만 사용하겠다는 의미로 설정하였다.
NUM_WORDS = 10000

모델정의

1
2
3
4
5
6
7
8
9
10
11
12
class MyModel(tf.keras.Model):
def __init__(self):
super(MyModel, self).__init__()
# input_dim, output_dim
self.emb = tf.keras.layers.Embedding(NUM_WORDS, 16)
self.rnn = tf.keras.layers.SimpleRNN(32)
self.dense = tf.keras.layers.Dense(2, activation='softmax')

def call(self, x, training=None, mask=None):
x = self.emb(x)
x = self.rnn(x)
return self.dense(x)

학습, 테스트 루프 정의

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Implement training loop
@tf.function
def train_step(model, inputs, labels, loss_object, optimizer, train_loss, train_accuracy):
with tf.GradientTape() as tape:
predictions = model(inputs, training=True)
loss = loss_object(labels, predictions)
gradients = tape.gradient(loss, model.trainable_variables)

optimizer.apply_gradients(zip(gradients, model.trainable_variables))
train_loss(loss)
train_accuracy(labels, predictions)

# Implement algorithm test
@tf.function
def test_step(model, images, labels, loss_object, test_loss, test_accuracy):
predictions = model(images, training=False)

t_loss = loss_object(labels, predictions)
test_loss(t_loss)
test_accuracy(labels, predictions)

데이터셋 준비

IMDB

  • review를 보고 긍정인지 부정인지를 예측하는 문제이며, y(target value)는 binary value(0 or 1)를 가지지만 x_data(feature)에서 각각의 review의 길이가 다르므로 입력에서 출력이 나오는 기준을 맞추기 위해 zero-padding을 해주는 작업을 실행할 것이다. 아래의 ‘pad_sequence’함수에서 maxlen=32는 최대 길이를 32글자로 맞추겠다는 의미이다.

  • maxlen=32로 함으로써 원래 본 데이터의 맨 뒤부분에서 시작해서 32번째 데이터 까지를 잘라서 사용하는 것이며, 이 부분에 데이터가 없을 시 0으로 padding 처리를 해주는 함수이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
imdb = tf.keras.datasets.imdb

(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=NUM_WORDS)

# padding='post' 뒤쪽으로 padding해준다.
x_train = tf.keras.preprocessing.sequence.pad_sequences(x_train,
value=0,
padding='pre',
maxlen=32)

x_test = tf.keras.preprocessing.sequence.pad_sequences(x_test,
value=0,
padding='pre',
maxlen=32)

train_ds = tf.data.Dataset.from_tensor_slices((x_train, y_train)).shuffle(10000).batch(32)
test_ds = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(32)

numpy에서 list로 묶은 것과 아닌 것의 차이

IMDB 전처리

학습 환경 정의

모델 생성, 손실함수, 최적화 알고리즘, 평가지표 정의

1
2
3
4
5
6
7
8
9
10
11
12
13
# 모델 생성
model = MyModel()

# 손실함수 및 최적화 기법 정의
loss_object = tf.keras.losses.SparseCategoricalCrossentropy()
optimizer = tf.keras.optimizers.Adam()

# 성능 지표 정의
train_loss = tf.keras.metrics.Mean(name="train_loss")
train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name="train_accuracy")

test_loss = tf.keras.metrics.Mean(name="test_loss")
test_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name="test_accuracy")

학습 루프 동작

1
2
3
4
5
6
7
8
9
10
11
12
13
for epoch in range(EPOCHS):
for seqs, labels, in train_ds:
train_step(model, seqs, labels, loss_object, optimizer, train_loss, train_accuracy)

for test_seqs, test_labels in test_ds:
test_step(model, test_seqs, test_labels, loss_object, test_loss, test_accuracy)

template = "Epoch {}, Loss: {}, Accuracy: {}, Test Loss: {}, Test Accuracy: {}"
print(template.format(epoch + 1,
train_loss.result(),
train_accuracy.result() * 100,
test_loss.result(),
test_accuracy.result() * 100))

IMDB에 대한 vanilla RNN의 성능

LSTM

  • keras는 고수준 API이므로 이미 내부에 구현이 되어있어 다음과 같이 변경해주는 것만으로 LSTM을 구현 할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyModel(tf.keras.Model):
def __init__(self):
super(MyModel, self).__init__()
# input_dim, output_dim
self.emb = tf.keras.layers.Embedding(NUM_WORDS, 16)

# tf.keras.layers.GRU(32)도 가능
# 참고로 RNN은 층을 쌓을수록 성능이 안좋아질 가능성이 높다는 점을 주의하자!
self.rnn = tf.keras.layers.LSTM(32)
self.dense = tf.keras.layers.Dense(2, activation='softmax')

def call(self, x, training=None, mask=None):
x = self.emb(x)
x = self.rnn(x)
return self.dense(x)

IMDB에 대한 LSTM의 성능