본문 바로가기
인공신경망(DL)/NLP

Recurrent Neural Network, RNN

by kiimy 2021. 8. 22.
728x90
  • 언어 모델 (Language Model)
    • 통계 기반 언어모델을 이해하고 설명할 수 있습니다.
    • 통계 기반 언어모델의 한계를 이해하고 이를 극복하기 위해 등장한 신경망 언어 모델의 장점을 설명할 수 있습니다.

 

  • 순환 신경망 (Recurrent Neural Network, RNN)
    • RNN의 구조와 작동 방식을 이해하고 설명할 수 있습니다.
    • RNN의 장점과 단점을 설명하고 이해할 수 있습니다.

 

  • LSTM & GRU
    • LSTM과 GRU가 고안된 배경과 구조를 연관지어 설명할 수 있습니다.
    • 두 방법의 차이에 대해서 설명할 수 있습니다.

 

  • Attention
    • Attention이 탄생하게 된 배경에 대해서 설명할 수 있습니다.
    • Attention의 장점에 대해서 설명하고 Attention 으로도 해결할 수 없는 RNN의 구조적 단점에 대해서도 이해할 수 있습니다.

정리: https://github.com/codestates/AIB04_Discussion/discussions/20

언어 모델 (Language Model)

- 문장과 같은 단어 시퀀스에서 각 단어의 확률을 계산하는 모델

 

신경망 언어 모델 (Neural Langauge Model)

횟수 기반 대신 Word2Vec이나 fastText 등의 출력값인 임베딩 벡터를 사용

그렇기 때문에 말뭉치에 등장하지 않더라도 의미적, 문법적으로 유사한 단어라면 선택될 수 있다.

임베딩 벡터에서는 "7" 이라는 단어의 벡터가 "1", "2" ... 등의 단어와 유사한 곳에 위치

 

순환 신경망 (RNN, Recurrent Neural Network)

- RNN 은 연속형(Sequential) 데이터를 잘 처리하기 위해 고안된 신경망

- 케라스에서는 SimpleRNN / Vanilla RNN

- RNN은 2D 텐서가 아니라 3D 텐서를 입력을 받는다( batch_size 추가해줘야함 )

통계적기반 언어모델에서는 corpus에서 훈련되지 않은 단어가 주어질 경우
0이 나오는 것을 개선하기 위해 n-gram을 사용했다. (고정된 개수의 단어만 입력으로 받음)

하지만 고정된 입력개수가 정해져 있어서 전체 문맥을 고려할 수 없었고 여전히 희소문제를 해결할 수 없었다.
그래서 만들어진게  Word2Vec이나 fastText 등의 출력값인 임베딩 벡터를 사용하는 것이다.

연속형 데이터 (Sequential Data)

  • Sequential Data란?
    • 어떤 순서로 오느냐에 따라서 단위의 의미가 달라지는 데이터
    • 데이터 집합 내의 객체들이 어떤 순서를 가진 데이터
  • Non-Sequential Data란?
    • 데이터 집합 내의 객체들이 어떤 순서를 가지지 않은 데이터( ex 사진 )

RNN 구조

  1. 입력 벡터가 은닉층에 들어가는 것을 나타내는 화살표
  2. 은닉층로부터 출력 벡터가 생성되는 것을 나타내는 화살표
  3. 은닉층에서 나와 다시 은닉층으로 입력되는 것을 나타내는 화살표

기존 신경망에서 특정 시점에서의 은닉 벡터가 다음 시점의 입력 벡터로 다시 들어가는 과정이 포함되있다.

현재 시점 t에서의 은닉 상태는 과거 시점의 동일한 RNN 셀에서의 모든 은닉 상태의

값들의 영향을 누적해서 받아온 값

 

메모리 셀  또는  RNN 셀

신경망을 사용하게되면 time-step을 추가하여 시계열데이터 처리가 가능하다

==> n-gram은 고정된 개수의 단어만 입력 받았는데 신경망의 경우는 입력길이를 고정하지 않아도 된다.

==> 전체 단어, 문맥을 고려할 수 있게 된다.

Sequential 데이터의 순서 정보를 모두 기억하기 때문에 Sequential 데이터를 다룰 때 RNN을 많이 사용

다양한 형태의 RNN

one-to-many : 1개의 벡터를 받아 Sequential한 벡터를 반환합니다. 이미지를 입력받아 이를 설명하는 문장을

만들어내는 이미지 캡셔닝(Image captioning)에 사용됩니다.

 

many-to-one : Sequential 벡터를 받아 1개의 벡터를 반환합니다. 문장이 긍정인지 부정인지를 판단하는 

감성 분석(Sentiment analysis)에 사용됩니다.

 

many-to-many(1) : Sequential 벡터를 모두 입력받은 뒤 Sequential 벡터를 출력합니다. 

시퀀스-투-시퀀스(Sequence-to-Sequence, Seq2Seq) 구조라고도 부릅니다.

번역할 문장을 입력받아 번역된 문장을 내놓는 기계 번역(Machine translation)에 사용됩니다.

 

many-to-many(2) : Sequential 벡터를 입력받는 즉시 Sequential 벡터를 출력합니다. 

비디오를 프레임별로 분류(Video classification per frame)하는 곳에 사용됩니다.

RNN 단점

- 비교적 짧은 시퀀스(sequence)에 대해서만 효과를 보이는 단점

- 시점(time step)이 길어질 수록 앞의 정보가 뒤로 충분히 전달되지 못하는 현상이 발생

 

1. 병렬화(parallelization) 불가능

RNN 구조가 가지고 있는 단점 중 하나는 벡터가 순차적으로 입력 된다는 점입니다.

==> 여전히 순차적으로 계산
이는 sequential 데이터 처리를 가능하게 해주는 요인이지만, 이러한 구조는 GPU 연산의 장점인

병렬화를 불가능하게 만듭니다.


그렇기 때문에 RNN 기반의 모델은 GPU 연산을 하였을 때 이점이 거의 없다는 단점을 가지고 있습니다.

 

2. 기울기 폭발(Exploding Gradient), 기울기 소실(Vanishing Gradient)

tanh 미분 했을시

역전파 과정에서 RNN의 활성화 함수인 tanh의 미분값을 전달하게 되는데 Recurrent가 계속 반복된다고

보면 시퀀스(단어들) 앞쪽에 있는 hidden-state 벡터에는 역전파 정보가 거의 전달되지 않는다.

(= 기울기 소실, Vanishing Gradient )

이를 장기 의존성 문제(the problem of Long-Term Dependencies)라고 한다.
= 중요한 정보가 시퀀스 앞에 있을 수도 있는데 이를 중요하게 판단하지 못 할 수 있다.
   RNN이 충분한 기억력을 가지고 있지 못한다면 다음 단어를 엉뚱하게 예측

반대로 값이 1보다 커지는 경우(?)  hidden-state 벡터에는 역전파 정보가 과하게 전달

(= 기울기 폭발, Exploding Gradient )

 

기울기 정보의 크기가 문제이고 '이 크기를 적절하게 조정해준다면 문제를 해결할 수 있지 않을까'라는

아이디어가 생김 == LSTM

LSTM (Long Term Short Memory, 장단기기억망)

- 단순한 RNN을 개선한 모델 (= 기울기 소실에서만 / 순차적으로 계산은 여전히 한계)

- 기울기 정보 크기를 조절하기 위한 Gate를 추가한 모델

- Sequential 데이터를 처리하기 위한 대표적인 모델

- 장기 의존성 문제를 개선

LSTM이 등장한 배경은  기울기 소실(Vanishing gradient)  문제를 해결하기 위함

 LSTM은 은닉층의 메모리 셀에 입력 게이트, 망각 게이트, 출력 게이트를 추가하여 불필요한 기억을 지우고,

기억해야할 것들을 정한다.

  1. forget gate : 과거 정보를 얼마나 유지할 것인가? sigmoid
  2. input gate  : 새로 입력된 정보는 얼마만큼 활용할 것인가? tanh
  3. output gate  : 두 정보를 계산하여 나온 출력 정보를 얼마만큼 넘겨줄 것인가? sigmoid

GRU (Gated Recurrent Unit)

- LSTM의 간소한 버전

- LSTM 은닉 상태를 업데이트하는 계산을 줄이고자 만든 모델

== 현재는 LSTM으로도 충분히 빠르고 크게 차이나지 않는 결과를 보여준다.

###code###

RNN 파라미터

rnn = SimpleRNN(3) # rnn = SimpleRNN(3, return_sequences=False, return_state=False)와 동일.

hidden_state = rnn(train_X)

print('hidden state : {}, shape: {}'.format(hidden_state, hidden_state.shape))

 

[[-0.866719 0.95010996 -0.99262357]], shape: (1, 3) # 마지막시점의 은닉 상태

 

[[[ 0.92948604 -0.9985648 0.98355013]

[ 0.89172053 -0.9984244 0.191779 ]

[ 0.6681082 -0.96070355 0.6493537 ]

[ 0.95280755 -0.98054564 0.7224146 ]]], shape: (1, 4, 3) # 모든시점의 은닉 상태

 

* return_sequences, return_state

return_sequencesFalse인 경우에는 SimpleRNN은 마지막 시점의 은닉 상태만 출력

return_sequences True로 지정하면 모든 시점의 은닉 상태를 출력

 

return_state True일 경우에는

return_sequences의 True/False 여부와 상관없이 마지막 시점의 은닉 상태를 출력

ex)

* return_sequencesFalse인데, retun_stateTrue인 경우 == 마지막 시점의 은닉 상태를 출력

* return_sequences True인데, retun_state True인 경우 == 모든시점, 마지막 시점 출력

rnn = SimpleRNN(3, return_sequences=True, return_state=True)

hidden_states, last_state = rnn(train_X)

rnn = SimpleRNN(3, return_sequences=True, return_state=True)

hidden_states, last_state = rnn(train_X)

* return_state

LSTM 레이어에서 주로 사용되는 값으로, cell_state를 출력할 것인지를 결정하는 값

 

* activation

활성화 함수를 선언하는 변수입니다. tanh, relu 등과 같은 함수를 사용

출처: https://davinci-ai.tistory.com/30 [DAVINCI - AI]

 

 

시퀀스-투-시퀀스(Sequence-to-Sequence)

- many-to-many(1) : Sequential 벡터를 모두 입력받은 뒤 Sequential 벡터를 출력

-  seq2seq는 기본적으로 입력 시퀀스와 출력 시퀀스의 길이가 다를 수 있다고 가정

ex) 나는 학생이다 --> i am a student 

     ==> 토큰이 2개인 문장을 넣었는데 토큰이 4개인 문장이 나온다

https://wikidocs.net/22893

참조: https://wikidocs.net/22893

seq2seq는 크게 두 개로 구성된 아키텍처로 구성되는데, 바로 인코더와 디코더입니다.

인코더는 입력 문장의 모든 단어들을 순차적으로 입력받은 뒤에 마지막에 이 모든 단어 정보들을 압축해서

하나의 벡터로 만드는데, 이를 컨텍스트 벡터(context vector)라고 합니다.

입력 문장의 정보가 하나의 컨텍스트 벡터로 모두 압축되면 (고정된 크기의 벡터 표현으로 압축)

 

인코더는 컨텍스트 벡터를 디코더로 전송합니다.

디코더는 컨텍스트 벡터를 받아서 번역된 단어를 한 개씩 순차적으로 출력

디코더는 인코더의 마지막 RNN 셀의 은닉 상태인 컨텍스트 벡터를 첫번째 은닉 상태의 값으로 사용

디코더의 첫번째 RNN 셀은 이 첫번째 은닉 상태의 값과, 현재 t에서의 입력값인 <sos>로부터,
다음에 등장할 단어를 예측합니다. 그리고 이 예측된 단어는 다음 시점인 t+1 RNN에서의
입력값이 되고, 이 t+1에서의 RNN 또한 이 입력값과 t에서의 은닉 상태로부터 t+1에서의 출력 벡터.
즉, 또 다시 다음에 등장할 단어를 예측하게 될 것 

예측하기 위한 함수 : softmax
출력 시퀀스의 각 단어별 확률값을 반환하고, 디코더는 출력 단어를 결정

하지만 문장의 길이가 매우 길어지면 모든 단어 정보를 고정 길이의 hiddem-state 벡터에 담기 어렵다.

1. 하나의 고정된 크기의 벡터에 모든 정보를 압축하려고 하니까 정보 손실이 발생합니다.
2. RNN의 고질적인 문제인 기울기 소실(Vanishing Gradient) 문제가 존재합니다.
3. 시계열 데이터이기 때문에 병력적으로 계산을 못해 == 최종적으로 Transformer 사용함

입력 문장의 모든단어들을 순차적으로 입력받은 뒤에 마지막에 이 모든 단어 정보들을 압축
--> 하나의 벡터로 만듬( context vector )
모든 정보를 압축할려고 하니까 정보 손실이 일어남 = 병목현상
즉, 단어가 많아지면 정보 압축이 어렵다는 것 인데 
이는 학습할 때 길이가 짧은 것만 들어오다가 test시 긴 문장이 들어오면
고정된 크기(context vector)로 인해 다 표현을 못 한다.

Attention의 등장( 장기의존성 문제를 개선하기 위한 )

Attention(Q, K, V) = Attention Value

어텐션 함수는 주어진 '쿼리(Query)'에 대해서

모든 '키(Key)'와의 유사도를 각각 구합니다.

 

그리고 구해낸 이 유사도를 키와 맵핑되어있는

각각의 '값(Value)'에 반영해줍니다.

 

그리고 유사도가 반영된 '값(Value)'을

모두 더해서 리턴합니다.

여기서는 이를 어텐션 값(Attention Value)

Q = Query : t 시점의 디코더 셀에서의 은닉 상태

K = Keys : 모든 시점의 인코더 셀의 은닉 상태들

V = Values : 모든 시점의 인코더 셀의 은닉 상태들

 

- 디코더에서 출력 단어를 예측하는 매 시점(time step)마다, 인코더에서의 전체 입력 문장을

  다시 한 번 참고한다는 점이다.

 

- 전체 입력 문장을 전부 다 동일한 비율로 참고하는 것이 아니라, 해당 시점에서 예측해야할

  단어와 연관이 있는 입력 단어 부분을 좀 더 집중(attention)

 

입력 시퀀스가 길어지면 출력 시퀀스의 정확도가 떨어지는 것을 보정

Attention은 각 인코더의 Time-step 마다 생성되는 hidden-state 벡터를 간직합니다.
입력 단어가 N개라면 N개의 hidden-state 벡터를 모두 간직하게 됩니다.
모든 단어가 입력되면 생성된 hidden-state 벡터를 모두 디코더에 넘겨줍니다.

디코더의 각 time-step 마다의 hidden-state 벡터는 쿼리(query)로 작용합니다.
인코더에서 넘어온 N개의 hidden-state 벡터를 키(key)로 여기고 이들과의 연관성을 계산합니다.
이 때 계산은 내적(dot-product)을 사용하고 내적의 결과를 Attention 가중치= score로 사용

 

시점 t에서 출력 단어를 예측하기 위해서 디코더의 셀은 두 개의 입력값을 필요로 하는데,

바로 이전 시점인 t-1의 은닉 상태와 이전 시점 t-1에 나온 출력 단어가 필요하다.

 

Attention은 여기에 추가적으로 어텐션 값(Attention Value)이 필요함

- Attention score를 구해야한다.

 

  1. 쿼리(Query)인 디코더의 hidden-state 벡터, 키(Key)인 인코더에서 넘어온 hidden-state 벡터를 준비합니다.
  2. 각각의 벡터를 내적한 값을 구합니다.어텐션 스코어(Attention Score)
  3. 이 값에 소프트맥스(softmax) 함수를 취해줍니다. 어텐션 분포(Attention Distribution)
  4. 소프트맥스를 취하여 나온 값에 밸류(Value)에 해당하는 인코더에서 넘어온 hidden-state 벡터를 곱해줍니다.       
  5. 이 벡터를 모두 더해줍니다. 이 벡터의 성분 중에는 쿼리-키 연관성이 높은 밸류 벡터의 성분이 더 많이 들어있게 됩니다. 어텐션 값(Attention Value)
  6. (그림에는 나와있지 않지만) 최종적으로 5에서 생성된 벡터와 디코더의 hidden-state 벡터를 사용하여 출력 단어를 결정하게 됩니다.

Attention을 활용하면 디코더가 인코더에 입력되는 모든 단어의 정보를 활용할 수 있기 때문에

장기 의존성 문제를 해결할 수 있습니다.

Time-step마다 출력할 단어가 어떤 인코더의 어떤 단어 정보와 연관되어 있는지,

즉 어떤 단어에 집중(Attention)할 지를 알 수 있습니다.

첫번째 초록색 동그라미 = attention score(dot product)


RNN 해석 어려움

환자 데이터를 가지고 병을 예측하는 모델을 만든다 했을때

순차적으로 계산을 진행하기 때문에 언제(몇번째 방문), 무엇이(원인)

해당 질병에 영향을 끼쳤는지 파악하기 어려워

그래서 RETAIN: Motivation이라는 것이 있음 or X-AI

728x90

댓글