임베딩(Embeddings)은 무엇이고 왜 중요한가
(simonwillison.net)임베딩이란?
- "임베딩"은 콘텐츠를 "부동 소수점 숫자의 배열"로 변환하는 것
- 이 배열의 핵심은 "콘텐츠 내용의 길이"에 관계없이 "배열의 크기"가 항상 같다는 것
- 배열의 크기는 사용하는 임베딩 모델에 의해서 결정됨 300, 1000, 1536 등
- 이 숫자 배열을 생각하는 가장 좋은 방법은 이걸 "매우 이상한 다차원 공간의 좌표"로 상상하는 것
- 왜 콘텐츠를 다차원 공간에 배치할까? 콘텐츠의 위치, 특히 근처에 있는 다른 콘텐츠를 기반으로 해당 콘텐츠에 대한 흥미로운 정보를 배울 수 있기 때문
- 공간에서의 위치는 임베딩 모델의 "이상한, 대부분은 이해할 수 없는 세계에 대한 이해"에 따른 콘텐츠의 "의미론적 의미(Semantic Meaning)"를 나타냄
- 임베드된 콘텐츠의 색상, 모양, 개념 또는 기타 모든 종류의 특성을 캡처할 수 있음
- 이러한 개별 숫자가 무엇을 의미하는지 완전히 이해하는 사람은 없지만, 그 위치가 콘텐츠에 대한 유용한 정보를 찾는 데 사용될 수 있다는 것은 알고 있음
임베딩을 사용하여 관련 콘텐츠 찾기
- 내가 임베딩으로 해결한 첫번째 문제는 내 TIL 블로그의 "Related Content" 기능을 만드는 것
- OpenAI의 text-embedding-ada-002 모델을 이용했음. API를 통해 사용 가능
- 지금 내 사이트에는 472개의 글이 있고, 각 글에 대해서 1536 차원 임베딩 벡터(부동 소수점 숫자의 배열)을 계산해서, 해당 벡터를 내 사이트의 SQLite DB에 저장했음
- 이제 특정 글에 대한 관련 글을 찾으려면 해당 글의 임베딩 벡터와 DB의 다른 글간의 코사인 유사성(Cosine Similarity)를 계산한다음 거리 별로 가장 가까운 일치 항목 10개를 리턴하면 됨
- 코사인 유사성을 위해서 사용한 파이썬 코드는 다음과 같음
def cosine_similarity(a, b):
dot_product = sum(x * y for x, y in zip(a, b))
magnitude_a = sum(x * x for x in a) ** 0.5
magnitude_b = sum(x * x for x in b) ** 0.5
return dot_product / (magnitude_a * magnitude_b)
- OpenAI의 임베딩 API는 매우 저렴하고 쉬움
- 내 TIL 웹사이트에 약 40만개의 토큰을 임베드 했는데, 1천개의 토큰당 $0.0001로 전체에 $0.04 밖에 들지 않음
- 그냥 API 키와 함께 POST 하면서 텍스트를 던지면, 부동 소수점 숫자로된 JSON Array를 리턴함
- 하지만 이건 독점모델이고, 몇달전 OpenAI는 임베딩 모델중 일부를 종료하기도 했음
- 즉, 해당 모델에서 많은 수의 임베딩을 저장했는데, 새로운 모델을 위해서는 임베딩을 다시 계산해야함
- OpenAI는 새로운 모델로 재임베딩 하는데 드는 비용은 보상하겠다고 얘기했지만, 독점 모델은 주의해야함
- 이는 강력한 공개 라이센스 모델로 회피 가능
이런 것들이 Word2Vec 모델에서 어떻게 동작하는지 알아보기
- 구글 리서치가 10년전에 Word2Vec이라는 초기 임베딩 모델을 설명하는 영향력 있는 논문을 발표함
- 2013년에 발표한 "Efficient Estimation of Word Representations in Vector Space" 으로 임베딩에 대한 관심을 불러이르킴
- Word2Vec은 단일 단어를 가져와 이를 300개의 숫자 목록으로 바꾸는 모델. 해당 숫자 목록은 관련 단어의 의미에 대한 정보를 포착
- 단어를 검색하면 해당 단어의 Word2Vec 표현에 대한 코사인 거리를 기준으로 유사한 단어를 찾을 수 있음
- "france"를 검색하면 "french : 0.70007~" "belgium: 0.69331~" "paris: 0.63349~" "germany: 0.62707~" 같은 값을 얻을 수 있음
- 이는 프랑스의(french) 것과 유럽의 지리가 혼합된 것
- 여기서 할 수 있는 정말 흥미로운 일은 이러한 벡터에 대해 산술 연산을 수행하는 것
- "germany"에 대한 벡터에 "paris"를 추가하고 "france"를 빼면 결과 벡터는 "베를린"에 가장 가까움
- 이 모델은 어떤 것들에서 산술을 사용하여 세계에 대한 추가적인 사실을 탐색할 수 있다는 국적과 지리에 대한 아이디어를 포착했음
- Word2Vec은 16억 단어의 콘텐츠에 대해 훈련되었으며, 오늘날 우리가 사용하는 임베딩 모델은 훨씬 더 큰 데이터 세트에서 훈련되어 기본 관계에 대한 훨씬 더 풍부한 이해를 포착함
내 도구들을 이용하여 임베딩 계산 및 검색하기
- 나는 LLM 이라고 하는 CLI 이자 Python 라이브러리를 만들고 있음
- LLM들과 상호작용하기 위한 CLI로 사용할 수 있으며, OpenAPI 연동도 가능
- 몇달전이 도구에 플러그인을 통해서 임베딩 모델을 실행하는 기능도 추가 (SentenceTransformers 라이브러리 이용 가능)
- 임베딩 컬렉션을 선택하고 유사한 것을 찾는 Vibes-based 검색 가능
- Python 코드베이스에서 Symbol을 찾는 Symbex 도구도 만드는 중. 이를 통해서 코드의 함수에 대한 임베딩을 계산하여 코드 검색엔진을 구축 가능
- (상세 구현부는 생략)
CLIP을 사용하여 텍스트와 이미지를 함께 임베딩
- 현재 가장 선호하는 임베딩 모델은 CLIP
- OpenAI가 2021년 1월에 출시한 모델로 "텍스트와 이미지" 모두 임베딩 가능하며 동일한 벡터 공간에 포함
- "dog"를 삽입하면 512차원 공간의 위치를 얻게됨(CLIP 구성에 따라 다름)
- 개 사진을 임베드 하면 같은 공간에 위치를 얻게 되는데 문자열 "dog"의 위치와 거리상으로 가까워짐
- 즉, 텍스트를 이용하여 관련 이미지를 검색하거나, 이미지를 사용하여 관련 텍스트를 검색 가능
- 해변 사진을 넣으면 "beach: 26.946%" "city: 19.839%" "sunshine: 24.146%" 같은 유사도 점수를 얻을수 있음
CLIP으로 수도꼭지 찾기
- Drew Breunig 는 llm-clip 플러그인으로 수도꼭지 검색엔진을 구축
- 2만장의 수도꼭지 사진을 가져와 CLIP을 실행
- 다른 수도꼭지와 비슷한 수도꼭지를 찾은 다음, 그중 유사하면서도 저렴한 옵션을 찾을수 있게됨
RAG로 질문에 답하기
- ChatGPT를 사용해본 사람들의 마지막 질문은 모두 같음
"어떻게 하면 내 노트나 우리 회사의 문서에 대해서 답변하게 만들수 있을까?" - 사람들은 막대한 비용을 들여 그 콘텐츠 기반으로 커스텀 모델을 훈련하는 것이라고 가정하지만,
- 실제로는 필요하지 않음. LLM 과 RAG(Retrieval Augmented Generation) 을 통해 가능해짐
- 핵심 아이디어는 "사용자가 질문을 한다"는 것
- 당신의 개인적인 문서에 대해서 해당 질문에 관련된 것을 찾은 다음
- 해당 콘텐츠의 발췌문을 원래 질문과 함께 LLM에 넣으면 됨
- 그러면 LLM은 당신이 추가로 제공한 콘텐츠 기반으로 질문을 할수 있게 됨
- 이 값싼 트릭은 놀라울 정도로 효과적
- 하지만 이 작업이 가능한 기본 버전이 동작하게 만드는 것은 쉽지 않음
- 사용자가 물어볼 수 있는 무한한 질문 세트를 고려할 때 가능한 잘 작동하도록 해야함
- RAG의 주요 문제는 LLM에게 보낼 프롬프트에 포함할 콘텐츠의 가장 좋은 발췌 내용을 파악하는 것
- 임베딩으로 구동되는 'Vibes-based' 시맨틱 검색은 사용자의 질문에 답하는 데 도움이 될 수 있는 관련성 높은 콘텐츠를 수집하는 데 필요한 기능
- 내 "블로그의 내용"에 대한 버전을 구축해서 공개함
- 결과적으로 RAG가 한줄짜리 Bash Script로 가능해짐
이 글 보고 주말에 시도해 보았어요. 한국어 모델을 시도했다가 환경 구성이 쉽지 않아서, ada v2 사용했고 총 0.03 달러 사용했네요. chatgpt 안써본 신규 사용자면, 무료 크레딧 5달러로 충분히 해볼 수 있겠습니다 ㅎ
코사인 유사성까지 계산해서 비교해 보았는데, 납득이 가는 결과였어요. 글 공유 감사합니다.