상세 컨텐츠

본문 제목

Langchain 과 OpenAI 를 이용한 데이터 임베딩과 RAG(Retrieval-Augmented Generation)

R&D

by devTak 2024. 7. 5. 10:23

본문

반응형

 

임베딩이란?

  • 자연어처리에서 사람이 쓰는 자연어를 기계가 이해할 수 있도록 숫자형태인 Vector로 바꾸는 과정 혹은 일련의 전체 과정을 의미한다.

One-Hot Enconding

  • 단어 집합의 크기를 벡터의 차원으로 하고, 표현하고 싶은 단어의 인덱스에 1의 값을 부여하고, 다른 인덱스에는 0을 부여하는 단어의 벡터 표현 방식이다.
아이폰 1 0 0 0 0
갤럭시 0 1 0 0 0
애플워치 0 0 1 0 0
맥북 0 0 0 1 0
갤럭시북 0 0 0 0 1

 

위와같은 형태의 벡터 데이터를 가질 수 있다.

One-Hot Encoding 의 단점

  • 위와 같은 벡터데이터에는 각 데이터의 크기와 상관없이 데이터 할당량 자체가 특정 사이즈로 고정되어있어 데이터크기 측면에서 불리한 점이 있다. 희소 벡터(Sparse vector)가 생긴다는 문제
  • 단어의 개수가 늘어나면 벡터의 차원이 한없이 커진다는 단점을 가지고 있다.
  • 단순히 0, 1 의 조합으로 단어를 벡터로 표현이 되었기 때문에 각 단어간 유사성을 판단할 근거가 없다.
    • ex) 위 표와 같이 아이폰, 애플워치, 맥북은 애플제품으로써 유사성을 가지고 갤럭시와 갤럭시북은 삼성제품으로써 유사성을 가지지만 0,1 만으로 데이터 유사성을 판단할 수 없는 단점이 있다.

Data Embedding

  • 데이터 임베딩 처리는 기존 One-hot 인코딩 방식의 단점을 보완하는 벡터표현방식
  • 0,1 로만 구성되어있는 벡터를 다양한 데이터벡터로 상대적으로 ont-hot 인코딩보다 저차원의 형태로 데이터를 구성

2차원 그래프에서 연관성을 표현

  • 2차원의 형태에서도 유사성 체크가 가능하나, 데이터양이 많아질 수록 더 정교한 유사성을 비교하기위해 N차원의 데이터 형태로 구성
  • one-hot 인코딩과는 다르게 더 적은 차원으로 데이터를 구성할 수 있기 때문에 데이터의 밀집도가 향상되고 더 빽빽한 데이터 형태(Dense Representation)로 구성
  • 데이터 임베딩 모델
    • Word2vec(by Google), FastText(by Facebook), BERT(by Google)

RAG (Retrieval-Augmented Generation) 처리 과정

Source 및 Load 단계 : 원천이되는 데이터 소스를 가져오거나 주입한다. 

from langchain_community.document_loaders import PyPDFLoader
loader = PyPDFLoader("https://snuac.snu.ac.kr/2015_snuac/wp-content/uploads/2015/07/asiabrief_3-26.pdf")

Transform 단계 : 로드한 데이터를 특정 기준에 맞게 Splitter 를 통한 Transform 을 진행한다

from langchain.text_splitter import RecursiveCharacterTextSplitter
textSplitter = RecursiveCharacterTextSplitter(chunk_size=50, chunk_overlap=0)

Embed 단계 : Splitter 로 쪼갠 데이터를 위에서 설명한 데이터 임베딩 처리

from langchain_openai import OpenAIEmbeddings

embeddingsModel = OpenAIEmbeddings(openai_api_key=OPENAI_KEY)
embeddings = embeddingsModel.embed_documents(documents)

print(embeddings[0])

# output
[-0.00743497050557687,
 -0.01563150953761078,
 0.0015626668057332756,
 -0.019168283291034625,
 -0.018213096531648893,
 0.014663413716354573,
 -0.008596684559761767,
 0.004595224625870433,
 -0.005343885021779546,
 -0.0034141486086942847,
 0.011862392228291914,....]

 

임베딩 쿼리 질의

from langchain_openai import OpenAIEmbeddings

embeddings_model = OpenAIEmbeddings(openai_api_key=OPENAI_KEY)
embeddings_query = embeddings_model.embed_query("안녕!")

print(len(embeddings_query))
print(embedded_query[:5])

#output
1536
[-0.00743497050557687, -0.01563150953761078, 0.0015626668057332756, -0.019168283291034625, -0.018213096531648893]

Store 단계 : Embedding 한 데이터를 벡터스토어에 저장

sample_texts = [
    "안녕!",
    "빨간색 공",
    "파란색 공",
    "붉은색 공",
    "푸른색 공",
]

documents = []
for item in range(len(sample_texts)):
    page = Document(page_content=sample_texts[item])
    documents.append(page)

db = Chroma.from_documents(documents=documents, embedding=embeddings_model)

query = "레드"
docs = db.similarity_search(query)
print(docs[0].page_content)

# output : 빨간색 공

query = "인사"
docs = db.similarity_search(query)
print(docs[0].page_content)

# output : 안녕!

 

Retrieve 단계 : VectorStores 에 저장된 Embedding 데이터를 Prompt 에 추가하여 AI 질의

import sys
sys.path.append('/Users/jinwook/Documents/langchain/quick_start/')
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
from chat_pdf_template import *
from langchain_openai import ChatOpenAI
from langchain.schema.runnable import RunnablePassthrough

from langchain_const import *

loader = PyPDFLoader("https://snuac.snu.ac.kr/2015_snuac/wp-content/uploads/2015/07/asiabrief_3-26.pdf")

# PDF 를 로드하고 일정 기준으로 스플릿한다.
pages = loader.load_and_split()

# 스플릿한 데이터를 추가적으로 스플릿한다.
text_splitter = RecursiveCharacterTextSplitter(chunk_size=50, chunk_overlap=0)
splits = text_splitter.split_documents(pages)

# 임베딩을 통한 벡터데이터 저장
vectorstore = Chroma.from_documents(documents=splits, embedding=OpenAIEmbeddings(openai_api_key=OPENAI_KEY)) # text-embedding-ada-002
retriever = vectorstore.as_retriever()

llmChatOpenAi = ChatOpenAI(model_name=GPT_MODEL, temperature=0, api_key=OPENAI_KEY)

# RunnablePassThrough 공부하기
ragChain = {"ragContext": retriever, "question": RunnablePassthrough()} | ragPromptCustom | llmChatOpenAi

print(ragChain.invoke('한국의 저출산 원인이 뭐야?'))

 

반응형

관련글 더보기