04 벡터 검색 실습
1. 핵심 개념 정리
Section titled “1. 핵심 개념 정리”1-1. 임베딩(Embedding)이란?
Section titled “1-1. 임베딩(Embedding)이란?”컴퓨터는 텍스트를 직접 이해하지 못합니다.
임베딩이란 텍스트(문자)를 컴퓨터가 계산할 수 있는 **숫자 벡터(배열)**로 변환하는 과정입니다.
"오늘 날씨가 좋다" → [0.12, -0.87, 0.44, ... , 0.03] (768개 숫자)"The weather is nice" → [0.11, -0.85, 0.46, ... , 0.02] (768개 숫자)💡 핵심: 의미가 비슷한 문장은 벡터 공간에서 가까운 위치에 놓입니다.
위 두 문장처럼 언어가 달라도 의미가 같으면 비슷한 벡터가 만들어집니다.
1-2. 단어 임베딩 vs 문장 임베딩
Section titled “1-2. 단어 임베딩 vs 문장 임베딩”단어 임베딩 (Word Embedding): “개별 식재료의 맛”
Section titled “단어 임베딩 (Word Embedding): “개별 식재료의 맛””- 개념: ‘사과’, ‘맛있다’, ‘먹다’ 등 단어 하나하나를 고유한 벡터(숫자)로 변환하는 것입니다. (예: Word2Vec)
- 특징: 단어들 사이의 관계(사과와 바나나는 비슷하다)는 잘 알 수 있습니다.
- 비유: 당근, 양파, 카레 가루 등 각각의 식재료가 어떤 맛을 내는지 파악하는 단계입니다.
단어에서 문장으로의 확장: “단순한 짬짜면?”
Section titled “단어에서 문장으로의 확장: “단순한 짬짜면?””단어 임베딩을 배웠으니, 이제 “사과가 맛있다”라는 문장을 기계에 넣고 싶어집니다. 가장 단순한 응용 방법은 무엇일까요?
- 초기 접근법 (단어 벡터의 평균): 문장에 쓰인 단어들의 임베딩 벡터 값을 그냥 더하거나 평균을 내버리는 방식입니다.
- 치명적 한계: 이 방식은 ‘어순’과 ‘문맥’을 완전히 무시합니다.
- 예시: “내가 너를 때렸다”와 “너가 나를 때렸다”는 단어 구성이 똑같아서 기계가 완전히 같은 문장(같은 벡터 값)으로 인식해 버립니다. 식재료를 그냥 한 냄비에 다 때려 넣고 섞어버린 셈입니다.
문장 임베딩 (Sentence Embedding): “완성된 요리의 맛”
Section titled “문장 임베딩 (Sentence Embedding): “완성된 요리의 맛””- 개념: 위와 같은 단어 임베딩의 한계를 극복하기 위해, 단순히 단어를 합치는 것을 넘어 문장 전체의 문맥과 어순을 고려해 하나의 압축된 벡터로 변환하는 기술입니다. (예: SBERT, 트랜스포머 기반 모델)
- 특징: “내가 너를 때렸다”와 “너가 나를 때렸다”의 뉘앙스 차이를 완벽하게 구분하여 서로 다른 벡터 공간에 배치합니다.
- 비유: 식재료들이 어떤 순서로, 어떻게 조리되어 최종적으로 어떤 ‘완성된 요리(카레라이스)‘의 맛과 향을 내는지 그 전체적인 느낌을 파악하는 것입니다.
📊 한눈에 보는 비교 (강의 화면용 추천)
Section titled “📊 한눈에 보는 비교 (강의 화면용 추천)”| 구분 | 단어 임베딩 (Word Embedding) | 문장 임베딩 (Sentence Embedding) |
|---|---|---|
| 분석 단위 | 개별 단어 | 문장 또는 문단 전체 |
| 어순 파악 | 불가능 (단어의 존재 유무만 앎) | 가능 (문맥과 뉘앙스를 완벽히 이해) |
| 비유 | 개별 식재료의 맛 | 완성된 요리의 전체적인 맛 |
| 주요 활용 | 연관 검색어 찾기, 단어 군집화 | 시맨틱 검색(RAG), AI 챗봇 질문 의도 파악, 문서 요약/분류 |
| 대표 모델 | Word2Vec, GloVe | BERT, GTE, BGE |
“단어 임베딩이 식재료 하나하나의 맛을 분석하는 것이라면, 문장 임베딩은 그 재료들이 조화롭게 섞인 완성된 요리의 맛을 평가하는 것입니다. 우리가 만드는 챗봇이 ‘문맥’을 찰떡같이 알아듣는 이유는, 단순히 단어의 합을 넘어 문장 전체를 꿰뚫어 보는 이 문장 임베딩 기술 덕분입니다.”
1-3. 코사인 유사도(Cosine Similarity)
Section titled “1-3. 코사인 유사도(Cosine Similarity)”두 벡터 간의 **방향(각도)**을 이용해 유사도를 측정합니다.
벡터의 크기(길이)에 영향받지 않아 텍스트 비교에 가장 많이 사용됩니다.
cos(θ) = (A · B) / (‖A‖ × ‖B‖)| 코사인 유사도 값 | 의미 |
|---|---|
| 1.0 | 두 벡터가 완전히 같은 방향 (동일한 의미) |
| 0.8 ~ 0.9 | 매우 유사한 의미 |
| 0.5 ~ 0.7 | 관련은 있으나 다른 내용 |
| 0.0 이하 | 관련 없거나 반대 의미 |
1-4. 시맨틱 검색(Semantic Search)
Section titled “1-4. 시맨틱 검색(Semantic Search)”| 방식 | 검색 원리 | 예시 |
|---|---|---|
| 키워드 검색 | 단어 일치 여부 | ”날씨”만 입력하면 “weather”는 검색 안 됨 |
| 시맨틱 검색 | 의미 유사도 | ”맑음”을 검색해도 “sunny”가 상위에 나옴 |
시맨틱 검색은 아래 3단계로 동작합니다:
① 모든 문장을 미리 임베딩 벡터로 변환 (인덱싱)② 검색어도 임베딩 벡터로 변환③ 검색어 벡터와 모든 문장 벡터의 코사인 유사도 계산 → 높은 순으로 반환2. 사용 모델: GTE-Multilingual-Base
Section titled “2. 사용 모델: GTE-Multilingual-Base”| 항목 | 내용 |
|---|---|
| 이름 | Alibaba-NLP/gte-multilingual-base |
| 유형 | Sentence Transformer (BERT 계열) |
| 임베딩 차원 | 768차원 |
| 최대 입력 | 8,192 토큰 |
| 지원 언어 | 다국어 (한국어, 영어, 중국어 등 70개 이상) |
| 특징 | 다국어 교차 언어 검색에 우수한 성능 |
모델 로드 코드 설명
Section titled “모델 로드 코드 설명”from sentence_transformers import SentenceTransformer
model = SentenceTransformer( "Alibaba-NLP/gte-multilingual-base", trust_remote_code=True # 모델에 커스텀 Python 코드 포함 → 필수)⚠️ 최초 실행 시: 허깅페이스(HuggingFace) 서버에서 모델을 자동 다운로드합니다.
다운로드 후에는 로컬 캐시(~/.cache/huggingface)에 저장되어 다음 실행부터는 빠릅니다.
3. 코드 흐름 설명
Section titled “3. 코드 흐름 설명”3-1. 임베딩 생성
Section titled “3-1. 임베딩 생성”sentences = ["오늘 날씨가 좋다", "The weather is nice", "파이썬 프로그래밍"]
embeddings = model.encode(sentences, show_progress_bar=False)# 결과 shape: (3, 768)# → 3개 문장, 각각 768차원 벡터model.encode()가 반환하는 것은 NumPy 행렬입니다.
각 행(row)이 하나의 문장에 대응하는 768차원 벡터입니다.
embeddings[0] → "오늘 날씨가 좋다" 의 벡터 (768개 숫자)embeddings[1] → "The weather is nice" 의 벡터 (768개 숫자)embeddings[2] → "파이썬 프로그래밍" 의 벡터 (768개 숫자)3-2. 코사인 유사도 계산
Section titled “3-2. 코사인 유사도 계산”from sklearn.metrics.pairwise import cosine_similarity
# query 한 문장을 벡터로 변환query_vec = model.encode(["날씨가 맑고 화창해요"]) # shape: (1, 768)
# 저장된 모든 문장과 한 번에 유사도 계산scores = cosine_similarity(query_vec, embeddings)[0]# scores: [0.95, 0.93, 0.12] → 문장 0, 1과는 유사, 문장 2는 무관
# 정렬 후 Top-3 출력ranked = sorted(enumerate(scores), key=lambda x: x[1], reverse=True)[:3]for rank, (idx, score) in enumerate(ranked, 1): print(f"{rank}위 (점수: {score:.4f}): {sentences[idx]}")3-3. 문장 추가 시 점진적 임베딩
Section titled “3-3. 문장 추가 시 점진적 임베딩”import numpy as np
# 새 문장 한 건만 임베딩new_vec = model.encode(["새로운 문장"]) # shape: (1, 768)
# 기존 행렬에 새 행(row)을 추가embeddings = np.vstack([embeddings, new_vec]) # shape: (N+1, 768)전체를 재계산하지 않고 새 문장만 임베딩하여 이어붙이므로 효율적입니다.
4. 실습 앱 사용
Section titled “4. 실습 앱 사용”Step 1: 현재 문장 리스트 확인
Section titled “Step 1: 현재 문장 리스트 확인”앱 실행 시 10개의 사전 정의 문장이 왼쪽 테이블에 표시됩니다.
Step 2: 의미 기반 검색 체험
Section titled “Step 2: 의미 기반 검색 체험”검색창에 문장을 입력하고 검색 버튼을 클릭합니다.
| 검색어 예시 | 기대 결과 |
|---|---|
맑은 하늘 | 날씨 관련 문장이 상위에 오름 |
sunny | 영어 검색어로도 한국어 문장이 검색됨 |
AI 학습 | 딥러닝/머신러닝 관련 문장이 상위에 오름 |
카페 음료 | 식당/카페 관련 문장이 상위에 오름 |
Step 3: 문장 추가 후 재검색
Section titled “Step 3: 문장 추가 후 재검색”직접 문장을 작성해 추가하고, 동일 검색어로 재검색하여 새 문장이 결과에 반영되는지 확인합니다.
5. 실습 퀴즈
Section titled “5. 실습 퀴즈”오늘 날씨가 화창하다와The weather is sunny의 코사인 유사도는 높을까요, 낮을까요?
→ 직접 검색해서 확인해보세요. 일본어 검색도 해보세요(今日はいい天気ですね! (오늘 맑은(좋은) 날씨네요!))- 완전히 다른 주제(예:
요리 레시피)를 검색했을 때 최고 점수는 얼마나 되나요? (예: 계랸찜이 먹고싶어요) - 직접 만든 문장을 추가하고, 기존 문장과 얼마나 유사한지 점수로 확인해보세요.
- 한국어로 추가한 문장을 영어 키워드로 검색하면 나타나는지 확인해보세요.
- 그 외 다양한 다국어 기반 검색이 잘 되는지 확인해보세요