当前位置: 首页 > news >正文

CLIP论文学习

1.CLIP模型架构

CLIP的核心思想是通过对比学习,让模型学习图像和文本之间的关联。它分别对图像和文本进行编码,将它们映射到同一个特征空间,使得相关的图像和文本在该空间中距离更近。
对比无监督预训练

2.模型训练原理(实例)

# 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

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

# joint multimodal embedding [n, d_e]
# 对两个特征进行线性投射,得到相同维度的特征,并进行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)

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

# symmetric loss function
# 对称的对比学习损失:等价于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

2.1数据流动以及实例

图片示例
  • 图片1一张高清照片,画面中有一只毛茸茸的白色猫,正慵懒地坐在米色的沙发上,周围有一些抱枕。
  • 图片2一张运动场景照片,一个穿着蓝色篮球服的人正在篮球场上高高跃起投篮,背景是观众和记分牌。
对应句子示例
  • 句子1“一只白色的猫惬意地坐在沙发上”
  • 句子2“一个人穿着蓝色球服在篮球场上投篮”
数学公式及数据流向展示
1. 输入数据
  • 图像输入
    • 假设小批量中有 n = 2 n = 2 n=2 张图像,每张图像大小为 h = 224 h = 224 h=224 像素高, w = 224 w = 224 w=224 像素宽, c = 3 c = 3 c=3(RGB 三个通道),则图像输入 I I I 的形状为 I [ n , h , w , c ] = I [ 2 , 224 , 224 , 3 ] I[n, h, w, c]=I[2, 224, 224, 3] I[n,h,w,c]=I[2,224,224,3]
  • 文本输入
    • 同样 n = 2 n = 2 n=2 条文本,每条文本经过分词后长度 l = 10 l = 10 l=10,则文本输入 T T T 的形状为 T [ n , l ] = T [ 2 , 10 ] T[n, l]=T[2, 10] T[n,l]=T[2,10]
2. 特征提取
  • 图像特征提取
    • 使用图像编码器 i m a g e _ e n c o d e r image\_encoder image_encoder 对输入图像 I I I 进行编码,公式为
      I f = i m a g e _ e n c o d e r ( I ) I_f = image\_encoder(I) If=image_encoder(I)
      得到图像特征 I f I_f If。假设图像编码器输出的特征维度 d i = 2048 d_i = 2048 di=2048,则 I f I_f If 的形状为 [ n , d i ] = [ 2 , 2048 ] [n, d_i]=[2, 2048] [n,di]=[2,2048]
    • 数据流向: I [ 2 , 224 , 224 , 3 ] → i m a g e _ e n c o d e r I f [ 2 , 2048 ] I[2, 224, 224, 3]\xrightarrow{image\_encoder}I_f[2, 2048] I[2,224,224,3]image_encoder If[2,2048]
  • 文本特征提取
    • 使用文本编码器 t e x t _ e n c o d e r text\_encoder text_encoder 对输入文本 T T T 进行编码,公式为
      T f = t e x t _ e n c o d e r ( T ) T_f = text\_encoder(T) Tf=text_encoder(T)
      得到文本特征 T f T_f Tf。假设文本编码器输出的特征维度 d t = 768 d_t = 768 dt=768,则 T f T_f Tf 的形状为 [ n , d t ] = [ 2 , 768 ] [n, d_t]=[2, 768] [n,dt]=[2,768]
    • 数据流向: T [ 2 , 10 ] → t e x t _ e n c o d e r T f [ 2 , 768 ] T[2, 10]\xrightarrow{text\_encoder}T_f[2, 768] T[2,10]text_encoder Tf[2,768]
3. 特征投影与归一化
  • 图像特征投影与归一化
    • 投影矩阵 W i W_i Wi 的形状为 [ d i , d e ] = [ 2048 , 512 ] [d_i, d_e]=[2048, 512] [di,de]=[2048,512],先进行线性变换
      I p r o j = np.dot ( I f , W i ) I_{proj}=\text{np.dot}(I_f, W_i) Iproj=np.dot(If,Wi)
      得到投影后的图像特征 I p r o j I_{proj} Iproj,形状为 [ 2 , 512 ] [2, 512] [2,512]
    • 再进行 l 2 l2 l2 归一化
      I e = l 2 _ n o r m a l i z e ( I p r o j , a x i s = 1 ) I_e = l2\_normalize(I_{proj}, axis = 1) Ie=l2_normalize(Iproj,axis=1)
      得到最终的图像嵌入特征 I e I_e Ie,形状仍为 [ 2 , 512 ] [2, 512] [2,512]
    • 数据流向: I f [ 2 , 2048 ] → np.dot ( . , W i [ 2048 , 512 ] ) I p r o j [ 2 , 512 ] → l 2 _ n o r m a l i z e I e [ 2 , 512 ] I_f[2, 2048]\xrightarrow{\text{np.dot}(., W_i[2048, 512])}I_{proj}[2, 512]\xrightarrow{l2\_normalize}I_e[2, 512] If[2,2048]np.dot(.,Wi[2048,512]) Iproj[2,512]l2_normalize Ie[2,512]
  • 文本特征投影与归一化
    • 投影矩阵 W t W_t Wt 的形状为 [ d t , d e ] = [ 768 , 512 ] [d_t, d_e]=[768, 512] [dt,de]=[768,512],先进行线性变换
      T p r o j = np.dot ( T f , W t ) T_{proj}=\text{np.dot}(T_f, W_t) Tproj=np.dot(Tf,Wt)
      得到投影后的文本特征 T p r o j T_{proj} Tproj,形状为 [ 2 , 512 ] [2, 512] [2,512]
    • 再进行 l 2 l2 l2 归一化
      T e = l 2 _ n o r m a l i z e ( T p r o j , a x i s = 1 ) T_e = l2\_normalize(T_{proj}, axis = 1) Te=l2_normalize(Tproj,axis=1)
      得到最终的文本嵌入特征 T e T_e Te,形状仍为 [ 2 , 512 ] [2, 512] [2,512]
    • 数据流向: T f [ 2 , 768 ] → np.dot ( . , W t [ 768 , 512 ] ) T p r o j [ 2 , 512 ] → l 2 _ n o r m a l i z e T e [ 2 , 512 ] T_f[2, 768]\xrightarrow{\text{np.dot}(., W_t[768, 512])}T_{proj}[2, 512]\xrightarrow{l2\_normalize}T_e[2, 512] Tf[2,768]np.dot(.,Wt[768,512]) Tproj[2,512]l2_normalize Te[2,512]
4. 相似度计算
  • 计算缩放的余弦相似度
    l o g i t s = np.dot ( I e , T e T ) × np.exp ( t ) logits=\text{np.dot}(I_e, T_e^T)\times\text{np.exp}(t) logits=np.dot(Ie,TeT)×np.exp(t)
    其中 I e I_e Ie 形状为 [ 2 , 512 ] [2, 512] [2,512] T e T T_e^T TeT 形状为 [ 512 , 2 ] [512, 2] [512,2],相乘得到一个 [ 2 , 2 ] [2, 2] [2,2] 的矩阵。假设温度参数 t = 0.07 t = 0.07 t=0.07,则将相似度得分乘以 np.exp ( 0.07 ) \text{np.exp}(0.07) np.exp(0.07) 进行缩放。
  • 数据流向: I e [ 2 , 512 ] → np.dot ( . , T e T [ 512 , 2 ] ) sim_matrix [ 2 , 2 ] → × np.exp ( 0.07 ) l o g i t s [ 2 , 2 ] I_e[2, 512]\xrightarrow{\text{np.dot}(., T_e^T[512, 2])} \text{sim\_matrix}[2, 2]\xrightarrow{\times\text{np.exp}(0.07)}logits[2, 2] Ie[2,512]np.dot(.,TeT[512,2]) sim_matrix[2,2]×np.exp(0.07) logits[2,2]
5. 损失计算
  • 首先创建标签
    l a b e l s = np.arange ( n ) = [ 0 , 1 ] labels=\text{np.arange}(n)=[0, 1] labels=np.arange(n)=[0,1]
  • 从图像视角计算交叉熵损失
    l o s s i = c r o s s _ e n t r o p y _ l o s s ( l o g i t s , l a b e l s , a x i s = 0 ) loss_i = cross\_entropy\_loss(logits, labels, axis = 0) lossi=cross_entropy_loss(logits,labels,axis=0)
  • 从文本视角计算交叉熵损失
    l o s s t = c r o s s _ e n t r o p y _ l o s s ( l o g i t s , l a b e l s , a x i s = 1 ) loss_t = cross\_entropy\_loss(logits, labels, axis = 1) losst=cross_entropy_loss(logits,labels,axis=1)
  • 最终损失
    l o s s = l o s s i + l o s s t 2 loss=\frac{loss_i + loss_t}{2} loss=2lossi+losst
  • 数据流向: l o g i t s [ 2 , 2 ] , l a b e l s [ 2 ] → c r o s s _ e n t r o p y _ l o s s ( a x i s = 0 ) l o s s i logits[2, 2], labels[2]\xrightarrow{cross\_entropy\_loss(axis = 0)}loss_i logits[2,2],labels[2]cross_entropy_loss(axis=0) lossi l o g i t s [ 2 , 2 ] , l a b e l s [ 2 ] → c r o s s _ e n t r o p y _ l o s s ( a x i s = 1 ) l o s s t logits[2, 2], labels[2]\xrightarrow{cross\_entropy\_loss(axis = 1)}loss_t logits[2,2],labels[2]cross_entropy_loss(axis=1) losst l o s s i , l o s s t → . + . 2 l o s s loss_i, loss_t\xrightarrow{\frac{. +.}{2}}loss lossi,losst2.+. loss

通过不断最小化这个损失 l o s s loss loss,CLIP 模型可以学习到图像和文本之间的关联,使得相关的图像和文本在特征空间中更加接近。

3.zero-shot

在这里插入图片描述

假设有一张图片,图片里是一只毛茸茸、长着长耳朵、眼睛又大又圆的动物,实际上这是一只兔子。要使用 CLIP 模型对这张图片进行零样本分类,分类的类别有“兔子”“猫咪”“狗狗”。

3.1.步骤一:文本编码
  • 生成文本描述:为每个类别生成对应的文本描述,如下:
    • t 1 t_1 t1 = “一张兔子的图片”
    • t 2 t_2 t2 = “一张猫咪的图片”
    • t 3 t_3 t3 = “一张狗狗的图片”
  • 文本编码过程:设文本模型为 E t E_t Et,它会将输入的文本转换为固定长度的特征向量。假设文本模型 E t E_t Et 把输入文本映射到一个 512 维的向量空间。当把 t 1 t_1 t1 输入到文本模型 E t E_t Et 中,会得到一个 512 维的向量 v t 1 \mathbf{v}_{t_1} vt1,例如:
    v t 1 = [ 0.1 , 0.2 , ⋯   , 0.3 ] \mathbf{v}_{t_1}=[0.1, 0.2, \cdots, 0.3] vt1=[0.1,0.2,,0.3]
    同理,对于 t 2 t_2 t2 t 3 t_3 t3,分别得到:
    v t 2 = [ 0.4 , 0.5 , ⋯   , 0.6 ] \mathbf{v}_{t_2}=[0.4, 0.5, \cdots, 0.6] vt2=[0.4,0.5,,0.6]
    v t 3 = [ 0.7 , 0.8 , ⋯   , 0.9 ] \mathbf{v}_{t_3}=[0.7, 0.8, \cdots, 0.9] vt3=[0.7,0.8,,0.9]
3.2.步骤二:图像编码
  • 将包含兔子的那张图片输入到视觉模型 E i E_i Ei 中。视觉模型 E i E_i Ei 会对图片进行特征提取,同样将其映射到 512 维的向量空间,得到图像特征向量 v i \mathbf{v}_i vi,假设:
    v i = [ 0.15 , 0.22 , ⋯   , 0.33 ] \mathbf{v}_i=[0.15, 0.22, \cdots, 0.33] vi=[0.15,0.22,,0.33]
3.3.步骤三:相似度计算

使用余弦相似度公式 sim ( v 1 , v 2 ) = v 1 ⋅ v 2 ∥ v 1 ∥ ∥ v 2 ∥ \text{sim}(\mathbf{v}_1,\mathbf{v}_2)=\frac{\mathbf{v}_1\cdot\mathbf{v}_2}{\|\mathbf{v}_1\|\|\mathbf{v}_2\|} sim(v1,v2)=v1∥∥v2v1v2 来计算图像特征向量与每个文本特征向量之间的相似度。

  • 计算图像与“兔子”文本描述的相似度 s 1 s_1 s1
    首先计算分子 v i ⋅ v t 1 \mathbf{v}_i\cdot\mathbf{v}_{t_1} vivt1,点积运算就是对应元素相乘再相加,即:
    v i ⋅ v t 1 = 0.15 × 0.1 + 0.22 × 0.2 + ⋯ + 0.33 × 0.3 \mathbf{v}_i\cdot\mathbf{v}_{t_1}=0.15\times0.1 + 0.22\times0.2+\cdots+0.33\times0.3 vivt1=0.15×0.1+0.22×0.2++0.33×0.3
    然后计算分母,向量的模 ∥ v ∥ = ∑ i = 1 n v i 2 \|\mathbf{v}\|=\sqrt{\sum_{i = 1}^{n}v_i^2} v=i=1nvi2 ,所以
    ∥ v i ∥ = 0.1 5 2 + 0.2 2 2 + ⋯ + 0.3 3 2 \|\mathbf{v}_i\|=\sqrt{0.15^2 + 0.22^2+\cdots+0.33^2} vi=0.152+0.222++0.332
    ∥ v t 1 ∥ = 0. 1 2 + 0. 2 2 + ⋯ + 0. 3 2 \|\mathbf{v}_{t_1}\|=\sqrt{0.1^2 + 0.2^2+\cdots+0.3^2} vt1=0.12+0.22++0.32
    最后得到 s 1 = v i ⋅ v t 1 ∥ v i ∥ ∥ v t 1 ∥ s_1=\frac{\mathbf{v}_i\cdot\mathbf{v}_{t_1}}{\|\mathbf{v}_i\|\|\mathbf{v}_{t_1}\|} s1=vi∥∥vt1vivt1,假设计算结果 s 1 = 0.8 s_1 = 0.8 s1=0.8

  • 计算图像与“猫咪”文本描述的相似度 s 2 s_2 s2
    同样的方法,分子 v i ⋅ v t 2 = 0.15 × 0.4 + 0.22 × 0.5 + ⋯ + 0.33 × 0.6 \mathbf{v}_i\cdot\mathbf{v}_{t_2}=0.15\times0.4 + 0.22\times0.5+\cdots+0.33\times0.6 vivt2=0.15×0.4+0.22×0.5++0.33×0.6
    分母 ∥ v i ∥ \|\mathbf{v}_i\| vi 不变,
    ∥ v t 2 ∥ = 0. 4 2 + 0. 5 2 + ⋯ + 0. 6 2 \|\mathbf{v}_{t_2}\|=\sqrt{0.4^2 + 0.5^2+\cdots+0.6^2} vt2=0.42+0.52++0.62
    得到 s 2 = v i ⋅ v t 2 ∥ v i ∥ ∥ v t 2 ∥ s_2=\frac{\mathbf{v}_i\cdot\mathbf{v}_{t_2}}{\|\mathbf{v}_i\|\|\mathbf{v}_{t_2}\|} s2=vi∥∥vt2vivt2,假设计算结果 s 2 = 0.3 s_2 = 0.3 s2=0.3

  • 计算图像与“狗狗”文本描述的相似度 s 3 s_3 s3
    分子 v i ⋅ v t 3 = 0.15 × 0.7 + 0.22 × 0.8 + ⋯ + 0.33 × 0.9 \mathbf{v}_i\cdot\mathbf{v}_{t_3}=0.15\times0.7 + 0.22\times0.8+\cdots+0.33\times0.9 vivt3=0.15×0.7+0.22×0.8++0.33×0.9
    分母 ∥ v i ∥ \|\mathbf{v}_i\| vi 不变,
    ∥ v t 3 ∥ = 0. 7 2 + 0. 8 2 + ⋯ + 0. 9 2 \|\mathbf{v}_{t_3}\|=\sqrt{0.7^2 + 0.8^2+\cdots+0.9^2} vt3=0.72+0.82++0.92
    得到 s 3 = v i ⋅ v t 3 ∥ v i ∥ ∥ v t 3 ∥ s_3=\frac{\mathbf{v}_i\cdot\mathbf{v}_{t_3}}{\|\mathbf{v}_i\|\|\mathbf{v}_{t_3}\|} s3=vi∥∥vt3vivt3,假设计算结果 s 3 = 0.2 s_3 = 0.2 s3=0.2

3.4.步骤四:分类决策

使用公式 j ∗ = arg ⁡ max ⁡ j = 1 , 2 , 3 s j j^*=\arg\max_{j = 1,2,3} s_j j=argj=1,2,3maxsj 来找到最大相似度对应的索引。比较 s 1 = 0.8 s_1 = 0.8 s1=0.8 s 2 = 0.3 s_2 = 0.3 s2=0.3 s 3 = 0.2 s_3 = 0.2 s3=0.2,可以发现 s 1 s_1 s1 最大,所以 j ∗ = 1 j^* = 1 j=1,这意味着模型将这张图片分类为“兔子”。

3.5.代码
import torch
import clip
from PIL import Image

# 加载CLIP模型和预训练权重
device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load("ViT-B/32", device=device)

# 定义分类类别
categories = ["兔子", "猫咪", "狗狗"]
text_descriptions = [f"一张{category}的图片" for category in categories]
text_tokens = clip.tokenize(text_descriptions).to(device)

# 加载待分类的图像
image_path = "test_image.jpg"
image = Image.open(image_path).convert("RGB")
image_input = preprocess(image).unsqueeze(0).to(device)

# 文本编码
with torch.no_grad():
    text_features = model.encode_text(text_tokens)
    text_features /= text_features.norm(dim=-1, keepdim=True)

    # 图像编码
    image_features = model.encode_image(image_input)
    image_features /= image_features.norm(dim=-1, keepdim=True)

# 相似度计算
similarities = (100.0 * image_features @ text_features.T).softmax(dim=-1)

# 分类决策
predicted_index = similarities.argmax().item()
predicted_category = categories[predicted_index]

相关文章:

  • 985本硕,网络安全方向,走算法还是走开发?
  • 【会议预告】人工智能与材料国际学术会议
  • 沃丰科技大模型标杆案例 | 索尼大模型智能营销机器人建设实践
  • 短视频矩阵碰一碰发视频源码技术开发,支持OEM
  • bypy的依赖库版本问题
  • STL —— 洛谷字符串(string库)入门题(蓝桥杯题目训练)(一)
  • Ubuntu24安装MongoDB(解压版)
  • 使用docker-compose运行服务
  • IM聊天系统架构实现
  • day12_调度和可视化
  • org.mortbay.jetty和org.eclipse.jetty的区别
  • 论文笔记:Scaling LLM Test-Time Compute Optimally can be More Effective than Scaling
  • 罗格科技发布全球首款税务智能合规终端“罗拉DeepTax双引擎AI一体机”
  • Grok 3当前唯一跑分超过1400分的模型,Grok 2 和 Grok 3 如何使用
  • 燕云十六声武器心法搭配推荐 燕云十六声心法怎么选择
  • GitBash输出中文乱码处理
  • 【ISO 14229-1:2023 UDS诊断(ECU复位0x11服务)测试用例CAPL代码全解析⑬】
  • 青少年编程与数学 02-009 Django 5 Web 编程 21课题、部署
  • idea-gradle打包运行配置
  • DeepSeek企业级部署实战指南:从服务器选型到Dify私有化落地
  • 绿景中国地产:洛杉矶酒店出售事项未能及时披露纯属疏忽,已采取补救措施
  • 将人工智能送上太空,我国太空计算卫星星座成功发射
  • 山东市监局回应“盒马一批次‘无抗’鸡蛋抽检不合格后复检合格”:系生产商自行送检
  • 4月份全国企业销售收入同比增长4.3%
  • 风雨天涯梦——《袁保龄公牍》发微
  • 彭丽媛同巴西总统夫人罗桑热拉参观中国国家大剧院