多模态模型补充-CLIP

CLIP [OpenAI 21.01]

Learning Transferable Visual Models From Natural Language Supervision

https://arxiv.org/pdf/2103.00020.pdf
https://github.com/openai/CLIP

本来打算放在多模态模型汇总-按需更新里面的,发现CLIP内容比较多,实验很丰富,解读很详细,还是单独介绍一下。

以下都是直觉翻译和认知加工,如有问题,欢迎指正。
花了好几天,仍然没读完...

私以为本文的几个亮点:

  1. 双流模型,单独提取图片和文本feature;
  2. 对比学习;
  3. 将分类模型转换成图文匹配任务,用文本来弱监督图片分类。

背景

一般的目标检测,图片分类等CV任务,都会预设有哪些类别,要识别哪些种类。实际图片信息是很丰富的,除了这些预设的类别,其他的视觉信息没有被充分利用,如果还要识别图上其他类别,就需要再加标签。

如果图片有文本描述,通过文本监督学习更多的图片信息不失为一个好方法。

  1. Mori et al. (1999) 训练图文对,预测文本中的nouns和adjectives,探索基于图片检索的方式改进内容;
  2. Quattoni et al. (2007) 训练图文对,预测文本描述,来学习分类权重空间,学习更多视觉表达;
  3. Srivastava & Salakhutdinov (2012) 训练多模态Deep Boltzmann Machines,数据为top of low-level image和对应文本tag特征,学习深层表达;
  4. Joulin et al. (2016) 用CNN训练图文对,预测文本表述,来学习图片表达;
  5. 还有些将标题,描述和hashtag等元数据,和图片一起训练,预测这些元数据的模型;Li et al.(2017)扩展了这个方法,除了预测individual words,还会预测n-grams,并显示这种系统在zero-shot transfer到其他分类数据集上的能力,即基于这些数据集的dictionary学习视觉n-grams,预测目标类别能拿到最高分;
  6. VirTex, ICMLML等模型展现了transformer模型在语言模型,masked语言模型,对比学习中的潜力。

虽然1~6展示了多模态(图文)学习在学习模态表征上的能力,目前通过自然语言监督学习视觉表达的研究还是比较少。

  1. 这种方式得到的模型结果不是最佳,比如 Li et al. (2017) 通过zero-shot方式,在ImageNet数据集上,只得到11.5%的准确率,但SOTA是88.4%;
  2. 文本数据是无限的,但是视觉数据的标签是有限的,打标签很费人力。

本文提出CLIP,Contrastive Language–Image Pre-training,用4亿对来自网络的图文数据集,将文本作为图像标签,进行训练。进行下游任务时,只需要提供和图上的concepts对应的文本描述,就可以进行zero-shot transfer。
模型在30个CV数据集上做了实验,实验任务包括OCR, action recognition in videos, geo-localization, and many types of fine-grained object classification。模型在大部分的任务上都达到最佳。而且,一般不用再做specific training,就可以和其他baseline 模型媲美。

Model

数据:4亿个网络公开的图文对。为覆盖到更多的视觉concepts, 用了50w个query在搜索引擎搜索图片,一个query差不多有2w张图片。
输入:一个batch有N个图像文本对;

CLIP 模型框架

模型:对比学习,预测N\times N对图文数据,将图片分类任务转换成图文匹配任务:

  1. 双流,2个encoder分别处理文本和图片数据,text encoder使用Transformer,image encoder用了2种模型,ResNetVision Transformer(ViT)
    a. 5种ResNet:ResNet-50, ResNet-101, EfficientNet-style的ResNet,包括RN50x4, RN50x16, RN50x64;
    b. 3种ViT:ViT-B/32, ViT-B/16, ViT-L/14;
  2. encoder representation直接线性投影到multi-modal embedding space;
  3. 计算2模态之间的cosine similarity,让N个匹配的图文对相似度最大,不匹配的图文对相似度最小;
  4. 对称的cross-entropy loss;
  5. 数据增强:对resized图片进行random square crop。

伪代码如下:

CLIP 伪代码

实验

1. Zero-shot Transfer

图片分类的zero-shot指的是对未知类别进行推理。
本文的zero-shot指的是对未知任务进行推理,通过zero-shot transfer衡量任务学习的能力。
Visual N-Grams (Li et al., 2017) 是第一个将zero-shot transfer应用到图片分类任务上的模型。模型用于学习长度为1~5grams的共142806个visual n-grams,对输入的图片,最大化对应的n-grams的probability。

同样的,CLIP在进行zero-shot transfer时,将数据集中的类别标签转换为文字描述,主要步骤如下:

  1. 输入:一张图片 + 所有类别转换的文本(100个类别就是100个文本描述);
  2. 转换向量:经过2个encoder,分别输出image和text的feature embedding;
  3. 计算cosine similarity;
  4. 预测类别:multinomial logistic regression classifier。

模型结果:以下3个数据集,CLIP的表现都要高于Visual N-Grams。

CLIP vs Visual N-Grams

PROMPT ENGINEERING AND ENSEMBLING
有些CV分类数据集,类别用ID表示,有的有映射的文本描述。像Flower102和GTSRB数据集,缺乏映射关系,导致有些数据不能进行zero-shot transfer;

同义词也会困扰模型:如果文本输入只是一个类别,因为缺乏上下文,text encoder就不能很好的区分词义。比如Oxford-IIIT Pet 数据集中的boxer指代一种狗,但因为缺乏上下文信息,CLIP的text encoder学习的不够充分,以至于将boxer识别成一种运动。

CLIP的训练数据集中,很少出现一张图片对应一个单词的现象。一般来说,都是用一句话来形容图片。为了减少训练集和其他任务数据集的gap,使用prompt template

Prompt template: “A photo of a {label}.”
比如,类别为狗,则输入文本为“A photo of a dog.”。
通过这种方式,模型在ImageNet上,提高了1.3%的准确率。

如果提供更细粒度的类别信息(可以理解为文本描述中加属性/类别标签),比如上文的“A photo of a {label}.”,细化到“A photo of a {label}, a type of pet.”或者‘A photo of a big {label}”。按照这种方式,在ImageNet数据集上,构建了80种不同形式的prompt template,准确率又提高了3.5%。

ANALYSIS OF ZERO-SHOT CLIP PERFORMANCE

  1. zero-shot classifier表现怎么样?
    参照模型Linear Probe on ResNet50:ResNet-50 + logistic regression。
    下图显示了,在27个数据集中,CLIP在16个数据上表现更好。


    zero-shot CLIP vs. Linear Probe on ResNet50
  2. zero-shot CLIP怎么做prediction?
    zero-shot prediction
    基于输入的图片,在类别描述中检索,找到最合适的类别。

"Ref:https://github.com/openai/CLIP"
import os
import clip
import torch
from torchvision.datasets import CIFAR100

# Load the model
device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load('ViT-B/32', device)

# Download the dataset
cifar100 = CIFAR100(root=os.path.expanduser("~/.cache"), download=True, train=False)

# Prepare the inputs
image, class_id = cifar100[3637]
image_input = preprocess(image).unsqueeze(0).to(device)
text_inputs = torch.cat([clip.tokenize(f"a photo of a {c}") for c in cifar100.classes]).to(device)
#cifar每个类别,输入图片,检索匹配的类别

# Calculate features
with torch.no_grad():
    image_features = model.encode_image(image_input)
    text_features = model.encode_text(text_inputs)

# Pick the top 5 most similar labels for the image
image_features /= image_features.norm(dim=-1, keepdim=True)
text_features /= text_features.norm(dim=-1, keepdim=True)
similarity = (100.0 * image_features @ text_features.T).softmax(dim=-1)
values, indices = similarity[0].topk(5)

# Print the result
print("\nTop predictions:\n")
for value, index in zip(values, indices):
    print(f"{cifar100.classes[index]:>16s}: {100 * value.item():.2f}%")

"""
Top predictions:
           snake: 65.31%
          turtle: 12.29%
    sweet_pepper: 3.83%
          lizard: 1.88%
       crocodile: 1.75%
"""

Linear-probe evaluation
通过CLIP的image_encoder得到视觉向量,结合标签做Logistic Regression。

"Ref:https://github.com/openai/CLIP"
import os
import clip
import torch

import numpy as np
from sklearn.linear_model import LogisticRegression
from torch.utils.data import DataLoader
from torchvision.datasets import CIFAR100
from tqdm import tqdm

# Load the model
device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load('ViT-B/32', device)

# Load the dataset
root = os.path.expanduser("~/.cache")
train = CIFAR100(root, download=True, train=True, transform=preprocess)
test = CIFAR100(root, download=True, train=False, transform=preprocess)

def get_features(dataset):
    all_features = []
    all_labels = []
    
    with torch.no_grad():
        for images, labels in tqdm(DataLoader(dataset, batch_size=100)):
            features = model.encode_image(images.to(device))

            all_features.append(features)
            all_labels.append(labels)

    return torch.cat(all_features).cpu().numpy(), torch.cat(all_labels).cpu().numpy()

# Calculate the image features
train_features, train_labels = get_features(train)
test_features, test_labels = get_features(test)

# Perform logistic regression
classifier = LogisticRegression(random_state=0, C=0.316, max_iter=1000, verbose=1) # c自定义
classifier.fit(train_features, train_labels)

# Evaluate using the logistic regression classifier
predictions = classifier.predict(test_features)
accuracy = np.mean((test_labels == predictions).astype(np.float)) * 100.
print(f"Accuracy = {accuracy:.3f}")

2. Data Overlap Analysis

预训练的数据集是否和下游数据集有重叠?如果有重叠,就会导致数据泄露,下游实验的结果就不可信。本文作者分析了训练集和下游任务的重叠程度,以及这种重叠对模型效果的影响。

  1. 对每个evaluation的数据集,做一个duplicate detector。对和训练集相似度高的数据进行人工审核,并确定一个threshold,保证高精度的同时最大化召回。通过这个threshold,将数据集ALL(evaluation的数据集)分解成2个子集:
    a. Overlap:和训练集的相似度高于threshold的数据;
    b. Clean:相似度低于threshold的数据。
  2. 计算CLIP zero-shot在ALL,Overlap和Clean这三种数据集上的准确率,ALL-Clean的准确率差距作为衡量标准;
  3. 因为overlap的程度比较轻,因此进行binomial significance test,使用Clean的准确率作为null hypothesis,计算Overlap的p-value。

作者在35个数据集上做了分析,其中,有9个数据集和训练集没有数据重叠。像e MNIST, CLEVR和GTSRB这类偏synthetic或者specialized的数据,往往不会被视为正常的图片,和训练集基本没有重叠。
重叠率最高的是Country211,重叠率达21.5%,它是从YFCC100M数据集剥离出来的,虽然重叠程度很高,但这种重叠率只带来0.2%的准确率的提升。也许是因为Country211主要是为了衡量geo-localization的ability,但在训练集中,文本描述并没有提及到image的location。

Overlap分析

虽然但是,作者也提到是不是duplicate detector做的不够好。

  1. detector选择threshold时,考虑保精度同时要求有高召回,但也没有办法去检查完召回到的400million的样本;
  2. Overlap和Clean数据集分布可能发生很大变化,比如Kinetics-700数据集,重叠的数据集都是black transition frames,所以上图左,Detected Data Overlap,Kinetics-700的准确率,相比Clean,降低了20%。

Limitation

  1. 不是和SOTA的比较:以上的数据分析,都是和a linear classifier on top of ResNet-50 features进行比较,大部分的数据集,都有对应的SOTA模型。为了达到SOTA,zero-shot CLIP估计要提高1000x的算力,当前情况不支持;
  2. 在部分fine-grained分类上表现不佳:
    a. 前面实验分析发现,模型不能很好的区分cars,species of flowers, 以及variants of aircraft;
    b. abstract和systematic任务表现不好,比如统计图上object的数量;
    c. 在训练集中基本不会出现的比较novel的任务,表现欠佳,比如classifying
    the distance to the nearest car in a photo;
  3. 训练集中没有出现的图片类型(out-of-distribution),表现不好,比如OCR识别数字效果可以,但是MNIST的准确率只有88%;
    ...
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容