CLIP에서 JinaCLIP까지: 검색 및 멀티모달 RAG를 위한 범용 텍스트-이미지 표현 학습
최근 멀티모달 임베딩 모델의 급증은 다양한 산업 전반에서 주목을 받으며, 기계가 텍스트와 이미지를 해석하는 방식을 변화시키고 있습니다. 그러나 상당한 진전에도 불구하고, 이러한 모델들은 핵심 과제에 직면해 있으며, 그중 하나가 모달리티 갭입니다. 이 갭은 동일한 객체를 설명하는 경우에도 이미지와 텍스트 임베딩이 잠재 공간에서 공간적으로 멀리 떨어져 있는 방식으로 나타납니다.
최근 Zilliz가 주최한 Unstructured Data Meetup에서 Jina AI의 엔지니어링 매니저인 Bo Wang,은 모달리티 갭의 복잡성과 OpenAI의 CLIP 모델에서 JinaCLIP으로의 전환에 대해 설명했습니다.
이 블로그에서는 그의 주요 내용을 요약하고 멀티모달 유사도 검색 시스템도 구현해 보겠습니다. 이 시스템은 JinaCLIP을 사용해 멀티모달 임베딩을 생성하고, Milvus 벡터 데이터베이스를 사용해 특정 쿼리가 주어졌을 때 유사한 임베딩을 저장하고 검색합니다. 더 자세한 내용은 YouTube에서 Bo의 전체 발표를 시청하시길 권장합니다.
좋은 임베딩 모델이란 무엇인가요?
임베딩 모델의 주요 기능은 텍스트와 이미지 같은 것들을 데이터 내의 의미적 관계를 포착하는 수치 표현인 벡터로 매핑하는 것입니다. 예를 들어, 두 벡터 사이의 거리는 그것들이 나타내는 두 항목의 유사성을 반영해야 하며, 이는 두 이미지, 두 텍스트 또는 각각 하나씩인 경우에도 마찬가지입니다.
임베딩 모델은 의미 검색, 이미지 검색 등 현대 AI 작업의 핵심에 있습니다. 그렇다면 무엇이 좋은 임베딩 모델을 만들까요?
도메인 전반의 다재다능성
좋은 임베딩 모델은 파인튜닝 없이도 광범위한 도메인 전반에서 잘 작동해야 합니다. 이러한 적응성은 입력이 텍스트, 이미지 또는 다른 데이터 유형이든 임베딩이 보편적으로 유용하도록 보장합니다. 예를 들어, 이미지가 벡터 공간에 임베딩되고 관련 텍스트가 동일한 공간에 임베딩된다면, 두 임베딩은 서로 가까워야 하며, 이는 의미적 유사성을 나타냅니다. 이러한 폭넓은 적용 가능성은 유사도 검색, 이미지 검색, 크로스 도메인 애플리케이션과 같은 AI 작업에 필수적입니다.
정확한 의미적 유사성
좋은 임베딩 모델의 핵심 특징은 의미적으로 관련된 항목에 대해 높은 유사도 점수를 가진 임베딩을 생성함으로써 좌우를 연결하는 능력입니다. 이는 단순한 텍스트 데이터를 넘어 모든 멀티모달 입력에 적용됩니다. 텍스트와 텍스트, 이미지와 이미지, 또는 텍스트와 이미지를 비교하든, 모델은 벡터 공간에서 임베딩의 근접성을 통해 올바른 관계를 반영해야 합니다.
그러나 텍스트와 이미지 모달리티를 연결했던 이전 모델들은 이 목표를 달성하는 데 더 어려움을 겪었습니다. 이들은 연결을 설정하기 위해 이미지에 태그를 지정하거나 주변 텍스트를 사용하는 것과 같은 수작업 프로세스에 의존했습니다. 이러한 방법은 특히 분포 밖 시나리오에서 일반화 성능이 좋지 않은 결과를 낳았습니다.
멀티모달 작업의 과제
CLIP과 같은 모델이 도입되기 전에는 모달리티(텍스트와 이미지)를 연결하는 작업이 매우 수동적이고 가설 중심적인 과제였습니다. Flickr 태그이든 사용자가 추가한 텍스트 설명이든, 그 과정은 결코 매끄럽지 않았습니다. 종종 분류기 레이블을 사용하는 지도 학습 접근법은 불안정하기 쉬웠고, 도메인 외 성능도 만족스럽지 않았습니다. 이는 이미지와 텍스트를 연결할 수는 있었지만, 특히 입력이 복잡할 때 결과가 항상 일관되지는 않았다는 뜻입니다.
이 문제를 해결하기 위해, 대조적 언어-이미지 사전학습 모델인 CLIP이 이미지-텍스트 쌍으로 학습하여 멀티모달 모델의 성능을 향상시키도록 개발되었습니다. 두 모달리티를 공유 임베딩 공간에 정렬하는 CLIP의 능력은 혁신적이었습니다. 그러나 이 모델에도 한계가 있습니다.
CLIP 모델: 제약이 있는 돌파구
CLIP은 텍스트용 인코더와 이미지용 인코더, 두 개의 별도 인코더를 학습함으로써 새로운 기준을 세웠습니다. 핵심 아이디어는 텍스트 벡터와 이미지 벡터가 공존할 수 있는 공유 임베딩 공간을 학습하여, 의미적으로 유사한 텍스트와 이미지가 더 가깝게 위치하도록 하는 것이었습니다. 결과는 인상적이었습니다. CLIP은 단순한 코사인 유사도 함수를 사용해 멀티모달 작업을 가능하게 했습니다.
그림: CLIP 모델의 작동 방식
그러나 CLIP에는 단점이 있습니다. 한 가지 중요한 문제는 텍스트 전용 작업을 효과적으로 처리하지 못한다는 점입니다. CLIP은 주로 짧은 캡션(대개 77자 미만)에 최적화되었기 때문에, 더 긴 텍스트는 도전 과제가 됩니다. 게다가 CLIP은 학습 과정에서 하드 네거티브 예제가 부족했습니다. 하드 네거티브는 가깝지만 잘못된 예제로, 특히 텍스트 검색과 같은 작업에서 모델을 정교화하는 데 매우 중요합니다. 이것들이 없으면, 세부적인 텍스트 이해가 필요한 작업에서 CLIP의 성능은 정체되었습니다.
JinaCLIP으로의 전환: Clip의 단점 해결
JinaCLIP은 기존 CLIP 아키텍처를 기반으로 그 한계를 해결합니다. 텍스트 입력을 확장하고 텍스트 인코딩을 위해 적응된 BERT v2 아키텍처를 사용합니다. 이미지 처리를 위해 JinaCLIP은 EVA-02 모델을 통합합니다. JinaCLIP의 학습 과정은 이미지 캡션의 짧은 텍스트 입력이 제기하는 과제를 극복하고 하드 네거티브를 도입하는 데 초점을 맞춥니다. 이 과정은 아래와 같이 세 단계로 이루어집니다.
그림: JinaCLIP의 학습 과정
단계는 정렬 학습, 긴 텍스트 통합, 파인튜닝입니다.
짧은 텍스트와 캡션을 통한 정렬 학습: 이 단계에서 모델은 캡션이 있는 이미지 데이터와 유사한 의미를 가진 텍스트 쌍을 모두 사용하여 학습됩니다. 목표는 텍스트-이미지 및 텍스트-텍스트 유사도를 공동으로 최적화하여 이미지와 텍스트 임베딩을 정렬하는 것입니다. 이 공동 학습 과정은 모델이 텍스트를 이미지와 연관시키는 법을 배우는 동시에 텍스트 전용 능력도 유지하도록 보장합니다. 텍스트 쌍만으로 학습하는 경우와 비교하면 텍스트 전용 성능이 약간 저하되지만, 이 단계는 균형 잡힌 접근 방식을 보존합니다.
긴 텍스트 설명의 통합: 두 번째 단계에서는 모델 학습을 위해 합성 데이터가 도입됩니다. 이 데이터는 이미지의 내용을 더 자세히 설명하는 AI 모델이 생성한 더 긴 텍스트와 이미지를 정렬합니다. 동시에 텍스트 전용 쌍도 학습에 계속 사용됩니다. 모델은 이미지와의 정렬을 유지하면서 더 광범위한 텍스트 설명을 처리하는 법을 배우며, 짧고 긴 텍스트-이미지 관계를 모두 이해하는 능력을 향상시킵니다.
텍스트 트리플릿과 하드 네거티브를 활용한 파인튜닝: 마지막 단계는 하드 네거티브를 포함한 텍스트 트리플릿을 사용하는 데 초점을 맞춥니다. 이는 세 개의 텍스트 중 두 개는 의미적으로 유사하지만, 하나는 의도적으로 다른 텍스트 쌍을 포함합니다. 이를 통해 모델은 특히 텍스트 전용 시나리오에서 더 세밀한 의미적 구분을 할 수 있습니다. 동시에 모델은 합성 이미지-긴 텍스트 쌍으로 계속 학습합니다. 이 단계는 초기 단계에서 학습한 이미지-텍스트 정렬이 견고하게 유지되도록 하면서도 모델의 텍스트 전용 성능을 크게 향상시킵니다.
이 접근 방식은 멀티모달 작업에서 강력한 성능을 유지하면서 텍스트 전용 시나리오에서의 역량을 향상시킵니다. 이 새로운 접근 방식이 기존 Clip과 어떻게 비교되는지 살펴보겠습니다.
성능 지표는 기존 CLIP 모델과 비교한 검색 성능의 변화를 보여줍니다. 아래 이미지에 표시된 것처럼 텍스트-텍스트 검색은 165%, 이미지-이미지는 12%, 이미지-텍스트는 6%, 텍스트-이미지 검색은 2% 변화했습니다.
Figure: jina-clip, openai-clip-vit-b-16, jina-embeddings-v2-base-en 간의 모델 성능 비교
새로운 학습 과정은 작업 전반의 일반화를 향상시키고 모달리티 격차를 줄이는 데 도움이 됩니다. 멀티모달 AI 모델의 주요 장애물인 모달리티 격차와 이 문제가 발생하는 이유에 대해 논의해 보겠습니다.
모달리티 격차: 왜 발생하는가
모달리티 격차는 텍스트와 이미지처럼 의미적으로 유사하지만 벡터 공간에서는 멀리 떨어져 있는 서로 다른 입력 유형의 임베딩 간 공간적 분리를 의미합니다. 이 격차는 임베딩이 관련 입력 간의 실제 관계를 완전히 반영하지 못하게 하므로 멀티모달 검색 시스템의 효과를 약화시킵니다. 아래 이미지에서 볼 수 있듯이, 표현은 절단된 원뿔처럼 보이며, 한쪽 끝에는 이미지 임베딩이, 다른 쪽 끝에는 텍스트 임베딩이 있어 모달리티 격차를 명확히 보여줍니다.
Figure: 완전히 무작위화된 가중치와 사전 학습이 없는 Jina CLIP의 이미지 및 텍스트 임베딩 초기 위치를 2차원으로 투영한 모습
현대 모델에서도 이 격차가 발생하는 데에는 몇 가지 주요 이유가 있습니다:
초기화 중 원뿔 효과
멀티모달 모델, 특히 텍스트와 이미지 입력을 처리하는 모델은 각 모달리티에 대해 별도의 인코더를 사용하는 경우가 많습니다. 이러한 인코더는 일반적으로 무작위 또는 사전 학습된 가중치로 초기화되며, 이로 인해 위 이미지에서 볼 수 있듯이 텍스트 임베딩은 벡터 공간의 한 영역에, 이미지 임베딩은 다른 영역에 군집하게 됩니다. 원뿔 효과라고 불리는 이러한 초기 분리는 서로 다른 모달리티의 임베딩(예: 이미지와 관련 텍스트)이 제대로 정렬되기 어렵게 만듭니다. 예를 들어, 푹신한 고양이에 대한 텍스트 임베딩과 고양이 이미지 임베딩은 의미적으로 관련되어 있음에도 불구하고 이러한 초기화 편향 때문에 처음에는 멀리 떨어져 있을 수 있습니다.
온도 스케일링
학습 중 AI 모델은 대조 손실 함수에서 온도 스케일링이라는 기법을 사용하여 임베딩이 얼마나 가깝게 정렬되는지 조정합니다. 이는 임베딩 간 거리를 미세 조정하는 데 도움이 되지만, 온도 스케일링은 의도치 않게 모달리티 간 초기 분리를 보존하여 모달리티 격차를 강화할 수도 있습니다. 예를 들어, 온도 스케일링이 신중하게 조정되지 않으면 장난기 많은 강아지에 대한 임베딩과 개 이미지의 임베딩은 같은 개념을 설명함에도 불구하고 벡터 공간에서 너무 멀리 떨어진 상태로 남을 수 있습니다.
배치 내 가짜 네거티브
대규모 데이터셋으로 학습할 때, 서로 매칭되지 않는 데이터 포인트 쌍(예: 강아지 이미지와 텍스트 “빨간 사과”가 짝지어진 경우)은 부정 예시로 처리됩니다. 하지만 이러한 거짓 부정(false negative)은 여전히 의미적으로 어느 정도 겹칠 수 있습니다. 예를 들어 두 항목이 모두 동물이라는 넓은 범주와 관련되어 있다면(예: 강아지 사진과 텍스트 “장난기 많은 늑대”), 모델은 이 임베딩들을 필요 이상으로 멀리 밀어낼 수 있으며, 이를 완전히 관련 없는 것으로 잘못 처리함으로써 모달리티 격차를 더욱 악화시킬 수 있습니다.
모달리티 격차가 왜 발생하는지 이해하는 것은 첫 번째 단계일 뿐입니다. 이 격차를 줄이기 위해 서로 다른 모달리티의 임베딩을 더 가깝게 만드는 다양한 학습 전략이 개발되어, 멀티모달 작업에서 더 정확한 검색을 보장합니다.
모달리티 격차 해결: 학습 기법과 그 이상
모달리티 격차는 쉬운 해결책이 없는 구조적 문제이지만, 그 영향을 완화하기 위한 전략들이 있습니다. 핵심은 학습 중 서로 다른 모달리티의 임베딩 간 분리를 줄여, 서로 함께 속하는 이미지와 텍스트가 벡터 공간에서 더 가깝게 매핑되도록 하는 것입니다.
더 높은 온도 스케일링
실제로 학습 중 온도를 높이면 모델의 학습 과정에 더 많은 무작위성을 추가하여 서로 다른 모달리티의 임베딩이 더 가까워지도록 유도할 수 있습니다. 예를 들어, 온도를 높이면 고양이 이미지와 텍스트 “복슬복슬한 고양이”의 임베딩을 더 밀접하게 정렬하는 데 도움이 될 수 있습니다. 하지만 이는 수렴 속도가 느려지고 더 많은 계산 리소스를 필요로 한다는 비용을 수반합니다. 높은 온도 스케일링으로 학습된 모델은 텍스트와 이미지 임베딩의 정렬을 개선하는 경향이 있지만, 그 대가는 종종 더 긴 학습 시간과 더 큰 계산 요구량입니다.
하드 네거티브 샘플링
의미적으로 가까운 비매칭 쌍인 하드 네거티브 예시를 도입하는 것도 모달리티 격차를 줄이는 또 다른 기법입니다. 이러한 하드 네거티브 쌍은 모델이 관련 개념들 사이의 더 미세한 차이를 학습하도록 밀어붙여 검색 정확도를 향상시킵니다. 예를 들어, 고양이 이미지를 텍스트 “작은 호랑이”와 짝짓는 것은 불일치처럼 보일 수 있지만, 모델은 이 두 입력이 의미적으로 겹친다는 점(둘 다 고양잇과 동물임)을 학습하며, 임베딩 공간에서 어느 정도 정렬되어야 한다는 것을 배웁니다. 이 과정은 모델이 관련 개념 간의 유사점과 차이점을 모두 인식하도록 가르쳐, 거의 일치하는 항목들을 구별하는 능력을 정교하게 만듭니다.
Milvus와 JinaCLIP을 활용한 멀티모달 검색: 실용적인 예시
이제 모달리티 격차의 기술적 원인을 살펴보았으니, 오픈 소스 벡터 데이터베이스인 Milvus,와 JinaCLIP을 사용해 멀티모달 검색 시스템을 구축하는 실용적인 예시를 살펴보겠습니다.
Milvus는 고차원 벡터를 관리, 검색, 쿼리하므로 멀티모달 검색 작업과 Retrieval Augmented Generation(RAG) 작업에 이상적인 솔루션입니다. 텍스트, 이미지 또는 기타 데이터 유형을 다루든, Milvus는 임베딩을 효율적으로 저장하고 고급 유사도 검색 기법을 사용해 관련 결과를 검색할 수 있게 해줍니다.
이 섹션에서는 Milvus를 사용해 텍스트와 이미지 임베딩을 처리하는 멀티모달 검색 시스템을 만드는 과정을 살펴보겠습니다. 이 시스템은 사용자가 텍스트 또는 이미지를 입력하고, 혼합 데이터셋에서 의미적으로 가장 관련성이 높은 결과를 검색할 수 있도록 합니다.
1단계: 환경 설정
먼저, 환경에서 시스템에 필요한 라이브러리를 설치해야 합니다:
!pip install pymilvus transformers torch timm
그런 다음, 필요한 라이브러리를 가져오고 인코더 클래스를 설정해야 합니다.
# Import necessary libraries
from transformers import AutoModel
from pymilvus import MilvusClient
import torch
# Define Encoder class to handle text and image embedding generation
class Encoder:
def __init__(self, model_name: str):
# Initialize the model (AutoModel from transformers instead of SentenceTransformer)
self.model = AutoModel.from_pretrained(model_name, trust_remote_code=True)
def encode_text(self, text: list[str]) -> list[float]:
# Generate embeddings for text only
with torch.no_grad():
text_emb = self.model.encode_text(text)
return text_emb
def encode_image(self, image_urls: list[str]) -> list[list[float]]:
# Generate embeddings for images only
with torch.no_grad():
image_emb = self.model.encode_image(image_urls)
return image_emb
# Initialize the encoder with the model jinaai/jina-clip-v1
model_name = "jinaai/jina-clip-v1"
encoder = Encoder(model_name)
위 코드에서는 먼저 필요한 라이브러리를 가져옵니다. 인코딩 모델을 위한 transformers의 AutoModel, Milvus와 상호작용하기 위한 MilvusClient, 그리고 텐서 연산을 위한 torch입니다.
그런 다음 transformers의 AutoModel을 래핑하는 Encoder 클래스를 정의합니다. encode_text 및 encode_image 메서드는 각각 모델을 사용하여 텍스트와 이미지에 대한 임베딩을 생성합니다. torch.no_grad() 컨텍스트 매니저는 추론에는 필요하지 않고 메모리를 절약해 주는 그래디언트 계산을 비활성화하는 데 사용됩니다.
마지막으로 텍스트와 이미지를 모두 공유 임베딩 공간으로 인코딩할 수 있는 jinaai/jina-clip-v1 모델로 인코더를 초기화합니다.
2단계: 데이터 준비
다음으로, Milvus에 임베딩하고 삽입할 샘플 데이터를 준비하겠습니다.
# Load data: images and text for embeddings
sentences = ['A blue cat', 'A red cat', 'A red cat generated by AI', 'A dog biting on a stick']
image_urls = [
'https://i.pinimg.com/600x315/21/48/7e/21487e8e0970dd366dafaed6ab25d8d8.jpg',
'https://i.pinimg.com/736x/c9/f2/3e/c9f23e212529f13f19bad5602d84b78b.jpg',
'https://images.fineartamerica.com/images/artworkimages/mediumlarge/1/red-cat-art-3771-bb-james-ahn.jpg',
'https://images.squarespace-cdn.com/content/v1/54822a56e4b0b30bd821480c/29708160-9b39-42d0-a5ed-4f8b9c85a267/labrador+retriever+dans+pet+care.jpeg?format=1500w'
]
# Generate embeddings for text and images
text_embeddings = encoder.encode_text(sentences)
image_embeddings = encoder.encode_image(image_urls)
# Ensure consistent dimensions
dim = len(image_embeddings[0])
여기에서는 샘플 문장과 이미지 URL의 목록을 정의합니다. URL에는 빨간 고양이, 파란 고양이, 그리고 강아지 이미지가 포함되어 있습니다. 그런 다음 인코더를 사용하여 텍스트와 이미지 모두에 대한 임베딩을 생성합니다. dim 변수는 Milvus 컬렉션을 만들 때 필요한 임베딩의 차원을 저장합니다.
3단계: Milvus 설정
이제 Milvus 클라이언트를 설정하고 멀티모달 데이터를 위한 컬렉션을 만들겠습니다.
# Insert embeddings into Milvus
collection_name = "multimodal_rag_demo"
milvus_client = MilvusClient(uri="./milvus_demo.db")
# Check if collection exists and drop it if so
if milvus_client.has_collection(collection_name):
print(f"Collection {collection_name} already exists. Deleting it...")
milvus_client.drop_collection(collection_name)
# Create Milvus collection
milvus_client.create_collection(
collection_name=collection_name,
auto_id=True,
dimension=dim,
enable_dynamic_field=True,
)
Milvus 클라이언트를 초기화하고 로컬 데이터베이스 파일에 연결합니다. 원하는 이름의 컬렉션이 이미 존재하는지 확인하고, 존재한다면 깨끗한 상태에서 시작할 수 있도록 삭제합니다.
그런 다음 지정한 이름으로 새 컬렉션을 만듭니다. auto_id=True 매개변수는 Milvus가 항목에 대한 ID를 자동으로 생성하도록 지시합니다. dimension은 임베딩과 일치하도록 설정하고 동적 필드를 활성화하여 항목에 추가 메타데이터를 더할 수 있도록 합니다.
4단계: 인덱스 생성
데이터를 삽입하기 전에 검색 성능을 최적화하기 위해 인덱스를 생성하겠습니다:
index_params = MilvusClient.prepare_index_params()
index_params.add_index(
field_name="vector", # The field to be indexed (your embedding field)
metric_type="COSINE", # Can be L2, COSINE, etc.
index_type="FLAT", # FLAT ensures exact search, ideal for small datasets
)
# Create the index for the collection
milvus_client.create_index(collection_name, index_params)
print(f"Index created successfully for collection: {collection_name}")
위 코드는 거리 메트릭으로 코사인 유사도 를 사용하여 FLAT 인덱스를 생성합니다.
Step 5: Milvus에 데이터 삽입하기
컬렉션과 인덱스 설정이 완료되었으므로 이제 데이터를 Milvus에 삽입할 수 있습니다.
data_to_insert = []
# Insert text embeddings
for idx, txt_emb in enumerate(text_embeddings):
data_to_insert.append({"text": sentences[idx], "vector": txt_emb})
# Insert image embeddings
for idx, img_emb in enumerate(image_embeddings):
data_to_insert.append({"image_url": image_urls[idx], "vector": img_emb})
# Insert data into Milvus
insert_result = milvus_client.insert(
collection_name=collection_name,
data=data_to_insert,
)
print(f"Insert result: {insert_result}")
milvus_client.load_collection(collection_name)
위 코드에서는 각각 텍스트 문장 또는 이미지 URL과 해당 임베딩 벡터를 포함하는 딕셔너리 목록을 생성합니다. 그런 다음 Milvus 클라이언트의 insert 메서드를 사용하여 이 데이터를 컬렉션에 추가합니다. 삽입 후에는 검색을 준비하기 위해 컬렉션을 메모리에 로드합니다.
Step 6: 멀티모달 검색 수행하기
마지막으로 이미지와 텍스트 쿼리를 모두 사용하여 멀티모달 검색을 수행합니다.
# Multimodal search with a combination of image and text query
query_image_url = 'https://imgcdn.stablediffusionweb.com/2024/4/5/5e70d71c-a7f6-44e9-972d-8c5a27d45c3d.jpg'
query_text = "Give me similar red cats"
# Generate query embedding (image + text)
query_embedding_image = encoder.encode_image([query_image_url])[0]
query_embedding_text = encoder.encode_text([query_text])[0]
# Perform search in Milvus using image embedding
search_results_image = milvus_client.search(
collection_name=collection_name,
data=[query_embedding_image],
output_fields=["image_url", "text"], # Ensure both fields are included in the results
limit=5, # Number of results to return
search_params={"metric_type": "COSINE", "params": {"nprobe": 10}}
)
# Perform search in Milvus using text embedding
search_results_text = milvus_client.search(
collection_name=collection_name,
data=[query_embedding_text],
output_fields=["image_url", "text"], # Ensure both fields are included in the results
limit=5, # Number of results to return
search_params={"metric_type": "COSINE", "params": {"nprobe": 10}}
)
# Retrieve and print results from image query
print("Image Query Results:")
for result in search_results_image:
for hit in result:
image_url = hit['entity'].get('image_url')
text = hit['entity'].get('text')
if image_url:
print(f"Retrieved Image URL (from image query): {image_url}")
if text:
print(f"Retrieved Text (from image query): {text}")
# Retrieve and print results from text query
print("Text Query Results:")
for result in search_results_text:
for hit in result:
image_url = hit['entity'].get('image_url')
text = hit['entity'].get('text')
if image_url:
print(f"Retrieved Image URL (from text query): {image_url}")
if text:
print(f"Retrieved Text (from text query): {text}")
위 코드에서는 멀티모달 검색을 수행하는 과정을 보여줍니다. 먼저 쿼리 이미지 URL과 쿼리 텍스트를 모두 정의합니다. 쿼리 이미지는 다음과 같습니다:
그림 2: 빨간색과 흰색 고양이의 쿼리 입력 이미지
그런 다음 인코더를 사용해 이러한 쿼리를 인코딩하여 각각의 임베딩을 생성합니다. 이어서 Milvus에서 두 개의 별도 검색을 수행합니다. 하나는 이미지 임베딩을 사용하고, 다른 하나는 텍스트 임베딩을 사용합니다. 각 검색마다 출력에서 image_url 및 text 필드를 모두 요청하여 두 유형의 데이터를 모두 검색할 수 있도록 합니다. 각 검색의 결과는 5개로 제한하고, 거리 메트릭으로 코사인 유사도를 사용합니다. 검색 파라미터의 nprobe 파라미터를 통해 검색할 클러스터 수를 세밀하게 조정할 수 있어, 검색 속도와 정확도 사이의 균형을 제공합니다. 마지막으로 결과를 표시하여 각 쿼리 유형에 대해 어떤 이미지 또는 텍스트가 검색되었는지 보여주며, 이를 통해 시스템이 텍스트 기반 및 이미지 기반 쿼리를 모두 처리하고 연관 지을 수 있음을 입증합니다.
전체 코드는 여기에서 확인할 수 있습니다.
다음은 샘플 결과입니다:
보시다시피 이미지를 사용해 벡터 검색을 수행하면 이미지 URL과 이미지와 관련된 텍스트를 모두 얻을 수 있으며, 그 반대도 마찬가지입니다. 이것이 멀티모달 검색의 힘입니다. 다음은 두 경우 모두에서 유사한 이미지로 검색된 이미지 중 하나입니다.
그림 3: Milvus에서 유사도 검색을 수행한 후 출력된 빨간 고양이 이미지
보시다시피 이 이미지는 우리가 시스템에 쿼리로 제공한 빨간 고양이 이미지와 유사합니다.
이 시스템에 reranker를 추가하여 검색 결과를 관련성 기준으로 정렬하고, 가장 관련성 높은 결과가 상단에 오도록 할 수 있습니다. 다만 분명히 보이듯이 Milvus는 최상의 매치를 먼저 검색하는 데도 훌륭한 성능을 보입니다. 또한 이 시스템을 발전시켜 멀티모달 RAG 시스템을 만들 수도 있습니다.
결론
Bo Wang은 멀티모달 모델에서 모달리티 간극을 연결하는 복잡한 과정과 CLIP에서 JinaCLIP으로의 전환을 설명했습니다. 그는 텍스트-이미지 정렬의 핵심 과제를 세분화하고 JinaCLIP이 이러한 문제를 어떻게 해결하는지 보여주었습니다.
이 글에서는 JinaCLIP을 사용해 임베딩을 생성하고 Milvus를 사용해 효율적인 검색을 달성하는 멀티모달 유사도 검색 시스템을 구축함으로써 그의 통찰을 확장했습니다. 이 지식을 바탕으로 이제 텍스트 및 이미지 기반 쿼리 전반에서 원활한 성능을 보장하는 멀티모달 검색 애플리케이션을 구현할 수 있으며, reranking과 같은 고급 검색 기법을 통합하여 한층 더 발전시킬 수도 있습니다.
추가 자료
계속 읽기

Zilliz Cloud Update: Smarter Autoscaling for Cost Savings, Stronger Compliance with Audit Logs, and More
What's new in Zilliz Cloud? Smarter autoscaling with scale-down, audit logs GA, enhanced SSO, and Milvus 2.6 in Private Preview.

Why Not All VectorDBs Are Agent-Ready
Explore why choosing the right vector database is critical for scaling AI agents, and why traditional solutions fall short in production.

What Exactly Are AI Agents? Why OpenAI and LangChain Are Fighting Over Their Definition?
AI agents are software programs powered by AI that can perceive their environment, make decisions, and take actions to achieve a goal—often autonomously.


