올바른 벡터 임베딩을 얻는 방법
이 글은 원래 The New Stack에 게시되었으며 허가를 받아 여기에 재게시되었습니다.
벡터 임베딩에 대한 포괄적인 소개와 인기 있는 오픈 소스 모델로 이를 생성하는 방법.
Pixabay의 Денис Марчук가 제공한 이미지
벡터 임베딩은 의미적 유사성을 다룰 때 매우 중요합니다. 하지만 벡터는 단순히 숫자의 나열일 뿐이며, 벡터 임베딩은 입력 데이터를 나타내는 숫자의 나열입니다. 벡터 임베딩을 사용하면 비정형 데이터를 구조화하거나, 어떤 유형의 데이터든 숫자의 나열로 변환하여 다룰 수 있습니다. 이 접근 방식을 통해 정성적 비교에 의존하는 대신 입력 데이터에 대해 수학적 연산을 수행할 수 있습니다.
벡터 임베딩은 많은 작업, 특히 의미적 검색에 큰 영향을 미칩니다. 그러나 사용하기 전에 적절한 벡터 임베딩을 얻는 것이 중요합니다. 예를 들어 이미지 모델을 사용해 텍스트를 벡터화하거나 그 반대로 하면, 아마도 좋지 않은 결과를 얻게 될 것입니다.
이 글에서는 벡터 임베딩이 무엇을 의미하는지, 다양한 모델을 사용해 애플리케이션에 맞는 올바른 벡터 임베딩을 생성하는 방법, 그리고 Milvus 및 Zilliz Cloud와 같은 벡터 데이터베이스로 벡터 임베딩을 최대한 활용하는 방법을 알아보겠습니다.
벡터 임베딩은 어떻게 생성되나요?
이제 벡터 임베딩의 중요성을 이해했으니, 그것이 어떻게 작동하는지 알아보겠습니다. 벡터 임베딩은 딥러닝 모델, 즉 임베딩 모델 또는 심층 신경망에서 입력 데이터의 내부 표현입니다. 그렇다면 이 정보를 어떻게 추출할까요?
마지막 레이어를 제거하고 끝에서 두 번째 레이어의 출력을 가져와 벡터를 얻습니다. 신경망의 마지막 레이어는 일반적으로 모델의 예측을 출력하므로, 우리는 끝에서 두 번째 레이어의 출력을 가져옵니다. 벡터 임베딩은 신경망의 예측 레이어에 공급되는 데이터입니다.
벡터 임베딩의 차원 수는 모델에서 끝에서 두 번째 레이어의 크기와 동일하며, 따라서 벡터의 크기 또는 길이와 상호 교환적으로 사용할 수 있습니다. 일반적인 벡터 차원 수에는 384(Sentence Transformers Mini-LM이 생성), 768(Sentence Transformers MPNet이 생성), 1,536(OpenAI가 생성), 2,048(ResNet-50이 생성)이 포함됩니다.
벡터 임베딩은 무엇을 의미하나요?
누군가 한 번 벡터 임베딩의 각 차원이 무엇을 의미하는지 물어본 적이 있습니다. 짧은 답은 아무것도 의미하지 않는다는 것입니다. 벡터 임베딩의 단일 차원은 너무 추상적이어서 그 의미를 결정할 수 없기 때문에 아무 의미도 없습니다. 하지만 모든 차원을 함께 고려하면 입력 데이터의 의미적 의미를 제공합니다.
벡터의 차원은 다양한 속성에 대한 고수준의 추상적 표현입니다. 표현되는 속성은 학습 데이터와 모델 자체에 따라 달라집니다. 텍스트 모델과 이미지 모델은 근본적으로 다른 데이터 유형을 위해 학습되기 때문에 서로 다른 임베딩을 생성합니다. 심지어 서로 다른 텍스트 모델도 서로 다른 임베딩을 생성합니다. 때로는 크기가 다르고, 때로는 표현하는 속성이 다릅니다. 예를 들어 법률 데이터로 학습된 모델은 의료 데이터로 학습된 모델과 다른 것을 학습합니다. 저는 이 주제를 벡터 임베딩 비교 글에서 살펴보았습니다.
올바른 벡터 임베딩 생성하기
적절한 벡터 임베딩은 어떻게 얻을까요? 모든 것은 임베딩하려는 데이터 유형을 식별하는 것에서 시작됩니다. 이 섹션에서는 다섯 가지 서로 다른 유형의 데이터, 즉 이미지, 텍스트, 오디오, 비디오, 멀티모달 데이터를 임베딩하는 방법을 다룹니다. 여기서 소개하는 모든 모델은 오픈 소스이며 Hugging Face 또는 PyTorch에서 제공됩니다.
이미지 임베딩
이미지 인식은 AlexNet이 등장한 2012년에 본격적으로 도약했습니다. 그 이후 컴퓨터 비전 분야는 수많은 발전을 목격했습니다. 최근 주목할 만한 이미지 인식 모델은 이전 ResNet-34 아키텍처를 기반으로 한 50층 깊이의 잔차 네트워크인 ResNet-50입니다.
잔차 신경망(ResNet)은 쇼트컷 연결을 사용하여 심층 합성곱 신경망의 기울기 소실 문제를 해결합니다. 이러한 연결은 이전 계층의 출력이 모든 중간 계층을 거치지 않고 바로 이후 계층으로 전달되도록 하여 기울기 소실 문제를 방지합니다. 이 설계는 ResNet을 이전에 최고 성능을 보였던 합성곱 신경망인 VGGNet(Visual Geometry Group)보다 덜 복잡하게 만듭니다.
예시로 두 가지 ResNet-50 구현을 추천합니다: Hugging Face의 ResNet 50 및 PyTorch Hub의 ResNet 50. 네트워크는 동일하지만 임베딩을 얻는 과정은 다릅니다.
아래 코드 샘플은 PyTorch를 사용해 벡터 임베딩을 얻는 방법을 보여줍니다. 먼저 PyTorch Hub에서 모델을 로드합니다. 다음으로 마지막 계층을 제거하고 모델이 추론용으로 실행되는 것처럼 동작하도록 지시하기 위해 .eval() 을 호출합니다. 그런 다음 embed 함수가 벡터 임베딩을 생성합니다.
# Load the embedding model with the last layer removed
model = torch.hub.load('pytorch/vision:v0.10.0', 'resnet50', pretrained=True) model = torch.nn.Sequential(*(list(model.children())[:-1]))
model.eval()
def embed(data):
with torch.no_grad():
output = model(torch.stack(data[0])).squeeze()
return output
HuggingFace는 약간 다른 설정을 사용합니다. 아래 코드는 Hugging Face에서 벡터 임베딩을 얻는 방법을 보여줍니다. 먼저 transformers 라이브러리에서 feature extractor와 모델이 필요합니다. feature extractor를 사용해 모델의 입력을 얻고, 모델을 사용해 출력을 얻은 뒤 마지막 hidden state를 추출합니다.
# Load model directly
from transformers import AutoFeatureExtractor, AutoModelForImageClassification
extractor = AutoFeatureExtractor.from_pretrained("microsoft/resnet-50")
model = AutoModelForImageClassification.from_pretrained("microsoft/resnet-50")
from PIL import Image
image = Image.open("<image path>")
# image = Resize(size=(256, 256))(image)
inputs = extractor(images=image, return_tensors="pt")
# print(inputs)
outputs = model(**inputs)
vector_embeddings = outputs[1][-1].squeeze()
텍스트 임베딩
엔지니어와 연구자들은 AI가 발명된 이후부터 자연어와 AI를 실험해 왔습니다. 초기 실험 중 일부는 다음과 같습니다:
- 최초의 AI 치료사 챗봇인 ELIZA.
- 중국어와 영어 간 번역 능력이 언어 이해를 필요로 하는지 검토하는 사고 실험인 John Searle의 Chinese Room.
- 영어와 러시아어 간의 규칙 기반 번역.
자연어에 대한 AI의 작동 방식은 규칙 기반 임베딩에서 크게 진화해 왔습니다. 기본적인 신경망에서 시작해, 시간의 단계들을 추적하기 위해 RNN을 통해 순환 관계를 추가했습니다. 이후 시퀀스 변환 문제를 해결하기 위해 transformers를 사용했습니다.
Transformers는 입력을 상태를 나타내는 행렬로 인코딩하는 encoder, attention matrix, 그리고 decoder로 구성됩니다. decoder는 상태와 attention matrix를 디코딩하여 출력 시퀀스를 완성할 올바른 다음 토큰을 예측합니다. 현재까지 가장 인기 있는 언어 모델인 GPT-3는 엄격한 decoders로 구성됩니다. 이들은 입력을 인코딩하고 올바른 다음 토큰(들)을 예측합니다.
다음은 OpenAI의 임베딩 외에도 사용할 수 있는 Hugging Face의 sentence-transformers 라이브러리 모델 두 가지입니다.
- MiniLM-L6-v2: 384차원 모델
- MPNet-Base-V2: 768차원 모델
두 모델의 임베딩은 동일한 방식으로 접근할 수 있습니다.
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("<model-name>")
vector_embeddings = model.encode(“<input>”)
멀티모달 임베딩
멀티모달 모델은 이미지 또는 텍스트 모델보다 덜 발전되어 있습니다. 이들은 주로 이미지를 텍스트와 연관 짓습니다.
가장 유용한 오픈 소스 예시는 이미지-텍스트 모델인 CLIP VIT입니다. 아래 코드에 표시된 것처럼 이미지 모델을 사용할 때와 같은 방식으로 CLIP VIT의 임베딩에 접근할 수 있습니다.
# Load model directly
from transformers import AutoProcessor, AutoModelForZeroShotImageClassification
processor = AutoProcessor.from_pretrained("openai/clip-vit-large-patch14")
model = AutoModelForZeroShotImageClassification.from_pretrained("openai/clip-vit-large-patch14")
from PIL import Image
image = Image.open("<image path>")
# image = Resize(size=(256, 256))(image)
inputs = extractor(images=image, return_tensors="pt")
# print(inputs)
outputs = model(**inputs)
vector_embeddings = outputs[1][-1].squeeze()
오디오 임베딩
오디오용 AI는 텍스트나 이미지용 AI보다 덜 주목받아 왔습니다. 오디오의 가장 일반적인 사용 사례는 콜센터, 의료 기술, 접근성 같은 산업에서의 음성-텍스트 변환입니다. 음성-텍스트 변환을 위한 인기 있는 오픈 소스 모델 중 하나는 OpenAI의 Whisper입니다. 아래 코드는 음성-텍스트 모델에서 벡터 임베딩을 얻는 방법을 보여줍니다.
import torch
from transformers import AutoFeatureExtractor, WhisperModel
from datasets import load_dataset
model = WhisperModel.from_pretrained("openai/whisper-base")
feature_extractor = AutoFeatureExtractor.from_pretrained("openai/whisper-base")
ds = load_dataset("hf-internal-testing/librispeech_asr_dummy", "clean", split="validation")
inputs = feature_extractor(ds[0]["audio"]["array"], return_tensors="pt")
input_features = inputs.input_features
decoder_input_ids = torch.tensor([[1, 1]]) * model.config.decoder_start_token_id
vector_embedding = model(input_features, decoder_input_ids=decoder_input_ids).last_hidden_state
비디오 임베딩
비디오 임베딩은 오디오나 이미지 임베딩보다 더 복잡합니다. 비디오는 동기화된 오디오와 이미지를 포함하므로, 비디오를 다룰 때는 멀티모달 접근 방식이 필요합니다. 인기 있는 비디오 모델 중 하나는 DeepMind의 multimodal perceiver입니다. 이 notebook tutorial은 해당 모델을 사용하여 비디오를 분류하는 방법을 보여줍니다.
입력의 임베딩을 얻으려면 출력을 삭제하는 대신 노트북에 표시된 코드에서 outputs[1][-1].squeeze()를 사용하세요. 저는 autoencode 함수에서 이 코드 스니펫을 강조합니다.
def autoencode_video(images, audio):
# only create entire video once as inputs
inputs = {'image': torch.from_numpy(np.moveaxis(images, -1, 2)).float().to(device),
'audio': torch.from_numpy(audio).to(device),
'label': torch.zeros((images.shape[0], 700)).to(device)}
nchunks = 128
reconstruction = {}
for chunk_idx in tqdm(range(nchunks)):
image_chunk_size = np.prod(images.shape[1:-1]) // nchunks
audio_chunk_size = audio.shape[1] // SAMPLES_PER_PATCH // nchunks
subsampling = {
'image': torch.arange(
image_chunk_size * chunk_idx, image_chunk_size * (chunk_idx + 1)),
'audio': torch.arange(
audio_chunk_size * chunk_idx, audio_chunk_size * (chunk_idx + 1)),
'label': None,
}
# forward pass
with torch.no_grad():
outputs = model(inputs=inputs, subsampled_output_points=subsampling)
output = {k:v.cpu() for k,v in outputs.logits.items()}
reconstruction['label'] = output['label']
if 'image' not in reconstruction:
reconstruction['image'] = output['image']
reconstruction['audio'] = output['audio']
else:
reconstruction['image'] = torch.cat(
[reconstruction['image'], output['image']], dim=1)
reconstruction['audio'] = torch.cat(
[reconstruction['audio'], output['audio']], dim=1)
vector_embeddings = outputs[1][-1].squeeze()
# finally, reshape image and audio modalities back to original shape
reconstruction['image'] = torch.reshape(reconstruction['image'], images.shape)
reconstruction['audio'] = torch.reshape(reconstruction['audio'], audio.shape)
return reconstruction
return None
벡터 데이터베이스로 벡터 임베딩 저장, 인덱싱 및 검색하기
이제 벡터 임베딩이 무엇인지, 그리고 다양한 강력한 임베딩 모델을 사용해 이를 생성하는 방법을 이해했으니, 다음 질문은 이를 어떻게 저장하고 활용할 것인가입니다. 그 해답은 벡터 데이터베이스입니다.
Milvus 및 Zilliz Cloud 같은 벡터 데이터베이스는 벡터 임베딩을 통해 방대한 비정형 데이터 데이터셋을 저장, 인덱싱, 검색하도록 특별히 구축되었습니다. 또한 다양한 AI 스택에서 가장 중요한 인프라 중 하나입니다.
벡터 데이터베이스는 일반적으로 근사 최근접 이웃(ANN) 알고리즘을 사용하여 쿼리 벡터와 데이터베이스에 저장된 벡터 간의 공간적 거리를 계산합니다. 두 벡터가 더 가깝게 위치할수록 더 관련성이 높습니다. 그런 다음 알고리즘은 상위 k개의 최근접 이웃을 찾아 사용자에게 제공합니다.
벡터 데이터베이스는 LLM 검색 증강 생성 (RAG), 질의응답 시스템, 추천 시스템, 시맨틱 검색, 이미지, 비디오 및 오디오 유사도 검색과 같은 사용 사례에서 널리 사용됩니다.
벡터 임베딩, 비정형 데이터, 벡터 데이터베이스에 대해 더 알아보려면 Vector Database 101 시리즈부터 시작해 보세요.
요약
벡터는 비정형 데이터를 다루는 강력한 도구입니다. 벡터를 사용하면 의미적 유사성을 기준으로 서로 다른 비정형 데이터 조각을 수학적으로 비교할 수 있습니다. 적절한 벡터 임베딩 모델을 선택하는 것은 모든 애플리케이션을 위한 벡터 검색 엔진을 구축하는 데 매우 중요합니다.
이 글에서는 벡터 임베딩이 신경망에서 입력 데이터의 내부 표현이라는 것을 배웠습니다. 그 결과, 벡터 임베딩은 네트워크 아키텍처와 모델을 학습시키는 데 사용된 데이터에 크게 의존합니다. 다양한 데이터 유형(예: 이미지, 텍스트, 오디오)에는 특정 모델이 필요합니다. 다행히도 사용할 수 있는 사전 학습된 오픈 소스 모델이 많이 있습니다. 이 글에서는 가장 일반적인 다섯 가지 데이터 유형인 이미지, 텍스트, 멀티모달, 오디오, 비디오를 위한 모델을 다루었습니다. 또한 벡터 임베딩을 최대한 활용하고 싶다면 벡터 데이터베이스가 가장 널리 사용되는 도구입니다.
계속 읽기

Announcing VDBBench 1.0: Open-Source VectorDB Benchmarking with Your Real-World Production Workloads
Discover VDBBench 1.0, an open-source tool for benchmarking vector databases with real-world production data, streaming ingestion, and concurrent workloads.

Balancing Precision and Performance: How Zilliz Cloud's New Parameters Help You Optimize Vector Search
Optimize vector search with Zilliz Cloud’s level and recall features to tune accuracy, balance performance, and power AI applications.

What is the K-Nearest Neighbors (KNN) Algorithm in Machine Learning?
KNN is a supervised machine learning technique and algorithm for classification and regression. This post is the ultimate guide to KNN.



