본문 바로가기

AI tech

Transformer 기본 개념

반응형

Transformer 구조에 대한 복습을 진행하면서 적은 글입니다. 

Go 언어로 Transformer 구현을 위해 간략히 정리해봤습니다!

 (관련 링크 : https://github.com/golansformer/golansformer/issues/6)

 

Transformer 복습

내가 이해한 어텐션 / 인코더는?

  • query, key, value가 각각 구성이 사실 같음
  • I, go, home → 이런 문장을 인코딩 한다고 해보자
  • 각 출력은 임베딩 벡터 h1, h2, h3로 뱉어짐
  • q, k, v로 부르면, 시퀀스 당 입력 q가 하나 주어지고(단어 하나), k, v 는 전체로 고정

‘I’ 의 인코딩 벡터를 구해보자

  • q는 I의 임베딩 벡터
  • k는 I, go, home의 각 임베딩 벡터를 담고 있음
  • q와 각 단어를 dot product하면서 유사도 구한 후, softmax
  • 그러면 예시를 들면, 0.2, 0.3, 0.5 이렇게 나오겠지?
  • v가 여기서 쓰임 → v도 I, go, home의 임베딩 벡터를 담고 있음
  • 위의 결과값으로 weighted sum하면, 그게 ‘I’의 인코딩 벡터
  • 근데? 보통 softmax 전 square root d(차원)로 나누어줌

결과에서 루트 dk로 나누어 주는 이유

  • scaling → 분산을 일정하게 하기 위해
  • softmax의 확률분포의 패턴(=분산)이 의도치않게 q, k에 대한 차원 때문에 영향을 받기 때문
  • 확률분포 때문 → 통계 쪽 지식

멀티 헤드 어텐션

  • 동일한 Q, K, V에 대해 → 동시에, 여러 버전의 어텐션을 병렬적으로 수행함
  • 서로 다른 버전의 어텐션의 개수만큼, 서로 다른 인코딩 벡터가 나옴
  • 이걸 모두 concat → 해당 Q의 인코딩 벡터를 얻게 됨
  • 여러 버전의 어텐션 수행하기 위한 선형 변환 matrix → 각 head라 부름

왜 필요할까?

  • 여러 문장 에서의 각 측면이 다르기 때문
  • 서로 다른 측면의 정보를 병렬적으로 뽑고, 그 정보를 다 합치는 형태로 구현

드디어 이제 Residual connection이 나온다(내가 구현할 부분)

  • Add 부분이 Residual connection, Norm이 레이어 정규화
  • 컴퓨터 비전 쪽에서 깊은 레이어의 기울기 소실을 해결하기 위해 탄생
  • 그냥, 기존 입력 값을 인코딩 벡터에 더해주는 것!!
  • 그래서, f(x) + x 가 나온 것
  • 결국, 입력값 대비 만들고자 하는 벡터에 대한 차이값 만을 어텐션 모듈에서 만들어줘야 하는 것
  • → 이렇게 해서 기울기 소실 해결 + 학습 안정화
  • 주의 : 입력과 출력의 차원을 동일하게 맞춰야 가능함

Norm 설명

  • 평균을 0, 분산을 1로 만든 후 원하는 평균과 분산을 주입할 수 있도록 하는
  • 선형 변환으로 이루어져 있음
  • 평균이 0이 되도록 → 각 모든 값에서 평균 값을 빼줌
  • 분산이 1이 되도록 → 각 모든 값에서 표준편차를 나눠줌

그렇게 하나의 트랜스포머 셀프 어텐션 모듈이 완성

  • 이걸 거쳤을 때, 최종적으로 나오는 건?
  • → 각 단어에 대응되는 인코딩 벡터

Positional Encoding → 트랜스포머의 또 다른 구성요소

  • 문장의 시퀀스(순서)를 반영할 수가 없다는 한계가 있어서 등장함
  • ex : I go home과 home go I 의 각 단어 인코딩 벡터가 모두 동일하게 나타남!
  • → 이 순서를 특정지을 수 있는 유니크한 상수 벡터를 각 순서에 등장하는 워드 입력벡터에 더해주는 것이 Position Encoding
  • 더해주는 벡터를 어떻게 결정하는지?
  • 위치에 따라 구별할 수 있는 벡터를 주기함수를 사용
  • → 그 함수값을 모아서 위치를 나타내는 벡터로 사용

  • 인덱스(위치) 별 각 디멘젼에 더해주어야 하는 값을 지정
  • → 이런 식으로 나옴

  • 위치 별로 서로 다른 벡터를 더해주도록 함으로써, 순서 정보를 반영할 수 있게 됨!

인코더 커버 완

  • Nx → N개의 블럭으로 쌓는다는 의미(주로 6, 12, 24)
  • 왼쪽이 인코딩, 오른쪽이 디코딩!
  • → 디코딩 : 입력 시퀀스를 받아서, 출력 시퀀스를 예측

그러면 디코더를 살펴보자

  • 번역하는 경우를 생각해보겠음!
  • 상황
    • 인코더에 I, go, home이 주어지면? (임베딩 벡터 형태로)
    • 디코더 입력에는 <sos>, 나는, 집에 → 시퀀스가 임베딩 벡터로 주어짐
    • 그러면? → 디코더는 뭘 뱉어야 하나?
      • 나는, 집에, 간다 → 이걸 최종적으로 뱉어야 함

이제 과정

  • 일단, 입력 시퀀스를 인코딩 과정에 태움
  • 단, 이때 Masked Multi-Head 어텐션 이용 → 일단 지나쳐~(뒤에 설명)
  • 그 다음, Multi-Head 어텐션 태우는데
    • 이 때 디코더의 hidden state 벡터가 쿼리로 들어감
    • 그리고 인코더의 output이 key, value로 들어감
  • 그러고 나온 인코딩 벡터를 Linear transformation 태워서, vocab size로 변환해줌
    • 예 : 한글 워드는 10만 개
  • 이후는 softmax 태워서 예측 수행

마지막 단 → 한글 단어에 대한 확률 분포는?

  • ground truth 단어와의 softmax loss를 통해서, back-prop으로 전체 네트워크 학습!

찐막 → Masked Multi-Head 어텐션

  • 기본 아이디어 : 디코딩 과정 중 단어 정보 접근의 가능 여부에서 기반함
  • 핵심 :
    • 학습 당시에는 배치 프로세싱을 위해 입력으로 동시에 주긴 하나
    • <SOS>를 쿼리로 사용해서 어텐션 모듈을 수행할 때는?
      • 벨류에서 ‘나는’ 과 ‘집에’ 라는 단어는 제외해 주어야 한다~

    • 정보를 날리고 나서는? → row 별로 합이 1이 되도록 normalization을 한다~
    • 이렇게 어텐션을 변형하는 방식 → masked-self 어텐션
반응형