6.1 Embedding의 개념과 Cosine Similarity

OpenAI Embedding API를 효과적으로 사용하려면, Embedding의 근본적인 개념과 그 활용 방식, 그리고 Embedding 간의 유사도를 비교하는 데 가장 널리 쓰이는 Cosine Similarity에 대한 이해가 중요합니다. 이 절에서는 Embedding이란 무엇인지부터 시작하여 Cosine Similarity의 수학적 정의, 구현과 활용에 이르기까지 순차적으로 자세히 설명하겠습니다.

6.1.1 Embedding이란 무엇인가

"Embedding"은 자연어 처리(NLP) 분야에서 텍스트 데이터를 의미 있는 벡터로 변환하는 기술입니다. 말 그대로 "임베딩(넣어넣기)"은 고차원 의미를 저차원 수치공간으로 매핑하는 과정을 뜻합니다. 즉, 사람이 이해하는 "의미"를 기계가 계산할 수 있는 수치로 변환하는 것을 말합니다.

Embedding의 요소

  • 일반적으로 단어나 문장을 Embedding하면, 해당 텍스트는 n차원의 실수 벡터 (예: [0.13, -0.87, 1.02, ...]) 로 변환됩니다.

  • 이 벡터는 텍스트의 의미적 특성을 내포하고 있어, 비슷한 의미의 텍스트는 벡터 공간 상에서도 서로 가깝게 위치합니다.

Embedding의 예시

텍스트
벡터 (단순화된 형태)

"고양이"

[0.21, -0.03, 0.77]

"개"

[0.19, -0.01, 0.75]

"자동차"

[-0.58, 0.45, 0.12]

위 예시에서 ‘고양이’와 ‘개’는 유사한 의미(반려동물)이므로 비슷한 방향의 벡터를 가집니다. 반면 ‘자동차’는 별개의 개념이기 때문에 벡터 공간상에서 방향이 다릅니다.

6.1.2 OpenAI Embedding 모델

OpenAI는 Embedding 생성을 위한 전용 모델을 제공합니다. 대표적인 모델은 다음과 같습니다:

  • text-embedding-ada-002 (가장 최신, 성능 대비 비용 효율 우수)

  • text-embedding-3-small / text-embedding-3-large (2024년 기준 최신)

이 모델들은 단어 단위가 아닌 문장, 단락, 문서 수준의 의미 구조를 파악하여 고차원 벡터(예: 1536차원)로 변환해줍니다.

간단한 코딩 예 (Python + openai 패키지):

import openai

openai.api_key = "your-api-key"

response = openai.embeddings.create(
    model="text-embedding-ada-002",
    input="올해 가장 인기 있는 여행 도시는 어디인가?"
)

embedding_vector = response.data[0].embedding
print(f"임베딩 벡터 차원: {len(embedding_vector)}")  # 일반적으로 1536 차원

6.1.3 임베딩 벡터 비교: Cosine Similarity

벡터로 변환하는 목적은 “비슷한 의미의 텍스트인지”를 비교하기 위함입니다. 이를 위해 벡터 간의 유사도를 측정하는 지표가 필요하며, 대부분의 경우 Cosine Similarity(코사인 유사도)를 사용합니다.

Cosine Similarity 정의

코사인 유사도는 두 벡터 사이의 "각도"를 측정해 이들이 얼마나 유사한 방향을 갖는지를 나타냅니다. 수식은 다음과 같습니다:

[ \text{cosine_similarity}(A, B) = \frac{A \cdot B}{|A| \cdot |B|} ]

여기서,

  • ( A \cdot B ): 두 벡터의 내적(dot product)

  • ( |A| ): 벡터 A의 크기 (Euclidean norm)

  • 결과값은 -1 ~ 1 사이의 실수

    • 1: 완전히 같은 방향 (즉, 매우 유사한 의미)

    • 0: 직각 (비슷하지 않음)

    • -1: 반대 방향 (의미가 서로 상반됨)

예시

from numpy import dot
from numpy.linalg import norm
import numpy as np

def cosine_similarity(v1, v2):
    return dot(v1, v2) / (norm(v1) * norm(v2))

vec1 = np.array([0.21, -0.03, 0.77])
vec2 = np.array([0.19, -0.01, 0.75])
vec3 = np.array([-0.58, 0.45, 0.12])

print(cosine_similarity(vec1, vec2))  # 매우 유사 → 0.99 등
print(cosine_similarity(vec1, vec3))  # 유사하지 않음 → 0.1 ~ 0.3

6.1.4 Embedding + Cosine Similarity의 실제 활용

실제 개발 환경에서는 다양한 형태로 이 기술 조합이 활용됩니다:

문서 검색 시스템 (RAG)

  • 유저의 질의(Query)를 Embedding한 후,

  • 방대한 문서 벡터들과 Cosine Similarity를 구해 가장 유사한 문서 추출

  • 이를 LLM에게 제공해 답변을 생성

챗봇의 문맥 회수 (Context Retrieval)

  • 이전 발화 내용 중 중요 요소를 벡터로 저장

  • 현재 대화와의 유사도 비교 후 관련 맥락 자동 추출

데이터 클러스터링

  • 임베딩 벡터들을 차원 축소(PCA, t-SNE) 후 시각화하거나

  • K-means, DBSCAN 등의 클러스터링에 활용해 의미 기반 자동 분류

6.1.5 Cosine Similarity 외 다른 유사도 지표

Cosine Similarity는 문장 길이 차이의 영향을 덜 받기 때문에 많이 쓰이지만, 경우에 따라 다음과 같은 거리 함수들도 사용됩니다:

  • Euclidean Distance (유클리드 거리): 절대 거리 중심

  • Manhattan Distance: 좌표 상 축 중심 거리 측정

  • Dot Product 자체: 빠르지만 정규화 부족

그러나 대부분 Embedding 기반 검색에서는 cosine similarity가 가장 안정적이고 의미 보존력이 뛰어납니다.

6.1.6 실전 Tip: 벡터 정규화는 필수

Embedding 벡터 비교 전에는 정규화를 수행하거나, 벡터를 사전에 L2 노멀라이즈(L2 normalize)된 상태로 저장하고 비교하는 것이 효율적입니다.

def normalize(vec):
    return vec / norm(vec)

이는 검색 엔진 구현 시 효율적인 인덱싱과 빠른 검색을 가능케 합니다 (FAISS나 Pinecone 등에서도 내부적으로 정규화 적용).

6.1.7 요약

항목
설명

Embedding

텍스트를 의미 기반의 벡터로 변환

목표

의미적으로 유사한 텍스트를 수치적으로 가까운 벡터로 표현

비교 방식

Cosine Similarity(벡터 간 각도 유사도)

활용 분야

검색엔진, 챗봇 프롬프트 회수, 분류기, 유사 문서 검출 등

라이브러리 예

numpy, scikit-learn, FAISS, Pinecone, Weaviate 등

다음 절에서는 Embedding을 실제로 어떤 방식으로 생성하고 활용하는지, 문서 단위의 벡터화와 OpenAI API를 사용하는 실습 단계를 안내합니다. 이제 개념을 이해했으니, 본격적인 구현으로 넘어가보겠습니다.

Last updated