어텐션(Attention)은 seq2seq의 문제점을 개선하기 위해 나온 해결책이다.

 

 

seq2seq의 문제점

seq2seq는 Encoder가 시계열 데이터를 인코딩하고, Encoder의 출력은 h(은닉 벡터)이며 h는 고정 길이의 벡터였다. 하지만 데이터가 모두 항상 동일한 길이일수도 없는 노릇이고 이것을 매번 고정 길이의 벡터로 출력하는 것은 데이터의 손실 및 공간 낭비의 문제가 발생하게 된다.

 

문장이 길어도 고정 길이 벡터로 출력된다.

 

 

 

 

Encoder 개선

이전에 설명한 seq2seq에서 우리는 RNN(LSTM)의 마지막 은닉 상태(h)만을 Decoder에 전달했다. 하지만 위의 문제점을 해결하기 위해서는 Encoder의 출력은 고정 길이 벡터가 아닌, 문장 길이에 따라 바꿔주는 것이 좋다. 따라서 우리는 이 문제점을 해결하고자 시각별 RNN(LSTM) 계층의 은닉 상태 벡터를 모두 이용한다.

 

모든 시각의 은닉 상태 벡터를 hs라고 한다.

 

위의 이미지처럼 각 시각(단어)의 은닉 상태 벡터를 모두 이용하면 입력된 단어와 같은 수의 벡터를 얻을 수 있다. 이는 코드로는 RNN 계층의 초기화 인수로 return_sequences=True로 설정하면 모든 시각의 은닉 상태 벡터(hs)를 반환하게 된다. 단순히 모든 시각의 은닉 상태 벡터를 꺼내는 것만으로, 우리는 입력 문장 길이에 비례한 정보를 인코딩 할 수 있게 되었다.

 

 

 

 

Decoder 개선 - Attention 계층 사용

개선된 Encoder에서 보내는 hs를 활용하기 위해서는 Decoder 또한 개선해야 한다. 기존의 Decoder는 기존의 Encoder가 마지막 은닉 상태 벡터만을 Decoder로 넘겼기 때문에, hs 전체를 활용할 수 있도록 개선해야 한다. 그렇다면 Decoder는 어떻게 hs 전체를 활용할 수 있을까?

 

우리는 기존에 한개만 받던 h를 뭉태기(hs)로 받게되었다. 이 말은 즉슨, 문장 전체에 대한 정보를 입력받을 수 있다는 소리다. 이 덕에, 우리는 입력과 출력의 여러 단어 중 어떤 단어끼리 서로 관련되어 있는가에 대한 대응 관계를 학습할 수 있게 되었다. 이러한 구조를 어텐션(Attention)이라고 하며, 어텐션은 필요한 정보에만 주목하여 그 정보로부터 시계열 변환을 수행하도록 한다.

 

 

위의 그림은 어텐션이 사용된 개선된 Decoder이다. 여기서 어텐션 계층의 입력 데이터는 Encoder로부터 받는 hs와 시각별 LSTM 계층의 은닉상태 벡터(h)이다. 어텐션 계층에서의 계산을 통해 필요한(중요한) 정보만이 Affine 계층으로 출력된다.

 

어텐션의 기본 아이디어는 Decoder에서 출력 단어를 예측하는 매 시각마다, Encoder에서의 전체 입력 문장을 다시 한 번 참고한다는 것이다. 여기서 어텐션은 전체 입력 문장을 전부 다 동일한 비율로 참고하는 것이 아니라, 해당 시점에서 예측해야할 단어와 연관이 있는 입력 단어 부분을 좀 더 집중(attention)해서 보게 된다.

 

어텐션 계층의 대략적인 개념을 설명했으니, 그래서 어텐션 계층이 어떻게 동작하는지 살펴보도록 하자. 우리는 어텐션 계층이 필요한 정보만을 추출해낸다고 이해했다. 하지만 어텐션 계층도 결국에는 학습을 통해 갱신되는 계층이다. 학습을 통해 갱신됨은 역전파를 활용하여 매개변수값을 조정해 나가는 것이고 이것은 미분을 의미한다. 미분에는 '선택'이라는 개념은 없다. 그렇다면 우리는 어떤 계산을 해야하는걸까?

 

 

 

 


 

 

 

 

 

Attention 계층의 세부 연산을 보여주는 이미지

 

위의 이미지를 보면 Attention 계층은 크게 2가지의 중요 연산으로 나눠 볼 수 있다. 여기서 입력 데이터인 hs는 Enocoder에서 입력되는 모든 은닉 상태의 데이터이며, h는 hs를 활용하여(정확히는 hs 벡터의 마지막 줄) LSTM 계층 연산을 통해 출력된 은닉 상태 벡터(h)이다. Attention Weight은 Encoder가 출력하는 각 단어의 벡터 hs에 주목하여 해당 단어의 가중치 a를 구하고, Weight Sum은 a와 hs의 가중합을 구해 맥락 벡터 c를 출력한다.

 

 

 

Attention Weight

단어의 가중치(기여도)를 나타내는 벡터인 a는 어떻게 구하는걸까?

 

Decoder의 LSTM 계층의 은닉 상태 벡터는 h이며, 우리는 이 h가 Encoder의 입력 데이터인 hs와 얼마나 비슷한가를 수치로 나타내고자 한다. 이를 위해서 우리는 벡터의 내적을 이용한다. 벡터의 내적은 두 벡터가 얼마나 같은 방향을 향하고 있는가를 의미하며, 이는 벡터간의 유사도를 표현하는 척도로 사용될 수 있다.

 

 

위의 이미지처럼 h와 hs의 내적으로 각 단어 벡터의 유사도를 구한 결과가 s이다. 이 s는 정규화 하기 이전의 값으로, 점수라고도 한다. 이 s를 정규화하기 위해 softmax함수를 적용시켜 나온 결과가 바로 우리가 원하는 가중치 a이다.

 

 

 

 

Weight Sum

Weight Sum 계층은 (Attention 계층 안에서도 크게 2가지로 나뉘기 때문에 계층이라고 부르겠다) 모든 은닉 상태 벡터(hs)와 가중치를 나타내는 행렬(a)이 연산(행렬곱)하여 그 결과를 합해 맥락 벡터(c)를 얻어낸다.

 

 

이렇게 어텐션은 두 시계열 데이터 사이의 대응 관계(얼라인먼트:Alignment)를 학습하게 되며, 중요한 정보를 집중적으로 파악할 수 있다. 어텐션에 대해 더 자세히 이해하고 싶다면 이 블로그를 참고하길 바란다.

 

 

 

 

 

seq2seq

seq2seq는 발음 그대로 sequence to sequence라는 뜻으로 여기서 sequence는 시계열 데이터를 의미한다. 즉, seq2seq는 하나의 시계열 데이터를 다른 시계열 데이터로 변환하는 모델을 의미한다. 예를 들자면 음성 인식 및 챗봇과 같은 것이 있겠다. seq2seq는 2개의 RNN을 사용한다.

 

seq2seq를 다른 말로 Encoder-Decoder 모델이라고도 한다. 이는 seq2seq가 Encoder와 Decoder를 사용하기 때문이며, Encoder는 입력 데이터를 인코딩(부호화)하고, Decoder는 인코딩된 데이터를 디코딩(복호화)한다.

 

 

위의 이미지처럼 Encoder가 인코딩한 정보에는 번역에 필요한 정보가 있고, Decoder는 이 정보를 바탕으로 문장을 생성해 출력한다. 이처럼 Encoder와 Decoder를 사용해 시계열 데이터를 다른 시계열 데이터로 변환하는 것이 seq2seq의 전체 그림이며, 우리는 Encoder와 Decoder에서 RNN을 사용한다.

 

Encoder

 

Encoder는 RNN(LSTM)을 이용해 시계열 데이터를 h라는 은닉 상태 벡터로 변환한다. Encoder에서 출력되는 h는 입력 문장(출발어)을 번역하는 데 필요한 정보가 인코딩되며 은닉 벡터 h는 고정 길이 벡터로, 결론적으로 인코딩의 의미는 임의 길이의 문장을 고정 길이 벡터로 변환하는 작업을 뜻한다.

 

 

Decoder

 

Decoder는 RNNLM과 동일한 구조(위에서는 RNN을 LSTM으로 대체함)이지만, LSTM 계층에 h를 입력받고 첫번째 단어가 <eos>라는 특수문자인 것이 큰 차이점이다. <eos>는 문장의 시작을 의미하며, 실질적으로 Decoder는 h의 데이터를 활용하여 문장을 생성해 나간다. Decoder의 첫번째 LSTM 셀은 h와 <eos>, 이 2개의 입력을 바탕으로 새로운 은닉 상태h를 계산하고 이를 Affine 계층과 Softmax 계층을 거쳐 다음에 등장할 확률이 높은 "I"를 예측한다. 이 과정을 문장의 종료를 의미하는 <eos>가 나올때까지 반복하는 것이 Decoder의 개념이다.

 

 

이처럼 seq2seq는 2개의 LSTM(Encoder의 LSTM과 Decoder의 LSTM)로 구성되며 Encoder의 LSTM에서 생성된 은닉 벡터인 h가 Decoder의 LSTM에 전해지면서 서로 다른 시계열 데이터로의 변환이 이루어질 수 있게 된다.

 

추가적으로 seq2seq 역시 신경망이기 때문에 미니배치 학습이 가능한데, 여기서 문제가 발생한다. 만약 seq2seq에 입력되는 문장의 길이들이 모두 동일하지 않고 다른 경우에 어떻게 미니배치 학습을 시킬 수 있을까? 미니배치는 미니배치에 속한 샘플들의 데이터 형상이 모두 똑같아야 하기때문에 패딩(padding)을 사용하여 전체 데이터의 길이를 일정하게 맞춰준다. 패딩은 원래의 데이터에 의미 없는 데이터를 채워 모든 데이터의 길이를 균일하게 맞추는 기법이다.

 

 

 


 

 

 

seq2seq 개선

1. 입력 데이터 반전(Reverse)

입력 데이터를 반전시키는 것만으로도 놀랍게도 seq2seq의 학습 속도는 빨라지고 정확도도 향상된다. 이에 대한 이론적인 부분에 대해서는 정확히 아는 바가 없지만, 참고한 책의 저자는 직관적으로 기울기 전파가 원활해지기때문이라고 한다. 나는 고양이로소이다.가 I am cat이 되기까지, '나'로부터 'I'까지 가기 위해서는 '는','고양이','로소',이다'까지 총 4가지 단어 분량의 LSTM 계층을 거쳐야하고 이는 기울기에 영향을 줄 수 있다. 따라서 입력 데이터를 반전하면 데이터가 대응하는 변환 후 단어와 가까워지는 경향이 많기 때문에 기울기가 더 잘 전해져서 학습 효율이 좋아진다고 이해할 수 있다.

 

2. 엿보기(Peeky)

이것은 DenseNet과 비슷한 개념을 갖고 있다. 즉, Decoder의 처음에 입력되면서 Encoder의 가장 중요한 정보를 갖고 있는 h가 단순히 Decoder 처음에만 입력되는 것이 아니라 다른 계층, 즉 Decoder 전체 계층에 전하는 것이다. 이처럼 중요한 정보를 하나의 LSTM 계층이 갖는 것이 아니라 모든 LSTM 계층이 갖게 되면 더 올바른 결정을 내릴 가능성이 커진다. 

 

 

 

 

 

 

앞서 설명한 RNN은 성능이 좋지 못하다.(ㅠㅠ 도대체 언제 좋은거 만들건데요) 그 원인은 대개 장기 의존 관계, 즉 긴 시계열의 패턴을 파악 및 학습하기 어렵다는 것이다. 따라서 앞서 설명한 RNN은 가장 기초적인 RNN의 개념 정도로만 이해하고 실제로 쓰이는 계층은 주로 LSTM과 GRU이다. 이 LSTM과 GRU는 기존의 RNN에 게이트라는 구조가 더해져 있어 시계열 데이터의 장기 의존 관계를 학습할 수 있다. 게이트가 무엇이고 어떤 구조이길래 장기 의존 관계를 학습할 수 있게 되었는지 LSTM을 통해 살펴보도록 하자.

 

 

 

기존 RNN의 문제점

LSTM을 설명하기 앞서, 기존 RNN이 데이터의 장기 의존 관계를 학습하기 어려운 이유에 대해 자세히 설명하도록 하겠다. 기존의 RNN이 장기 의존 관계를 학습하기 어려운 이유는 BPTT에서 기울기 소실 혹은 기울기 폭발이 일어나기 때문이다. 앞서 BPTT에서 설명했다시피, BPTT는 시간 크기가 커질수록 기울기가 불안정하다. 이와 관련해서 RNNLM을 활용한 하나의 예시를 들도록 하겠다.

 

철수는 교실 책상에 앉아 있다. 영희는 교실로 들어갔다. 영희는 ___에게 인사를 했다.

 

여기서 ___에 들어갈 말은 무엇일까? 이것을 알기 위해서는 사람이나 RNN이나 똑같다. 우리는 영희가 '철수'에게 인사를 한다는 것을 문맥의 흐름으로 유추할 수 있다. 그렇기 위해서는 철수가 교실에 있다는 정보를 기억해야한다. RNN도 동일하다. 영희가 '철수'에게 인사를 한다는 것을 앞서 학습했던 문장을 기억하여 예측할 수 있다. 이런 정보를 RNN 계층은 은닉 상태에 인코딩해 보관해둔다.

 

그렇다면 이 예제에서 RNNLM은 어떻게 학습을 할까? 정답으로 '철수'가 주어졌을 때 RNNLM은 그 시점(정답이 주어진 시점)으로부터 과거 방향으로 기울기를 전달하게 된다.

 

Tom을 철수라고 생각해 이해하자.

 

RNN 계층은 과거 방향으로 의미 있는 기울기를 전달함으로써 시간 방향의 의존 관계를 학습할 수 있다. 하지만 기울기 소실, 혹은 폭발이 일어난다면 유의미한 기울기가 전달되지 못하고 그 결과 가중치 매개변수가 제대로 갱신되지 않아 학습이 잘 되지 않는다. 그렇다면 기존 RNN 계층에서 왜 기울기 소실 혹은 폭발이 일어나는 것일까?

 

 

기울기 소실 및 폭발 원인

1. 활성화 함수 (tanh)

기존 RNN의 활성화 함수로는 tanh함수를 주로 사용하는데, 이는 모든 신경망의 기울기 소실 이유와 동일한 양상을 띠게 된다. tanh함수를 역전파시키면 층이 깊어질수록 기울기값이 점점 작아지는 문제가 발생하게 되기 때문이다.

 

 

2.MatMul(행렬 곱) 노드

기존 RNN의 역전파 시 기울기는 MatMul 노드에 의해서도 변화하게 된다. (여기서는 기울기 폭발을 생각하기 위해 tanh함수의 역전파는 무시하도록 한다.) 기울기는 MatMul 노드를 지나가는 횟수에 비례해 폭발적으로 증가 혹은 감소하게 된다. MatMul 노드의 값이 1 이상인 경우는 층이 깊어질수록 곱해지면서 기울기 폭발이 일어나고, 1 이하인 경우는 층이 깊어질수록 기울기 감소가 일어나게 된다. 지금 설명은 MatMul 노드가 스칼라값이지만 행렬일 경우에는 행렬의 특잇값(데이터가 얼마나 퍼져 있는지를 나타냄)이 척도가되어 특잇값의 최댓값이 1보다 크면 지수적으로 증가하고, 1보다 작으면 지수적으로 감소할 가능성이 높다고 예측한다.

 

 

기울기 폭발에 대한 대책으로는 기울기 클리핑(gradient clipping)을 사용한다. 기울기 클리핑의 식은 다음과 같다.

 

기울기 클리핑

 

신경망에서 사용되는 모든 매개변수에 대한 기울기를 하나로 처리한다고 가정(모든 매개변수에 대한 기울기의 합)하고, 이를 g라고 표현했다. 이때 ||g||이 문턱값을 초과하면 두번째 줄의 수식과 같이 기울기를 수정하는 것을 기울기 클리핑이라고 하며 이는 기울기 폭발을 효과적으로 잘 대처한다.

 

 

 

 

LSTM

기존 RNN 계층의 기울기 소실 문제를 해결하기 위한 게이트를 추가한 것이 바로 LSTM이다. LSTM은 기울기 소실이 일어나기 매우 어려운 구조로 되어있기 때문에 대부분의 시계열 데이터 처리의 가장 기본으로 LSTM을 주로 사용한다.

 

σ 는 Sigmoid 함수를 의미한다.

 

기억 셀(memory cell)

LSTM은 은닉 벡터인 h뿐만 아니라 c라는 경로도 있다. c를 기억 셀(memory cell)이라 하며, LSTM 전용의 기억 메커니즘이다. 기억 셀의 특징은 은닉 벡터인 h와 다르게 데이터를 LSTM 계층 내에서만 주고받고 다른 계층으로는 출력하지 않는다는 것이다. ct는 시각 과거부터 시각 t까지에 필요한 모든 정보가 저장되어 있다. ct는 은닉 상태 ht의 계산에 사용되기 때문에(ht=tanh(ct)) 은닉 상태와 기억 셀의 원소 수는 동일하다.

 

 

LSTM을 구성하는 다양한 게이트들을 설명하기에 앞서 게이트의 정의에 대해 설명하도록 하겠다. 게이트는 데이터의 흐름을 제어하는 역할을 한다. LSTM에 사용하는 게이트는 열기, 닫기 뿐만 아니라 어느 정도의 데이터를 흘려 보낼지에 대한 제어도 할 수 있다. 이것 역시 데이터로부터 자동으로 학습되는 정보이다. 게이트는 게이트의 열림 상태를 제어하기 위해 전용 가중치 매개변수를 이용하며, 이 가중치 매개변수는 학습 데이터로부터 갱신된다. 게이트의 열림 상태를 제어하는 것을 학습하는데 사용되는 함수는 Sigmoid 함수이다.

 

 

 

output 게이트

ouput 게이트

 

output 게이트는 ht(=tanh(ct))의 각 원소에 대해 그것이 다음 시각의 은닉 상태에 얼마나 중요한가를 조정한다. 즉, 데이터를 얼마나 흘려보낼지를 결정하는 게이트이다. output 게이트의 열림 상태는(몇 %를 흘려보낼까) 입력 xt와 이전 상태 ht-1로부터 구한다.

 

output 게이트 수식

 

이 output 게이트 식과 tanh(c)의 원소별 곱(아마다르 곱)은 h로 출력된다.

 

 

 

 

 

forget 게이트

 

forget 게이트는 기억셀이 불필요한 기억을 잊도록 돕는 게이트이다.

 

 

 

 

 

새로운 기억 셀

 

forget 게이트를 거치면서 이전 시각의 기억 셀로부터 잊어야 할 기억이 삭제된 후, 새로 기억해야 할 정보를 기억셀에 추가해야 한다. 이를 위해 우리는 tanh 노드를 추가한다. tanh 노드가 계산한 결과가 이전 시각의 기억 셀(ct-1)에 더해진다. 이는 기억 셀에 새로운 정보를 추가하는 것으로, 여기서 사용되는 tanh는 게이트가 아니다. tanh를 사용하는 목적은 기억 셀에 새로운 정보를 추가하는 것이 목적이다. 따라서 새로운 기억셀에 대한 식은 다음과 같다.

 

 

g는 새로운 기억으로 이전 시각의 기억 셀인 ct-1에 더해진다.

 

 

 

 

input 게이트

 

input 게이트는 새로운 기억인 g에 추가하는 게이트로, g의 각 원소가 새로 추가되는 정보로써의 가치가 얼만큼인지를 판단한다. 새 정보를 무비판적으로 수용하는 것이 아니라, 적절히 선택하는 것이 이 게이트의 역할이다.

 

 

 

결론적으로 LSTM은 기존의 RNN과 달리 기억 셀이라는 것이 존재하고 이 기억 셀을 잘 활용하기 위해 output, forget, input 게이트가 사용된다. 이 기억 셀은 역전파시 +와 x노드만을 지나고, +노드는 역전파시 상류에서 전해지는 기울기를 그대로 흘리기 때문에 기울기 소실이 발생하지 않으며 기억 셀에서 사용되는 x노드는 행렬 곱이 아닌 원소별 곱이기 때문에 매번 새로운 게이트 값을 이용하므로 곱셈 효과가 누적되지 않아 기울기 소실이 발생하지 않는다.

 

LSTM의 x노드는 forget 게이트가 제어하며, forget 게이트가 잊어야 한다고 판단한 기억 셀의 원소에 대해서는 기울기값이 작아지고 잊지 말아야 한다고 판단한 기억 셀의 원소에 대해서는 기울기 소실 없이 그대로 전파된다.

 

LSTM에 사용되는 게이트들의 식을 보면 다음과 같이 4개의 가중치(또는 편향)를 하나로 모을 수 있고, 원래 별개로 4번의 계산을 수행해야 했던 것이 단 1회의 계산만으로 동일한 결과를 얻을 수 있게 된다.

 

 

 

 

 

 


 

 

 

 

 

 

추가적으로 RNN의 개선방안에 대해 간략하게 이야기하고 넘어가겠다.

RNN도 여타 신경망과 같이 overfitting의 문제가 발생한다. 이를 해결하기 위해서는 훈련 데이터의 양 늘리기와 모델의 복잡도 줄이기, 정규화, 드롭아웃(drop out)이 있다. 이 중에서 드롭아웃에 대해 살펴보면, RNN에서는 dropout 계층을 어디에 삽입해야할까? 정답은 상하 방향으로 삽입하는 방법이다.

 

dropout 계층 사용의 좋은 예

 

이렇게 상하 방향으로 드롭아웃을 삽입하는 이유는 드롭아웃을 시계열 방향으로 삽입하면 학습 시 시간이 흐를수록 드롭아웃에 의한 노이즈가 축적되어 정보가 사라질 수 있기 때문이다. 상하 방향으로 드롭아웃을 삽입하면 시간 방향(좌우 방향)에 영향을 주지 않는다.

 

하지만 의지의 인간은 기존의 드롭아웃 말고 새로운 드롭아웃을 만들어 시간 방향에도 드롭 아웃을 사용할 수 있게 했는데 자세한 내용은 여기를 참고하길 바란다.

 

 

 


 

 

 

 

또한 가중치 공유는 RNN의 성능을 높이는데 큰 도움을 준다. Embedding 계층의 가중치와 Affine 계층의 가중치를 연결하는 방법인 가중치 공유는 두 계층의 가중치를 공유함으로써 학습하는 매개변수 수가 크게 줄어드는 동시에 정확도도 향상된다.

 

 

이로써 LSTM에 대한 설명은 끝이 났다. 필자가 처음에 LSTM을 공부할 땐 제대로 이해가 안갔는데 3번 정도 읽으니 이해가 갔다.(ㅠㅠ) 모두들 힘내봅시다!

 

 

 

이전에 소개했던 word2vec은 기존의 자연어 처리 방법보다 효과적이지만, 치명적인 단점이 존재하는데 맥락이 길어지면 길어질수록 그와 비례해 가중치 매개변수가 늘어나 연산량이 늘어난다는 점이다. 이 문제 때문에 우리는 결국 엄청난 말뭉치의 데이터를 학습하는데 어려움을 겪게 된다. 이 단점의 근본적인 원인은 우리가 이전에 배웠던 신경망들은 전부 feed forward 유형의 신경망이었기 때문이다. feed forward란 흐름이 단방향인 신경망을 의미하고 feed forward는 시계열 데이터의 성질(패턴)을 충분하게 학습할 수 없다.

 

그 이유를 간단하게 말하자면 feed forward 방식은 단방향의 신경망으로, 흐름을 따라갈수만 있지 기억할 수 없기 때문이다. 자연어나 기타 시계열 데이터는 데이터의 흐름성을 기억하며 그 흐름성의 특징을 기억해야하기 때문에 기존의 feed forward 방식의 신경망으로는 시계열 데이터를 다룰 수 없다. 따라서 우리는 시계열 데이터를 처리할 때 RNN이라는, 직역하면 순환 신경망인 신경망을 사용한다.

 

 

 

RNN(Recurrent Neural Network)

RNN은 기존의 feed forward방식의 한계점을 개선하고자 순환하는 경로가 있다. 순환하는 경로가 뭐고 왜 필요한걸까? 순환하는 경로는 다른 말로 닫힌 경로라고도 불리며, 이 경로가 존재해야 데이터가 같은 장소를 반복해 왕래할 수 있고 그 데이터가 순환하며 과거의 정보를 기억하는 동시에 새로운 정보를 끊임없이 갱신할 수 있다.

 

 

Xt는 RNN 계층에 입력되는 시계열 데이터를 의미하며 그 입력에 대응한 출력이 ht로 나오게 된다. Xt를 조금 더 자세히 설명하자면 문장 데이터인 경우, 각 단어의 분산 표현(단어 벡터)이 Xt가 되며, 이 분산 표현이 순서대로 하나씩 RNN 계층에 입력됨을 의미한다. 위의 계층은 결론적으로 오른쪽으로, 즉 한 방향으로 뻗어나가는 구조를 갖고, 이는 feed forward 신경망과 같은 구조이나 각 RNN 계층이 그 계층으로의 입력(X1)과 전의 RNN 계층으로부터의 출력(h0)을 받아 두 정보를 바탕으로 현 시각의 출력을 계산한다.

 

이때문에 RNN 의 가중치는 2개인데 하나는 입력 x를 출력 h로 변환하기 위한 가중치 Wx이고 하나는 RNN 출력을 다음 시각의 출력으로 변환하기 위한 가중치 Wh이다. 위의 이미지를 보면 각 RNN의 계산 결과인 ht는 출력이 되면서 다음 RNN 계산에 입력되는데, 이 ht는 각 RNN의 출력 결과물로 상태를 의미한다. 따라서 RNN 계층을 상태를 갖는 계층 혹은 메모리(기억력)가 있는 계층이라고 표현한다. 또한 RNN의 출력 ht는 은닉 상태 또는 은닉 상태 벡터라고도 한다.

 

 

 

 

BPTT(Backpropagation Through Time)

위의 이미지와 같이 순환 구조를 펼친 후의 RNN에는 일반적인 오차역전파법을 적용할 수 있다. 이를 시간 방향으로 펼친 신경망의 오차역전파법이라는 뜻으로 BPTT라고 한다. 우리는 BPTT를 통해 RNN을 학습할 수 있게 되는데, 긴 시계열을 학습할 경우에는 메모리 사용량 증가 및, 시간 크기가 커질수록 기울기가 불안정하다는 문제점이 발생한다. 이를 해결하기 위한것이 바로 Truncated BPTT기법이다.

 

 

 

 

Truncated BPTT

시간축 방향으로 너무 길어진 신경망을 적당한 지점에서 잘라내어 작은 신경망 여러 개로 만든다는 아이디어를 사용하여, 잘라낸 작은 신경망에서 오차역전파법을 수행하면 기존 BPTT에서 발생할 수 있는 문제점을 해결할 수 있다. Truncated BPTT는 순전파는 그대로 유지하고(계속 연결됨) 역전파의 연결만 끊는다.

 

 

Truncated BPTT 또한 미니배치 학습을 진행할 수 있는데, 미니배치 학습 수행을 할 경우, 데이터를 제공하는 시작 위치를 각 미니배치(각 샘플)로 옮겨준 후 순서대로 제공하면 된다. 또한 데이터를 순서대로 입력하다 끝에 도달하면 다시 처음부터 입력하도록 하여 RNN의 특징을 살리면서 미니배치 학습을 할 수 있다. Truncated BPTT는 긴 시계열 데이터 학습 시 메모리 사용량 증가와 기울기 불안정 문제를 해결하기 위해 역전파의 경우에만 신경망을 일정하게 끊어 역전파를 구하는 방법이다. 이 Truncated BPTT는 데이터를 순서대로 제공하는 것과 미니배치별로 데이터를 제공하는 시작 위치를 옮기는 것이 데이터 제공 면에서 가장 중요하다.

 

 

 

 


 

 

 

 

 

위의 그림은 RNN Language Model(RNNLM)로, 자연어를 처리하는 RNN이라고 보면 된다. 단어ID인 Wt가 들어가 Embedding 계층을 통해 단어의 분산 표현(딴어 벡터)으로 변환된다. 이 분산 표현이 RNN에 들어가고 RNN의 출력 데이터는 은닉상태(ht)를 Affine층으로 출력함과 동시에, 다음 시각의 RNN 계층으로 출력하게 된다.

 

 

RNN을 이용하여 자연어를 처리(RNNLM)하면 이전에 설명했던 word2vec 신경망과는 달리 이전의 데이터에 대한 정보도 기억하고 있다. RNN은 과거의 정보를 응집된 은닉 상태 벡터(ht)로 저장해두고 있다. 이 정보를 Affine 계층에, 그리고 다음 시각의 RNN 계층에 전달하는 것이 RNN 계층이 하는 일이다.

 

이러한 RNNLM은 지금까지 입력된 단어를 '기억'하고, 그것을 바탕으로 다음에 출현할 단어를 예측한다. 이것이 가능한 이유는 RNN 계층이 과거에서 현재로 데이터를 계속 흘려보내주기 때문에 과거의 정보를 인코딩해 저장(기억)할 수 있기 때문이다.

 

언어 모델은 주어진 과거 정보(단어)로부터 다음에 출현할 단어의 확률분포를 출력한다. 이 때 언어 모델의 예측 성능을 평가하는 척도로 퍼플렉서티(Perplexity,혼란도)를 자주 사용한다. 퍼플렉서티는 확률의 역수로, 퍼플렉서티가 작으면 작을수록 좋은 모델이다. 이것에 대해 조금 더 자세히 말하자면, 퍼플렉서티는 분기수로 해석할 수 있으며 이 말은 퍼플렉서티가 1에 가까우면 단어의 후보가 1개라는 의미이고, 퍼플렉서티가 5이면 단어의 후보가 5개라는 의미이다. 따라서 퍼플렉서티가 작으면 작을수록 분기수, 즉 단어의 후보 수도 적기 때문에 좋은 모델이 된다.

 

 

 

 

앞서 설명했던 시소러스와 통계 기반 기법과 달리 이번에 설명할 추론 기반 기법은 신경망을 사용한다.

 

 

통계 기반 기법의 문제점

통계 기반 기법에 대해 간단히 설명하자면, 통계 기반 기법은 주변 단어의 빈도를 기초로 단어를 표현하는 방법이다. 구체적으로는 단어의 동시발생 행렬을 만들고 그 행렬에 특잇값 분해(SVD)를 적용하여 밀집벡터(단어의 분산 표현)를 얻었다. 하지만 이러한 방식은 실제 생활에서 사용하는 수많은 단어를 다루기에는 적합하지 않다. 예를 들어 어휘가 100만 개라면, 통계 기반 기법에서는 100만x100만이라는 거대 행렬을 만들기 때문이다. 이처럼 행렬이 매우 크기 때문에 특잇값 분해(SVD)를 사용해 차원을 축소하는 것은 사실상 불가능한 일이다.

 

 

 

 

추론 기반 기법

추론 기반 기법은 신경망을 사용하여 단어를 처리하는 기법으로 미니배치 학습을 하여 수많은 어휘를 효율적으로 학습한다. 추론 기반 기법과 통계 기반 기법의 차이점에 대해서는 아래의 표를 참고하길 바란다.

 

통계 기반 기법(배치 학습) 학습 데이터를 한꺼번에 처리한다.
/
어휘에 추가할 새 단어 발생시 단어 분산 표현 갱신을 위해 처음부터 다시 계산해야한다.
/
단어의 유사성 인코딩
추론 기반 기법(미니배치 학습) 학습 데이터의 일부를 사용하여 순차적으로 학습한다.
/
어휘에 추가할 새 단어 발생시 단어 분산 표현 갱신을 위해 매개변수만 다시 학습하면 되므로 기존에 학습한 내용을 해치지 않고 단어의 분산 표현을 효율적으로 갱신할 수 있다.
/
단어의 유사성 인코딩 및 단어 사이의 패턴 파악 가능
ex. king-man+woman=queen

 

 

통계 기반 기법은 단어의 맥락을 파악했다면, 추론 기반 기법은 맥락을 입력하면 사이에 나올 단어의 출현 확률을 출력하는 형태이다. 예를 들어 you ___ goodbye and I say hello. 라는 문장에서 ___ 에 들어갈 문장에 대한 확률을 추측하는 것이 바로 추론 기반 기법이다.

 

 

추론 기반 기법이란 위의 이미지에서의 모델이 맥락 정보를 입력받아 ___에 나올 수 있는 단어의 출현 확률을 출력하고, 우리는 말뭉치를 사용해 모델이 올바른 추측을 하도록 학습시키며 그 학습의 결과로 단어의 분산 표현을 얻는 기법을 뜻한다.

 

위의 모델은 신경망을 의미한다. 그럼 어떻게 해야 신경망이 you와 goodbye를 이해하며 받아들일 수 있을까? 이를 위해 우리는 input data인 단어들을 one-hot 벡터로 변환하여 입력한다.

 

 

one-hot 벡터는 위의 you, say, goodbye의 각각의 벡터들과 같이 본인들이 표현되는 위치만 1이고 나머지는 모두 0인 벡터를 의미한다. 이처럼 one-hot encoding을 하는 이유는 신경망의 입력층의 뉴런 수를 고정시키기 위해서이다. 이렇게 만들어진 각각의 벡터들은 기존에 우리가 배운 신경망의 학습 방법과 동일하게 가중치와의 연산을 통해 은닉층으로 넘어가게 되고 이 과정을 반복하며 유의미한 가중치(매개변수)를 얻어낼 수 있다.

 

 

 

 


 

 

Word2Vec

CBOW 모델

word2vec이라는 용어는 원래 프로그램이나 도구를 가리키는 데 사용됐다고 한다. 하지만 이 용어가 유명해지면서, 문맥에 따라 신경망 모델을 가리키는 경우도 볼 수 있다고 한다. 이 글에서의 word2vec은 신경망 모델을 가리키는 경우로 판단하길 바란다. CBOW 모델은 wrod2vec에서 제안하는 신경망으로 맥락으로부터 타깃을 추측하는 용도의 신경망이다. 여기서 타깃이란 중앙 단어이고 그 주변 단어들을 맥락이라고 표현한다. 즉 위의 예제에서 you goodbye는 맥락, ___에 들어갈 say가 타깃이라고 볼 수 있겠다.

 

 

CBOW 모델의 구조는 위의 이미지와 같은데 여기서 입력층이 2개인 이유는 맥락으로 고려할 단어를 2개로 정했기 때문이다. 만약 맥락에 포함시킬 단어를 N개로 지정하면 입력층도 N개가 된다.

 

아무튼 이 입력층 데이터는 은닉층을 거쳐 출력층으로 나오고, 두 입력층에서 은닉층으로의 변환은 똑같은 완전연결계층(가중치 : Win)이 처리한다. 또한 은닉층에서 출력층 뉴런으로의 변환은 다른 완전연결계층(가중치 : Wout)이 처리한다. 결론적으로 입력층과 은닉층 사이의 매개변수인 Win은 두개의 입력층이 같은 값을 공유한다는 이야기이며 입력층과 은닉층 사이의 가중치와 은닉층과 출력층 사이의 가중치는 서로 다른 값이라는 이야기이다.

 

은닉층의 뉴런은 입력층 전체의 평균이며, 출력층의 뉴런은 총 7개로, 뉴런 하나하나가 문장 각각의 단어에 대응한다. 또한 출력층 뉴런은 각 단어의 점수를 의미하며 이 점수가 Softmax 함수를 지나면 출현 확률로 나타내진다.

 

또한 입력층과 은닉층 사이의 매개변수인 Win은 단어의 분산 표현을 의미한다. Win의 크기는 위의 이미지를 참고하면 7x3의 행렬이며, 가중치의 각 행은 해당 단어의 분산 표현이다. 따라서 학습이 진행될수록 맥락에서 출현하는 단어를 잘 추측하는 방향으로 이 분산 표현들이 갱신될 것이다.

 

은닉층의 뉴런 수는 입력층의 뉴런 수보다 적어야하는데, 그 이유는 은닉층에는 단어 예측에 필요한 정보를 간결하게 담아 밀집벡터 표현을 얻기 위해서이다. 입력층과 매개변수(Win)의 연산 결과로 나온 은닉층(인코딩)은 인간이 이해할 수 없으나 이를 인간이 이해할 수 있는 표현으로 복원(디코딩)하게 되면 우리는 밀집벡터 표현을 얻을 수 있다.

 

설명한 내용 시각화

 

 

CBOW 모델이 학습하는 것은 매개변수이다. 이 매개변수들은 가중치에 단어의 출현 패턴을 파악한 벡터가 학습된다. CBOW 모델은 단어 출현 패턴을 사용하는 말뭉치에서 배우기 때문에 말뭉치가 다르면 학습 후 얻게 되는 단어의 분산 표현도 달라질 수 있다.

 

CBOW 모델은 결론적으로 다중 클래스를 분류하는 신경망으로, 학습에 사용되는 것들은 Softmax 함수와 Cross Entropy(교차 엔트로피) 오차이다. 여기서 Softmax 함수는 출력층의 결과인 점수를 확률로 변환하는 것이고, 그 확률과 정답 라벨의 오차(분류이기 때문에 Cross Entropy 사용)를 손실로 사용하여 매개변수를 학습한다.

 

 

 


 

 

 

CBOW모델 개선

Embedding(임베딩) 계층

CBOW 모델의 입력층인 맥락은 위에서 설명한것처럼 one-hot encoding된 형태일 수 있지만 이렇게 되면 단어의 개수가 많아질수록 연산량 또한 많아진다. 하지만 실질적으로 one-hot encoding된 입력층과 MatMul(Win) 계층의 행렬 곱은 단지 행렬의 특정 행을 추출하는 것 뿐이다.

 

 

따라서 one-hot encoding한 입력층과 MatMul 계층의 행렬 곱 연산은 사실상 필요하지 않다. 따라서 이와 같은 효과를 지닌, 즉 가중치 매개변수로부터 단어 ID에 해당하는 행(벡터)을 추출하는 계층인 Embedding(임베딩)계층을 사용한다. 결론적으로 Embedding 계층은 단어의 분산 표현을 저장하는 것이다. MatMul 계층을 Embedding 계층으로 전환하는 것은 메모리 사용량 감소와 계산량 감소의 효과를 불러일으킨다.

 

 

 

이진 분류

이진 분류는 은닉층 이후의 연산에 대한 병목 현상, 즉 다중 분류의 문제점을 효과적으로 해결하기 위한 방안이다. 은닉층 이후에서 계산이 오래 걸리는 곳은 은닉층의 뉴런과 가중치 행렬(Wout)의 곱과 Softmax 연산, 이 두곳이다. 이 두곳의 문제점을 해결하는 방법은 이진 분류이다. 우리는 은닉층 이후의 병목 현상이 나타나는 이유로, 다중 분류의 문제점을 파악할 수 있다. 다중 분류는 수많은 어휘 각각마다의 확률 및 계산 결과를 알아야하기 때문에 그만큼 연산량이 많아지지만, 이를 이진 분류 문제로 바꿔 Yes/No의 대답으로 나타낼 수 있게끔 하면 계산량이 효과적으로 줄어들 수 있다. 예를 들어 맥락이 you와 goodbye일 때, 타깃 단어가 say냐는 물음에 우리는 say가 나올 확률을 출력하면 된다.

 

 

결론적으로 앞에서 설명했던 방식의 출력층은 모든 단어를 대상으로 계산을 수행했으나, 타깃으로 예상되는 단어에 주목하여 그 점수, 확률만을 계산하는 것이 차이이다.

 

우리는 CNN 신경망에 대해 자세히 공부하면서 이진 분류일 경우 출력층에서 Sigmoid 함수를, 다중 분류일 경우에는 Softmax 함수를 사용한다는 것을 알 수 있었다.(손실 함수는 둘 다 교차 엔트로피 사용) 따라서 우리는 CBOW 모델을 이진 분류를 수행하는 모델로 바꿔 계산량을 효과적으로 줄일 수 있다.

 

 

위의 이미지에서 은닉층 뉴런 h와 출력 측의 가중치 Wout에서 단어 'say'에 해당하는 단어 벡터와의 내적을 계산하고, 계산 결과를 Sigmoid with Loss 계층에 입력해 최종 손실을 얻는다.

 

 

 

Negative Sampling

위의 이진 분류는 정답에 대해서만 학습하고 오답인 경우에 대해서는 학습하지 않았다. 이 말을 달리 표현하자면 오답인 단어도 충분히 정답과 같은 확률로 나타내질 수 있다는 이야기이다. 우리는 이 신경망 모델이 정답에 대해서는 Sigmoid의 출력이 1에 가깝도록, 오답에 대해서는 0에 가깝도록 만드는 것이 최종적인 목표이다. 따라서 오답인 경우에 대해서도 학습을 시켜야 한다. 어떻게 하면 오답인 경우에 대해서도 효과적으로 학습할 수 있을까?

 

학습에 사용되는 말뭉치에서 오답인 경우를 모두 학습시킨다는 것은 현실적으로 말이 되지 않는다. 따라서 우리는 이런 경우에 효과적인 학습을 위해 Negative Sampling을 사용한다. Negative Sampling은 부정적인 예(오답) 몇 개를 선택(샘플링)하여 사용하는 것이다. 네거티브 샘플링은 긍정적인 예(정답)를 타깃으로 한 경우의 손실과 부정적인 예 몇 개를 샘플링(선별)하여, 그 부정적인 예에 대해서도 손실을 구하고 각각의 데이터의 손실을 더한 값을 최종 손실로 하는 것을 의미한다.

 

그렇다면 어떻게 부정적인 예를 샘플링 할 수 있을까? 단순히 무작위로 샘플링하는 것보다 좋은 방법이 존재하는데, 그것은 바로 말뭉치에서 자주 등장하는 단어를 많이 추출하고 드물게 등장하는 단어를 적게 추출하는 방법이다. 이를 위해 말뭉치에서 각 단어의 출현 횟수를 구해 확률분포로 나타낸 후, 그 확률분포대로 단어를 샘플링한다.

 

Negative Sampling 식

 

위의 Negative Sampling 식에서 확률분포의 각 요소를 0.75 제곱하는 이유는 출현 확률이 낮은 단어의 확률을 살짝 올려 샘플링에서 배제되는 것을 방지하기 위함이다. 꼭 0.75가 아닌 다른 숫자가 와도 된다.

 

 

 

 

 

 

 

Skip-gram 모델

skip-gram 모델은 CBOW에서 다루는 맥락과 타깃을 역전시킨 모델이다. 즉, 입력층에 중앙 단어(CBOW에서 타깃이었던 단어)로부터 주변의 여러 단어(맥락)를 추측한다. skip-gram 모델은 입력층이 하나고 출력층이 맥락의 수만큼 존재한다.

 

 

word2vec에서는 단어의 분산 표현으로 입력과 은닉층 사이의 가중치 Win을 최종 단어의 분산 표현으로 이용한다.

 

그런데 왜 word2vec은 CBOW와 skip-gram 모델 두가지를 추천하는 걸까?

이에 대해서는 두 모델의 장단점을 보면 알 수 있는데, 단어 분산 표현의 정밀도 면에서는 skip-gram 모델의 결과가 더 좋은 경우가 많지만(말뭉치가 커질수록 저빈도 단어나 유추 문제의 성능이 skip-gram이 더 뛰어남) 학습 속도 측면에서는 CBOW모델이 더 빠르다.

 

word2vec으로 얻은 단어의 분산 표현을 사용하면, 벡터의 덧셈과 뺄셈으로 유추 문제를 풀 수 있다. 예를 들어 king : man = queen : ? 에서 ?에 woman을 대답할 수 있고, take : took = go : ? 에서 ?에 went를 대답할 수 있다. 이 말은 즉, 단어의 단순한 의미 뿐만 아니라 문법적 패턴도 파악할 수 있다는 뜻이다.

 

 

 

 


 

 

 

현재까지 설명한 내용 중, 모든 내용이 중요하지만 가장 근본적으로 중요한 것은 역시 단어나 문장을 고정 길이 벡터로 변환할 수 있다는 것이다. 자연어를 벡터로 변환할 수 있게 됨으로써 우리는 일반적인 머신러닝 기법을 적용할 수 있게 되었기 때문이다. 이러한 word2vec의 근본적인 해결책과 생각들은 자연어 뿐만 아니라 음성, 이미지, 동영상 등에서도 응용이 되어 다양한 딥러닝 분야 발전에 도움을 주었다.

 

+ Recent posts