Deep learning

[Supervised Learning / review article] Recurrent Neural Networks(RNN), Long Short-Term Memory Units (LSTM)

JaykayChoi 2017. 4. 30. 17:16

RNN과 LSTM 을 공부하기 위해  아래의 포스팅을 참고하여 공부했습니다.

http://karpathy.github.io/2015/05/21/rnn-effectiveness/


기존의 CNN과 같은 신경망은 연결된 데이터를 다루기에는 적합하지 않는 딥러닝 방식입니다.

연결된 데이터란 예를 들어 I am a boy 와 같은 문장이 있다 할 때, 사실상 세상의 모든 문장을 하나의 input 데이터로 할 수 없기에

I, am, a, boy 와 같이 하나 하나의 단어를 input 데이터로 넣어 문장을 파악하려 할 것입니다.

이런데 이때 기존의 신경망을 이용할 경우 위 4개의 단어는 그저 각각의 단어로 인식될 뿐 연속적인 데이터에 대한 정보는 이용하지 못할 것입니다.

이런 문제를 해결하기 위해 I 다음의 am 이라는 단어를 input 으로 넣어 단어를 인식할 때 바로 앞의 I 나 뒤에 a, boy 를 같이 넣어 신경망에서 처리한다면 

이 문제를 해결할 수 있을 것입니다. 이를 위해 아래와 같은 신경망을 구성하게 되고 이를 RNN 이라 합니다.

위 이미지에서 분홍색 네모는 input, 녹색은 rnn cell, 파란색은 output 입니다. 여기서 중요한 rnn cell 이 하는 일은 자신의 input 을 처리할 때 자신과 연결된 rnn cell 에서 온 값도 같이 이용하여 처리를 하는 것입니다.


RNN 은 다음과 같은 원리로 동작을 하게 됩니다.

https://en.wikipedia.org/wiki/Recurrent_neural_network

Elman network[10]
Jordan network[11]

Variables and functions

  • : input vector
  • : hidden layer vector
  • : output vector
  •  and : parameter matrices and vector
  •  and : Activation functions





참고한 포스팅에서는 RNN 을 설명하기 위해 hello 라는 단어를 인식하는 신경망을 만드는 것을 예로 들었습니다.

이 신경망은 h 를 입력하면 l 을 반환하고 e 는 l, l은 l, 그리고 다음 l 에는 e 가 반환되게 하는 것이 목표인 신경망입니다.

기존의 신경망이라면 3번째 문자열 l 과 4번째 문자열 l 의 차이점을 알 수 없기에 여기서 기존의 신경망과 RNN 의 차이를 알 수 있습니다.


다음으로 LSTM 이란 RNN의 변형 방법 중 하나로써 학습이 이뤄지는 back propagation 에서 loss 값이 잘 유지되며 전달되게 만든 방법입니다. 

LSTM 의 각 cell 은 3개의 gate(write, read, keep)로 구성되어 있고 각 gate는 0~1 사이의 값을 가지고 있으며 이 값을 통해 cell 의 정보를 저장할지 불러올지 유지할지 결정합니다. 이 gate 의 0~1사이의 값은 신경망의 weighs 들과 마찬가지 원리로 학습됩니다. 사실 RNN 과 마찬가지로 LSTM 도 일일이 구현을 하기 까다로운 방법이지만 tensorflow 등과 같은 프레임워크를 사용하면 아래와 같이 쉽게 이용할 수 있습니다. 



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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import tensorflow as tf
 
 
x_data = [
    [1.0.0.0.],   # h
    [0.1.0.0.],   # e
    [0.0.1.0.],   # l
    [0.0.1.0.],   # l
]
 
y_data = [
    1,  #e
    2,  #l
    2,  #l
    3   #o
]
 
targets = tf.reshape(y_data[:], [-1])
 
 
# Parameters
learning_rate = 0.01
time_step_size = 4
rnn_num_units = 4

 
 
# RNN
lstm_cell = tf.contrib.rnn.BasicLSTMCell(rnn_num_units)
= tf.split(x_data, time_step_size)
outputs, state = tf.contrib.rnn.static_rnn(lstm_cell, x, dtype=tf.float32)
weights = tf.ones([time_step_size])
 
 
logits = tf.reshape(tf.concat(outputs, 1), [-1, rnn_num_units])
loss = tf.contrib.legacy_seq2seq.sequence_loss_by_example([logits], [targets], [weights])
cost = tf.reduce_sum(loss)
update = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
 
 
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for i in range(1000):
        sess.run(update)
        result = sess.run(tf.arg_max(logits, 1))
        print(i, result)
cs



먼저 input 데이터 x_data 를 one-hot-encoding 방식으로 보기 좋기 list 에 담아둡니다, 여기서 사용되면 문자열은 h e l o 밖에 없으므로 h->0, e->1, l->2, o->3 으로 정의합니다.

다음으로 label Y 인 y_data 도 마찬가지로 list 에 담아둡니다. 첫 번째 h에 대한 라벨은 e 이므로 1, 두 번째 e 에 대한 라벨은 l 이므로 2 와 같은 식으로 1,2,2,3 을 라벨로 만듭니다.

이 y_data 을 tensorflow 에서 사용하기 위해 reshape 하여 1차원의 배열의 tensor 로 만듭니다.

x_data = [
    [1.0.0.0.],   # h
    [0.1.0.0.],   # e
    [0.0.1.0.],   # l
    [0.0.1.0.],   # l
]
 
y_data = [
    1,  #e
    2,  #l
    2,  #l
    3   #o
]
 
targets = tf.reshape(y_data[:], [-1])
cs



다음으로 필요한 인자값들을 정의합니다

여기서 time_step_size 란 아래 이미지와 같이 RNN cells 의 옆으로 늘어선 개수입니다.

rnn_num_units 은 RNN 의 각 cell 에 몇 개의 unit 을 만들지에 대한 값입니다. 여기서는 공교롭게 time_step_size 와 값이 같아 햇갈릴 수 있지만 rnn_num_units 값을 8과 같은 값으로 변경해도 무관합니다. 하지만 실제 학습 시 4가 적당한 값임을 알 수 있습니다.

# Parameters
learning_rate = 0.01
time_step_size = 4
rnn_num_units = 4
cs



다음으로 RNN 을 구성하는 부분입니다.

먼저 cell 을 LSTM 방식으로 만듭니다. 여기서는 tf.contrib.rnn.BasicLSTMCell 함수를 사용했습니다.

다음으로 x 를 tensorflow 에서 사용하기 위해 1,4 의 배열을 4개 가지고 있는 리스트로 만듭니다.

그리고 만들어진 cells 와 x 로 RNN 신경망을 구성합니다. 함수는 tf.contrib.rnn.static_rnn 을 사용합니다.

여기서 output을 얻을 수 있는데 역시  1,4 의 배열을 4개 가지고 있는 리스트입니다.

다음으로 원소를 4개 가지고 있는 1차 배열의 weights 을 만듭니다.

# RNN
lstm_cell = tf.contrib.rnn.BasicLSTMCell(rnn_num_units)
= tf.split(x_data, time_step_size)
outputs, state = tf.contrib.rnn.static_rnn(lstm_cell, x, dtype=tf.float32)
weights = tf.ones([time_step_size])
cs



이제 만들어진 신경망을 이용해 학습을 구성하는 부분입니다.

먼저 predict Y 값을 4,4의 배열로 logits 에 reshape 하여 담아둡니다.

loss 는 tf.contrib.legacy_seq2seq.sequence_loss_by_example 함수를 사용하여 쉽게 계산합니다.

cost 는 loss 의 합으로 합니다.

만들어진 cost 를 통해 AdamOptimizer 으로 학습합니다.

logits = tf.reshape(tf.concat(outputs, 1), [-1, rnn_num_units])
loss = tf.contrib.legacy_seq2seq.sequence_loss_by_example([logits], [targets], [weights])
cost = tf.reduce_sum(loss)
update = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
cs