GN⁺: 코사인 유사도(Cosine Similarity)를 함부로 사용하지 말 것
(p.migdal.pl)- 데이터 과학자들은 모든 것을 벡터로 변환함. 이는 AI의 언어임
- 그러나 코사인 유사도를 맹목적으로 적용하면 잘못된 방향으로 이끌 수 있음
- 이 글에서는 유사도를 더 의도적으로 사용하여 더 나은 결과를 얻는 방법을 설명함.
임베딩(Embeddings)
- 임베딩은 벡터화된 데이터 표현으로, 개체 간 관계를 나타내거나 유사 항목을 찾는 데 매우 유용
- 예를 들어, "brother"와 "sister"는 원시 ID로는 관계가 없지만 벡터화하면 의미적 관계를 표현 가능
- 벡터는 머신러닝 모델의 입력 구조로 사용되거나 자체적으로 유사성 탐색에 활용
- 대형 언어 모델(LLM) 기반의 문장 임베딩은 현재 가장 인기 있는 임베딩 활용 사례 중 하나
- 모델의 미세 조정 없이도 텍스트의 핵심을 캡처할 수 있을 정도로 강력
- 관련 연구: Text Embeddings Reveal (Almost) As Much As Text, 2023
- 이러한 강력한 기능은 데이터 보안과 의도적 사용에 대한 책임을 요구
예제: 코사인 유사도로 문장 비교
- 세 문장 비교
- A: "Python can make you rich."
- B: "Python can make you itch."
- C: "Mastering Python can fill your pockets."
- 문자 기반 비교
- 원시 문자열을 비교하면 A와 B는 2문자 차이, A와 C는 21문자 차이
- 그러나 의미적으로는 A와 C가 더 유사 (돈과 관련된 내용)
- 벡터 기반 비교
-
OpenAI text-embedding-3-large를 사용해 다음과 같은 임베딩 벡터 생성:
- A:
[-0.003738, -0.033263, -0.017596, 0.029024, -0.015251, ...]
- B:
[-0.066795, -0.052274, -0.015973, 0.077706, 0.044226, ...]
- C:
[-0.011167, 0.017812, -0.018655, 0.006625, 0.018506, ...]
- A:
- 벡터 차원 수: 3072 (길지만 품질 저하 없이 축소 가능)
-
OpenAI text-embedding-3-large를 사용해 다음과 같은 임베딩 벡터 생성:
- 코사인 유사도 계산
- A와 C: 0.750 (의미적으로 유사)
- A와 B: 0.576 (문자적으로 유사)
- 결과: 의미는 철자보다 중요한 유사성 요소
코사인 유사도란?
- 코사인 유사도(cosine similarity)는 두 벡터 간 각도의 코사인을 계산하여 유사성을 측정
- 벡터가 고차원 공간에 존재하기 때문에 직관적 기하학적 이해는 종종 실패
- 수학적으로는 정규화된 벡터의 점곱(dot product)
- 주요 특성:
- 동일한 벡터는 1
- 무작위 벡터는 0에 가까움 (고차원에서 평균화 효과)
- 결과 값은 -1에서 1 사이에 존재
- 이 단순함은 오해의 소지가 있음
- 값이 0~1 사이에 있다고 해서 확률이나 의미 있는 척도로 오해하면 안 됨
- 예: 0.6이라는 값은 강한 유사성을 의미하지 않을 수 있음
- 음수 값은 드물게 의미적 반대를 나타냄
- 대부분은 무의미하거나 노이즈에 가까운 결과
- 값이 0~1 사이에 있다고 해서 확률이나 의미 있는 척도로 오해하면 안 됨
- Glove(
glove.6B.300d
)를 사용해 "dog"와 유사한 단어 탐색을 해보면:- 가까운 단어는 예상 가능
- 가장 먼 단어는 의미 없는 결과를 종종 생성
- 코사인 유사도는 "덕트 테이프"처럼 간단하고 빠르게 다양한 벡터 비교를 가능하게 함
- 이미지, 텍스트, 오디오, 코드 등 비교 가능
- 그러나 임시방편일 뿐, 더 깊은 문제를 감출 수 있음
- 예: 배관을 덕트 테이프로 고치듯, 신뢰하기 어렵고 영구적이지 않음
- 코사인 유사도가 효과적으로 보일 때도 있지만, 실패 시 원인을 파악하기 어려움
- 종종 즉흥적 해결책을 찾게 되고, 이는 새로운 문제를 야기할 수 있음
코사인 유사도와 상관 계수의 관계
- Pearson 상관 계수는 세 가지 단계로 계산:
- 평균을 빼서 데이터를 중심화
- 벡터를 단위 벡터로 정규화
- 두 벡터의 점곱(dot product)을 계산
- 벡터가 중심화되고 정규화되었을 경우:
- Pearson 상관 계수 = 코사인 유사도 = 점곱
- 실용적인 사용 방식
- 각 쌍 비교 시마다 벡터를 중심화하거나 정규화하지 않음
- 대신, 미리 처리한 후 점곱만 계산
- 코사인 유사도를 사용할 수 있다면 Pearson 상관 계수도 동일하게 사용 가능
- 두 척도는 실질적으로 동일한 맥락에서 활용 가능
- 각 쌍 비교 시마다 벡터를 중심화하거나 정규화하지 않음
코사인 유사도를 유사성 측도로 사용할 때의 문제
- 코사인 유사도를 머신러닝 모델의 훈련 목표로 사용하는 것은 수학적으로 유효
- 문제는 코사인 유사도의 적합성을 넘어서는 영역에서 발생:
- 모델 훈련에 사용된 손실 함수가 코사인 유사도가 아닐 경우
- 훈련 목표가 실제 애플리케이션의 요구와 다를 경우
- 일반적으로 모델은 비정규화된 벡터로 학습:
- 예: 점곱(dot product)을 기반으로 한 확률 예측 및 로지스틱 손실 함수 사용
- 일부 모델은 유클리드 거리를 최소화하여 같은 클래스 항목을 가깝게 학습
- 정규화는 수학적 속성(결과를 -1과 1 사이로 제한)을 제공하지만, 이는 "임시방편"
- 도움이 될 때도 있고 그렇지 않을 때도 있음 (참고 논문)
- 코사인 유사도 또는 그 직접적인 함수로 훈련된 모델만이 안전한 사용 가능
- 모델이 코사인 유사도로 명시적으로 훈련되었더라도 유사성의 정의가 불분명:
- 문학 비평가: 테마 공유
- 사서: 장르 분류
- 독자: 감정적 반응
- 조판자: 페이지 수와 형식
- 코사인 유사도는 다양한 정의를 단일 숫자로 단순화하여 오해의 소지가 있음
- 예시: "espresso"와 "cappuccino"
- word2vec은 이 두 단어를 거의 동일하게 간주 (미국 기준)
- 그러나 이탈리아에서는 동일하게 간주되지 않음
코사인 유사도가 실패하는 경우
- 간단한 예제: 열쇠를 찾는 질문
- 질문: "What did I do with my keys?"
- 비교 대상 문장들:
- "I left them in my pocket"
- "They are on the table"
- "What did I put my wallet?"
- "What I did to my life?"
- 문제점
- 코사인 유사도를 사용한 결과:
- 가장 가까운 문장은 적절한 답변 대신 또 다른 질문 ("What I did to my life?")
- 의미적 관련성이 아닌 단순한 문장 구조 유사성에 의존
- Python과 관련된 문장은 유사도가 거의 0에 가까워 무관함을 제대로 반영
- 코사인 유사도를 사용한 결과:
- 현실 세계의 한계
- 실제 응용에서는 수천 개의 문서를 다루게 됨
- 컨텍스트 윈도우를 초과하는 대규모 데이터셋에서 더 큰 노이즈에 민감
- 데이터셋 크기가 커질수록 유사성 점수는 고차원 룰렛 게임처럼 작동
- 실제 응용에서는 수천 개의 문서를 다루게 됨
코사인 유사도 대신 사용할 대안은 뭐가 있을까?
가장 강력한 접근법
-
LLM 쿼리 활용:
- 두 항목 비교를 위해 강력한 언어 모델을 사용
- 예: "Is {sentence_a} a plausible answer to {sentence_b}?"
- LLM을 활용하면 의미 있는 비교 가능:
- 간단한 질문과 답변의 구별
- 결과를 JSON과 같은 구조화된 형식으로 제공 가능
- 그러나 데이터셋이 크다면 비효율적이고 비용이 높음
임베딩 최적화
-
태스크별 임베딩 생성:
- 기존 모델의 가중치를 조정하는 미세 조정(Fine-tuning)
- 모델의 지식을 활용해 새롭고 집중된 임베딩 생성하는 전이 학습(Transfer Learning)
- 대칭적 유사성:
- "A와 B는 유사한가?"라는 질문을 벡터 공간에서 표현
- 필요 없는 차원을 줄이고 관련 특성만 유지
- 비대칭적 유사성:
- 예: "문서 B는 질문 A에 대한 올바른 답인가?"를 확률로 표현
- 쿼리와 키 각각의 특화된 공간으로 변환
프롬프트 엔지니어링
-
문맥 설정을 위한 프롬프트 추가:
- 예: "Nationality of {person}" 으로 국적과 관련된 맥락 강조
- 단순한 프롬프트보다는 구체적 문장 사용:
- "This is a country that has produced many influential historical figures, including {person}"
- 결과 품질이 크게 개선되나, 완벽하지는 않음
텍스트 재작성 및 문맥 추출
-
임베딩 전 텍스트 전처리:
- "다음 텍스트를 표준 영어로 200단어 이내로 요약하라"와 같은 간단한 프롬프트로 표면적 유사성 제거
- 불필요한 형식적 요소(오타, 서식 등)를 무시하고 콘텐츠에 집중
-
구조화된 문맥 생성:
- 고객 대화를 요약하여 명확한 요구 사항과 문제점을 추출:
- "대화를 요약하여 최대 10개의 Markdown 포인트로 작성하라"
- 페이지 역시 동일한 형식으로 변환해 보다 정밀한 매칭 가능
- 고객 대화를 요약하여 명확한 요구 사항과 문제점을 추출:
결론
- 다양한 대안적 방법은 코사인 유사도의 단점을 보완하며, 더 신뢰할 수 있는 결과를 제공
- 프로젝트 상황에 따라 적합한 접근법을 선택해 적용
요약
-
코사인 유사도의 한계:
- 코사인 유사도는 -1에서 1 사이의 값을 제공하지만, 이를 확률로 간주하면 안 됨
- 대부분의 모델은 코사인 유사도를 목표로 학습되지 않으며, 결과는 보장되지 않는 상관 관계에 불과함
- 모델이 코사인 유사도를 학습했더라도, 해당 유사성 정의가 우리의 필요와 일치하는지 이해해야 함
-
벡터 유사성의 효과적 사용 방법:
- 데이터에 특화된 임베딩을 훈련
- 관련 측면에 초점을 맞춘 프롬프트 설계
- 임베딩 전에 텍스트를 정리하고 표준화
Hacker News 의견
-
코사인 유사성을 사용하는 RAG 애플리케이션에서는 "semantic re-ranker"나 "L2 re-ranking model"을 사용하여 결과를 재정렬하는 것이 좋음
- pgvector-python의 예시에서는 cross-encoder 모델을 사용하여 재정렬을 수행함
- 언어 모델을 사용하여 재정렬할 수도 있지만, 재정렬에 특화된 모델보다는 성능이 떨어질 수 있음
- Azure RAG 접근법에서는 Bing이 검색 결과를 재정렬하는 데 사용하는 AI Search semantic ranker를 사용함
-
단어 벡터는 두 단어가 같은 문맥에 나타나지 않더라도 강하게 연관될 수 있는 문제를 해결함
- "Python"과 "Ruby"는 같은 문맥에 나타나지 않을 수 있지만, "scripting"은 둘 다의 문맥에서 발견될 수 있음
- 그러나 차원의 저주 때문에 잘 작동하지 않는 경우가 많음
- 단어 임베딩을 벡터 대신 정점으로 표현할 수 있을지에 대한 아이디어 제시
-
미국에서는 word2vec이 espresso와 cappuccino를 거의 동일하다고 판단할 수 있지만, 이탈리아에서는 그렇지 않음
- LLM 쿼리를 직접 사용하여 두 항목을 비교하는 것이 가장 좋은 접근법임
- LLM은 "지갑을 어디에 두었지?"와 "열쇠를 어디에 두었지?"를 매우 유사하다고 판단할 수 있음
-
코사인 유사성은 대부분의 딥러닝 기반 시맨틱 검색에서 사용됨
- SentenceTransformers와 같은 모델은 코사인 유사성을 사용하도록 훈련됨
- 이미지의 벡터 표현을 위해 CLIP과 같은 모델도 코사인 유사성을 사용함
-
LLM 쿼리를 직접 사용하여 두 항목을 비교하는 것이 가장 강력한 접근법임
- Cross encoder는 성능이 뛰어나고 빠른 솔루션임
-
HyDE는 질문에 대한 가상의 답변을 생성하고 유사성을 비교하는 방법임
- 청크의 형식을 표준화하고 동일한 형식으로 가상의 답변을 생성하는 것이 더 나은 방법임
-
코사인 유사성과 top-k RAG는 구식처럼 느껴짐
- 코사인 유사성은 데이터의 우연한 속성일 뿐임
- 새로운 임베딩 모델은 코사인 유사성을 유사성 측정으로 사용하도록 훈련됨
-
RAG 접근법을 시도한 후 실망감을 느꼈으며, 모델이 RAG를 훈련 중에 수행할 수 있도록 구조화해야 한다고 생각함
- 모델이 임베딩, 형식, 검색 프로세스를 정의하도록 하여 훈련 데이터 모델링을 개선할 수 있음
-
3D 그래픽과 물리학에서는 중요성과 정확성이 명확하지만, 머신러닝에서는 벡터 공간이 너무 많은 것을 나타내어 점곱 사용이 모호하게 느껴짐