랭체인 Text Embeddings

 

Text Embedding

텍스트를 숫자로 이루어진 고차원 벡터로 변환하는 과정.

🔹 주요 역할

  • 텍스트 간의 유사도 계산 가능 (비슷한 의미의 문장은 가까운 벡터를 가짐)
  • 검색(Retrieval)추천 시스템 에 활용
  • GPT 같은 LLM이 문맥을 이해하는 데 도움

🔹 예시 (OpenAI Embeddings 사용)

from openai import OpenAI 

client = OpenAI() 
response = client.embeddings.create( 
	input="최성식의 연락처는?", model="text-embedding-ada-002" 
) 

embedding_vector = response.data[0].embedding

 

📌 즉, 텍스트 임베딩은 "문장의 의미"를 숫자로 표현하는 기술! 🚀

 

  • 대부분의 경우, 대용량 말뭉치를 통해 사전학습된 모델로 쉽게 임베딩
    • 임베딩 모델 : 비정형 데이터를 수치화해서 좌표상에 위치할 수 있도록 해줌
    • 다차원의 벡터를 통해 비정형 언어를 정형 데이터로 바꾸는 역할을 담당하는 것
    • 임베딩 모델이 학습되지 않은 문장에 대해서도 수치화하는 것을 잘할 수 있게 됨

 

사전학습 임베딩 모델

  • OpenAI에서 제공하는 ada 모델, HuggingFace 모델 등
  • 사용 목적 및 요구 사항에 따른 적절한 임베딩을 고르는 것이 RAG의 가장 주요한 부분

 

실습: Text Embeddings

실습 코드 : Text Embedding.ipynb

OpenAI Embeddings - ada-002

  • OpenAIEmbeddings : OpenAI 임베딩 모델
  • embeddings_model.embed_documents : 여러 개의 문장을 한꺼번에 임베딩
  • 한글 문장을 embeddings에 저장
from langchain_openai import OpenAIEmbeddings

embeddings_model = OpenAIEmbeddings(openai_api_key = '{API KEY}')

embeddings = embeddings_model.embed_documents(
    [
        "안녕하세요",
        "제 이름은 이하얀입니다.",
        "이름이 무엇인가요?",
        "랭체인은 유용합니다.",
        "Hello World!"
    ]
)
len(embeddings), len(embeddings[0])

하나의 문장이 1536개의 차원을 가진 하나의 행이 된다는 의미

 

  • 유사도 확인
    • 지금 넣은 2문장도 1536차원으로 임베딩되었음을 알 수 있음
embedded_query_q = embeddings_model.embed_query("이 대화에서 언급된 이름은 무엇입니까?")
embedded_query_a = embeddings_model.embed_query("이 대화에서 언급된 이름은 이하얀입니다.")
print(len(embedded_query_q), len(embedded_query_a))

  • 벡터 간 유사도 확인
    • 코사인 유사도 사용
    • 순서 : 질문-답변, 질문-두 번째 문장, 질문-네 번째 문장
from numpy import dot
from numpy.linalg import norm
import numpy as np

def cos_sim(A, B):
  return dot(A, B) / (norm(A)*norm(B))
  
print(cos_sim(embedded_query_q, embedded_query_a))
print(cos_sim(embedded_query_q, embeddings[1]))
print(cos_sim(embedded_query_q, embeddings[3]))

 

오픈 소스 - HuggingFaceEmbeddings

  • sentence-transformers 라이브러리 다운
!pip install sentence-transformers

1. BAAI/bge-small-en 임베딩 모델

  • 주의 : 구글 코랩 환경일 경우 런타임 > 런타임 유형 변경 > GPU로 변경하여 사용
from langchain_community.embeddings import HuggingFaceEmbeddings

model_name = "BAAI/bge-small-en"
bge_embedding= HuggingFaceEmbeddings(
    model_name=model_name
)

  • 한글 문장 테스트
examples = bge_embedding.embed_documents(
     [
        "안녕하세요",
        "제 이름은 홍두깨입니다.",
        "이름이 무엇인가요?",
        "랭체인은 유용합니다.",
     ]
 )
 
 embedded_query_q = bge_embedding.embed_query("이 대화에서 언급된 이름은 무엇입니까?")
embedded_query_a = bge_embedding.embed_query("이 대화에서 언급된 이름은 홍길동입니다.")

print(cos_sim(embedded_query_q, embedded_query_a))
print(cos_sim(embedded_query_q, examples[1]))
print(cos_sim(embedded_query_q, examples[3]))

  • 영어 문장 테스트
examples2 = bge_embedding.embed_documents(
     [
        "today is tuesday",
        "weather is nice today",
        "what's the problem?",
        "langchain in useful",
        "Hello World!",
        "my name is morris"
     ]
 )

embedded_query_q = bge_embedding.embed_query("Hello? who is this?")
embedded_query_a = bge_embedding.embed_query("hi this is harrison")

print(cos_sim(embedded_query_q, embedded_query_a))
print(cos_sim(embedded_query_q, examples2[1]))
print(cos_sim(embedded_query_q, examples2[3]))

  • 여러개 문장 비교
sentences = [
    "안녕하세요",
    "제 이름은 홍길동입니다.",
    "이름이 무엇인가요?",
    "랭체인은 유용합니다.",
    "홍길동 아버지의 이름은 홍상직입니다."
]
examples3 = bge_embedding.embed_documents(sentences)

embedded_query_q = bge_embedding.embed_query("홍길동은 아버지를 아버지라 부르지 못하였습니다. 홍길동 아버지의 이름은 무엇입니까?")
embedded_query_a = bge_embedding.embed_query("홍길동의 아버지느 엄했습니다.")

print("질문: 홍길동은 아버지를 아버지라 부르지 못하였습니다. 홍길동 아버지의 이름은 무엇입니까? \n", "-"*100)
print("홍길동의 아버지는 엄했습니다. \t\t 문장 유사도: ", round(cos_sim(embedded_query_q, embedded_query_a),2))
print(sentences[1] + "\t\t 문장 유사도: ", round(cos_sim(embedded_query_q, examples3[1]),2))
print(sentences[3] + "\t\t 문장 유사도: ", round(cos_sim(embedded_query_q, examples3[3]),2))
print(sentences[4] + "\t 문장 유사도: ", round(cos_sim(embedded_query_q, examples3[4]),2))

 

2. jhgan/ko-sroberta-multitask

from langchain.embeddings import HuggingFaceEmbeddings

#HuggingfaceEmbedding 함수로 Open source 임베딩 모델 로드
model_name = "jhgan/ko-sroberta-multitask"
ko_embedding= HuggingFaceEmbeddings(
    model_name=model_name
)

examples = ko_embedding.embed_documents(
     [
        "안녕하세요",
        "제 이름은 홍두깨입니다.",
        "이름이 무엇인가요?",
        "랭체인은 유용합니다.",
     ]
 )

embedded_query_q = ko_embedding.embed_query("이 대화에서 언급된 이름은 무엇입니까?")
embedded_query_a = ko_embedding.embed_query("이 대화에서 언급된 이름은 홍길동입니다.")

print(cos_sim(embedded_query_q, embedded_query_a))
print(cos_sim(embedded_query_q, examples[1]))
print(cos_sim(embedded_query_q, examples[3]))

 

3. OpenAI 임베딩 모델 - text-embedding-3-small

import os
import openai
from langchain_openai import OpenAIEmbeddings
from google.colab import userdata

openai.api_key = userdata.get('OPENAI_API_KEY')

embeddings_model = OpenAIEmbeddings(model = 'text-embedding-3-small')
embeddings = embeddings_model.embed_documents(
    [
        "Hi there!",
        "Oh, hello!",
        "What's your name?",
        "My friends call me World",
        "Hello World!"
    ]
)
len(embeddings), len(embeddings[0])

  • OpenAI 임베딩 모델로 청크들을 임베딩 변환
from langchain_community.document_loaders import PyPDFium2Loader
from langchain_text_splitters import RecursiveCharacterTextSplitter

#임베딩 모델 API 호출
embeddings_model = OpenAIEmbeddings(model = 'text-embedding-3-small')

#PDF 문서 로드
loader = PyPDFium2Loader("/content/drive/MyDrive/NLP톺아보기/file/[이슈리포트 2022-2호] 혁신성장 정책금융 동향.pdf")
pages = loader.load()

#PDF 문서를 여러 청크로 분할
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=100
)

texts = text_splitter.split_documents(pages)

embeddings = embeddings_model.embed_documents([i.page_content for i in texts])
len(embeddings), len(embeddings[0])