🚀 免費嘗試 Zilliz Cloud,完全托管的 Milvus,體驗速度提升 10 倍!立即嘗試

milvus-logo
LFAI
  • Home
  • Blog
  • 如何取得正確的向量嵌入

如何取得正確的向量嵌入

  • Engineering
December 08, 2023
Yujian Tang

本文最初發表於The New Stack,經授權後在此轉載。

全面介紹向量嵌入以及如何使用流行的開放原始碼模型產生向量嵌入。

Image by Денис Марчук from Pixabay 圖片:Денис Марчук 來自 Pixabay

向量嵌入在處理語意相似性時非常重要。不過,向量只是一連串的數字;向量嵌入則是代表輸入資料的一連串數字。使用向量內嵌,我們可以將非結構化的資料結構化,或將任何類型的資料轉換成一連串的數字來處理。這種方法讓我們可以對輸入資料執行數學運算,而不是依賴於定性比較。

向量內嵌對許多任務都很有影響力,特別是對於語意搜尋。然而,在使用之前,取得適當的向量內嵌是至關重要的。舉例來說,如果您使用圖像模型來向量化文字,或反之亦然,您很可能會得到很差的結果。

在這篇文章中,我們將學習向量嵌入的意義、如何使用不同的模型為您的應用程式產生適當的向量嵌入,以及如何透過向量資料庫 (例如MilvusZilliz Cloud) 來善用向量嵌入。

向量內嵌是如何產生的?

既然我們瞭解向量內嵌的重要性,讓我們來瞭解它們如何運作。向量嵌入是深度學習模型(也稱為嵌入模型或深度神經網路)中輸入資料的內部表示。那麼,我們如何擷取這些資訊呢?

我們透過移除最後一層,並從倒數第二層的輸出取得向量。神經網路的最後一層通常會輸出模型的預測,因此我們取倒數第二層的輸出。向量嵌入是饋送給神經網路預測層的資料。

向量嵌入的維度等同於模型中倒數第二層的大小,因此可與向量的大小或長度互換。常見的向量維度包括 384 (由 Sentence Transformers Mini-LM 產生)、768 (由 Sentence Transformers MPNet 產生)、1,536 (由 OpenAI 產生) 和 2,048 (由 ResNet-50 產生)。

向量嵌入是什麼意思?

曾經有人問我向量嵌入中每個維度的意義。簡短的答案是沒什麼。向量內嵌中的單一維度沒有任何意義,因為它太抽象,無法確定其意義。但是,當我們把所有的維度放在一起時,它們就提供了輸入資料的語意。

向量的維度是不同屬性的高層次抽象表示。所代表的屬性取決於訓練資料和模型本身。文字模型和圖像模型會產生不同的內嵌,因為它們是針對根本不同的資料類型所訓練的。即使是不同的文字模型也會產生不同的嵌入。有時它們的大小不同,有時它們代表的屬性也不同。例如,針對法律資料訓練的模型與針對健康照護資料訓練的模型會學到不同的東西。我在比較向量內嵌的文章中探討過這個主題。

產生正確的向量內嵌

如何獲得正確的向量嵌入?首先要確定您想要嵌入的資料類型。本節涵蓋嵌入五種不同類型的資料:影像、文字、音訊、視訊和多模態資料。我們在此介紹的所有模型都是開放原始碼,來自 Hugging Face 或 PyTorch。

圖像嵌入

2012 年,AlexNet 一炮而紅,圖像識別隨之興起。自此之後,電腦視覺領域見證了無數的進步。最新的顯著圖像識別模型是 ResNet-50,這是基於前 ResNet-34 架構的 50 層深度殘差網路。

殘差神經網路 (ResNet) 使用捷徑連接解決了深度卷積神經網路中的梯度消失問題。這些連接允許較早層的輸出直接進入較後層,而不經過所有中間層,從而避免了虛擬梯度問題。這種設計使得 ResNet 的複雜度低於 VGGNet (Visual Geometry Group),VGGNet 是之前表現最出色的卷繞神經網路。

我推薦兩個 ResNet-50 實作為範例: Hugging Face 上的 ResNet 50PyTorch 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 函式庫中的特徵萃取器和模型。我們會使用特徵萃取器來取得模型的輸入,並使用模型來取得輸出和萃取最後的隱藏狀態。

# 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()

文字嵌入

自從人工智能發明以來,工程師和研究人員就一直在實驗自然語言和人工智能。最早的一些實驗包括

  • ELIZA, 第一個 AI 治療師聊天機器人。
  • John Searle's Chinese Room,一個研究中英文互譯能力是否需要理解語言的思想實驗。
  • 英語與俄語之間基於規則的翻譯。

AI 對自然語言的操作已從其基於規則的嵌入顯著演進。從初級神經網路開始,我們透過 RNN 增加遞歸關係來追蹤時間步驟。從此,我們使用轉換器來解決序列轉換問題。

轉換器由編碼器、注意矩陣和解碼器組成,編碼器將輸入編碼為代表狀態的矩陣。解碼器對狀態和注意力矩陣進行解碼,以預測正確的下一個符號來完成輸出序列。GPT-3 是目前最流行的語言模型,包含嚴格的解碼器。它們對輸入進行編碼,並預測正確的下一個符號。

以下是兩個來自 Hugging Face 的sentence-transformers 函式庫的模型,除了 OpenAI 的 embeddings 之外,您還可以使用這些模型:

您可以以相同的方式存取這兩種模型的嵌入式資料。

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()

音訊嵌入

與文字或圖片的人工智慧相比,音訊的人工智慧受到的關注較少。音訊最常見的使用案例是呼叫中心、醫療技術和無障礙等行業的語音轉文字。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 的多模態感知器本筆記本教學將展示如何使用該模型來對視訊進行分類。

若要取得輸入的 embeddings,請使用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

使用向量資料庫儲存、索引和搜尋向量內嵌值

既然我們瞭解了向量內嵌是什麼,以及如何使用各種強大的內嵌模型來產生它們,接下來的問題就是如何儲存並運用它們。向量資料庫就是答案。

MilvusZilliz Cloud之類的向量資料庫,是專為透過向量嵌入,在大量非結構化資料集上進行儲存、索引和搜尋而建立的。它們也是各種 AI 堆疊最重要的基礎架構之一。

向量資料庫通常使用近似最近鄰 (ANN)演算法來計算查詢向量與資料庫中儲存的向量之間的空間距離。兩個向量的位置越接近,相關性就越高。然後,演算法會找出前 k 個最近的鄰居,並將它們提供給使用者。

向量資料庫在使用案例中很受歡迎,例如LLM 檢索擴增生成(RAG)、問答系統、推薦系統、語義搜尋,以及圖像、視訊和音訊相似性搜尋。

若要進一步瞭解向量嵌入、非結構化資料和向量資料庫,請考慮從向量資料庫 101系列開始。

摘要

向量是處理非結構化資料的強大工具。使用向量,我們可以根據語意相似性,以數學方式比較不同的非結構化資料。選擇正確的向量嵌入模型,對於為任何應用程式建立向量搜尋引擎來說都至關重要。

在這篇文章中,我們了解到向量嵌入是神經網路中輸入資料的內部表示。因此,它們在很大程度上取決於網路架構和用來訓練模型的資料。不同的資料類型(例如圖像、文字和音訊)需要特定的模型。幸運的是,有許多預先訓練好的開放原始碼模型可供使用。在這篇文章中,我們涵蓋了五種最常見資料類型的模型:影像、文字、多模態、音訊和視訊。此外,如果您想要善用向量嵌入,向量資料庫是最常用的工具。

Like the article? Spread the word

繼續閱讀