RNN(Recurrent Nueral Networks)
RNN
RNN은 Recurrent Neural Networks와 더불어 자연어처리 분야에서 각광받고 있는 모델.
Recursive, Recurrent Neural Neworks
두 모델은 음성, 문자 등 순차적 데이터 처리에 강점을 지니고 있음
이름이 유사하지만, 조금은 차이가 있다.
Recurrent Nueral Networks
RNN의 기본 구조
- RNN은 히든 노드가 방향을 가진 엣지로 연결돼 순환구조를 이루는(directed cycle) 인공신경망의 한 종류
- 시퀀스 길이에 관계없이 인풋과 아웃풋을 받아들일 수 있는 네트워크 구조 > 다양하고 유연하게 구조를 만들 수 있다는 점 RNN 큰 특징
- ht는 직전 시점의 히든 state h(t-1)를 받아 갱신
- hidden state의 activation function은 tanh
RNN의 기본 동작
- 글자가 주어졌을때 바로 다음 글자를 예측하는 Chracater-level-model을 만든다고 칠때
- h0는 random하게 주어지고, hidden layer를 fowrard propagation을 하면서 모두 갱신
- 정답셋을 바탕으로 backpropagation을 수행해 parameters의 값들을 갱신
- RNN이 학습하는 parameter는 무엇일까?
- Wxh, Whh, W_hy의 parameters
- x > hidden, hidden > hidden, hidden > y
LSTM
- RNN은 관련 정보와 그 정보를 사용하는 지점 사이거리가 멀 경우 vanishing gradient problem이 발생
- vanishing gradient problem: backpropagation시 gradient가 점차 줄어들어 학습 능력 저하
- 위 문제를 극복하기 위해서 바로 LSTM을 사용 (https://ratsgo.github.io/natural%20language%20processing/2017/03/09/rnnlstm/)
- LSTM은 RNN의 hidden state에 cell_state를 추가
- cell state는 일종의 컨베이어 벨트 역할
- state가 꽤 오래 경과하더라도 gradient가 비교적 전파가 잘 된다.
- forget gate
- '과거 정보 잊기'
- sigmoid를 하기 때문에 0이라면 이전 상태의 정보를 잊고, 1이라면 이전 상태의 정보를 온전히 기억
- input gate
- '현재 정보를 기억하기 위한'
- i(t)의 범위는 0~1, g(t)의 범위는 -1~1, 각각 강도와 방향을 나타낸다.
- H(t)에서 행을 기준으로 4등분해, i,f,o,g 각각에 해당하는 activation 함수를 적용
Python 코드
def lossFun(inputs, targets, hprev, cprev):
xs, hs, cs, is_, fs, os, gs, ys, ps= {}, {}, {}, {}, {}, {}, {}, {}, {}
hs[-1] = np.copy(hprev) # t=0일때 t-1 시점의 hidden state가 필요하므로
cs[-1] = np.copy(cprev)
loss = 0
H = hidden_size
# forward pass
for t in range(len(inputs)):
xs[t] = np.zeros((vocab_size, 1))
xs[t][inputs[t]] = 1
tmp = np.dot(Wxh, xs[t]) + np.dot(Whh, hs[t - 1]) + bh # hidden state
is_[t] = sigmoid(tmp[:H])
fs[t] = sigmoid(tmp[H:2 * H])
os[t] = sigmoid(tmp[2 * H: 3 * H])
gs[t] = np.tanh(tmp[3 * H:])
cs[t] = fs[t] * cs[t-1] + is_[t] * gs[t]
hs[t] = os[t] * np.tanh(cs[t])
# compute loss
for i in range(len(targets)):
idx = len(inputs) - len(targets) + i
ys[idx] = np.dot(Why, hs[idx]) + by # unnormalized log probabilities for next chars
ps[idx] = np.exp(ys[idx]) / np.sum(np.exp(ys[idx])) # probabilities for next chars
loss += -np.log(ps[idx][targets[i], 0]) # softmax (cross-entropy loss)
# backward pass: compute gradients going backwards
dWxh, dWhh, dWhy = np.zeros_like(Wxh), np.zeros_like(Whh), np.zeros_like(Why)
dbh, dby = np.zeros_like(bh), np.zeros_like(by)
dhnext, dcnext = np.zeros_like(hs[0]), np.zeros_like(cs[0])
n = 1
a = len(targets) - 1
for t in reversed(range(len(inputs))):
if n > len(targets):
continue
dy = np.copy(ps[t])
dy[targets[a]] -= 1 # backprop into y
dWhy += np.dot(dy, hs[t].T)
dby += dy
dh = np.dot(Why.T, dy) + dhnext # backprop into h
dc = dcnext + (1 - np.tanh(cs[t]) * np.tanh(cs[t])) * dh * os[t] # backprop through tanh nonlinearity
dcnext = dc * fs[t]
di = dc * gs[t]
df = dc * cs[t-1]
do = dh * np.tanh(cs[t])
dg = dc * is_[t]
ddi = (1 - is_[t]) * is_[t] * di
ddf = (1 - fs[t]) * fs[t] * df
ddo = (1 - os[t]) * os[t] * do
ddg = (1 - np.tanh(gs[t]) * np.tanh(gs[t])) * dg
da = np.hstack((ddi.ravel(),ddf.ravel(),ddo.ravel(),ddg.ravel()))
dWxh += np.dot(da[:,np.newaxis],xs[t].T)
dWhh += np.dot(da[:,np.newaxis],hs[t-1].T)
dbh += da[:, np.newaxis]
dhnext = np.dot(Whh.T, da[:, np.newaxis])
n += 1
a -= 1
for dparam in [dWxh, dWhh, dWhy, dbh, dby]:
np.clip(dparam, -5, 5, out=dparam) # clip to mitigate exploding gradients
return loss, dWxh, dWhh, dWhy, dbh, dby, hs[len(inputs) - 1], cs[len(inputs) - 1]
참고
'AI, 머신러닝 > 머신러닝' 카테고리의 다른 글
optimizer 원리 (0) | 2021.05.07 |
---|---|
로지스틱 회귀모델의 모수 추정 (0) | 2021.05.06 |
로지스틱 함수 (0) | 2021.05.06 |
[MachineLearning] libFM 사용 방법 (0) | 2021.05.03 |
XGBoost parameters (0) | 2021.05.03 |
Imbalanced data를 처리하는 기술 7가지 (0) | 2021.05.03 |
Class imbalanced problem - 데이터 비대칭 문제 (oversampling, undersampling) (0) | 2021.05.03 |
[머신러닝] Machine Learning? (0) | 2021.05.03 |