순차 데이터(Sequential Data)
샘플에 순서를 갖는 데이터를 말합니다. 순서를 갖는다는 것은 각 샘플이 독립적이지 않다는 것을 의미합니다.
다음은 주식 데이터입니다.
일정 시간 간격으로 배치되어 현재의 정보가 과거의 정보와 연관된 것입니다. 이러한 순차 데이터는 특히 시계열 데이터(time series data)라고 합니다.
순환 신경망(Recurrent Neural Network, RNN)
완전 연결 신경망이나 합성곱 신경망은 이전의 샘플에 대해 고려하지 않기 때문에 순차 데이터를 처리하기에 적합하지 않습니다.
이를 위한 것이 순환 신경망(recurrent nueral network)으로 순환 구조를 통해 순차 데이터를 모델링할 수 있습니다. 순환 구조는 이전 타임 스텝의 출력을 현재 타임 스텝의 입력으로 사용하는 것인데, 신경망 내부에 상태를 저장하는 것이라고 할 수 있습니다. 또, 이러한 상태를 은닉 상태(hidden state)라고 합니다.
순환 신경망은 용도에 따라 입력과 출력의 길이를 다르게 설계할 수 있습니다. 텍스트 이진 분류와 같은 문제는 다대일(many-to-one)에 해당되며, 텍스트 생성, 번역기 등과 같은 문제는 다대다(many-to-many)에 해당됩니다.
순환 신경망의 뉴런을 셀(cell)이라고 하며, 하나의 셀을 타임 스텝으로 펼치면 다음과 같습니다.
이전 타임 스텝의 은닉 상태를 계속해서 다음 타임 스텝으로 전달함으로써 과거의 정보를 기억하고 업데이트하는 것이라고 할 수 있습니다.
하이퍼볼릭 탄젠트 함수(Hyperbolic Tangent Function)
비선형 활성화 함수 중 하나로 순환 신경망에서 셀의 출력인 은닉 상태의 활성화 함수로 사용합니다. 출력은 $ (-1, 1) $ 의 범위를 갖습니다.
$ tanh(x) =\frac { { e }^{ x }-{ e }^{ -x } }{ { e }^{ x }+{ e }^{ -x } } $
$ \frac{d}{dx}tanh(x)=1-tanh(x)^{2} $
import numpy as np
import matplotlib.pyplot as plt
def tanh(x):
return (np.exp(x) - np.exp(-x)) / (np.exp(x) + np.exp(-x))
x = np.arange(-10, 10, 0.1)
plt.plot(x, tanh(x))
plt.title('Tanh Function')
plt.xlabel('x')
plt.ylabel('tanh(x)')
plt.show()
순전파(Forward-Propagation)
입력 데이터의 시퀀스 길이(타임 스텝)만큼 순환되는 출력(은닉상태)의 계산 과정을 알아봅니다.
셀을 이루는 가중치는 입력 데이터 $X$ 와 곱해지는 $ W_x $ 와 은닉 상태 $ H $ 와 곱해지는 $ W_h $ 그리고 편향 $ b $ 입니다.
현재 타임 스텝의 은닉 상태 $ H_t $ 에 대한 계산은 다음과 같습니다.
$ H_t = tanh(X_t W_x + H_{t-1} W_h + b) $
다음은 순환 신경망의 순전파 계산입니다. (시퀀스 길이 8, 입력 벡터 차원 2, 은닉층 크기 4)
import numpy as np
t = 8
input_dim = 2
hidden_size = 4
Wx = np.random.random((hidden_size, input_dim))
Wh = np.random.random((hidden_size, hidden_size))
b = np.random.random((hidden_size,))
print('Wx shape:', np.shape(Wx))
print('Wh shape:', np.shape(Wh))
print('b shape:', np.shape(b))
print('total params:', Wx.shape[0] * Wx.shape[1] + Wh.shape[0] * Wh.shape[1] + b.shape[0])
hidden_states = []
hidden_state = np.zeros((hidden_size,))
input_ = np.random.random((t, input_dim))
# print('input:', input_)
for x in input_:
hidden_state = np.tanh(np.dot(Wx, x) + np.dot(Wh, hidden_state) + b)
hidden_states.append(list(hidden_state))
print('timestep:', len(hidden_states), hidden_state)
# print(np.stack(hidden_states))
Wx shape: (4, 2)
Wh shape: (4, 4)
b shape: (4,)
total params: 28
timestep: 1 [0.84105377 0.8297238 0.91622967 0.67137979]
timestep: 2 [0.99128408 0.97884487 0.99519833 0.9828166 ]
timestep: 3 [0.99892693 0.99607506 0.99888751 0.99707515]
timestep: 4 [0.99853079 0.99417363 0.99869668 0.9965562 ]
timestep: 5 [0.99916201 0.9972471 0.99901747 0.99749684]
timestep: 6 [0.99737831 0.99456041 0.99775821 0.99475771]
timestep: 7 [0.99921775 0.99734956 0.99906598 0.99759901]
timestep: 8 [0.99661161 0.99204837 0.99747657 0.99395993]
케라스를 이용하여 파라미터 개수 정보를 확인합니다.
from keras.models import Sequential
from keras.layers import SimpleRNN
model = Sequential()
model.add(SimpleRNN(4, input_shape=(4, 2)))
model.summary()
____________________________________________________________________________________________________
Layer (type) Output Shape Param Connected to
====================================================================================================
simplernn_1 (SimpleRNN) (None, 4) 28 simplernn_input_1[0][0]
====================================================================================================
Total params: 28
Trainable params: 28
Non-trainable params: 0
____________________________________________________________________________________________________
구현
다대다 순환 신경망 모델을 구현합니다.
학습 데이터를 정의합니다.
char = {
0: 'h',
1: 'e',
2: 'l',
3: 'r',
4: 'o'
}
x_train = [[[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 0, 1, 0],
[0, 0, 0, 0, 1]],
[[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0]],
[[1, 0, 0, 0, 0],
[0, 0, 0, 0, 1],
[0, 0, 1, 0, 0],
[0, 1, 0, 0, 0]]]
y_train = [[0, 1, 3, 4], # hero
[0, 1, 2, 2], # hell
[0, 4, 2, 1]] # hole
신경망을 정의합니다.
import tensorflow as tf
import numpy as np
class Model:
def __init__(self):
tf.reset_default_graph()
with tf.name_scope('input'):
self.x = tf.placeholder(tf.float32, [None, 4, 5])
self.y = tf.placeholder(tf.int32, [None, 4])
with tf.name_scope('layer'):
cell = tf.nn.rnn_cell.BasicRNNCell(4)
outputs, state = tf.nn.dynamic_rnn(cell, self.x, dtype=tf.float32)
with tf.name_scope('output'):
self.logits = tf.layers.dense(outputs, 5)
with tf.name_scope('loss'):
weights = tf.ones([3, 4])
self.loss = tf.contrib.seq2seq.sequence_loss(logits=self.logits, targets=self.y, weights=weights)
with tf.name_scope('optimizer'):
self.train_op = tf.train.AdamOptimizer(0.1).minimize(self.loss)
self.sess = tf.Session()
self.sess.run(tf.global_variables_initializer())
def predict(self, x):
logits = self.sess.run(self.logits, {self.x: x})
return np.argmax(logits, 2)
def train(self, x_train, y_train, epochs):
for e in range(epochs):
loss, _ = self.sess.run([self.loss, self.train_op], {self.x: x_train, self.y: y_train})
# predict = self.predict(x=x_train)
# print('epoch:', e + 1, '/ loss:', loss, '/ predict:', predict)
모델을 학습하고 테스트합니다.
model = Model()
model.train(x_train, y_train, epochs=30)
predict = model.predict(x_train)
for i, word in enumerate(predict):
print(i + 1, 'word: ', end='')
for c in word:
print(char[c], end='')
print()
1 word: hero
2 word: hell
3 word: hole
'머신러닝 > 딥러닝' 카테고리의 다른 글
순환 신경망(Recurrent Neural Network) (3) (0) | 2021.01.12 |
---|---|
순환 신경망(Recurrent Neural Network) (2) (0) | 2021.01.04 |
합성곱 신경망(Convolutional Neural Network) (0) | 2020.11.13 |
소프트맥스 회귀(Softmax Regression) (1) (0) | 2020.11.10 |
교차 검증(Cross Validation) (0) | 2020.11.09 |