基础论文学习(4)——CLIP

news2024/12/23 22:16:16

《Learning Transferable Visual Models From Natural Language Supervision》

CLIP的英文全称是Contrastive Language-Image Pre-training,即一种基于对比文本-图像对的预训练模型。CLIP是一种基于对比学习的多模态模型,与CV中的一些对比学习方法如moco和simclr不同的是,CLIP的训练数据是文本-图像对:一张图像和它对应的文本描述,这里希望通过对比学习,模型能够学习到文本-图像对的匹配关系,预训练模型在未知数据集上实现zero-shot

1. CLIP模型架构

1.1 文本-图像的预训练方法

CLIP的模型结构其实非常简单:包括两个部分,即文本编码器(Text Encoder)图像编码器(Image Encoder)。Text Encoder选择的是Text Transformer模型;Image Encoder选择了两种模型,一是基于CNN的ResNet(对比了不同层数的ResNet),二是基于Transformer的ViT

在这里插入图片描述
CLIP在文本-图像对数据集上的对比学习训练过程如下:

  • 对于一个包含N个<文本-图像>对的训练batch,使用Text Encoder和Image Encoder提取N个文本特征和N个图像特征。
  • 这里共有N个正样本,即真正属于一对的文本和图像(矩阵中的对角线元素),而剩余的 N 2 − N N^2-N N2N个文本-图像对为负样本。
  • 将N个文本特征和N个图像特征两两组合,CLIP模型会预测出 N 2 N^2 N2 个可能的文本-图像对的相似度,这里的相似度直接计算文本特征和图像特征的余弦相似性(cosine similarity),即上图所示的矩阵。
  • 那么CLIP的训练目标就是最大化N个正样本的相似度,同时最小化 N 2 − N N^2-N N2N个负样本的相似度,即最大化对角线中蓝色的数值,最小化其它非对角线的数值: m i n ( ∑ i = 1 N ∑ j = 1 N ( I i ⋅ T j ) i ! = j − ∑ i = 1 ( I i ⋅ T j ) ) min(\sum_{i=1}^{N}\sum_{j=1}^{N}(I_i \cdot T_j)_{i!=j}-\sum_{i=1}(I_i \cdot T_j)) min(i=1Nj=1N(IiTj)i!=ji=1(IiTj))

对应的伪代码实现如下所示:

# image_encoder - ResNet or Vision Transformer
# text_encoder - CBOW or Text Transformer
# I[n, h, w, c] - minibatch of aligned images
# T[n, l] - minibatch of aligned texts
# W_i[d_i, d_e] - learned proj of image to embed
# W_t[d_t, d_e] - learned proj of text to embed
# t - learned temperature parameter

# 分别提取图像特征和文本特征
I_f = image_encoder(I) #[n, d_i]
T_f = text_encoder(T) #[n, d_t]

# 对两个特征进行线性投射,得到相同维度的特征,并进行l2归一化
I_e = l2_normalize(np.dot(I_f, W_i), axis=1)
T_e = l2_normalize(np.dot(T_f, W_t), axis=1)

# 计算缩放的余弦相似度:[n, n]
logits = np.dot(I_e, T_e.T) * np.exp(t)

# 对称的对比学习损失:等价于N个类别的cross_entropy_loss
labels = np.arange(n) # 对角线元素的labels
loss_i = cross_entropy_loss(logits, labels, axis=0)
loss_t = cross_entropy_loss(logits, labels, axis=1)
loss = (loss_i + loss_t)/2

通过大批量的文本-图像预训练后, CLIP可以先通过编码,计算输入的文本和图像的余弦相似度,来判断数据对的匹配程度。

在这里插入图片描述

1.2 迁移预训练模型实现zero-shot

可以看到训练后的CLIP其实是两个模型:视觉模型+文本模型,与CV中常用的先预训练然后微调不同,CLIP可以直接实现zero-shot的图像分类,即不需要任何训练数据,就能在某个具体下游任务上实现分类。

经过在文本-图像对数据上训练的模型,有能力判断给定的文本和图像是否匹配。这时CLIP已经完成了其全部训练过程,完全不需要Imagenet或其它数据集中的图像-类别标签,即可以直接做图像分类了。

这也是CLIP这个模型最大的亮点:zero-shot图像分类。这是如何实现的呢,其实也非常简单:

在这里插入图片描述

  1. 根据任务的分类标签构建每个类别的描述文本(以Imagenet有N=1000类为例):A photo of {label},然后将这些文本送入Text Encoder得到对应的文本特征,如果类别数目为N,那么将得到N个文本特征
# 首先生成每个类别的文本描述(例如6个类别文本)
labels = ["dog", "cat", "bird", "person", "mushroom", "cup"]
text_descriptions = [f"A photo of a {label}" for label in labels]
text_tokens = clip.tokenize(text_descriptions).cuda()

# 提取文本特征
with torch.no_grad():
    text_features = model.encode_text(text_tokens).float()
    text_features /= text_features.norm(dim=-1, keepdim=True)
  1. 将要预测的图像送入Image Encoder得到图像特征,然后与N个文本特征计算缩放的余弦相似度(和训练过程一致),然后选择相似度最大的文本对应的类别作为图像分类预测结果,进一步地,可以将这些相似度看成logits,送入softmax后可以到每个类别的预测概率。
# 读取待预测图像
original_images = []
images = []
texts = []

for label in labels:
    image_file = os.path.join("images", label+".jpg")
    name = os.path.basename(image_file).split('.')[0]

    image = Image.open(image_file).convert("RGB")
    original_images.append(image)
    images.append(preprocess(image))
    texts.append(name)

image_input = torch.tensor(np.stack(images)).cuda()

# 提取图像特征  
with torch.no_grad():
    image_features = model.encode_image(image_input).float()
    image_features /= image_features.norm(dim=-1, keepdim=True)

# 计算余弦相似度(未缩放)
similarity = text_features.cpu().numpy() @ image_features.cpu().numpy().T

# 对得到的余弦相似度计算softmax,得到每个预测类别的概率值
logit_scale = np.exp(model.logit_scale.data.item())
text_probs = (logit_scale * image_features @ text_features.T).softmax(dim=-1)
top_probs, top_labels = text_probs.cpu().topk(5, dim=-1)

2. 实验分析

在这里插入图片描述
我们从左图中看到,CLIP在16个数据集上可以超过全监督的ResNet50;但是在一些较为特殊的数据集上,CLIP表现差于ResNet50,例如MNIST等。这个原因来自于MNIST中手写体数字图片,在其搜集的4亿文本-图像对中很少出现,导致CLIP没有学习到这么特殊的图像/文本。而ResNet50采取全监督的训练方式,将数据集的特殊性都学习到了,因此分类准确率较高。(个人猜测: 如果Open AI收集一些相似于特殊数据集中的图像,加入其文本-图像对数据集中,也可以在这些特殊数据集上提升效果)

同时,我们从右图中看到,CLIP和全监督训练的ResNet101在ImageNet验证集上都能达到76.2%的准确率,而在下面一些分布漂移(数据集中不同类别图像的数量分布不均衡)的数据集上,CLIP更是远超全监督训练的ResNet101。最明显的是,在ImageNet-A数据集上,CLIP可以达到77.1%,而ResNet只有2.7%(基本属于瞎猜)。这证明了使用文本-图像做预训练的CLIP具备更强的鲁棒性。

除了图像分类任务,CLIP还实现了文本-图像的预训练。这也为其后续做文本-图像生成及更多下游任务做了铺垫。

2.1 局限性

论文的最后也对CLIP的局限性做了讨论,这里简单总结其中比较重要的几点:

  • CLIP的zero-shot性能虽然和有监督的ResNet50相当,但是还不是SOTA,作者估计要达到SOTA的效果,CLIP还需要增加1000x的计算量,这是难以想象的;
  • CLIP的zero-shot在某些数据集上表现较差,如细粒度分类,抽象任务等;
  • CLIP在自然分布漂移上表现鲁棒,但是依然存在域外泛化问题,即如果测试数据集的分布和训练集相差较大,CLIP会表现较差;
  • CLIP并没有解决深度学习的数据效率低下难题,训练CLIP需要大量的数据;

2.2 总结

CLIP 的最大贡献在于打破了固定种类标签的桎梏,让下游任务的推理变得更灵活,并且在 zero-shot 的情况下,它的效果很不错

  • 有监督预训练模型仍需微调,无法实现zero-shot:在计算机视觉领域,最常采用的迁移学习方式就是先在一个较大规模的数据集如ImageNet上预训练,然后在具体的下游任务上再进行微调。这里的预训练是基于有监督训练的,需要大量的数据标注,因此成本较高。

  • 很多自监督预训练模型也需要下游微调:近年来,出现了一些基于自监督的方法,这包括基于对比学习的方法如MoCoSimCLR基于图像掩码的方法如MAEBeiT,自监督方法的好处是不再需要标注,但是无论是有监督还是自监督方法,它们在迁移到下游任务时,还是需要进行有监督微调,而无法实现zero-shot。

  • CLIP解决了自监督预训练模型需要下游微调的现状!

在这篇工作发表之后,涌现出了一大批在其他领域的应用,包括物体检测、物体分割、图像生成、视频动作检索等。在创新度、有效性、影响力方面都非常出色。如扩展到文本-视频,VideoCLIP就是将CLIP应用在视频领域来实现一些zero-shot视频理解任务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/910073.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软考高级架构师下篇-12层次式架构设计理论与实践

目录 1. 考情分析2. 层次式体系结构概述3. 表现层框架设计4. 中间层框架设计5. 数据访问层设计6. 数据架构规划与设计7. 物联网层次架构设计7. 前文回顾1. 考情分析 根据考试大纲,层次式架构设计理论与实践知识点会涉及单选题型(约占2~5分)和案例题(25分),本小时内容偏重于方…

lesson9: C++多线程

1.线程库 1.1 thread类的简单介绍 C11 中引入了对 线程的支持 了&#xff0c;使得 C 在 并行编程时 不需要依赖第三方库 而且在原子操作中还引入了 原子类 的概念。要使用标准库中的线程&#xff0c;必须包含 < thread > 头文件 函数名 功能 thread() 构造一个线程对象…

LCD液晶屏接口静电浪涌保护用TVS/ESD二极管,如何选型?

LCD 液晶屏是Liquid Crystal Display 的简称&#xff0c;指将玻璃和LCD驱动器集成到一起的LCD显示产品&#xff0c;为用户提供了一个标准的LCD显示驱动接口&#xff0c;用户可以按照接口&#xff08;有4位、8位、VGA等不同类型&#xff09;要求进行操作来控制LCD正确显示。众所…

Fsm onehot

module top_module(input in,input [9:0] state,output [9:0] next_state,output out1,output out2);assign out1(state[8]|state[9])?1:0;assign out2(state[9]|state[7])?1:0;assign next_state[0](state[0]&(~in)) |(state[1]&(~in)) |(state[2]&(~in)) |(sta…

LVS+Keepalived 实验

Keepalived 是什么 Keepalived 是一个基于VRRP协议来实现的LVS服务高可用方案&#xff0c;可以解决静态路由出现的单点故障问题的一款检查工具 在一个LVS服务集群中通常有主服务器&#xff08;MASTER&#xff09;和备份服务器&#xff08;BACKUP&#xff09;两种角色的服务器…

ShardingSphere01-docker环境安装

使用docker安装数据库是一个非常好的选择&#xff0c;后续的读写分离、数据分片等功能的数据库都是由docker创建。 一、安装准备 1、前提条件 Docker可以运行在Windows、Mac、CentOS、Ubuntu等操作系统上 Docker支持以下的CentOS版本&#xff1a; CentOS 7 (64-bit)CentOS …

LLM预训练大型语言模型Pre-training large language models

在上一个视频中&#xff0c;您被介绍到了生成性AI项目的生命周期。 如您所见&#xff0c;在您开始启动您的生成性AI应用的有趣部分之前&#xff0c;有几个步骤需要完成。一旦您确定了您的用例范围&#xff0c;并确定了您需要LLM在您的应用程序中的工作方式&#xff0c;您的下…

第59步 深度学习图像识别:误判病例分析(TensorFlow)

基于WIN10的64位系统演示 一、写在前面 本期内容对等于机器学习二分类系列的误判病例分析&#xff08;传送门&#xff09;。既然前面的数据可以这么分析&#xff0c;那么图形识别自然也可以。 本期以mobilenet_v2模型为例&#xff0c;因为它建模速度快。 同样&#xff0c;基…

Linux下Jenkins安装 (最新)

环境概述 随着软件开发需求及复杂度的不断提高&#xff0c;团队开发成员之间如何更好地协同工作以确保软件开发的质量已经慢慢成为开发过程中不可回避的问题。Jenkins自动化部署可以解决集成、测试、部署等重复性的工作&#xff0c;工具集成的效率明显高于人工操作&#xff1b…

Android动画进阶指北

原文链接 Android Animation Advanced Tricks 前面的文章介绍了动画的基本使用方法&#xff0c;本文来聊一聊涉及到动画的高级技巧&#xff0c;以及一些非常优质的学习资源和动画三方库和框架。 页面之间的过渡动画 常规的动画都是针对某一页面上的某个元素做动画&#xff0c…

3、Spring_容器执行

容器执行点 1.整合 druid 连接池 添加依赖 <dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version> </dependency>1.硬编码方式整合 新建德鲁伊配置 <?xml version"1.…

微信小程序 车牌号输入组件

概述 一个小组件&#xff0c;用于方便用户输入车牌号码 详细 概述 有时候我们开发过程中会遇到需要用户输入车牌号的情况&#xff0c;让客户通过自带键盘输入&#xff0c;体验不好且容易出错&#xff0c;例如车牌号是不能输入O和I的&#xff0c;因此需要有一个自定义的键盘…

FPGA中锁存器(latch)、触发器(flip-flop)以及寄存器(register)详解

文章目录 1 定义1.1 锁存器&#xff08;latch&#xff09;1.2 触发器&#xff08;flip-flop&#xff09;1.3 寄存器&#xff08;register&#xff09; 2 比较2.1 锁存器&#xff08;Latch&#xff09;危害即产生原因2.2 寄存器和锁存器的区别2.3 锁存器和触发器的区别 3 结构3.…

dvwa环境搭建

靶场搭建 环境作用apache网站代理&#xff0c;部署网站php一种开源通用脚本语言&#xff0c;用来处理程序mysql数据库&#xff0c;用来存储数据 1.打开sever 2008&#xff0c;远程桌面连接&#xff0c;将文件拷贝到虚拟机&#xff0c;打开微软常用集合运行库&#xff0c;等待…

「Vue|网页开发|前端开发」01 快速入门:用vue-cli快速写一个Vue的HelloWorld项目

本文主要介绍如何用vue开发的标准化工具vue-cli快速搭建一个符合实际业务项目结构的hello world网页项目并理解vue的代码文件结构以及页面渲染流程。 文章目录 一、准备工作&#xff1a;安装node.js二、项目搭建创建项目目录全局安装vue-cli使用Webpack初始化项目启动项目学会…

RedisDesktopManager 连接redis

redis查看是否启动成功 ps -ef | grep redis以上未启动成功 cd /usr/local/bin/ 切换根目录 sudo -i 开启服务端 ./redis-server /usr/local/redis/redis.conf 开启客户端 ./redis-cli

Ganache 本地测试网远程连接

文章目录 前言1. 安装Ganache2. 安装cpolar3. 创建公网地址4. 公网访问连接5. 固定公网地址 前言 Ganache 是DApp的测试网络&#xff0c;提供图形化界面&#xff0c;log日志等&#xff1b;智能合约部署时需要连接测试网络。 Ganache 是一个运行在本地测试的网络,通过结合cpol…

MySQL如何进行表之间的关联更新

在实际编程工作或运维实践中&#xff0c;对MySQL数据库表进行关联更新是一种比较常见的应用场景&#xff0c;比如在电商系统中&#xff0c;订单表里保存了商品名称的信息&#xff08;冗余字段设计&#xff09;&#xff0c;但如果商品名称发生变化&#xff0c;则需要通过关联商品…

[已解决]SpringBoot 返回日期时间格式不正确

最近开发中不知道为什么&#xff0c;返回给前端的日期时间格式变成了这样子&#xff0c;晚了8小时&#xff0c;在网上找了解决办法&#xff1a; 原返回值&#xff1a; 需要修改的地方&#xff1a; 在application.yml中添加下面的代码&#xff0c;重启springboot项目即可。 sp…

C++信息学奥赛1121:计算矩阵边缘元素之和

题解&#xff1a;i0 or j0 or in-1 or jm-1 or in-1 or jm-1 代码&#xff1a; #include<iostream> // 包含输入输出流库 #include<cmath> // 包含数学函数库 using namespace std; // 使用标准命名空间int main() {int n,m;cin>>n>>m; // 输入…