如今深度學習領域有一個比較熱門的領域叫做:多模態。多模態這個詞整得比較玄學,但是其實主要思想就是將文本,圖像,語音等不同類型的數據,放到同一個特征空間去表示,這樣的好處就是可以將不同類型數據打通,在一個任務上利用到更多更全面的數據,來提升業務指標的效果。比如對搜索來說就可以通過多模態實現以文搜圖,最火的stable diffusion model 文本生成圖像也是多模態的一個場景。今天筆者就介紹一下目前比較火的一個多模態模型clip。
通過無監督對比學習的預訓練方式將文本數據和圖片數據表示到同一個特征空間,從而實現zero-shot 的圖像分類。
CLIP 模型
CLIP(Contrastive Language–Image Pre-training )是由OpenAI開源的基于對比學習的大規模圖文預訓練模型,其整個架構如下圖(1)所示:
- 一個文本編碼器,文本編碼器可以是transformer。
- 一個圖像編碼器,圖像編碼器可以是resnet50或vision transformer(ViT)等
- 通過無監督的對比學習預訓練將文本和圖像聯系起來
下圖(2) (3)則是利用預訓練好的模型進行零樣本(zero shot)的文本分類
- 將所有labels的文本通過 文本編碼器進行編碼
- 將要預測的圖像通過 圖像編碼器進行編碼
- 在計算 圖像編碼 與 所有 labels 文本編碼的 內積,取內積最大的那個作為預測label。
其中特別值得注意的一點是,clip 預訓練的方式采用的在batch 內負采樣的方式進行的對比學習,如下圖所示:一個batch內,一個文本編碼,只有與它對應的圖像是正樣本,其他的圖像都是負樣本。目標就是優化這個矩陣,希望對角線的值越大越好,矩陣其他地方的值越小越好。
實戰部分
模型下載
筆者去huggface上搜索了一下clip,看是否有中文的clip模型,還真找到了一個
IDEA-CCNL的太乙多模態模型。它其實就是將openAI的圖像編碼器至今拿過來用,采用Roberta作為中文文本編碼器,在Clip預訓練的數據的漢化版上進行了進一步的預訓練。其中太乙102M的文本編碼器 對應的是openAI的 VIT-patch32的圖像編碼器。筆者將下方兩個模型下載到本地。
項目目錄結果如下圖,其中openai32 下面就是openai放出的圖像編碼器,
clipChineseText 就是IDEA-CCNL的太乙文本模型編碼器。
具體代碼如下圖,先加載太乙文本編碼器,在加載openai的圖像編碼器。
from PIL import Image
import requests
# import clip
import torch
from transformers import BertForSequenceClassification, BertConfig, BertTokenizer
from transformers import CLIPProcessor, CLIPModel
import numpy as np
labels = ["貓", "狗",'豬', '虎'] # 這里是輸入文本的,可以隨意替換。
# 加載Taiyi 中文 text encoder
text_tokenizer = BertTokenizer.from_pretrained("./clip")
text_encoder = BertForSequenceClassification.from_pretrained("./clip").eval()
text = text_tokenizer(labels, return_tensors='pt', padding=True)['input_ids']
# 加載CLIP的image encoder
clip_model = CLIPModel.from_pretrained("openai32/")
processor = CLIPProcessor.from_pretrained("openai32/")
加載完畢后,就可以進行無監督的圖像分類預測了。過程和上方介紹的clip無監督文本分類的步驟一摸一樣,先將labels = ["貓", "狗",'豬', '虎'] 用文本編碼器進行編碼,再將圖片進行編碼,計算和目標圖像編碼內積最大的那個作為預測label。
def get_label(url):
image = processor(images=Image.open(url), return_tensors="pt")
with torch.no_grad():
image_features = clip_model.get_image_features(**image)
text_features = text_encoder(text).logits
# 歸一化
image_features = image_features / image_features.norm(dim=1, keepdim=True)
text_features = text_features / text_features.norm(dim=1, keepdim=True)
# 計算余弦相似度 logit_scale是尺度系數
logit_scale = clip_model.logit_scale.exp()
logits_per_image = logit_scale * image_features @ text_features.t()
probs = logits_per_image.softmax(dim=-1).cpu().numpy()
print(url+"的label是"+labels[np.argmax(probs)])
url = "./pig.jpg"
get_label(url)
url = "./tiger.jpg"
get_label(url)
在百度上下載了一種豬,一張虎的圖,進行測試。
完全正確,零樣本圖像分類就這樣完成了,clip的威力確實很強大。
結語
clip 不僅可以完成零樣本圖像分類,還可以完成以文搜圖等,其文本特征和圖像特征也可用于推薦的召回和排序階段??傊嗄B是一種趨勢,不同數據的融合勢必比單獨使用要強一點。
https://aistudio.baidu.com/aistudio/projectdetail/4458949
https://github.com/IDEA-CCNL/Fengshenbang-LM