Zorba blog
트랜스포머(Transformer) 모델 / 디코더 본문
10. 인코더에서 디코더로(From Encoder To Decoder)
- 구현된 인코더는 총 num_layers 만큼의 층 연산을 순차적으로 한 후에 마지막 층의 인코더의 출력을 디코더로 전달.
- 디코더 또한 num_layers 만큼의 연산을 하는데, 이때마다 인코더가 보낸 출력을 각 디코더 층 연산에 사용.
11. 디코더의 첫번째 서브층 : 셀프 어텐션과 룩-어헤드 마스크
- 디코더도 인코더와 동일하게 임베딩 층과 포지셔널 인코딩을 거친 후의 문장 행렬이 입력.
- 트랜스포머 또한 seq2seq와 마찬가지로 교사 강요(Teacher Forcing) 을 사용하여 훈련.
- 학습 과정에서 번역할 문장에 해당되는 <sos> je suis etudiant의 문장 행렬을 한 번에 입력 받음.
문장 행렬을 한 번에 입력 받는 방식에서 문제 발생.
- seq2seq의 디코더에 사용되는 RNN 계열의 신경망은 입력 단어를 매 시점마다 순차적으로 입력 받으므로 다음 단어 예측에 현재 시점을 포함한 이전 시점의 단어들만 참고.
- 반면, 트랜스포머는 문장 행렬로 입력을 한 번에 받으므로 현재 시점의 단어를 예측하고자 할 때, 미래 시점의 단어까지도 참고할 수 있는 현상이 발생.
- 이를 위해 트랜스포머의 디코더에서는 현재 시점의 예측에서 미래 시점의 단어들을 참고하지 못하도록 룩-어헤드 마스크(look-ahead mask)를 도입.
- 룩-어헤드 마스크(look-ahead mask)는 디코더의 첫 번째 서브층에서 이루어짐.
- 디코더의 첫 번째 서브층인 멀티 헤드 셀프 어텐션 층은 인코더의 첫 번째 서브층인 멀티 헤드 셀프 어텐션 층과 동일한 연산 수행.
- 차이점은 어텐션 스코어 행렬에서 마스킹을 적용한다는 점.
- 아래와 같이 셀프 어텐션을 통해 어텐션 스코어 행렬을 얻음.
- 그리고 아래와 같이 자신보다 미래에 있는 단어들을 참고하지 못하도록 마스킹.
- 마스킹 된 후의 어텐션 스코어 행렬의 각 행을 보면 자기 자신과 그 이전 단어들만을 참고.
- 트랜스포머에는 총 세 가지 어텐션이 존재하며, 모두 멀티 헤드 어텐션을 수행하고, 함수 내부에서 스케일드 닷 프로덕트 어텐션 함수를 호출하는데 각 어텐션 시 함수에 전달하는 마스킹은 아래와 같음.
- 인코더의 셀프 어텐션 : 패딩 마스크를 전달
- 디코더의 첫번째 서브층인 마스크드 셀프 어텐션 : 룩-어헤드 마스크, 패딩 마스크를 전달
- 디코더의 두번째 서브층인 인코더-디코더 어텐션 : 패딩 마스크를 전달
12. 디코더의 두번째 서브층 : 인코더-디코더 어텐션
- 디코더의 두 번째 서브층은 멀티 헤드 어텐션을 수행한다는 점에서는 이전의 어텐션들과 같으나, 셀프 어텐션이 아님.
- 셀프 어텐션은 Query, Key, Value가 같은 경우. 인코더-디코더 어텐션은 Query가 디코더, Key와 Value는 인코더 행렬.
인코더의 첫 번째 서브층 : Query = Key = Value 디코더의 첫 번째 서브층 : Query = Key = Value 디코더의 두 번째 서브층 : Query : 디코더 행렬 / Key = Value : 인코더 행렬 |
- 디코더의 두 번째 서브층을 확대하면 인코더로부터 두 개의 화살표가 그려짐.
- 두 개의 화살표는 각각 Key와 Value를 의미하며, 인코더의 마지막 층에서 온 행렬로부터 얻음.
- 반면 Query는 디코더의 첫 번째 서브층의 결과 행렬로부터 얻음.
- 그 외에 멀티 헤드 어텐션을 수행하는 과정은 다른 어텐션들과 같음.
13. 트랜스포머 하이퍼파라미터 정하기
small_transformer = transformer(
vocab_size = 9000,
num_layers = 4,
dff = 512,
d_model = 128,
num_heads = 4,
dropout = 0.3,
name="small_transformer")
14. 손실 함수 정의하기
- 단어 예측의 경우 다중 클래스 분류 문제이므로 크로스 엔트로피 함수를 손실 함수로 정의.
def loss_function(y_true, y_pred):
y_true = tf.reshape(y_true, shape=(-1, MAX_LENGTH - 1))
loss = tf.keras.losses.SparseCategoricalCrossentropy(
from_logits=True, reduction='none')(y_true, y_pred)
mask = tf.cast(tf.not_equal(y_true, 0), tf.float32)
loss = tf.multiply(loss, mask)
return tf.reduce_mean(loss)