Recurrent Neural Network : 순환신경망
vanila RNN : RNN의 여러가지 변형 중에서 기본이라는 의미
1. Sequence is important for Pos tagging
문장의 구조를 학습하고 추론하는 과정
주어다음 동사, 동사 다음 목적어
"i work at google" 에서 google을 판단할 때, i=대명사, work=동사, at=전치사를 추론한 각각의 값을 이어 받아서 명사라고 추론하는 구조이다.
문자의 순서가 바뀌어도 그 자리에 오는 단어에 대해서 같은 형태소로 추론 해준다.
예측 prediction
logit : softmax 함수의 input값
prediction : softmax 함수의 output값
정답(target)과 예측값(pred)을 비교하여 이 둘의 차이를 줄여나가는 과정
가중치와 편향치 를 최적화 시켜준다.
W_xh : 현재 input값의 가중치
W_hh : 이전 sell의 값의 가중치
b : 편향치
gradient decendent
BPTT : back propagation throgh time
각 셀마다 W_xh, W_hh, b가 있지만 모델 구조상 각각 하나의 변수들이 변형된 것과 같다.
하나의 변수를 변형하는 과정이므로 back propagation 이 아닌 back propagation through time 이라고 부른다.
문장의 감정을 수치화한 분석
좋아요, 싫어요
happy, unhappy 등
최종 output 값을 예측해야하므로 softmax 함수가 마지막 cell 다음에 오게 된다.
주어진 정답값(targe)과 예측값(pred)값의 오차를 최소화하기 위한 최적화를 하게 된다.
최적화 방식은 bptt를 따른다.
하나의 변수를 조정한다.
gradient decendent 방식으로 조정
3. simplify of model diagram
RNN 모델 구조를 단순화하면 다음과 같다.
output값을 출력해주는 활성화함수의 연산 : 가중합
$h_t = tanh(W_{xh}x_t + W_{hh}h_{t-1} + b)$
현재 input x_t와 가중치 W_xh의 곱
이전 state의 값 h_t-1과 가중치 W_hh의 곱
편향치 b 를 모두 더해준다.
import tensorflow as tf
tf .__version__
>> >
'2.8 .0 '
X = []
Y = []
for i in range (6 ) :
lst = list (range (i , i + 4 ))
X .append (list (map (lambda c : [c / 10 ], lst )))
Y .append ((i + 4 ) / 10 )
X = np .array (X )
Y = np .array (Y )
for i in range (len (X )) :
print (X [i ], Y [i ])
>> >
[[0. ]
[0.1 ]
[0.2 ]
[0.3 ]] 0.4
[[0.1 ]
[0.2 ]
[0.3 ]
[0.4 ]] 0.5
[[0.2 ]
[0.3 ]
[0.4 ]
[0.5 ]] 0.6
[[0.3 ]
[0.4 ]
[0.5 ]
[0.6 ]] 0.7
[[0.4 ]
[0.5 ]
[0.6 ]
[0.7 ]] 0.8
[[0.5 ]
[0.6 ]
[0.7 ]
[0.8 ]] 0.9
input_shape=[timesteps, input_dim]
units : simple RNN 레이어에 존재하는 뉴런의 수
return_sequences : 출력으로 시퀀스 전체를 출력할지 여부 설정
model = tf .keras .Sequential ([
tf .keras .layers .SimpleRNN (units = 10 , return_sequences = False , input_shape = [4 , 1 ]),
tf .keras .layers .Dense (1 )
])
model .compile (optimizer = "adam" , loss = "mse" , metrics = "accuracy" )
model .summary ()
hist_sr = model .fit (X , Y , epochs = 100 , verbose = 1 )
hist_sr
작은 길이의 데이터에서는 정확도가 높은 편이다.
def plot_trainning_result (hist ) :
plot_target = ["loss" , "accuracy" ]
for each in plot_target :
plt .plot (hist .history [each ], label = each )
plt .figure (figsize = (8 , 6 ))
plot_trainning_result (hist_sr )
plt .legend ()
plt .show () ;
Y는 (i+4) / 10 이므로, 6 + 4 / 10 = 1
예측값이 1이 나올 수록 정확하다.
model .predict (np .array ([[[0.6 ], [0.7 ], [0.8 ], [0.9 ]]]))
>> >
array ([[0.9631898 ]], dtype = float32 )
-0.1 + 4 / 10 = 0.3
예측값이 0.3에 가깝게 나올수록 정확하다.
model .predict (np .array ([[[- 0.1 ], [0.0 ], [0.1 ], [0.2 ]]]))
>> >
array ([[0.22828916 ]], dtype = float32 )
입력값이 커지면 RNN의 성능은 떨어진다.
gradient vanishing 현상으로 인한 장기 의존성이 높아지기 때문이다.
균일분포의 데이터를 랜덤하게 생성
0~100 중 2개의 정수를 선택하여 idx 값으로 저장
원소가 100개인 영벡터 생성한 후 idx에 해당하는 값을 1로 저장
X 데이터는 균일분포와 영벡터를 zip을 사용하여 합한다.
Y 데이터는 균일분포 데이터에서 idx에 해당한는 값 2개를 곱한 후 저장한다.
X = []
Y = []
for i in range (3000 ) :
lst = np .random .rand (100 )
idx = np .random .choice (100 , 2 , replace = False )
zeros = np .zeros (100 )
zeros [idx ] = 1
X .append (np .array (list (zip (zeros , lst ))))
Y .append (np .prod (lst [idx ]))
print (X [0 ], Y [0 ])
>> >
[[0. 0.12081525 ]
[0. 0.92541031 ]
[0. 0.8219348 ]
[0. 0.42718652 ]
[0. 0.67883278 ]
[1. 0.78966009 ]
[0. 0.09728805 ]
[0. 0.62496675 ]
[0. 0.70654689 ]
[0. 0.31958938 ]
[0. 0.76415308 ]
[0. 0.74883606 ]
[0. 0.4148991 ]
...]
len (X ), len (Y ), X [0 ].shape , Y [0 ].shape
>> >
(3000 , 3000 , (100 , 2 ), ())
model = tf .keras .Sequential ([
tf .keras .layers .SimpleRNN (units = 30 , return_sequences = True ,
input_shape = [100 , 2 ]),
tf .keras .layers .SimpleRNN (units = 30 ),
tf .keras .layers .Dense (1 )
])
model .compile (optimizer = "adam" , loss = "mse" )
model .summary ()
X = np .array (X )
Y = np .array (Y )
history = model .fit (X [:2560 ], Y [:2560 ], epochs = 100 , validation_split = 0.2 )
loss 값과 val_loss 값의 차이가 점차 벌어진다.
bptt 과정에서 vanishing 또는 exploding 문제가 발생하기 때문
import matplotlib .pyplot as plt
% matplotlib inline
plt .plot (history .history ["loss" ], 'b--' , label = "loss" )
plt .plot (history .history ["val_loss" ], "r--" , label = "vla_lostt" )
plt .xlabel ("Epoch" )
plt .legend ()
plt .show () ;