안녕, 세상!

transformer 본문

It공부/Deep learning

transformer

dev_Lumin 2021. 6. 30. 11:34

transformer은 워낙 유명한 모델이며 현재 다양한 분야에서 응용되어 사용되고 있습니다.

그리하여 기본적인 작동에 대한 설명이 잘 되어 있는 글은 정말 많습니다.

제 글은 transformer에서 특정 구조의 설계에 대한 이유,

무슨 의도로 다음과 같이 구성을 하였는지에 대한 설명을 중점으로 기술하였습니다.  

(1) Seq2seq의 한계와 attention의 발전

Attention

seq to seq의 문제점은 context vector가 고정된 크기로 되었다는 것입니다.

입력 data의 문장의 길이와 상관없이 context vector가 고정되었다는 것은 긴 문장들의 경우에 과도하게 정보를 압축하게 되므로 정보의 손실이 발생되며 효율적이지 못한 방법입니다.

 

사람이 문장을 번역할 때 '어떤 단어'에 주목하여 그 단어의 변환을 수시로 하게 될 것입니다.

이를 모델에 적용하여 '입력과 출력의 여러 단어 중 어떤 단어끼리 서로 관련되어 있는가'라는 대응관계를 seq2seq에게 학습을 시킬 수 있다면 보다 훌륭하게 학습을 할 것입니다.

 

이에 따라서 attention 기법이 도입이 됩니다.

 

Encoder 변화

attention이 도입되면서 seq2seq의 encoder부분에서 변화가 생깁니다.

기존 context vector은 마지막 결과에 나오는 은닉 상태만을 고정된 벡터로 decoder에 넘겨서 수행했습니다.

이를 개선하여 각 입력 단어들 마다의 문맥적 의미를 지닌, 각 LSTM으로부터 나온 은닉 상태 벡터를 모두 이용하여 입력된 단어와 같은 수의 벡터를 얻어 이를 decoder에게 정보를 제공합니다.

시각별 LSTM계층의 은닉 상태에는 직전에 입력된 단어에 대한 정보가 많이 포함되어 있을 것이기 때문에 각 단어의 문맥을 나타내는 벡터라고 생각할 수 있습니다.

 

Decoder의 변화

'어떤계산' 이라는 부분이 바로 attention기법이 적극적으로 도입되는 부분입니다.

정답에 대해 학습을 할 때 어떤 부분을 더 주목하여 데이터를 학습시킬 것인지가 바로 이 부분에서 이뤄지는 것입니다.

Encoder의 입력단어들에 대한 정보를 Decoder에서 참조합니다.

Decoder은 Decoder의 입력 단어들에 대한 다음에 올 단어가 무엇인지 예측하는 과정에서 Encoder의 입력 단어와 Decoder의 입력 단어의 관계를 파악하고,

Decoder의 입력단어가 Encoder로부터 제공받은 단어들 중 어떤 단어와 연관성이 제일 높은지에 대한 정보를 고려하게 되는 것입니다.

 

'어떤 계산'의 input은 Encoder로부터 받을 hs와 decoder의 각 LSTM의 시각별 계층의 은닉 상태입니다.

그리고 hs의 마지막 줄, seq2seq에서 context vector와 같이 LSTM의 첫 번째 계층에 전달됩니다.

 

'어떤 계산'은 예시를 들어 역할을 설명하면 decoder의 "I"를 출력할 때 hs에서 "나"에 대응하는 벡터에 집중해서 학습되도록, 즉 해당 벡터가 비중 있게 선택되도록 하는 역할을 합니다.

이에 따라 decoder의 단어에 대해서 encoder의 어떤 단어가 중요한지에 대한 각 단어의 중요도(기여도)를 나타내는 '가중치'를 별도로 계산해야 합니다.

 

중요도는 확률분포처럼 0.0~1.0 사이의 스칼라(단일 원소)이며, 모든 원소의 총합은 1입니다.

중요도가 구해지면 hs에 중요도(단일 원소)가 각 행에 스칼라곱을 하여 나온 결과의 행들의 합을 구하여 이를 맥락 벡터라고 합니다.

a가 바로 중요도

 

중요도 구하는 법

중요도는 가중치로 데이터로부터 자동으로 학습할 수 있도록 구축되어야 합니다.

decoder의 LSTM계층의 은닉 상태 벡터(h)hs를 '어떤 계산'에 입력으로 사용된다고 앞서 말했습니다.

이 h의 벡터는 곧 decoder의 입력 단어에 대한 의미를 나타내는 벡터가 될 것이고,

중요도를 알려면 h와 hs의 각 단어 벡터들이 서로 얼마나 비슷한가(연관성이 있는가)를 알면 이것이 곧 중요도입니다.

두 개의 벡터의 비슷한 정도를 알기 위해 단순하게 '내적'을 사용하면 됩니다.

이를 통해 중요도를 알 수 있습니다.

이것이 가능한 이유는 hs와 h 모두 지속적인 학습을 통해서 encoder과 decoder에 입력된 각각의 단어들에 대한 의미 벡터가 점차 형성이 될 것이며, ( 의미 벡터란 해당 단어가 언어에서의 문맥적 의미)

단어마다 의미 벡터는 우리가 사용하는 언어에 맞게 학습이 됩니다.

만약 특정 단어들 간에 연관성이 있다면 서로 의미 벡터들이 비슷한 방향으로 형성된다고 기대를 할 수 있고 그에 따라 내적으로 두 단어가 연관도가 높다는 것을 알 수 있어 중요도 값이 결정될 수 있는 것입니다.

애초에 attention 매커니즘의 가정은 예시로 설명하자면,

인코더가 '고양이'를 받아서 벡터로 만든 결과는 Decoder가 'cat'을 예측할 때 쓰는 벡터와 유사할 것이라는 점입니다. 

 

 

 

 

(2) Transformer

Transformer

위에서 설명한 attention은 인간의 사고의 특징 attention을 자동화로 학습시킬 수 있는 체계를 컴퓨터로 구축이 가능하여 attention기법이 도입이 가능하게 되었습니다.

이 attention 기법이 모델을 진화시키는데 핵심적인 역할을 또다시 합니다.

 

앞서 설명한 모델의 큰 단점이 있습니다.

바로 병렬 처리로 빠르게 계산을 하지 못한다는 단점입니다.

그 이유는 바로 LSTM(RNN), 시계열에 의존하는 구조를 사용하기 때문에 동시에 계산을 할 수 있는 병렬 처리를 할 수 없습니다.

ex) 두 번째 LSTM은 첫 번째 LSTM의 결과에 종속성을 가지고 있어서 병렬 처리가 불가

 

이를 해결하려면 구조 자체를 바꿔야 합니다.

그래서 LSTM(RNN)을 없애버리고 attention 기법을 사용하여 병렬 처리가 가능한 모델이 바로 transformer입니다.

 

Embedding

보통 입력 부분에서 임베딩 과정을 거칩니다. 

입력 차원을 입력하는 단어의 개수와 일치하게 해 줄 수 있게 하며,

입력값들을 임베딩 형태로 표현해주기 위해서 사용하는 계층입니다.

쉽게 말하면 단어의 의미를 숫자, 벡터로 표현해줄 수 있는 가장 단순한 작업입니다.

 

앞서 말했듯이 transformer는 seq2seq의 병렬적 한계를 해결하기 위해서 LSTM을 없애버렸습니다.

LSTM의 존재는 곧 단어들의 순서에 대한 정보가 포함되어 있습니다.

그러한 LSTM이 없어졌으니 추가적으로 단어들의 위치를 표현해줄 정보가 필요합니다.

 

 

positional Encoding

위치의 정보를 embedding 계층에 더하여 그 값을 encoder 혹은 decoder에 제공되도록 합니다.

처음에는 embedding layer에 단순한 덧셈이 왜 위치에 대한 정보가 제공되는 것이고 encoder, decoder에 복잡한 덧셈과 곱셈들로 계산들이 존재하는데 이 위치정보가 유지되지 않을 것이라는 생각에 존재의 이유를 혼동하였습니다.

위치의 정보를 embedding 계층에 더하게 되면 같은 단어라도 만약 다른 위치에 있을 시 입력값 자체가 다르게 됩니다. 

즉 입력 자체에 위치에 대한 정보를 더하여 입력 자체가 위치정보를 가지니 encoder, decoder에 들어가서 해당 정보가 뚜렷하게 유지되는 것이 아니겠지만 분명하게 입력의 위치정보를 전달한 것이고, 다음에 입력에 같은 단어가 다른 위치에 오면 그것은 다른 수치의 입력값이 되므로 위치가 구분된다고 할 수 있는 것입니다.

이것이 바로 embedding 계층에 위치정보를 더하는 이유입니다.

위치 정보에 대한 계산은 위와 같이 하며 cos과 sin을 사용한 이유는 문장의 길이마다 매 번 단순하게 값을 더하여 위치를 표현하는 것보다 고정적인 형태로 상대적 위치를 표현해주기 위함입니다.

 

transformer에서는 위치에 대한 정보가 함수로 주어졌는데 bert에서는 이러한 위치의 정보도 학습이 될 수 있도록 구현이 되었습니다.

 

residual learning 

기존의 네트워크는 입력 x를 받고 layer을 거쳐 H(x)를 출력하고

목적은 입력값 x를 타깃 값(정답) y로 mapping 하는 함수 H(x)를 얻는 것, H(x)와 y의 차이가 없도록 학습시키는 것이 목적입니다.

residual learning은 출력과 입력의 차인 H(x)-x를 F(x)라고 할 때 F(x)를 최소화가 목적이 되어서

출력과 입력의 차이를 줄이는 F(x)가 0이 되는 것에 학습하는 것이 목적이 됩니다.

(F(x)는 input을 통과하는 함수)

(참조: https://phil-baek.tistory.com/entry/ResNet-Deep-Residual-Learning-for-Image-Recognition-%EB%85%BC%EB%AC%B8-%EB%A6%AC%EB%B7%B0 )

 

residual learning의 forward 측면에서 보게 된다면 중간의 계층들이 학습이 잘못될 경우 이를 예방해 주는 것입니다.

예시를 들어 총 3개의 계층이 존재한다고 가정하겠습니다. 

만약 두 번째 계층의 가중치들이 원치 않은 방향으로 학습될 시 residual이 없다면 첫 번째에서 제대로 학습된 결과물이 무시되므로 성능이 나빠집니다.

그런데 첫 번째 계층에서 residual을 수행하여 두 번째 계층을 건너뛰고 세 번째 계층에 들어가기 전으로 넘어간다고 가정하면,

첫 번째의 제대로 된 학습을 한 정보가 세 번째에 잘 전달되어 두 번 내에서 나쁘게 학습되더라도 성능 저하를 예방할 수 있습니다.

 

residual learning의 구조의 설계 목적은 네트워크 계층이 깊어질수록 기울기 소실 혹은 폭발이 일어날 확률이 높아져서 그로 인해 학습이 제대로 되지 못하는 현상을 예방하고자 설계가 되었습니다.

그리고 다음과 같이 설계를 한 목적을 backward 측면에 알 수 있습니다.

backward의 측면에서 보면 덧셈의 역전파(backward)는 그대로 값을 흘러보냅니다. 

residual learning은 이전의 값을 그대로 뛰어넘어 덧셈만을 수행했으니 역전파시 기울기가 넘어가면서 소실과 폭발을 예방할 수 있습니다.

 

 

normalization 역시 residual learning과 마찬가지로 모델의 성능을 향상하는 역할 중 하나입니다.

 

 

Multi-Head Attention

Multi-head attention부분이 바로 앞서 설명한 seq2seq의 attention부분과 거의 유사합니다.

Multi-head attention의 입력은 크게 Query, Key, Value로 구성되어 있습니다.

Query는 주가 되는 단어입니다.

물어보는 단어로써 Query가 Key의 단어들과 어떠한 연관성이 있는지 모두 비교하게 되는 단어입니다.

Key는 정보를 제공하는 단어들의 집합니다.

Value는 key에 대한 의미적 결과 값입니다.

(Value의 존재 이유와 이에 대한 설명은 뒤에 자세히 다룹니다.)

 

앞서 seq2seq에서 구현했던 것과 마찬가지로 중요도를 구하는 과정이 바로 query와 key의 내적 과정입니다.

(transformer의 논문을 보면 seq2seq에서는 additive attention을 사용하여 관련 중요도를 구한 것이라고 나옵니다. 저는 '밑바닥부터시작하는딥러닝2'의 설명을 기반으로 seq2seq을 설명한 것이기 때문에 seq2seq에서 중요도를 구할 때 이미 내적인 'dot-product attention'을 사용하였습니다.)

query와 key의 내적 과정이 이뤄지고 나온 결과에 대한 softmax를 하여 중요도가 구해집니다.

그리고 이 중요도와 key에 대한 결과 value와 곱을 하여 seq2seq와 마찬가지로 문맥 벡터가 구해지는 것입니다.

이러한 문맥 벡터에 대한 정보, 즉 어떠한 단어에 집중해서 학습을 할 수 있도록 되는 것입니다.

 

seq2seq의 LSTM의 구조를 대처한 부분이 바로 이 attention부분인 것입니다.

그런데 이름을 보면 Multi-head attention이고 그림을 봐도 head가 여러 개로 되어있는 attention인 것을 확인할 수 있습니다.

이렇게 head를 여러 개 두어서 학습을 시킨 이유는 문장을 학습하는데 다양한 관점에서 정보를 학습할 수 있도록 하기 위해서입니다.

즉 다양한 attention 특징들을 가지는 여러 개의 head들을 만드는 것입니다.

 

 

attention의 행렬적 구조

여기서는 임베딩 차원 dmodle이 4이고 head의 수는 2라고 가정한것입니다.

결과로 나온 Attetion이 곧 문맥 벡터가 되며 결과의 차원은 각 query, key, value의 차원과 일치하는 것을 확인할 수 있습니다.

위 과정이 하나의 head에 대한 과정이고 attention의 결과가 (3x2)로 나왔고 head의 수는 2이며, 위의 그림에서 head끼리 모두 concat을 하게 되면 (3x4) 모양으로 나오니, 맨 처음 입력한 (3x4)와 크기가 동일합니다.

-> 그림과 설명이 잘못 된 부분이 존재합니다. 추후 수정하겠습니다.

: multi head attention은 다양한 관점에서 attention을 하는것이고 이는 곧 하나의 head를 처음 FF layer을 거치기 전에 차원이 (전체 임베딩 차원 / n_heads ) 입니다.

첫 번 째 사진에 나온 결과가 두 번 째 사진과 이어져서 진행된것 처럼 설명되어 있지만 이는 잘못되었습니다. 

만약 첫 번 째 사진이 하나의 head가 계산되는 과정을 그리며, 나온 결과가 두 번 째 결과와 이어지려면, 전체 임베딩의 차원이 4이고, head의 수가 2라고 가정할 때, 
첫번 째 사진의 처음 (3x4)를 (3x2) 2개로 쪼개지며, 이 중 하나가 W( nn.Linear(2,2) )를 거쳐서 (3x2)가 나와야 해당 결과가 두 번 째 사진과 이어지게 되는 것입니다.

설명과 사진이 잘못되어서 추후 직접 그려서 그림과 설명을 수정하겠습니다.  

 

attention의 softmax

softmax의 경우 중간 부분이 상대적으로 gradient가 크고 side로 가면 갈수록 작아지는 특징을 가지고 있는데 값이 너무 커지는 상태에서 softmax가 이뤄지면 side 쪽 gradient가 너무 작아 지기 때문에 이를 방지하여 특정 scale factor 만큼 곱해주어서(나눔) 값을 작게 만들어 학습이 잘 될 수 있도록 합니다.

 

 

value 값이 의미하는 바

앞 서 seq2seq+attention에서는 query 역할을 하는 것이 h이고 key 역할을 하는 것이 hs입니다.

(위의 그림 기준 h와 hs)

여기서 중요도는 h와 hs 즉 query와 key의 내적으로부터 구하였고 

해당 중요도를 다시 hs와 원소 별 곱을 하여서 Encoder로부터 받은 정보 hs 중에 어떤 것과 집중하여 학습을 할지 결정을 하였습니다.

여기서 hs가 바로 value입니다.

즉, seq2seq+attention에서는 key와 value가 같습니다.

이를 통해 value라는 것은 key가 가지고 있는 단어별 의미 즉 값을 가지고 있는 벡터

key에 대한 의미적 결괏값이라는 것을 알 수 있습니다.

seq2seq+attention에서는

value는 인코더의 단어들 각각에 대한 의미적 벡터를 가진 놈이자 곧 key이며 value 였습니다.

 

그런데 transformer에서는 바로 이 key와 value를 분리해서 구성이 됩니다. 

key와 value 정보를 나눠서 서로 다른 파라미터로 학습시키면 결과가 더 좋아지기 때문입니다.

(transformer에서는 attention이 self-attention(encoder ver, decoder ver), encoder-decoder attention 3가지가 있음을 고려)

 

transformer에서 둘이 분리해서 사용할 수 있는 이유는 value자체의 의미와 value값이 형성되기 위한 transformer의 구조를 보면 알 수 있습니다.

여기서 w가중치의 행의 차원 길이는 (embedding 계층의 차원)/(head의 수)

그림의 가장 오른쪽에 나온 3개의 결과가 바로 각각 query key value입니다.

query, key, value가 결과 값으로 나오는데 각각에 대한 가중치 행렬들이 존재하게 되고,

여기서 주목할 점은 이 3개 모두 가장 왼쪽에 있는 단어별 의미적 벡터를 가진 행렬을 input으로 가지고 모두 같은 계층에서 가중치의 계산이 이뤄진다는 것입니다.

같은 계층에서 동일한 형태의 계산이 이뤄진다는 것은 각각의 가중치에 대한 값과 결과가 모두 다르겠지만 의도하는 의미적 관점에서는 같다는 것을 알 수 있습니다.

seq2seq에서 key와 value는 같았습니다.

즉 의미적으로도 같다는 뜻이고 위와 같이 같은 계층에서 같은 형태로 계산되도록 구조를 취한 동시에 key와 value 값을 분리한 것을 알 수 있습니다.

그리하여 위와 같은 구조는 key와 value가 분리되었음에도 불구하고 구조적으로 같게 하여 의미적으로 같은 역할이 가능하다고 기대할 수 있기 때문에 위와 같이 구성을 한 것입니다.

 

 

attention의 종류

Encoder Self-Attention

encoder에서 입력된 단어 간의 관계를 알고 싶은 의도이므로 단어 모두 서로 참조를 하여 attention을 판단합니다.

query, key, value 모두 encoder의 값입니다.

 

Masked Decoder Self-Attention

decoder에서 입력된 단어 간의 self-attention을 얻는 과정이며,

attention의 중요도를 구할 시 자신의 단어의 오직 앞 단어들만 참조하여 중요도를 구하여 attention matrix를 구하게 됩니다.

decoder의 경우 attention 중에서 마스크가 씌워져 있습니다.

즉 attention을 할 시 고려해야 할 단어에 조건을 둬서 제한을 하는 것입니다.

query로 선정된 단어가 key들의 단어를 선정할 때 key들의 단어는 query의 단어의 오직 앞에 존재하는 단어들만 attention의 중요도 값을 구합니다.

그 이유는 decoder의 구조에 있습니다.

decoder의 경우 입력으로 encoder의 입력에 대한 원하는 정답을 넣고 결과로 decoder의 입력된 단어 다음 단어를 예측하도록 설계가 되어있습니다.

만약 현재 query의 단어 기준으로 뒤쪽의 단어도 attention을 하는데 참조를 한다면 이는 곧 정답을 cheating 하는 것과 마찬가지가 됩니다. 

다음 단어가 무엇인지 예측하는 것에 학습이 되는 decoder가 다음 단어인 뒷 단어들을 미리 참조하여 학습을 하는 꼴이 되는 것이기 때문입니다.

그리하여 decoder에서는 오직 앞 단어들만 고려하여 attention이 형성되도록 masking 과정을 거칩니다.

query, key, value 모두 decoder의 값입니다.

 

Encoder-Decoder Attention

Encoder의 입력 단어들의 의미 벡터를 참조하여 Decoder의 입력 단어가 Encoder의 단어들 중 어느 단어와 연관도가 높은지 파악하여 attention matrix를 구하게 됩니다.

중요도를 구하는데 

query는 Decoder의 값, key, value는 Encoder의 값이 됩니다.

 

 

 

 

 

참조 :

https://www.youtube.com/watch?v=AA621UofTUA    (동빈나 님 자료)  

밑바닥부터 시작하는 딥러닝 2 (한빛 미디어)

transformer 논문

'It공부 > Deep learning' 카테고리의 다른 글

(2)-5-3 RnnLM 구현  (0) 2021.02.10
(2)-5-2 RNN 구현  (0) 2021.01.22
(2)-5-1 순환 신경망(RNN)  (3) 2021.01.21
(2)-4-2 개선된 word2vec 학습  (0) 2021.01.20
(2)-4-1 word2vec 속도 개선  (0) 2021.01.19
Comments