트랜스포머·PEFT 2일 과정2장 · Transformer 입력 표현8 / 15← 이전목차다음 →MetaContents

2장. Transformer 입력 표현

위치 정보가 필요한 이유

카드 게임에서 손에 든 카드 석 장을 탁자에 엎어 섞었다고 해 봅시다. 어떤 카드가 있었는지는 알지만, 어떤 순서로 들고 있었는지는 알 수 없습니다. 1장의 RNN 은 문장을 한 줄씩 차례로 읽었으므로 순서를 저절로 알았습니다. 그런데 Transformer 의 Self-Attention 은 모든 토큰을 한꺼번에 봅니다. 그대로 두면 "dog bites man(개가 사람을 문다)" 과 "man bites dog(사람이 개를 문다)" 이 같은 카드 묶음으로 보입니다.

위치 정보가 없으면 dog bites man 과 man bites dog 이 같은 단어 카드 묶음이 되고, 위치 번호 1, 2, 3 을 더하면 서로 다른 입력 표현이 되는 그림

그림 왼쪽은 위치 정보가 없을 때입니다. 두 문장에서 순서를 떼어 내면 dog, bites, man 의 같은 카드 묶음만 남아 두 문장의 차이를 알 수 없습니다. 오른쪽은 카드마다 1, 2, 3 위치 번호를 붙인 모습입니다. 같은 dog 라도 1번 자리와 3번 자리는 다르게 읽힙니다.

I am a student 의 Input Embeddings 에 Positional Encodings 를 더해(Add) Input + Positional Embeddings 를 만드는 그림

Transformer 는 번호를 따로 적지 않고, 임베딩 벡터에 위치마다 다른 벡터(Positional Encoding)를 더합니다. 그림의 세 줄이 차례로 임베딩, 위치 벡터, 둘을 더한 결과입니다. 더하기라서 모양은 (토큰 수, d_model) 그대로입니다.

위치 정보가 있을 때와 없을 때

경우dog bites manman bites dog모델이 보는 것
위치 정보 없음{dog, bites, man}{dog, bites, man}같은 카드 묶음
위치 정보 더함dog@1, bites@2, man@3man@1, bites@2, dog@3서로 다른 입력

짧은 예시

Python
import numpy as np

# 손으로 만든 임베딩 표: 0 = dog, 1 = bites, 2 = man (d_model 2)
emb = np.array([[1.0, 0.0], [0.0, 1.0], [1.0, 1.0]])
a = emb[[0, 1, 2]]   # dog bites man
b = emb[[2, 1, 0]]   # man bites dog

def same_bundle(x, y):
    # 행의 순서를 무시하고 같은 행들이 들어 있는지 본다(카드를 섞어 놓고 비교)
    return sorted(map(tuple, x.round(3))) == sorted(map(tuple, y.round(3)))

print(same_bundle(a, b))  # 결과: True  순서만 다른 같은 카드 묶음

# 위치 0, 1, 2 에 다른 벡터를 준다: [sin(위치), cos(위치)]
pos = np.arange(3)
pe = np.stack([np.sin(pos), np.cos(pos)], axis=1)
print(pe.round(3))
# 결과:
# [[ 0.     1.   ]
#  [ 0.841  0.54 ]
#  [ 0.909 -0.416]]

print(same_bundle(a + pe, b + pe))  # 결과: False  위치를 더하니 다른 묶음
print((a + pe)[0].round(3), (b + pe)[2].round(3))  # 결과: [1. 1.] [ 1.909 -0.416]  같은 dog, 다른 자리

이 코드가 뜻하는 것

카드를 섞어 놓고 비교하는 함수 same_bundle 로 두 문장을 견줘 본 코드입니다. 위치를 더하기 전에는 True, 즉 같은 묶음입니다. 위치 벡터를 더한 뒤에는 False 가 됩니다. 마지막 줄은 같은 dog 라도 0번 자리에서는 [1, 0] + [0, 1] = [1, 1], 2번 자리에서는 [1, 0] + [0.909, -0.416] = [1.909, -0.416] 이 된다는 뜻입니다.

줄하는 일쉽게 말하면
emb[[2, 1, 0]]순서를 바꾼 문장의 임베딩카드 순서 바꾸기
same_bundle(a, b)순서를 무시하고 비교한다섞어 놓고 견주기
pe = [sin, cos]위치마다 다른 벡터를 만든다번호표 만들기
a + pe임베딩에 위치 벡터를 더한다카드에 번호표 붙이기

주의할 점

  • 모든 위치에 같은 벡터를 더하면 순서를 구분할 수 없습니다. 위치마다 다른 값이어야 같은 토큰이라도 첫 번째와 다섯 번째 자리를 다르게 나타냅니다.
  • 이 예시는 원리를 보이려고 d_model 을 2로 줄였습니다. 실제로는 수백 차원이라 위치 무늬와 뜻 정보가 서로 덜 부딪힙니다.
← 이전 절2장 · 임베딩: 번호를 성격표로다음 절 →2장 · 사인·코사인 위치 인코딩