임베딩과 벡터

김소희·2025년 11월 20일

임베딩이란 무엇인가

임베딩(Embedding)은 단어나 문장 같은 텍스트를 숫자 벡터로 변환하여 의미를 수치화하는 기술이다. 사람은 단어의 의미를 직관적으로 이해하지만, 컴퓨터는 모든 정보를 숫자로 처리하기 때문에 언어를 숫자 형태로 변환해야 한다. 임베딩은 복잡한 언어의 세계(고차원 데이터)를 단순화된 형태(저차원 데이터)로 번역하는 다리 역할을 한다.
단어 임베딩의 핵심은 문장 내에서 단어의 맥락에 대한 많은 정보를 포착한다는 점이다. 동일한 맥락에서 사용되는 단어는 유사한 의미를 가질 가능성이 높으며, 이는 벡터 공간에서도 그대로 반영된다. 비슷한 단어는 벡터 공간에서 서로 가까이 위치하고, 다른 단어는 멀리 위치하게 된다.

벡터의 개념

벡터는 수학에서 방향과 크기를 가진 화살표로 표현된다.
예를 들어 오른쪽으로 3, 위로 4만큼 이동하는 벡터는 (3, 4)로 표현되고 그 크기는 피타고라스 정리에 따라 5가 된다.

일상에서도 벡터는 자주 등장한다. 북동쪽으로 초속 10m로 부는 바람, 스마트폰 화면을 밀었을 때 손가락이 움직인 방향과 거리, 게임 캐릭터가 앞으로 달리는 움직임 등이 모두 방향과 크기를 갖는 벡터다.

프로그래밍에서는 벡터를 숫자의 배열로 표현한다.
예를 들어 float[] vector = {0.12f, -0.85f, 0.44f}; 처럼 여러 수가 한 줄에 나열된 배열과 같은 구조다.

임베딩의 작동 원리

임베딩을 거친 단어는 고차원 벡터로 변환된다. 실제 예시를 보면 다음과 같다.

  • "고양이" → [0.21, -0.34, 0.87, ...]
  • "강아지" → [0.20, -0.30, 0.85, ...]
  • "비행기" → [-0.75, 0.12, 0.55, ...]

벡터의 차원이 1536처럼 매우 큰 이유는 단어의 의미적 특징을 더 정교하게 담기 위해서다.
차원이 높을수록 더 세밀한 의미 차이를 표현할 수 있다.

벡터 공간에서의 의미 표현

이 벡터들은 고차원 공간의 점(좌표)으로 생각하면 이해가 쉬워진다.
의미가 비슷한 단어는 벡터 공간에서도 서로 가까이 위치한다.

2차원으로 단순화해서 설명하면, "고양이"가 [1, 0], "강아지"가 [0.9, 0.1]이라면 두 점의 거리는 매우 가깝다. 반대로 "비행기"가 [0.1, 0.9]에 있다면 고양이나 강아지와는 멀리 떨어져 있게 된다. 즉, 벡터 간 거리가 가까우면 의미가 유사하고, 멀면 의미가 다르다는 뜻이다.

코사인 유사도: 방향으로 의미 비교하기

코사인 유사도는 두 문장이나 단어가 얼마나 비슷한 방향을 바라보는지를 숫자로 표현하는 방법이다.
거리가 아니라 방향을 비교하기 때문에, 얼마나 같은 의미로 쓰였는가를 판단할 때 유용하다.

단어벡터 표현 (예시)
강아지[0.8, 0.7]
고양이[0.9, 0.6]
[-0.2, 0.9]

각도에 따른 유사도는 다음과 같이 해석한다.

  • 각도 0도 (완전히 같은 방향) → 유사도 1.0
  • 각도 90도 (서로 관련 없음) → 유사도 0.0
  • 각도 180도 (정반대 방향) → 유사도 -1.0

벡터 유사도 검색 구현

실제로 벡터 데이터베이스에서 유사도 검색을 수행하는 가장 기본적인 쿼리는 다음과 같다.

SELECT id, content, metadata,
       embedding <-> :queryEmbedding AS distance
FROM vector_store
ORDER BY distance ASC
LIMIT 5;

여기서 <-> 연산자는 L2 거리(Euclidean Distance)를 계산하며, 거리(distance)가 작을수록 유사한 텍스트를 의미한다. 코사인 유사도나 L2 거리 같은 방법이 벡터 간 거리 계산에 사용된다.

정리

결국 임베딩은 언어를 기계가 이해할 수 있는 벡터로 바꿔주는 과정이며, 이 벡터 공간에서의 위치와 거리를 활용해 검색, 추천, 분류, 의미 분석 등 다양한 AI 기능을 구현할 수 있게 해준다.

  • 벡터 = 여러 숫자로 된 좌표 (의미를 수학적으로 표현한 것)
  • 임베딩 = 텍스트/이미지를 벡터로 바꾸는 과정
  • 벡터 DB (pgvector 등) = 벡터들을 저장하고 가장 가까운 의미를 빠르게 찾아줌

초급 개발자도 간단한 텍스트 → 임베딩 → DB 저장 → 유사도 검색 흐름으로 시작하면 충분히 연습 가능하다. 단어를 자르고 처리하는 과정이 복잡하긴 해도 정형화된 방법이 있으므로, 기존 라이브러리와 도구를 활용하면 쉽게 시작할 수 있다.


자연어 처리(NLP)에서의 활용

임베딩은 자연어 처리 분야에서 다양한 언어 관련 작업의 성능을 향상시키는 데 중요한 역할을 한다.

감성 분석

감성 분석은 텍스트에서 표현된 감정을 이해하는 작업이다. 임베딩은 단어의 의미를 포착할 수 있기 때문에 주어진 텍스트가 긍정적인 감정, 부정적인 감정, 중립적인 감정을 가지고 있는지를 판단하는 데 유용하게 사용된다.
예를 들어 "I absolutely loved the new superhero movie!"라는 문장을 생각해보면, 긍정적인 감성은 개별적인 긍정적 단어뿐만 아니라 문장의 전체 구조에서도 나타난다.

pythonimport openai

response = openai.Embedding.create(
    model="gpt-3.5-turbo",
    texts=["I absolutely loved the new superhero movie!"]
)

embeddings = response['embeddings']
# 이러한 임베딩을 감성 분석 모델의 입력으로 사용한다

얻은 임베딩은 감성을 인식하는 모델에 입력으로 사용되며, 이를 통해 문장의 감성을 예측할 수 있다.

개체명 인식(NER)

개체명 인식은 텍스트 내에서 개체(사람, 조직, 위치 등)를 식별하는 작업이다. 임베딩은 의미 정보를 포착하는 단어 표현을 제공하여 모델이 서로 다른 유형의 개체를 구분할 수 있도록 돕는다.

pythonimport openai

response = openai.Embedding.create(
    model="gpt-3.5-turbo",
    texts=["Microsoft was founded by Bill Gates and Paul Allen in Albuquerque."]
)

embeddings = response['embeddings']
# 이러한 임베딩을 NER 모델의 입력으로 사용한다

이 텍스트에서 얻은 임베딩에는 문장에 포함된 개체에 대한 정보가 포함되어 있으며, 이를 인식하는 모델에 입력으로 사용할 수 있다.

기계 번역

기계 번역은 텍스트를 한 언어에서 다른 언어로 번역하는 작업이다. 임베딩은 다양한 언어의 단어와 구문의 의미를 포착할 수 있어 번역 품질을 향상시키는 데 활용된다. 특히 GPT-3와 같은 다국어 데이터로 훈련된 모델의 임베딩이 매우 유용하다.

pythonimport openai

response = openai.Embedding.create(
    model="gpt-3.5-turbo",
    texts=["Je suis un étudiant."]
)

embeddings = response['embeddings']
# 이러한 임베딩을 기계 번역 모델의 입력으로 사용한다

"Je suis un étudiant"라는 문장(프랑스어로 "나는 학생입니다")이 임베딩으로 변환되고, 이를 번역 모델에 전달하여 해당하는 영어 문장을 얻을 수 있다.

시맨틱 검색

시맨틱 검색은 사용자의 의도를 문맥적 의미를 통해 이해하여 검색 정확성을 향상시키는 것을 목표로 한다. 임베딩을 사용하면 키워드 일치뿐만 아니라 개념적으로 관련된 검색 결과를 검색할 수 있다.
시맨틱 검색 엔진을 구축하는 과정은 다음과 같다. 먼저 데이터베이스 내의 모든 문서를 인코딩하여 문서마다 하나의 임베딩을 얻는다.

pythonimport openai

docs = ["문서 1", "문서 2", "문서 3", ...]
doc_embeddings = openai.Embedding.encode(docs)
사용자가 검색 질의를 입력하면 동일한 방식으로 질의를 인코딩한다.
pythonquery = "사용자의 검색 질의"
query_embedding = openai.Embedding.encode(query)
그런 다음 질의 임베딩과 각 문서 임베딩 간의 코사인 유사도를 계산한다. 유사도 점수가 가장 높은 문서가 사용자의 질의와 가장 관련성이 높다.
pythonfrom sklearn.metrics.pairwise import cosine_similarity

scores = cosine_similarity(query_embedding, doc_embeddings)
top_docs = scores.argsort()[-10:][::-1]

문서 군집화

문서 군집화는 문서를 유사성에 따라 그룹화하는 작업이다. 임베딩을 사용하면 문서 전체를 벡터로 표현하여 유사성을 측정하고 그에 따라 문서를 군집화할 수 있다.

추천 시스템

추천 시스템에서는 임베딩을 사용하여 사용자의 선호도와 항목 속성을 나타낼 수 있다. 노래, 영화, 제품을 추천하는 시스템에서 사용자 및 항목 임베딩 간의 유사성을 사용하여 사용자가 좋아할 만한 항목을 추천한다.

텍스트 분류

텍스트 분류는 임베딩이 매우 유용한 또 다른 일반적인 작업이다. 각 문서를 벡터로 표현한 다음, 이러한 임베딩을 분류 모델의 입력으로 사용한다.
뉴스 기사 데이터셋이 있고 각 기사를 "스포츠", "정치", "기술" 등의 여러 범주로 분류하려는 경우를 가정해보자. 먼저 각 문서를 임베딩으로 인코딩한다.

pythonarticles = ["기사 1", "기사 2", "기사 3", ...]
article_embeddings = openai.Embedding.encode(articles)
그런 다음 이러한 임베딩으로 분류 모델을 학습한다. 이는 간단한 선형 모델, 신경망 또는 다른 유형의 모델일 수 있다.
pythonfrom sklearn.linear_model import LogisticRegression

labels = ["스포츠", "정치", "기술", ...]
clf = LogisticRegression().fit(article_embeddings, labels)

이제 새로운 기사가 주어지면 기사를 임베딩으로 인코딩하고 모델을 통해 카테고리를 예측할 수 있다.

pythonnew_article = "새로운 기사 내용"
new_embedding = openai.Embedding.encode(new_article)
prediction = clf.predict(new_embedding)

생물 정보학

생물 정보학에서 임베딩은 단백질 구조 예측에 사용된다. 아미노산은 속성을 포착하는 임베딩으로 표현할 수 있으며, 이를 사용하여 아미노산 시퀀스의 구조를 예측할 수 있다.


pgvector 설치 및 설정

벡터 검색을 실제로 구현하려면 PostgreSQL에 pgvector 확장을 설치해야 한다. 다음은 Docker를 사용한 설치 과정이다.

PostgreSQL 이미지 다운로드 및 컨테이너 실행

먼저 PostgreSQL 이미지를 다운로드한다.

docker pull postgres

이미지가 제대로 다운로드되었는지 확인한다.

docker image ls

다음 명령으로 PostgreSQL 컨테이너를 실행한다. 여기서는 사용자명을 user, 비밀번호를 1004, 데이터베이스명을 regdb로 설정하고 5432 포트를 연결한다.

docker run --name postgresql -e POSTGRES_USER=user -e POSTGRES_PASSWORD=1004 -e POSTGRES_DB=regdb -p 5432:5432 -d postgres

컨테이너가 정상적으로 실행 중인지 확인한다.

docker ps

pgvector 설치

컨테이너 내부로 접속한다. 컨테이너 ID의 앞 3자리만 입력해도 된다.

docker exec -it 49e /bin/bash

PostgreSQL 버전을 확인한다.

psql -V

pgvector를 설치하기 위한 필수 패키지를 설치한다.

apt-get update
apt-get install -y git build-essential postgresql-server-dev-18

pgvector 소스코드를 다운로드하고 빌드한다.

git clone https://github.com/pgvector/pgvector.git
cd pgvector
make
make install

pgvector 확장 활성화

PostgreSQL만으로는 벡터를 생성할 수 없으므로 확장 프로그램인 pgvector를 깃에서 클론으로 받아주어야 한다.

psql -U user -d regdb

pgvector 확장을 활성화한다.

CREATE EXTENSION IF NOT EXISTS vector;

설치된 확장을 확인한다.

\dx

정상적으로 설치되었다면 다음과 같은 결과를 볼 수 있다.

  Name   | Version |   Description
---------+---------+------------------------------------------------------
 plpgsql | 1.0     | PL/pgSQL procedural language
 vector  | 0.8.1   | vector data type and ivfflat and hnsw access methods

이제 벡터 데이터 타입을 사용하고 유사도 검색을 수행할 준비가 완료되었다.


가장 쉬운 방법 → pgvector가 이미 들어있는 이미지 사용

docker run -d \
  --name pgvector-db \
  -e POSTGRES_USER=reguser \
  -e POSTGRES_PASSWORD=1004 \
  -e POSTGRES_DB=regdb \
  -p 5432:5432 \
  ankane/pgvector

참고자료

임베딩 - wikidocs
임베딩 차원 시각화 사이트
pgvector란? - 티스토리 블로그
pgvector - github

profile
백엔드 개발자의 노트

0개의 댓글