검색
← 모듈 로드맵

임베딩과 벡터 유사도: 원-핫에서 의미 공간까지

강의 · 입문자 · KAITABASE 정리

원제 · Embeddings (Google MLCC 참고)

원-핫의 한계, 임베딩 조회, 내적 · 코사인 유사도를 손계산으로 익히는 기초 수업

먼저 알아야 할 것

토큰과 토큰 id벡터 · 행렬 곱내적과 벡터 길이

다루는 내용

단어 · 상품 · 문장을 뜻이 담긴 짧은 벡터로 바꾸는 임베딩을 다룹니다. 원-핫 표현의 문제, 임베딩 조회가 원-핫과 행렬의 곱이라는 점, 내적 · 코사인 유사도 · 거리를 작은 숫자로 계산합니다. 정적 · 문맥 임베딩의 차이와 문장 임베딩이 의미 검색 · RAG로 이어지는 흐름까지 정리합니다.

해설

임베딩과 벡터 유사도: 원-핫에서 의미 공간까지

임베딩(embedding) 은 단어 · 상품 · 문장을 '뜻이 비슷하면 가까이 놓이는' 짧은 숫자 벡터로 바꾼 것입니다. 이 수업에서는 원-핫 표현의 한계에서 출발해, 임베딩 조회가 사실은 행렬 곱이라는 것, 그리고 내적 · 코사인 유사도로 '비슷함'을 재는 법을 손으로 계산합니다.

항목내용
참고 출처Google Machine Learning Crash Course 「Embeddings」 모듈 (개요, Embedding space)
트랙 · 수준NLP·트랜스포머 · 기초
이 수업이 다루는 범위원-핫의 문제, 임베딩 행렬과 조회, 내적 · 코사인 유사도 · 거리, 의미 공간 직관, 정적 · 문맥 임베딩, 문장 임베딩과 검색

들어가기 전에

한눈에 보기

  • 원-핫 표현이 왜 크고, 비효율적이고, '비슷함'을 담지 못하는지 설명할 수 있습니다.
  • 임베딩 조회 = 원-핫 벡터 × 임베딩 행렬이라는 것을 숫자로 확인합니다.
  • 내적 · 코사인 유사도 · 유클리드 거리를 직접 계산하고 언제 무엇을 쓰는지 압니다.
  • 정적 임베딩(word2vec)과 문맥 임베딩(BERT · LLM)의 차이를 압니다.
  • 문장 임베딩이 의미 검색 · RAG의 바탕이 되는 이유를 압니다.

1. 원-핫 표현의 한계

직관(해설용 비유). 원-핫(one-hot)은 "5,000칸짜리 출석부에서 내 칸에만 동그라미"를 치는 방식입니다. 누가 누구와 비슷한지는 출석부에 전혀 적혀 있지 않습니다.

단계.

  1. 항목(단어 · 메뉴 등)마다 번호를 붙입니다.
  2. 길이가 '항목 수'인 벡터를 만들고, 자기 번호 칸만 1, 나머지는 0으로 둡니다.
ei=(0,…,0,1⏟i번째,0,…,0)∈{0,1}V\mathbf{e}_i = (0, \dots, 0, \underbrace{1}_{i\text{번째}}, 0, \dots, 0) \in \{0,1\}^{V}
기호뜻
VV항목(어휘) 개수
ei\mathbf{e}_iii번 항목의 원-핫 벡터

MLCC는 5,000개 메뉴를 다루는 음식 추천 앱을 예로 들어 세 가지 문제를 짚습니다. ① 입력 벡터가 길이 5,000이라 신경망 가중치가 많아지고, 그만큼 데이터 · 계산 · 메모리가 더 듭니다. ② 모든 항목이 서로 똑같이 무관해, 핫도그가 샐러드보다 샤와르마에 더 가깝다는 사실을 담지 못합니다. ③ 가중치가 너무 많아 기기 안(on-device)에서 돌리기 어렵습니다.

숫자로 해 보기(해설용). 서로 다른 두 원-핫 벡터의 내적은 언제나 0입니다. e고양이⋅e강아지=0\mathbf{e}_{\text{고양이}}\cdot\mathbf{e}_{\text{강아지}} = 0, e고양이⋅e자동차=0\mathbf{e}_{\text{고양이}}\cdot\mathbf{e}_{\text{자동차}} = 0. 즉 "고양이와 강아지가 고양이와 자동차보다 비슷하다"는 정보가 원-핫에는 없습니다.

2. 임베딩 행렬과 조회

직관. 항목마다 '짧은 좌표'를 하나씩 배정한 표를 만들고, 그 좌표를 학습으로 맞춥니다. 비슷한 항목은 학습이 끝나면 좌표가 가까워집니다.

단계.

  1. V×dV \times d 크기의 임베딩 행렬 EE 를 만듭니다. 행 하나가 항목 하나의 벡터입니다.
  2. 처음에는 무작위 값으로 채웁니다.
  3. 모델이 과제(다음 단어 예측, 추천 등)를 풀면서 손실을 줄이도록 EE 의 값도 경사 하강법으로 함께 고칩니다.
  4. 항목 ii 의 임베딩은 EE 의 ii번째 행입니다.
xi=ei⊤E∈Rd\mathbf{x}_i = \mathbf{e}_i^\top E \in \mathbb{R}^{d}
기호뜻
EE임베딩 행렬 (VV행 dd열)
dd임베딩 차원 — 사람이 정하는 하이퍼파라미터
xi\mathbf{x}_i항목 ii 의 임베딩 벡터

숫자로 해 보기(해설용). 어휘 4개(0:고양이, 1:강아지, 2:자동차, 3:버스), d=3d=3 인 행렬을

E=(0.90.80.10.80.90.20.10.20.90.20.10.8)E = \begin{pmatrix} 0.9 & 0.8 & 0.1 \\ 0.8 & 0.9 & 0.2 \\ 0.1 & 0.2 & 0.9 \\ 0.2 & 0.1 & 0.8 \end{pmatrix}

이라 합시다. '강아지'의 원-핫은 (0,1,0,0)(0,1,0,0) 이고, 이를 EE 에 곱하면 각 열에서 두 번째 값만 남아 (0.8,0.9,0.2)(0.8, 0.9, 0.2) — 정확히 두 번째 행입니다. 그래서 실제 구현은 곱셈 대신 '행 꺼내기(lookup)'로 처리합니다. PyTorch의 nn.Embedding 이 이 일을 합니다.

왜 이렇게 하나. 원-핫 × 행렬과 결과가 같으니, 임베딩은 "원-핫 입력을 받는 첫 선형층"과 같습니다. 그래서 따로 특별한 학습법이 필요 없고, 신경망 전체와 함께 역전파로 학습됩니다. MLCC도 임베딩을 신경망 안에서 함께 얻는 방법과 word2vec처럼 따로 학습하는 방법을 소개합니다.

차원은 얼마로? MLCC는 실제 임베딩 차원이 3보다 훨씬 크지만 원래 데이터 차원보다는 작고, 단어 임베딩의 경우 256 · 512 · 1024가 흔하다고 소개합니다. 차원이 크면 표현력이 늘지만 계산 · 저장 비용과 과적합 위험도 늡니다.

3. 비슷함을 재는 세 가지 방법

직관. 두 화살표가 같은 쪽을 가리키면 비슷하다고 봅니다. 길이까지 볼지, 방향만 볼지에 따라 방법이 나뉩니다.

a⋅b=∑j=1dajbj,cos⁡(a,b)=a⋅b∥a∥ ∥b∥,∥a−b∥=∑j(aj−bj)2\mathbf{a}\cdot\mathbf{b} = \sum_{j=1}^{d} a_j b_j, \qquad \cos(\mathbf{a},\mathbf{b}) = \frac{\mathbf{a}\cdot\mathbf{b}}{\lVert\mathbf{a}\rVert\,\lVert\mathbf{b}\rVert}, \qquad \lVert\mathbf{a}-\mathbf{b}\rVert = \sqrt{\sum_j (a_j-b_j)^2}
기호뜻
a⋅b\mathbf{a}\cdot\mathbf{b}내적(dot product) — 방향이 같고 길이가 길수록 큼
∥a∥\lVert\mathbf{a}\rVert벡터 길이(노름) =a⋅a= \sqrt{\mathbf{a}\cdot\mathbf{a}}
cos⁡\cos코사인 유사도 — 방향만 봄, −1-1 ~ 11
∥a−b∥\lVert\mathbf{a}-\mathbf{b}\rVert유클리드 거리 — 작을수록 비슷

숫자로 해 보기(해설용, 위의 EE).

  • 고양이 (0.9,0.8,0.1)(0.9,0.8,0.1) · 강아지 (0.8,0.9,0.2)(0.8,0.9,0.2): 내적 =0.72+0.72+0.02=1.46= 0.72+0.72+0.02 = 1.46. 길이는 1.46≈1.208\sqrt{1.46}\approx1.208, 1.49≈1.221\sqrt{1.49}\approx1.221. 코사인 ≈1.46/(1.208×1.221)≈0.990\approx 1.46/(1.208\times1.221) \approx 0.990.
  • 고양이 · 자동차 (0.1,0.2,0.9)(0.1,0.2,0.9): 내적 =0.09+0.16+0.09=0.34= 0.09+0.16+0.09 = 0.34. 자동차 길이 0.86≈0.927\sqrt{0.86}\approx0.927. 코사인 ≈0.34/(1.208×0.927)≈0.303\approx 0.34/(1.208\times0.927)\approx 0.303.

고양이는 자동차보다 강아지에 훨씬 가깝습니다. 원-핫에서는 둘 다 0이었던 값이 이제 의미 차이를 드러냅니다.

무엇을 쓸까. 벡터 길이가 '인기도'나 '문서 길이' 같은 잡음을 담는 경우가 많아, 의미 검색에서는 코사인을 많이 씁니다. 모든 벡터를 길이 1로 정규화해 두면 코사인과 내적이 같아지고, 거리 순서도 같아집니다(∥a−b∥2=2−2cos⁡\lVert\mathbf a-\mathbf b\rVert^2 = 2-2\cos). 그래서 벡터 DB는 정규화 후 내적으로 빠르게 계산하는 경우가 많습니다.

4. 의미 공간이라는 직관

MLCC는 음식을 '샌드위치다움' 같은 상상의 축에 놓고, 축을 '디저트다움' · '액체다움'으로 늘려 가며 가까운 점끼리 비슷한 음식이 되는 그림을 보여 줍니다. 다만 실제로 학습된 임베딩의 각 축은 이렇게 사람이 읽을 수 있는 뜻을 갖는 경우가 드물다고 덧붙입니다.

단어의 경우, 비슷한 문맥에 나오는 단어는 가까운 벡터를 갖게 됩니다(MLCC 예: 'burro'와 'horse'). 이것이 "단어의 뜻은 함께 나오는 이웃이 정한다"는 분포 가설이고, 이를 대규모로 구현한 것이 word2vec 입니다.

정적 임베딩 vs 문맥 임베딩. word2vec 같은 정적(static) 임베딩은 단어마다 점 하나라서, '배(과일)'와 '배(선박)'를 구별하지 못합니다. MLCC도 이를 정적 임베딩의 한계로 짚습니다. BERT · GPT 같은 트랜스포머는 같은 토큰이라도 주변 문장에 따라 다른 벡터를 만드는 문맥(contextual) 임베딩을 냅니다. 트랜스포머 입력층의 토큰 임베딩은 정적 조회이고, 층을 지나며 어텐션으로 주변 정보가 섞여 문맥 벡터가 됩니다.

mermaid
flowchart LR
  A[글] --> B[토크나이저<br/>토큰 id]
  B --> C[임베딩 행렬 조회<br/>정적 벡터]
  C --> D[트랜스포머 층<br/>어텐션으로 문맥 섞기]
  D --> E[문맥 벡터]
  E --> F[평균 · CLS 등으로<br/>문장 벡터]
  F --> G[코사인 유사도로<br/>검색 · 분류 · 군집]

5. 문장 임베딩과 검색

직관. 문장 전체를 벡터 하나로 만들 수 있으면, "질문과 가장 가까운 문서 찾기"가 "가장 가까운 점 찾기"로 바뀝니다.

단계.

  1. 문서를 적당한 크기로 나눠(청킹) 각 조각을 문장 임베딩 모델로 벡터화해 저장합니다.
  2. 질문도 같은 모델로 벡터화합니다.
  3. 질문 벡터와 코사인 유사도가 높은 문서 조각 kk 개를 꺼냅니다.
  4. 이 조각을 LLM에 함께 주면 RAG(검색 증강 생성)가 됩니다.

숫자로 해 보기(해설용). 질문 벡터 q=(0.7,0.7,0.1)\mathbf q = (0.7, 0.7, 0.1) 과 문서 벡터 A =(0.9,0.8,0.1)=(0.9,0.8,0.1), B =(0.1,0.2,0.9)=(0.1,0.2,0.9) 의 코사인을 비교하면 A 쪽이 훨씬 큽니다(A는 거의 같은 방향, B는 다른 방향). 검색 결과 1위는 A입니다.

주의. 토큰 임베딩을 단순 평균하면 문장 뜻이 잘 안 담기는 경우가 많습니다. 문장 단위 유사도에 맞게 따로 학습한 모델이 필요하며, 그 대표가 Sentence-BERT 와 DPR 입니다. 같은 모델로 만든 벡터끼리만 비교할 수 있다는 점도 꼭 기억해야 합니다 — 모델이 다르면 좌표계가 다릅니다.

연습 문제

  1. 어휘 3만 개, 임베딩 차원 512인 임베딩 행렬의 파라미터 수는?
    • 풀이: 30,000×512=15,360,00030{,}000\times512 = 15{,}360{,}000, 약 1,536만 개입니다.
  2. a=(1,2)\mathbf a=(1,2), b=(2,4)\mathbf b=(2,4) 의 코사인 유사도와 유클리드 거리는?
    • 풀이: 내적 =2+8=10=2+8=10, 길이 5\sqrt5, 20\sqrt{20} → 코사인 =10/100=1=10/\sqrt{100}=1. 거리 =1+4=5≈2.236=\sqrt{1+4}=\sqrt5\approx2.236. 방향은 같지만(코사인 1) 거리는 0이 아닙니다.
  3. 위 EE 에서 자동차 (0.1,0.2,0.9)(0.1,0.2,0.9) 와 버스 (0.2,0.1,0.8)(0.2,0.1,0.8) 의 내적은?
    • 풀이: 0.02+0.02+0.72=0.760.02+0.02+0.72=0.76 입니다.
  4. 길이 1로 정규화된 두 벡터의 코사인이 0.8이면 유클리드 거리는?
    • 풀이: ∥a−b∥2=2−2(0.8)=0.4\lVert\mathbf a-\mathbf b\rVert^2 = 2-2(0.8)=0.4 → 거리 ≈0.632\approx 0.632 입니다.

스스로 점검

  1. 임베딩 조회가 "원-핫 × 행렬"과 같다는 사실은 학습에 어떤 의미가 있나요?
    • 답: 임베딩이 선형층과 같으므로 다른 가중치처럼 역전파로 함께 학습됩니다.
  2. 왜 의미 검색에서는 내적보다 코사인을 많이 쓰나요?
    • 답: 벡터 길이에 섞인 잡음(문서 길이 · 빈도 등)을 빼고 방향, 즉 뜻만 비교하기 위해서입니다. 정규화해 두면 둘은 같아집니다.
  3. 정적 임베딩의 대표적인 한계는?
    • 답: 단어마다 벡터가 하나라 여러 뜻을 가진 단어를 문맥에 따라 구별하지 못합니다.

용어 정리

용어쉬운 뜻
원-핫(one-hot)자기 칸만 1, 나머지 0인 벡터
임베딩(embedding)항목을 뜻이 담긴 짧은 숫자 벡터로 바꾼 것
임베딩 행렬항목마다 벡터 한 줄씩 담은 학습 가능한 표
임베딩 차원벡터 하나의 길이
내적(dot product)같은 자리끼리 곱해 더한 값
코사인 유사도두 벡터의 방향이 얼마나 같은지(−1~1)
노름(norm)벡터의 길이
정적 임베딩단어마다 고정된 벡터 하나
문맥 임베딩주변 문장에 따라 달라지는 벡터
문장 임베딩문장 전체를 벡터 하나로 나타낸 것

더 깊이 보려면

다음에 볼 것

라이선스

본문은 KAITABASE 자체 해설입니다. 참고 자료인 Google Machine Learning Crash Course 본문은 CC BY 4.0, 코드 예제는 Apache 2.0입니다. 임베딩 행렬 EE 와 질문 벡터 숫자는 이 수업을 위해 만든 해설용 예입니다.

출처

  • Google MLCC Embeddings: https://developers.google.com/machine-learning/crash-course/embeddings
  • Google MLCC Embedding space and static embeddings: https://developers.google.com/machine-learning/crash-course/embeddings/embedding-space

AI 원리부터 이해하기 · NLP·트랜스포머 모듈

NLP·트랜스포머 모듈 학습

이 글은 NLP·트랜스포머 모듈의 학습 자료입니다. 전체 23개 자료 중 2번째입니다.

AI 기초 과정은 현재 진도 저장을 지원하지 않습니다.

출처·원문

원문 보기

요약만

본문 자체 작성 · 참고 자료 Google MLCC(CC BY 4.0)