Sentence Embedding
- 문장을 고정된 크기의 벡터로 변환
- 문장 내의 단어 순서, 구조, 맥락 등을 고려해 문장의 의미를 보존
- 머신러닝 모델이 문장을 수치 데이터로 처리할 수 있게 도와줌
- query 와 특정 문장의 embedding vector 끼리의 내적을 통해 유사도를 측정할 수 있다
Huggingface: bge-m3
- sentence embedding 을 진행하기 위해 huggingface 에서
bge-m3 model 을 import 해봤다.
- 이 모델은 한국어 embedding 이 가장 잘 된다고 알려져 있다.
import bge-m3
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("BAAI/bge-m3")
embedded_vector = model.encode("야 저기 차 온다")
embedded_vector.shape
>>> 1024
- bge-m3 의 embedding dimension 이 1024 인 것을 알 수 있다.
유사도 측정
- 위에서 인코딩한 "야 저기 차 온다" 라는 문장과 가장 유사한 문장을 dataset 에서 찾아보자
import pandas as pd
data = [
"내일 차타고 놀러가자",
"지금 오는 버스는 어디서 오는 버스야?",
"차 한잔 하면서 이야기 하시죠",
"5차 공동구매! 오늘만 세일!",
"홍차 녹차 중에 어떤 차가 좋으세요?",
]
df = pd.DataFrame(data, columns=["text"])
- 각 문장의 embedding vector 를 생성하고, df 에 이를 나타내는 column 을 추가해보자
- 이를 위해 list comprehension 을 사용했다
- apply 를 사용해도 되나, list comprehension 이 더 가독성이 좋다고 생각했다.
- 하지만, 각 row / column 에 적용해야 할 함수가 복잡하면 apply 가 유리할 수 있다.
def get_embedding(text):
"""
text: str
input text to be embedded
returns: embedding vector of input text
"""
return list(model.encode(text))
df["embedding"] = [get_embedding(text) for text in df["text"]]
- query 와 각 문장들의 cosine similarity 를 구하고 정렬
import numpy as np
def cos_sim(A, B):
"""
A, B: list
embedding vectors
returns: cosine similarity of A and B
"""
return A @ B / (np.linalg.norm(A) * np.linalg.norm(B))
def get_candidate(df, query):
"""
df: string
list of embedding vectors of candidates
query: string
sentence to be compared with candidates
returns: df of top 3 candidates
"""
query_embedded = get_embedding(query)
df["similarity"] = [cos_sim(np.array(emb), query_embedded) for emb in df["embedding"]]
candidates_sorted = df.sort_values("similarity", ascending=False, ignore_index=True)
return candidates_sorted.head(3)
top_3_candidates = get_candidate(df, "야 저기 차 온다!")
top_3_candidates
>>> 내일 차타고 놀러가자
>>> 지금 오는 버스는 어디서 오는 버스야?
>>> 차 한잔 하면서 이야기 하시죠
top_3_candidates = get_candidate(df, "예쁜 카페에 가고 싶어.")
top_3_candidates
>>> 차 한잔 하면서 이야기 하시죠
>>> 내일 차타고 놀러가자
>>> 지금 오는 버스는 어디서 오는 버스야?
- "차"라는 단어가 polysemic 하기 때문에 다양한 우선순위가 생성된다
- "예쁜 카페에 가고 싶다"는 말과 "내일 차 타고 놀러가자" 의 유사도가 예상보다 높았다.
- query 가 어딘가에 놀러간다는 의미를 내포하기 때문인 것으로 생각된다.
OpenAI API
- 이번에는 OpenAI 의 API 를 발급받아,
text-embedding-ada-002 를 이용해보자
Client 구현
- API server 에 요청을 보낼 client 를 구현하자
- OpenAI 에서 발급받은 API key 를 전달해야 하는데, 아래 방법들을 통해 노출을 방지할 수 있다
- API key 를 환경변수로 전달하는 방법
os.environ["OPENAI_API_KEY"] =
- 다른 py 파일에 선언 후 import
import os
import sys
sys.path.append(os.path.abspath("../../data"))
from openai import OpenAI
import API_KEY
API_KEY = API_KEY.OpenAI_KEY
client = OpenAI(api_key=API_KEY)
- key 를 담은 파일이 있는 module 을 계속 추가해줘야 하는 번거로움이 있다.
- API Key 는 환경변수로 한 번 설정하면 다른 파일에서 추가적인 설정이 필요없기 때문에 1번을 채택
from dotenv import load_dotenv
from openai import OpenAI
load_dotenv()
client = OpenAI()
embedding = client.embeddings.create(
model="text-embedding-ada-002",
input=["야 저기 차 온다!", "저건 어디로 가는 버스야?"],
)
len(embedding.data[0].embedding)
>>> 1536
- 이후 과정은 huggingface model 을 이용했을 때와 동일하다