理解 OpenAI 的 CLIP 模型

IcyFeather233發表於2024-07-10

來源:https://medium.com/@paluchasz/understanding-openais-clip-model-6b52bade3fa3

CLIP 是由 OpenAI 在 2021 年釋出的,自那時起已成為許多多模態 AI 系統中的基礎構件之一。本文深入探討了 CLIP 是什麼、它是如何工作的、如何使用以及其實現方式。

引言

CLIP,即 Contrastive Language-Image Pre-training,對比語言-影像預訓練,是一種從自然語言監督中學習的高效方法,於 2021 年在論文 Learning Transferable Visual Models From Natural Language Supervision 中被引入。

簡而言之,CLIP 是一個聯合的影像和文字 嵌入 模型,透過 4 億個影像和文字對以自監督的方式進行訓練。這意味著它將文字和影像對映到同一個嵌入空間中。例如,一張狗的圖片和句子“一張狗的圖片”將具有非常相似的嵌入,並在向量空間中彼此接近。這一點非常重要,因為你可以用這樣的模型構建許多有趣的應用,例如用描述搜尋影像資料庫或反之。

作者發現,CLIP 可以用於各種未經過訓練的任務。例如,它在多個基準測試上取得了顯著的 零樣本 效能,如 ImageNet,這是一個影像分類資料集。零樣本學習 指的是模型未明確訓練於 ImageNet 資料集中的任何 128 萬個訓練樣本。儘管如此,CLIP 的準確度與原始的 ResNet-50 相當,後者是基於該資料進行訓練的!

但如何使用 CLIP 進行影像分類呢?以 ImageNet 為例,你可以將其 1000 個可能的類別/物件分別用 CLIP 嵌入,使用提示“一張 {物件} 的照片”(例如“一張狗的照片”或“一張貓的照片”)。這將給你 1000 個不同的嵌入,對應所有可能的類別。接下來,你取你想要分類的影像,比如一張狗的照片,並用 CLIP 嵌入它。最後,你計算影像嵌入與所有文字嵌入之間的 點積。由於 CLIP 經過訓練,使得影像和文字在同一個嵌入空間中,並且點積計算嵌入之間的相似度,因此與“一張狗的照片”的點積很可能是最高的。因此,你可以預測該影像是狗。注意,如果你想將 CLIP 轉變為一個真正的分類器,你還可以透過 softmax 函式 傳遞點積,以獲得每個類別的預測機率。

上述過程可以在下圖的步驟 2 和 3 中看到。

圖片 2

來源:OpenAI 的 部落格,展示如何使用 CLIP 進行零樣本影像分類。

現在讓我們更詳細地瞭解 CLIP 的工作原理。

模型細節

架構

CLIP 模型有兩個主要元件,一個文字編碼器(嵌入文字)和一個影像編碼器(嵌入影像)。對於文字編碼器,使用了 Transformer。這種架構自 2017 年以來徹底改變了 NLP 領域,因此它的使用並不令人驚訝。有關更直觀的解釋,請參見以下 部落格

對於影像編碼器,作者嘗試了兩種不同的模型,一個 ResNet-50 和一個 Vision Transformer (ViT)ResNet-50 是使用卷積神經網路 (CNNs) 的原始最先進架構,用於影像分類。ViT 是原始 Transformer 的更近期適應,用於影像,其中每個影像可以分割成一系列 patch,並傳遞到模型中,類似於一系列 token。作者發現 ViT 訓練得更快。

最大的 ResNet 模型,RN50x64,在 592 個 V100 GPU 上訓練了 18 天,而最大的 Vision Transformer 在 256 個 V100 GPU 上訓練了 12 天。

文字和影像編碼器都是從頭開始訓練的。

我們從頭開始訓練 CLIP,不使用 ImageNet 權重初始化影像編碼器,也不使用預訓練權重初始化文字編碼器。

對於所有架構,如論文所述,進行了一些小的修改。

訓練

作者最初嘗試訓練一個影像字幕模型,該模型可以預測給定影像的確切字幕/描述。

我們最初的方法與VirTex類似,從頭開始聯合訓練一個影像CNN和文字轉換器來預測影像的字幕。然而,我們遇到了有效擴充套件這種方法的困難。

但是,他們發現它無法擴充套件到在4億(影像,文字)對上進行訓練,因此他們選擇了一種對比表示學習方法。對比表示學習的目標是學習一個嵌入空間,在這個空間中,相似的樣本對彼此靠近,而不相似的則相隔較遠。

在標準的對比學習方法中,你會給模型提供形式為_(錨點,正面,負面)_的示例,其中_錨點_是一個類別的影像,比如說一隻狗,_正面_是同一類別的另一張影像,也是一隻狗,而_負面_是另一個類別的影像,比如說一隻鳥。然後你嵌入這些影像,並以這樣的方式訓練模型:同一類別的兩個嵌入之間的距離(也就是狗的錨點和正面之間的距離)_minimize(anchor, positive)_被最小化,不同類別的兩個嵌入之間的距離(狗和鳥)_maximize(anchor, negative)_被最大化。這鼓勵模型為同一物體輸出非常相似的嵌入,為不同物體輸出不相似的嵌入。

Image 3

對比學習的視覺化。來源:https://www.v7labs.com/blog/contrastive-learning-guide

相同的方法也可以應用於文字以及文字和影像的組合。例如,對於CLIP,對於單個訓練示例,錨點可以是一張狗的圖片,正面可以是字幕“一張狗的圖片”,負面可以是字幕“一張鳥的圖片”。

CLIP進一步使用多類N對損失,這是上述方法的擴充套件,但當你為每個錨點有多個正面和負面時。正如論文中描述的:

給定一批N(影像,文字)對,CLIP被訓練為預測在一批中N × N可能的(影像,文字)配對實際上發生了哪些。為此,CLIP透過聯合訓練影像編碼器和文字編碼器來學習一個多模態嵌入空間,以最大化批中N個真實對的影像和文字嵌入之間的餘弦相似性,同時最小化N² − N個不正確配對的嵌入之間的餘弦相似性。它在這些相似性分數上最佳化了一個對稱的交叉熵損失。

下面提供的虛擬碼很好地概括了論文中的核心細節:

Image 4

來源:從自然語言監督中學習可轉移的視覺模型

步驟包括:

  1. 使用影像編碼器嵌入影像,使用文字編碼器嵌入文字。
  2. 影像和文字嵌入來自不同的模型,具有不同的維度,因此透過(乘以一個學習的投影矩陣)將它們投影到相同的聯合多模態嵌入空間中。例如,np.dot(I_f, W_i)將大小為_[n, d_i]的矩陣與大小為[d_i, d_e]的矩陣相乘,結果得到一個大小為[n, d_e]的投影矩陣。
  3. 對新的嵌入向量進行歸一化處理。這使得它們變成單位向量。
  4. 計算點積矩陣。
  5. 計算每一行和每一列的交叉熵損失,併除以2,因為每對會被計算兩次。

提示工程與整合

隨著語言模型的興起,提示工程已成為從生成模型中獲得良好輸出的非常常見的做法。由於CLIP中的文字編碼器是一個Transformer模型,作者發現這對於獲得良好的零樣本效能也非常關鍵。作者發現,在他們預訓練的資料集中,與影像配對的文字很少只是一個單詞,例如用“狗”來表示一個類別標籤。更常見的是,文字是一個完整的句子,如影像的標題或描述。因此,作者發現提示“一張{物件}的照片”是一個很好的預設設定,但在某些情況下,更專業的提示效果更好。例如,對於衛星影像,他們發現“一張{物件}的衛星照片”效果很好。

作者還嘗試了不同模型的整合。整合是指將幾個不同模型對相同輸入的預測結合起來以獲得最終輸出,這是機器學習中解決高方差和低偏差(過擬合)問題的常見技術。在CLIP的情況下,作者透過使用許多不同的提示構建分類器來構建整合。

提示工程和整合在ImageNet上都顯示了顯著的效能提升。

在ImageNet上,我們整合了80個不同的上下文提示,這比上述單一預設提示的效能提高了3.5%。綜合考慮,提示工程和整合將ImageNet的準確性提高了近5%。

侷限性

儘管論文深入探討了許多實驗和結果,但重要的是也要提到CLIP並不完美,存在各種侷限性。

  • 由於前面提到的設計決策,這不是一個生成模型,例如不能進行影像標註。
  • 作者指出,CLIP仍然遠未達到最先進水平(僅與頂部帶有線性層的ResNet相當)。它在某些任務上的泛化能力非常差,例如在簡單的MNIST手寫數字識別資料集上僅達到88%。這可能是因為其訓練中沒有類似的影像,但CLIP對此幾乎沒有解決辦法。
  • CLIP是在網際網路上的影像-文字對上進行訓練的。這些影像-文字對未經篩選和整理,導致CLIP模型學習了許多社會偏見。(這與當前大型語言模型(LLMs)的類似擔憂相似,這些擔憂正透過RLFHF直接偏好最佳化等技術來解決)。
  • Transformer文字編碼器的最大序列長度(可以傳遞的最大令牌數)在原始實現中被限制為76,因為資料集主要是影像和標題,這些通常是短句。因此,使用現成的預訓練模型處理較長文字時效果不佳,因為它們會在76個令牌後被截斷,並且模型是針對短文字進行訓練的。

實現細節

使用HuggingFace Transformers進行推理

你可以在自己的計算機上使用HuggingFace的Transformers庫用幾行程式碼就使用CLIP!首先,匯入庫並載入預訓練模型。

import transformers
model = transformers.CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
processor = transformers.CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")

然後建立一個標題/描述列表和一個影像列表。影像可以是URL或PIL影像。

import PIL.Image
images = [PIL.Image("for_example_a_dog_image.jpeg")]
possible_classes = ["an image of a bird", "an image of a dog", "an image of a cat"]

呼叫處理器,它會對文字和影像進行標記化,並準備它們以便傳遞給模型。這與標準文字使用情況中呼叫標記器非常相似。由於我們有一個描述批處理,我們需要使用填充(padding)將它們全部填充到相同的長度,以便能夠儲存為張量,並使用截斷(truncation)將任何長句子截斷到最大序列長度(如前所述為76)。然後將標記化的輸入傳遞給模型,模型透過文字和影像編碼器傳遞它們。

with torch.no_grad():
    inputs = processor(text=descriptions, images=images, return_tensors="pt", padding=True, truncation=True)
    outputs = model(**inputs)

現在我們可以使用兩個不同的函式檢索點積矩陣。使用logits_per_image獲取形狀為_[num_of_images, num_of_text]的點積矩陣,使用logits_per_text獲取形狀為[num_of_text, num_of_images]_的矩陣。

dot_products_per_image = outputs.logits_per_image
dot_products_per_text = outputs.logits_per_text

最後,如果我們想要為每個影像獲取機率分佈,可以將這些結果透過softmax函式。

probabilities = dot_products_per_image.softmax(dim=1)

深入實現細節

Transformers CLIP的原始碼可以在github上找到,我發現它是一個非常模組化和優秀的實現。主要模型在CLIPModel類中實現,你可以在forward方法中看到主要邏輯,如下所示:

Image 5

CLIP在最高層次的核心實現。來源:modeling_clip.py

視覺模型和文字模型在嵌入和層歸一化方面有一些細微差別,如下所示:

Image 6

CLIP文字編碼器是一個Transformer。來源:modeling_clip.py

Image 7

CLIP影像編碼器是一個視覺Transformer。來源:modeling_clip.py

但它們都共享相同的CLIPEncoder,這是主要的Transformer編碼器。這包括許多子塊,它們稱為CLIPEncoderLayer。回想一下,在Transformer架構中,每個編碼器和解碼器被堆疊在一起N次。對於CLIP,我們不使用解碼器,因為我們不生成任何文字。

Image 8

來自Attention is All You Need的Transformer架構。

每個CLIPEncoderLayer然後由注意力機制、歸一化層和簡單的前饋層/多層感知器(MLP)組成。

Image 9

N個編碼器層之一。來源:modeling_clip.py

最後,我透過並註釋了多頭注意力機制的實現,如下所示——享受吧!

進一步工作

如前所述,CLIP 有多種應用方式,特別是在語義搜尋類應用中。例如,我們可以透過使用影像描述來從資料庫中檢索影像。

CLIP 及其替代品也是自那時起出現的許多多模態模型的構建模組。例如,在 Flamingo 中,一個視覺語言模型,它可以一次性處理一系列文字和影像並生成文字。Flamingo 使用視覺編碼器將影像轉換為與文字相同的嵌入空間。

Image 10

來源:Flamingo 論文。有關 Flamingo 如何工作的詳細資訊,請參閱我的另一篇文章。

作者同時嘗試了 CLIP 和他們的類似訓練版本。

最後,像 Google 的 Gemini 這樣的模型,雖然我們瞭解不多,但它們很可能採用類似的方法來結合來自各種模態(包括音訊和影片)的輸入資料!

Image 11

來源:Gemini 論文

結論

總之,CLIP 是一個聯合文字和嵌入模型,可用於多種應用並構建多模態 AI 系統。它也非常容易在 Python 中僅用幾行程式碼在 CPU 上執行。

希望你覺得它有用,感謝閱讀!如果你喜歡,你可能還想檢視我的關於 Flamingo 的文章——一個很好的後續內容!

相關文章