RNN은 연속적인 데이터를 처리하는데 좋은 '자연어 처리'를 담당하는 인공신경망이다.
이에 대한 예시를 몇개 들어보자면 다음과 같다.
EX : 연관검색어, 감상평을 보고 긍정인지 부정인지 분석, 앞으로의 주가 방향 분석, 동영상 (동영상도 이미지의 연속적인 데이터!)을 보고 동작 분석, 번역 시스템 등등...
여기서 연속적인 데이터는 Word Embedding를 통해 단어에서 숫자로 바뀐다!
Ex : "나는 사람이다."라고 있을 때, '나는', '사람', '이다.'로 나누어 각각 원-핫 방식으로
'나는' =x1=[1,0,0], '사람' =x2=[0,1,0], '이다.' =x3=[0,0,1]으로 나타낼 수 있다!
그리고 위의 Word Embedding한 결과를 가지고 NN에 하나씩 순차적으로 넣는 것이 RNN의 접근법이다!!
RNN의 동작 방식을 그림으로 보면 다음과 같다. (출처 : 혁펜하임님의 ALL DEEP DIVE 강의 내용)
위에서 보이는 xt는 Word Embedding한 연속적인 데이터들이고, yt는 중간의 은닉층(ht)을 지나고 난 뒤의 결과이다.
여기서 중요한 RNN의 특징은 x2에 연결되는 은닉층(h2)을 보았을 때, h2는 x2와 h1을 모두 참고하여 y2라는 결과를 낸다는 것이다!!
즉, RNN은 바로 이전의 정보를 담아낸다는 것이다!
위의 나온 기호들을 수식으로 전개하면 다음과 같다!
xt : Word Embedding의 결과. ht : tanh(xtWx+ht−1Wh+b) yt=htWy+by
위의 그림과 수식에서 보면 모든 layer들이 FC layer로 되어있다는 것을 볼 수 있고,
중요한 성질로Wx,Wh,Wy,b,by는 시간에 따라 다르지 않다는 것이다!
(출처 : 혁펜하임님의 ALL DEEP DIVE 강의 내용)
[*] tanh란? → sigmoid에서 y값의 범위를 -1에서 1까지로 넓힌 것이라고 보면 된다!
[*] 그렇다면 왜 FC layer로 연결되어 있을까? 최적화를 진행하면 원-핫 방식이기에 한 웨이트만 살아남을텐데...?
[*] 최적화를 결국 진행해야되는데 웨이트에 대한 행렬과 벡터들이 시간에 따라 다르지 않다는 것은 최적화를 진행하지 않는다는 것인가? → 아니다. 그 의미가 아니라 Wx,Wh,Wy,b,by 이 웨이트들이 계속 참조가 된다는 의미이기에 최적화를 하면 전에 있던 모든 부분에서 웨이트가 수정된다.
RNN의 backpropagation과 구조적 한계 이해하기
이 주제를 이해하기 위해서 검색 기능에서 자동완성 기능을 예시로 알아볼 것이다.
단어 'HELLO'를 치기 위해서 한 알파벳을 쳤을 때, 다음 알파벳이 무엇일지 예측을 해보자!
'H'를 검색창에 쳤을 때 다음 알파벳이 무엇이 나올지 고민하는 것이기 때문에 이는 다중 분류(알파벳 여러가지 중에 선택하는 것이기에..!)에 해당하고, 이는 y를 Softmax에 통과시켜 Cross-Entropy를 계산하면 된다!
이것을 위의 예시에서 보자면 알파벳 'H'를 넣고 다음으로 'ELLO'가 나오는 과정에서의 y들의 Cross-Entropy를 모두 더하여 이를 Loss함수로 쓰면 될 것이다!! 그런데.. 여기서 마지막 'O'가 나오는데까지 'H'가 gradient에 미치는 영향력은 얼마나 될까?
이에 대해 확인하기 위해 Wx,Wh,Wy,b,by에 대한 gradient를 구해보겠다!!
일단 위에서 보면 'O'는 y4에 해당하기에 y4에 대한 Loss 함수만 구하면 다음과 같다.
L4=CE(y4,y4) (여기서 y4는 실제 분포를 의미한다.)
그리고 아래는 backpropagation에 필요한 수식을 위에서 가져온 것! ht : tanh(xtWx+ht−1Wh+b) yt=htWy+by
이제 하나씩 Chain-rule를 가지고 backpropagation을 하면 다음과 같다.
(우리는 RNN backpropagation을 가지고 RNN의 구조적 한계를 보기 위하여 계산하기 때문에 위의 웨이트들을 스칼라로 보고 진행하겠다.)
Wy의 경우 Wy→y4→L4의 경로를 지나므로 ∂Wy∂L4=∂y4∂L4⋅∂Wy∂y4가 나온다.
Wh의 경우 Wh→h4→y4→L4의 경로를 지난다.
또한!!! Wh는 h1→h2와 h2→h3,h3→h4 모두 다 똑같은 웨이트 Wh를 쓰기에 위의 경로에 대한 것들도 파악해주어야 한다!!
즉, Wh→h3→h4→y4→L4와 Wh→h2→h3→h4→y4→L4의 경로까지 더해주면 다음과 같이 나오게 된다. ∂Wh∂L4=∂y4∂L4⋅∂h4∂y4⋅∂Wh∂h4+∂y4∂L4⋅∂h4∂y4⋅∂h3∂h4⋅∂Wh∂h3+∂y4∂L4⋅∂h4∂y4⋅∂h3∂h4⋅∂h2∂h3⋅∂Wh∂h2
Wx의 경우 Wh처럼 Wx를 모두 똑같이 쓰기 때문에 'H, E, L, L' 모든 경우에서 Wx를 봐야한다!
그러므로 경로는 Wx→h4→y4→L4,Wx→h3→h4→y4→L4,Wx→h2→h3→h4→y4→L4,Wx→h1→h2→h3→h4→y4→L4로 나와 모두 더하면 다음과 같다. ∂Wx∂L4=∂y4∂L4⋅∂h4∂y4⋅∂Wx∂h4+∂y4∂L4⋅∂h4∂y4⋅∂h3∂h4⋅∂Wx∂h3+∂y4∂L4⋅∂h4∂y4⋅∂h3∂h4⋅∂h2∂h3⋅∂Wx∂h2+∂y4∂L4⋅∂h4∂y4⋅∂h3∂h4⋅∂h2∂h3⋅∂h1∂h2⋅∂Wx∂h1
b의 경우 Wh와 똑같은 방식으로 backpropagation이 진행되기에 생략.
by의 경우 Wy와 똑같은 방식으로 backpropagation이 진행되기에 생략.
이제 위의 경우에서 Wx를 봐보자! ∂Wx∂L4=∂y4∂L4⋅∂h4∂y4⋅∂Wx∂h4+∂y4∂L4⋅∂h4∂y4⋅∂h3∂h4⋅∂Wx∂h3+∂y4∂L4⋅∂h4∂y4⋅∂h3∂h4⋅∂h2∂h3⋅∂Wx∂h2+∂y4∂L4⋅∂h4∂y4⋅∂h3∂h4⋅∂h2∂h3⋅∂h1∂h2⋅∂Wx∂h1에서 각각의 xt가 영향을 주는 정도를 간단하게 나눠서 보면 다음과 같다. ∂y4∂L4⋅∂h4∂y4는 모두 들어가있기에 생략하고 ∂Wx∂h4는 activation의 미분(겉미분) ⋅x4(속미분)으로 나와 " 액⋅x4 "으로 표현할 수 있다.
그리고 ∂h3∂h4의 경우 activation의 미분(겉미분) ⋅Wh(속미분)으로 나와 "액 ⋅ 웨 "로 표현할 수 있다!!
그러므로 다음과 같이 정리될 수 있다.
위에서 x1쪽을 보자! 보면 activation의 미분이 네 번이나 곱해져있는 것을 볼 수 있다!
sigmoid의 경우에서 위처럼 곱해져있으면 바로 Vanishing Gradient가 일어났을 것이다..!
(실제로는 tanh라 그래도 최대 기울기가 1 정도이긴 하다.. sigmoid보다 조금 나은 정도..?) 즉, RNN의 구조적 한계는 멀수록 잊혀진다는 것이다! (backpropagation)
그리고 forward propagation의 입장에서 보았을 때, tanh이기에 이전에 넣은 값들이 점점 정제되고 본래의 의미를 잃어가서 결국 갈수록 흐려진다는 한계도 있다!
RNN의 유형
RNN은 크게 일 대 다(one-to-many), 다 대 일(many-to-one), 다 대 다(many-to-many)로 나뉜다.
일 대 다(one-to-many)
대표적으로 이미지 캡셔닝(image captioning)에 쓰인다!
이미지 캡셔닝이란 아래처럼 사진을 입력하고 사진의 제목을 달아주는 것을 의미한다.
(출처 : 혁펜하임님의 ALL DEEP DIVE 강의 내용 중 일부)
다 대 일(many-to-one)
단어 시퀀스에 대해 하나의 출력을 하는 다 대 일 방식은 주로 감성 분류, 스팸 메일 분류 등에서 쓰인다!
(출처 : 혁펜하임님의 ALL DEEP DIVE 강의 내용 중 일부)
다 대 다(many-to-many)
다 대 다 방식은 챗봇, 번역기, 개체명 인식 등에서 쓰인다!
(여기서 번역기는 seq2seq 구조가 더 잘 쓰인다.)
(출처 : 혁펜하임님의 ALL DEEP DIVE 강의 내용 중 일부)
seq2seq (sequence-to-sequence)
일단 seq2seq의 동작 방식을 그림으로 보여주면 다음과 같다. (출처 : 혁펜하임님의 ALL DEEP DIVE 강의 내용 중 일부)
위의 그림을 설명하면 다음과 같다.
일단 seq2seq는 기본적으로 encoder, decoder로 다른 두 RNN으로 구성이 된다.
(encoder쪽의 웨이트와 decoder쪽의 웨이트가 다르고, 학습도 따로 됨.)
그리고 encoder의 마지막 h(context vector 라고 함.)는 decoder의 처음 h로 이어진다.
또한, encoder가 끝나고 decoder의 시작을 알리는 x 벡터는 <sos> (start-of-sequence),
decoder의 끝은 <eos> (end-of-sequence)로 둘 다 원-핫 방식으로 하나의 값을 가진다!
또한, 성능 문제로 인해 plain RNN이 아니라 LSTM이나 GRU를 사용한다!
(이들을 사용하면서 멀면 덜 고려하는 문제를 그나마 해결한다..!)
[*] LSTM? GRU? → LSTM(Long Short Term Memory)과 GRU(Gated Recurrent Unit)은 간단히 말해서 "해당 cell을 얼마만큼 비중을 둘 것인지"까지 학습을 하는 것이다! h에서 4개의 layer로 쪼개져 sigmoid나 Pointwise 곱셈으로 이 cell을 얼마나 비중을 둘 것인지 학습한다!
자세한 내용은 아래 글을 참조하면 좋을 것 같다..! https://velog.io/@h4y3j1n/Learning-To-Rank-%EA%B8%B0%EB%B3%B8-Pointwise-Pairwise-Listwise
마지막으로 seq2seq는 학습 시에 teacher forcing(지도 학습이라 가능)이라는 decoder쪽의 x cell에 미리 정답을 넣어주는 것을 하고, test때는 뽑은 결과 y를 그 다음 x cell에 넣는 방식으로 출력 나온 것을 입력으로 사용한다!!
이렇게 번역기에 대표적으로 쓰는 seq2seq의 구조를 알아보았는데, 사실 seq2seq도 다음과 같은 문제점을 가지고 있다..!
1. 멀수록 잊혀진다. (LSTM과 GRU를 써도 encoder, decoder 둘 다 완벽하게 해결되지는 않는다..!)
2. context vector에 마지막 단어의 정보가 가장 많이 담긴다..!
첫 단어의 정보에서 마지막 단어의 정보로 갈수록 흐려지고, 이러한 정보가 담긴 h를 decoder가 번역하니..마지막 단어를 유심히 보게 된다..!
예를 들어 위의 문장 '저는' / '강사' / '입니다.'를 decoder에 넣었을 때, 'I' / 'am' / 'an' / 'instructor'에서
'I'를 뽑아내는데 '저는'을 보는 것이 아닌 '입니다.'를 더 많이 보게 되는 것이다..!
이는 인간의 번역 방식과는 조금 차이가 있는 부분이다..!
(이를 보완할 수 있는 방법은 무엇일까..?)
Transformer
우리가 배운 RNN 기법은 마지막 부분을 중요시 한다는 문제가 커서 이에 대해 여러 변형 버젼의 RNN이 나왔다.
그러나, 이들도 모두 갈수록 흐려지고, 멀수록 잊혀진다는 문제를 완벽히 해결하지 못했다.
이에 대한 저항으로 나온 것이 바로 Transformer이다!!
Transformer는 한 순가에 뚝딱 나온 것이 아니라 하나의 아이디어에서 출발한 신경망이다.
이 아이디어는 바로<Attention is all you need>라는 제목의 논문이었다..!
Attention이란 '주목도'를 의미한다.
우리가 위에서 배운 RNN에 Attention이라는 개념을 적용하면 시퀀스의 어느 한 부분을 보기 위한 Attention을 학습하는 것이다!
예를 들자면 '나는' / '강사' / '입니다.'에서 '나는'을 'I'로 해석하는데 앞의 세 단어 중에 어느 단어를 주목해야 하는지 학습을 하는 것이다!!
이는 LSTM, GRU와는 다르게 학습하면서 얼만큼 비중을 가져갈지 보는 것이 아니라, 앞의 번역해야 될 단어들을 살펴보며 '주목도'를 학습하는 것이다.
그리고 attention하는 방법으로는 내적을 통해 '닮은 정도'를 보는 식으로 학습을 하였다!
이로 인해 'RNN + Attention'으로 RNN의 효과를 높였지만, 결국 본질이 RNN이라는 것이기 때문에 위의 두 문제를 완벽히 해결할 수 없었고, 마지막 h에 Attention을 한 나머지 결국 이미 흐려져있는 정보에 주목을 한다는 문제가 있었다..
이에 대해 구글은 2017년에 머신 러닝의 척도를 바꾼 Transformer를 발표하게 되었다!!
이는 RNN을 완전히 버리고 self-attention을 사용하여 인코더와 디코더를 채우는 방법을 사용하였다!!
여기서 self-attention은 단어 임베딩 된 것들에 대해 attention 벡터 시퀀스를 만들고, 이를 softmax를 돌려 어디에 주목을 해야하는지 학습을 한다!
예를 들자면'나는'[x1] / '강사'[x2] / '입니다.'[x3]를 다음과 같이 행렬로 나타낸다. ⎝⎜⎛x1⋅x1x2⋅x1x3⋅x3x1⋅x2x2⋅x2x3⋅x2x1⋅x3x2⋅x3x3⋅x3⎠⎟⎞ (여기서 ⋅는 내적(닮은 정도)을 의미한다!)
위의 행렬 결과로는 대각선에 있는 것들은 일치하기에 내적이 1로 나올 것이다.
대각은 제외하고 나머지 부분이 중요한데, '나는' 과 '강사'의 경우 '나는' 과 '입니다.'보단 더 닮은 정도가 클 것이라고 생각할 수 있다..!
그러므로 '나는' 과 '강사'의 경우가 내적이 클 것이고, 이에 대해 softmax를 돌려 attention을 학습하였다..!
(더 자세한 내용은 따로 글을 올리도록 할 것이다..)
결국, transformer는 RNN+ attention의 세가지 문제를 완전히 해결할 수 있었고, 더 나아가 자연어처리 뿐만 아니라 이미지 처리에서도 활발히 활용할 수 있게 되었다!!
정리
RNN은 자연어처리를 위해 고안된 신경망 모델이다.
RNN은 Word Embedding 후 NN에 순차적으로 담는데, 여기서 중요한 특징은 이전 정보를 다시 불러온다는 것이다!
하지만 RNN은 멀수록 잊혀지고, 갈수록 흐려진다는 단점이 존재한다.
seq2seq은 encoder와 decoder 두 개로 RNN 변형 모델을 사용해 번역을 목적으로 사용하였다.
Attention은 RNN에서 단어의 주목도를 학습하는 것이다.
(이는 내적으로 닮은 정도를 파악해 학습한다.)
Transformer는 self-Attention을 사용해 RNN의 단점을 완벽히 없애고 더 나아가 CNN의 기능까지 활용되며 머신러닝의 중요한 터닝 포인트로 자리매김하고 있다!!
강의 마무리 (딥러닝은 어떻게 잘해야 할까?)
결국 딥러닝은 직관을 바탕으로 하는 아이디어 싸움이다.
사전 정보를 어떻게 심어주는지가 중요하다.
ex1) CNN : 가까운 픽셀 먼저 보고 (선택과 집중), 먼 픽셀은 나중에 정제해서 조합. Transformer : 단어 간의 관계 정보를 파악하여 번역하자!
ex2) Resnet의 Skip-connection : 이전 layer와 다음 layer는 값의 차이가 별로 없을 것이다.
ex3) loss는? → 회귀일 때 MSE.. 출력이 확률 분포이니 Cross-Entropy.. Overfitting 방지를 위해 weight 크기 조절하자는 의미로 Regularization
이 위의 두 문장이 바로 "인간은 어떻게 학습을 할까?"라는 딥러닝의 목표에 대한 답변이다.
이 '어떻게'를 직관적으로 파악하며, 사전 정보를 어떻게 어느 정도 심어주는지를 통해 효율적인 딥러닝 모델이 만들어진다.
그리고 수식은 결국 이에 따라오는 양념인 셈이다. (물론 수학적 근거가 있어야 설득력이 올라간다..!)