RAG & LANCHAIN (3)- Langchain 개념 & 문법 정리 ch.08 임베딩 - 캐시와 임베딩 왜 속도에 영향을 주는가?

이영락·2024년 8월 30일
0

인공지능 공부

목록 보기
17/33

임베딩 캐시와 로컬 파일 시스템을 활용한 성능 최적화

개요

이 예제는 머신러닝 임베딩을 캐싱하고 이를 로컬 파일 시스템에 저장하여 성능을 최적화하는 방법을 보여줍니다. 특히, 동일한 문서나 데이터에 대해 반복적으로 임베딩을 생성해야 할 때, 캐시를 활용하면 성능이 크게 향상됩니다.

캐시란 무엇인가?

캐시는 자주 사용되거나 접근할 가능성이 높은 데이터를 임시로 저장해두는 고속의 메모리입니다. 프로세서나 메모리와 비교하여 상대적으로 빠른 접근이 가능하며, 필요할 때 해당 데이터를 빠르게 불러올 수 있습니다.

임베딩에서 캐시의 역할

임베딩 과정에서 같은 데이터가 여러 번 처리될 가능성이 있습니다. 예를 들어, NLP 모델에서 문장이나 단어가 자주 사용된다면, 동일한 단어에 대해 반복적으로 임베딩을 계산해야 할 수 있습니다. 이때, 캐시는 이전에 계산된 임베딩 결과를 저장해두어, 동일한 데이터에 대해 다시 임베딩을 계산할 필요 없이 캐시에 저장된 값을 바로 가져올 수 있게 합니다.

캐시가 있는 경우 더 빨라지는 이유

캐시가 있으면 임베딩 과정에서 이미 계산된 결과를 재사용할 수 있기 때문에, 불필요한 재계산을 줄일 수 있습니다. 그 결과, 전체 연산 속도가 빨라집니다.

원리

  1. 초기 접근: 데이터가 처음 임베딩될 때, 해당 데이터의 임베딩 결과가 계산되어 캐시에 저장됩니다.
  2. 반복 접근: 동일한 데이터가 다시 임베딩 요청을 받으면, 캐시에서 이전에 계산된 임베딩 값을 불러옵니다. 이때는 추가적인 계산 없이 즉시 결과를 반환할 수 있습니다.
  3. 캐시 미스(Cache Miss): 만약 캐시에 데이터가 없다면(즉, 이전에 한 번도 처리되지 않은 데이터라면), 그때 임베딩 계산을 수행하고 그 결과를 캐시에 저장합니다.

구성 요소 설명

  1. OpenAI 임베딩: OpenAI에서 제공하는 임베딩 모델을 사용하여 문서의 텍스트를 고차원 벡터로 변환합니다.

  2. LocalFileStore: 로컬 파일 시스템을 캐시 저장소로 사용합니다. 여기서 임베딩 결과가 파일 형태로 저장됩니다. 이를 통해 동일한 임베딩 계산을 반복하지 않고도 저장된 결과를 재사용할 수 있습니다.

  3. CacheBackedEmbeddings: 임베딩을 생성할 때 캐시를 지원하는 래퍼 클래스입니다. 이 클래스는 임베딩 결과를 캐시에서 먼저 찾고, 캐시에 없을 경우에만 임베딩 계산을 수행한 후 결과를 캐시에 저장합니다.

코드 설명

  1. 임베딩 설정 및 로컬 파일 저장소 설정:

    from langchain.storage import LocalFileStore
    from langchain_openai import OpenAIEmbeddings
    from langchain.embeddings import CacheBackedEmbeddings
    
    # OpenAI 임베딩을 사용하여 기본 임베딩 설정
    embedding = OpenAIEmbeddings()
    
    # 로컬 파일 저장소 설정
    store = LocalFileStore("./cache/")
    
    # 캐시를 지원하는 임베딩 생성
    cached_embedder = CacheBackedEmbeddings.from_bytes_store(
        underlying_embeddings=embedding,
        document_embedding_cache=store,
        namespace=embedding.model,  # 네임스페이스로 모델 이름 사용
    )
    • OpenAIEmbeddings: OpenAI에서 제공하는 임베딩 모델을 사용합니다.
    • LocalFileStore: 로컬 파일 시스템에 캐시를 저장합니다.
    • CacheBackedEmbeddings: 이 객체는 임베딩 결과를 캐시에서 먼저 확인한 후, 캐시에 없으면 계산하여 저장합니다.
  1. 캐시된 키를 확인:

    # store에서 키들을 순차적으로 가져옵니다.
    list(store.yield_keys())
    • 캐시에 저장된 임베딩 결과의 키(문서 ID)를 확인할 수 있습니다. 이는 캐시에 어떤 임베딩이 저장되어 있는지를 보여줍니다.
  2. 문서 로드 및 임베딩 생성:

    from langchain.document_loaders import TextLoader
    from langchain_text_splitters import CharacterTextSplitter
    from langchain.vectorstores import FAISS
    
    # 문서 로드
    raw_documents = TextLoader("./data/appendix-keywords.txt").load()
    
    # 문자 단위로 텍스트 분할 설정
    text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
    
    # 문서 분할
    documents = text_splitter.split_documents(raw_documents)
    
    # 코드 실행 시간을 측정합니다.
    %time db = FAISS.from_documents(documents, cached_embedder)
    • TextLoader: 파일에서 텍스트를 로드합니다.
    • CharacterTextSplitter: 문서를 지정된 크기만큼 분할합니다.
    • FAISS: 분할된 문서에 대해 임베딩을 생성하고 벡터 데이터베이스로 관리합니다.
  3. 캐시 활용에 따른 성능 비교:

    # 캐싱된 임베딩을 사용하여 FAISS 데이터베이스 생성
    %time db2 = FAISS.from_documents(documents, cached_embedder)
    • 처음 문서 임베딩을 생성할 때는 캐시가 비어 있기 때문에 임베딩 계산이 필요합니다.
    • 동일한 문서에 대해 두 번째로 임베딩을 생성할 때는 캐시가 활용되므로 훨씬 빠르게 처리됩니다.

결론: 왜 더 빨라지는가?

  1. 초기 임베딩 생성: 처음 문서를 임베딩할 때는 모든 문서에 대해 임베딩을 계산하고, 그 결과를 캐시에 저장합니다.

  2. 반복적인 임베딩 생성: 두 번째로 동일한 문서를 임베딩할 때는 캐시에서 이미 계산된 결과를 불러오기 때문에, 임베딩 계산에 걸리는 시간이 거의 없습니다. 이로 인해 전체 처리 속도가 대폭 빨라집니다.

  3. 성능 최적화: 캐시를 사용하면 동일한 데이터에 대해 불필요한 계산을 피할 수 있으므로, 특히 대규모 데이터 세트나 자주 사용되는 데이터를 처리할 때 성능이 크게 향상됩니다.

따라서, 캐시를 활용하는 임베딩 시스템은 반복적인 작업에서 특히 효과적이며, 전체 시스템의 처리 속도를 비약적으로 개선할 수 있습니다.

캐시를 사용하면 동일한 데이터에 대한 중복 계산을 피할 수 있어 연산 시간이 크게 줄어듭니다. 이는 전체 시스템의 성능을 향상시키고, 특히 대규모 데이터나 실시간 처리가 중요한 경우에 매우 유용합니다.

예시

  • 예를 들어, "apple"이라는 단어를 임베딩할 때, 처음엔 "apple"의 임베딩 벡터를 계산하고 캐시에 저장합니다.
  • 이후 다시 "apple"이라는 단어를 임베딩해야 한다면, 이미 계산된 결과가 캐시에 있으므로 즉시 캐시에서 해당 벡터를 가져올 수 있습니다.
profile
AI Engineer / 의료인공지능

0개의 댓글

관련 채용 정보