clip-cnblog

xle97發表於2024-05-27

CLIP

github

Learning Transferable Visual Models From Natural Language Supervision

CLIP全稱Constrastive Language-Image Pre-training,是OpenAI推出的採用對比學習的文字-影像預訓練模型。CLIP驚豔之處在於架構非常簡潔且效果好到難以置信,在zero-shot文字-影像檢索,zero-shot影像分類,文字→影像生成任務guidance,open-domain 檢測分割等任務上均有非常驚豔的表現

Zero-Shot Learning

介紹

零次學習(Zero-Shot Learning,簡稱ZSL)假設斑馬是未見過的類別,但根據描述外形和馬相似、有類似老虎的條紋、具有熊貓相似的顏色,透過這些描述推理出斑馬的具體形態,從而能對斑馬進行辨認。零次學習就是希望能夠模仿人類的這個推理過程,使得計算機具有識別新事物的能力,如下圖所示

有監督學習可以使得模型在已知資料集已知標籤的情況, 得到讓人驚訝的效果。但是, 我們對於人工智慧的期望要更加的高, 我們期望模型具有推理的能力, 識別新類別的能力。ZSL就是希望我們的模型能夠對其從沒見過的類別進行分類,讓機器具有推理能力,實現真正的智慧。其中零次(Zero-shot)是指對於要分類的類別物件,一次也不學習。

問題

領域漂移問題(domain shift problem)

同一種屬性,在不同的類別中,視覺特徵的表現可能很大。如圖3所示,斑馬和豬都有尾巴,因此在它的類別語義表示中,“有尾巴”這一項都是非0值,但是兩者尾巴的視覺特徵卻相差很遠。如果斑馬是訓練集,而豬是測試集,那麼利用斑馬訓練出來的模型,則很難正確地對豬進行分類。

樞紐點問題(Hubness problem)

在高維空間中,某些點會成為大多數點的最近鄰點。由於ZSL在計算最終的正確率時,使用的是K-NN,所以會受到hubness problem的影響。

語義間隔(semantic gap)

樣本的特徵往往是視覺特徵,比如用深度網路提取到的特徵,而語義表示卻是非視覺的,這直接反應到資料上其實就是:樣本在特徵空間中所構成的流型與語義空間中類別構成的流型是不一致的。這使得直接學習兩者之間的對映變得困難。

模型詳解

模型特點

  • 多模態的, 結合CV和NLP
  • zero-shot, 不受類別數量的影響
  • Constastive learning, 兩個encoder得到的向量表徵對映到同一個空間, 消去不同模態之間的向量表示的gap, 便於後續的cosine相似度的計算

訓練

對比式無監督訓練

假設我們有 N 個影像與它們各自的描述集合,例如:<image1, text1>, <image2, text2>, <imageN, textN>。

對比式無監督預訓練的目的是同時訓練影像編碼器和文字編碼器,產生影像嵌入[I1, I2 ... IN]和文字嵌入[T1, T2 ... TN],其方式為:

正確的嵌入對<I1,T1>, <I2,T2>(其中 i=j)的餘弦相似度是最大的。

以對比的方式,不相似的對<I1,T2>, <I1,T3>...<Ii,Tj>(其中 i≠j)的餘弦相似性最小。

以clip_res50為例

該模型使用對稱的交叉熵損失函式作為其最佳化目標。這種型別的損失函式既能最佳化影像到文字的方向,也能有最佳化文字到影像的方向(對比損失函式矩陣同時保持<I1,T2>和<I2,T1>的餘弦相似度)

加速訓練: 預測文字描述-圖片 -> bag of words, 即將文字抽象為特徵, 預測特徵-圖片 -> 預測文字-圖片

  1. 首先接收 N 個對。
  2. text encoder是一個標準的 Transformer 模型,進行了 GPT2 風格的修改。影像編碼器可以是 ResNet 或 Vision Transformer。
  3. 對於每個影像,影像編碼器都會計算一個影像向量。比如第一幅影像對應於 I1 向量,第二幅對應於 I2 向量,以此類推。每個向量的大小為 de(de 是潛在維度的大小)。因此,這一步的輸出是 N * de 矩陣。clip_res50的de維度是512
  4. 同樣地,文字描述被壓縮成文字嵌入[T1, T2 ... TN],產生一個 N * de 矩陣。
  5. 最後,我們將這些矩陣相乘,計算每張圖片和文字描述之間的成對餘弦相似度。這將產生一個 N * N 矩陣,如上圖所示。
  6. 目標是使對角線上的餘弦相似度最大化,這些是正確的對。以對比的方式,非對角線元素的相似度應該最小化(例如,I1 影像由 T1 描述,而不是由 T2、T2、T3 等描述)。

Zero-Shot 分類

提供一組文字描述,如一張狗或貓吃冰淇淋的照片(任何我們認為最能描述一張或多張影像的內容)。這些文字描述被編碼為文字嵌入。然後,我們對影像做同樣的事情——影像被編碼成影像嵌入。最後,CLIP 計算影像嵌入和文字嵌入之間的成對餘弦相似度。具有最高相似度的文字提示被選擇為預測結果。當然,我們也可以輸入一張以上的影像。CLIP 巧妙地快取了輸入的文字嵌入,所以它們不必為其餘的輸入影像重新進行計算。這就是 CLIP 端到端的工作方式。

資料

CLIP 使用多達 30 個公共資料集進行預訓練。用大量的資料擬合一個大型語言模型是很重要的。對於如CIFAR只有一個單詞作為標籤的資料集, clip的作者會將標籤加上“prompt”轉成句子, 如dog -> A photo of a dog

code

一個例子, 預測圖片對應的text

import torch

import clip

from PIL import Image

device = "cuda" if torch.cuda.is_available() else "cpu"

model, preprocess = clip.load("ViT-B/32", device=device)

image = preprocess(Image.open("CLIP.png")).unsqueeze(0).to(device)

text = clip.tokenize(["a diagram", "a dog", "a cat"]).to(device)

with torch.no_grad():
	image_features = model.encode_image(image)
	text_features = model.encode_text(text)
	logits_per_image, logits_per_text = model(image, text)
	probs = logits_per_image.softmax(dim=-1).cpu().numpy()

print("Label probs:", probs)  # prints: [[0.9927937  0.00421068 0.00299572]]

將text 編碼和image編碼進行 norm、矩陣相乘, 如上圖

    def forward(self, image, text):
        image_features = self.encode_image(image)
        text_features = self.encode_text(text)

        # normalized features
        image_features = image_features / image_features.norm(dim=1, keepdim=True)
        text_features = text_features / text_features.norm(dim=1, keepdim=True)

        # cosine similarity as logits
        logit_scale = self.logit_scale.exp()
        logits_per_image = logit_scale * image_features @ text_features.t()
        logits_per_text = logits_per_image.t()

        # shape = [global_batch_size, global_batch_size]
        return logits_per_image, logits_per_text

reference

https://blog.csdn.net/lsb2002/article/details/132275132

https://xie.infoq.cn/article/f7680d1fe54f4a0e2db7acbd3