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

2장. Transformer 입력 표현

임베딩: 번호를 성격표로

학교 출석부를 떠올려 봅니다. 출석 번호 7번과 8번은 번호가 붙어 있을 뿐, 두 학생의 성격이 비슷하다는 뜻은 아닙니다. 학생을 제대로 알려면 번호로 생활기록부를 찾아 "활발함 0.8, 꼼꼼함 0.3, 수학 좋아함 0.9" 같은 성격표를 봐야 합니다. 토큰 ID 도 그냥 번호라서 5913번과 5914번이 비슷한 뜻이라는 보장이 없습니다. 그래서 번호마다 실수 여러 개짜리 성격표(벡터)를 붙이는데, 이것이 임베딩입니다.

토큰 ID 1079 로 임베딩 층(어휘 수 × d_model)에서 1079번 행을 그대로 꺼내 토큰 임베딩 벡터(1 × d_model)를 얻는 그림

그림 왼쪽의 정수 ID 1079(Qwen 에서 " am")가 가운데의 큰 표, 임베딩 층으로 들어갑니다. 표의 크기는 (어휘 수 × d_model)이고, 1079번 행을 그대로 꺼내 오른쪽의 (1 × d_model) 벡터가 됩니다. 곱셈 없이 번호로 바로 찾아오는 조회(lookup)라서 빠릅니다. 데이터 분석으로 치면 행이 15만 개, 열이 896개인 DataFrame 에서 df.iloc[1079] 로 한 행을 꺼내는 일입니다.

임베딩 층의 성질

성질설명출석부로 치면
모양(어휘 수, d_model) 표학생 수 × 성격 항목 수
꺼내는 법토큰 ID 번째 행을 그대로 꺼낸다(lookup)번호로 생활기록부 펼치기
처음 값무작위 숫자아무렇게나 적은 첫 기록
학습 뒤비슷한 뜻의 토큰끼리 가까운 벡터가 된다지내 보며 고쳐 쓴 기록
같은 ID언제나 같은 행을 꺼낸다같은 번호면 같은 기록부

짧은 예시

Python
import numpy as np
from transformers import AutoConfig

# 손으로 만든 작은 임베딩 표: 사전 4개 × d_model 3
# 행 번호가 토큰 ID 다(0: 나, 1: 는, 2: 학생, 3: 입니다 라고 해 두자)
table = np.array([
    [0.1, 0.5, 0.2],
    [0.0, 0.3, 0.9],
    [0.8, 0.1, 0.4],
    [0.2, 0.7, 0.6],
])

# 토큰 ID 리스트로 행을 한꺼번에 꺼낸다(NumPy 의 팬시 인덱싱 = lookup)
ids = [2, 0, 2]
x = table[ids]
print(x.shape)        # 결과: (3, 3)  토큰 3개 × d_model 3
print(x[0], x[2])     # 결과: [0.8 0.1 0.4] [0.8 0.1 0.4]  같은 ID 2 는 같은 행

# 실제 Qwen 의 표 크기는 설정 파일(config)만 읽어 확인한다. 모델 무게는 내려받지 않는다
# AutoConfig = 모델 이름만 주면 그 모델의 설정표를 불러오는 도구
config = AutoConfig.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct")
print(config.vocab_size, config.hidden_size)  # 결과: 151936 896
rows_x_cols = config.vocab_size * config.hidden_size
print(f"{rows_x_cols:,}")                     # 결과: 136,134,656
print(f"BF16(2바이트) 메모리: {rows_x_cols * 2 / 1e6:.1f} MB")  # 결과: BF16(2바이트) 메모리: 272.3 MB

이 코드가 뜻하는 것

출석 번호 [2, 0, 2] 로 생활기록부를 세 번 펼친 코드입니다. 2번은 두 번 나왔으므로 같은 기록이 두 번 꺼내집니다. 아래 절반은 실제 Qwen 의 출석부 크기입니다. 손으로 곱하면 151,936 × 896 = 136,134,656 칸이고, 한 칸에 2바이트(BF16)면 272,269,312바이트, 약 272 MB 입니다. 0.5B(5억 개) 모델 파라미터의 4분의 1 남짓이 이 표 하나에 들어 있습니다.

줄하는 일쉽게 말하면
table[ids]ID 번째 행들을 꺼내 쌓는다번호로 기록부 펼치기
x.shape(토큰 수, d_model)행은 토큰, 열은 성격 항목
AutoConfig.from_pretrained(...)설정표만 읽는다출석부의 표지만 보기
vocab_size * hidden_size표의 칸 수파라미터 수

주의할 점

  • Qwen 의 config.vocab_size 는 151,936 이고, 실습 1에서 찍을 len(qwen_tokenizer) 는 151,665 입니다. 계산을 빠르게 하려고 표의 행을 넉넉히 만들어 두었기 때문에 표가 실제 사전보다 조금 큽니다. 남는 행은 쓰이지 않습니다.
  • 표에서 꺼낸 벡터는 같은 ID 면 늘 같습니다. 하지만 3장의 Self-Attention 을 지나면 주변 토큰의 정보가 섞여, 같은 토큰이라도 문장마다 다른 벡터가 됩니다. "배"가 과일인지 타는 배인지는 이 단계에서 가려집니다.
  • 꺼낸 행렬의 모양은 (토큰 수, d_model)입니다. 열 수는 사전 크기(4)가 아니라 d_model(3)입니다. shape 을 헷갈리면 뒤의 행렬곱에서 오류가 납니다.
← 이전 절2장 · 토큰 수가 중요한 이유다음 절 →2장 · 위치 정보가 필요한 이유