정의 : 어떤 Sequence(연속된 데이터)들을 다른 Sequence로 Mapping하는 알고리즘
구성 : 정보 압축을 위한 Encoder->새로운 데이터를 생성해내는 Decoder
문제 :
정의 : Decoder에서 출력 단어를 예측하는 매 시점(time step)마다, Encoder에서의 전체 입력 문장을 다시 한 번 참고하는 알고리즘.
Attention(Q,K,V) = Attention Value
Q = Query : t 시점의 디코더 셀에서의 은닉 상태
K = Keys : 모든 시점의 인코더 셀의 은닉 상태들
V = Values : 모든 시점의 인코더 셀의 은닉 상태들
(출처 : https://wikidocs.net/22893)
말 그대로 번역기
A국가의 문장 혹은 단어를 입력받으면 인코더와 디코더를 지나 B국가의 문장 혹은 단어로 출력해주는 것
기존 Seq2seq 모델 : 기존 seq2seq 모델에 Attention을 보조로 사용
transformer : Attention으로만 구성되어있다.
RNN, LSTM의 약점
Transformer
Encoder의 구성
Multi-head Self Attention / Add & Normalize / Position-wise FFNN라는 모듈들로 구성
Multi-head Self Attention과 Attention의 차이점
- Attention은 Encoder의 Hidden state와 Decoder의 Hidden state를 연산해서 Attention score값을 계산
- Self-Attention은 Encoder로 들어간 벡터와 Encoder로 들어간 모든 벡터를 연산해서 Attention score값을 계산
(출처 : https://engineering-ladder.tistory.com/73)
1. Decoder에는 Multi-head Self Attention에 Masked가 들어가있다.
- Decoder는 현재까지 들어온 데이터 보다 미래의 데이터를 보면서 학습하면 안되기 때문에 미래에 해당하는 Attention score들에는 매우 작은 음수값(-1e9)를 넣어서 이 부분을 Masking해버린다.
한 번 더 Attention을 진행
- 이 때는 Self-Attention이 아니라, 일반적인 Attention을 사용하여 Output을 추측하는데 사용.
- 이 때의 input으로는 Decoder에서 사용한 Masked Attention Matrix와 Encoder에서 만든 Matrix를 Attention에 넣게 된다.
d_model = 512
트랜스포머의 Encoder와 Decoder에서의 정해진 입력과 출력의 크기를 의미.
Embedding 벡터의 차원 또한 d_model이며, 각 Encoder와 Decoder가 다음 층의 Encoder와 Decoder로 값을 보낼 때에도 이 차원을 유지.
논문에서는 512로 설정.
num_layers= 6
Transformer에서 하나의 Encoder와 Decoder를 층으로 생각하였을 때, Transformer 모델에서 Encoder와 Decoder가 총 몇 층으로 구성되었는지 의미
논문에서는 Encoder와 Decoder를 각각 총 6층으로 설정.
num_heads = 8
Transformer에서는 Attention을 사용할 때, 한 번 하는 것보다 여러 개로 분할해서 병렬로 Attention을 수행하고, 결과값을 다시 하나로 합치는 방식을 채택
num_heads는 이때 이 병렬의 개수를 의미.
d_ff
Transformer 내부에는 feed forward 신경망이 존재하며 해당 신경망의 은닉층의 크기를 의미.
feed forward 신경망의 input layers와 output layers의 크기는 d_model
(feed forward : input layer로 데이터가 입력되고, 1개 이상으로 구성되는 hidden layer를 거쳐서 마지막에 있는 output layer로 output data를 내보내는 과정)
(출처 : https://wikidocs.net/31379)
(출처 : https://wikidocs.net/31379)
Encoder와 Decoder가 6개씩 존재하는 Transformer의 구조.
(출처 : https://wikidocs.net/31379)
RNN이 유리했던 이유는 단어의 위치에 따라 단어를 순차적으로 입력받아서 처리하는 RNN의 특성으로 인해 각 단어의 위치 정보(position information)를 가질 수 있었기 때문이다.
Transformer는 단어의 위치 정보를 얻기 위해서 각 단어의 Embedding 벡터에 위치 정보들을 더하여 모델의 입력으로 사용하는데, 이것을 포지셔널 인코딩(positional encoding)이라고 한다.
(출처 : https://wikidocs.net/31379)
입력으로 사용되는 Embedding 벡터들이 Transformer의 입력으로 사용되기 전에 포지셔널 인코딩의 값이 더해지는 것을 보여준다.
Embedding 벡터가 Encoder의 입력으로 사용되기 전 포지셔널 인코딩값이 더해지는 과정의 시각화
(출처 : https://wikidocs.net/31379)
Transformer의 위치 정보를 가진 값을 만들기 위한 함수 공식
(출처 : https://wikidocs.net/31379)
pos = 입력 문장에서의 Embedding 벡터의 위치
i = Embedding 벡터 내의 차원의 인덱스
d_model = 트랜스포머의 인코더와 디코더에서의 정해진 입력과 출력의 크기
사인 함수와 코사인 함수의 그래프를 상기해보면 요동치는 값의 형태를 생각해볼 수 있는데, Transformer는 사인 함수와 코사인 함수의 값을 Embedding 벡터에 더해주므로서 단어의 순서 정보를 더하여 준다.
Embedding 벡터와 포지셔널 인코딩의 덧셈은 Embedding 벡터가 모여 만들어진 문장 행렬과 포지셔널 인코딩 행렬의 덧셈 연산을 통해 이루어진다.
Embedding 벡터 내의 각 차원의 인덱스가 짝수인 경우 (pos,2i) -> 사인 함수
Embedding 벡터 내의 각 차원의 인덱스가 홀수인 경우 (pos,2i+1) -> 코사인 함수
Embedding 벡터는 d_model의 차원을 가진다.
위와 같은 포지셔널 인코딩 방법을 사용하면 순서 정보가 보존되는데, 각 임베딩에 포지셔널 인코딩의 값을 더하면 같은 단어라고 하더라도 문장 내의 위치에 따라서 Transformerr의 입력으로 들어가는 Embedding 벡터의 값이 달라진다.
이에 따라 Transformer의 입력은 순서 정보가 고려된 Embedding 벡터가 된다.
class PositionalEncoding(tf.keras.layers.Layer):
def __init__(self, position, d_model):
super(PositionalEncoding, self).__init__()
self.pos_encoding = self.positional_encoding(position, d_model)
def get_angles(self, position, i, d_model):
angles = 1 / tf.pow(10000, (2 * (i // 2)) / tf.cast(d_model, tf.float32))
return position * angles
def positional_encoding(self, position, d_model):
angle_rads = self.get_angles(
position=tf.range(position, dtype=tf.float32)[:, tf.newaxis],
i=tf.range(d_model, dtype=tf.float32)[tf.newaxis, :],
d_model=d_model)
# 배열의 짝수 인덱스(2i)에는 사인 함수 적용
sines = tf.math.sin(angle_rads[:, 0::2])
# 배열의 홀수 인덱스(2i+1)에는 코사인 함수 적용
cosines = tf.math.cos(angle_rads[:, 1::2])
angle_rads = np.zeros(angle_rads.shape)
angle_rads[:, 0::2] = sines
angle_rads[:, 1::2] = cosines
pos_encoding = tf.constant(angle_rads)
pos_encoding = pos_encoding[tf.newaxis, ...]
print(pos_encoding.shape)
return tf.cast(pos_encoding, tf.float32)
def call(self, inputs):
return inputs + self.pos_encoding[:, :tf.shape(inputs)[1], :]
50 x 128의 크기를 가지는 포지셔널 인코딩 행렬을 시각화
# 문장의 길이 50, 임베딩 벡터의 차원 128
sample_pos_encoding = PositionalEncoding(50, 128)
plt.pcolormesh(sample_pos_encoding.pos_encoding.numpy()[0], cmap='RdBu')
plt.xlabel('Depth')
plt.xlim((0, 128))
plt.ylabel('Position')
plt.colorbar()
plt.show()
(1, 50, 128)
========
도움받은 사이트 :
https://wikidocs.net/31379
https://wikidocs.net/22893
https://engineering-ladder.tistory.com/73
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=beyondlegend&logNo=221373971859