一、CLIP 是什么
CLIP 的全称是:
Contrastive Language-Image Pre-training
中文通常翻译为:
对比式语言---图像预训练。
CLIP 的核心目标,是让模型学习图片和自然语言之间的语义对应关系。
它不是传统意义上的固定类别图像分类器,也不是能够直接生成句子的图像描述模型。
CLIP 本质上包含两个编码器:
- 图片编码器 Image Encoder
- 文本编码器 Text Encoder
图片编码器负责:
图片 -> 图片特征向量
文本编码器负责:
文本 -> 文本特征向量
随后,CLIP 比较图片向量和文本向量之间的相似度。
如果图片和文本表达的是同一个内容,模型希望它们的向量相似度较高;如果二者语义不匹配,模型希望它们的相似度较低。
例如:
图片:一只金毛犬在草地上奔跑
候选文本:
- 一只狗在草地上奔跑
- 一辆红色汽车
- 一碗面条
CLIP 应该让图片向量与第一段文本向量最接近,而与其他文本向量相距较远。
二、CLIP 最核心的思想
CLIP 学习的不是:
图片 -> 固定类别编号
而是:
图片 -> 图片语义向量
文本 -> 文本语义向量
然后:
图片语义向量与文本语义向量 -> 相似度
因此,CLIP 的核心可以概括为:
让匹配的图片和文本在向量空间中靠近,让不匹配的图片和文本在向量空间中远离。
这里的"向量空间"可以理解为一种统一的语义坐标系。
例如,经过训练以后,下面这些内容对应的向量可能比较接近:
- 一张金毛犬的图片
- 一张拉布拉多犬的图片
- "a photo of a dog"
- "a golden retriever running"
- "a pet playing outdoors"
而这些内容的向量通常会离得较远:
- 一张狗的图片
- "a passenger airplane"
三、为什么需要 CLIP
1. 传统图像分类模型的问题
普通图像分类模型一般是:
图片 -> 图像骨干网络 -> 分类层 -> 固定类别概率
例如训练时固定为四个类别:
- 猫
- 狗
- 汽车
- 飞机
模型输出可能是:
猫:0.10
狗:0.80
汽车:0.07
飞机:0.03
这种模型的类别在训练时通常已经确定。
如果后来增加一个新类别"羊驼",往往需要:
- 收集羊驼图片;
- 对图片进行人工标注;
- 修改分类层;
- 重新训练或者微调模型。
2. CLIP 的区别
CLIP 不需要在模型内部固定所有类别。
推理时可以临时输入候选文本:
- a photo of a cat
- a photo of a dog
- a photo of an alpaca
- a photo of a car
文本编码器会把这些类别描述转换成文本向量,然后与图片向量比较。
因此,CLIP 可以根据推理时提供的文本动态定义类别。
这也是 CLIP 能够进行零样本分类和开放词汇识别的重要原因。
四、CLIP 的整体结构
CLIP 是一个典型的双塔模型,也叫 Dual Encoder。
整体流程如下:
图片
-> 图片编码器
-> 图片原始特征
-> 图片投影层
-> 图片语义向量
文本
-> 分词器
-> 文本编码器
-> 文本原始特征
-> 文本投影层
-> 文本语义向量
最后:
图片语义向量 + 文本语义向量
-> 归一化
-> 计算相似度
CLIP 的两个编码器参数不共享。
所谓"共享语义空间",是指图片编码器和文本编码器最终输出的向量具有相同维度,并且可以直接计算相似度。
五、图片编码器
CLIP 的图片编码器可以使用不同的视觉网络,例如:
- ResNet
- Vision Transformer,也就是 ViT
图片编码器的作用是把一张图片转换成特征向量。
假设输入图片为 x,图片编码器的模型参数为 theta_image,那么:
图片特征 = image_encoder(x, theta_image)
可以写成普通文本形式:
h_image = f_image(x; theta_image)
然后通过一个投影层,把视觉特征映射到统一的多模态空间:
z_image = h_image × W_image
其中:
- h_image 是图片编码器输出的原始视觉特征;
- W_image 是图片投影层参数;
- z_image 是最终用于图文比较的图片向量。
例如,最终可能得到一个 512 维向量:
z_image = 0.12, -0.36, 0.81, ..., 0.25
这个向量本身不是"狗""猫"或者"汽车"的概率,而是图片在语义空间中的表示。
六、文本编码器
CLIP 的文本编码器通常使用 Transformer。
例如输入:
a photo of a dog
首先经过分词器,转换成 token:
a, photo, of, a, dog, end_token
然后输入文本 Transformer:
文本特征 = text_encoder(tokens, theta_text)
普通文本公式为:
h_text = f_text(tokens; theta_text)
再经过文本投影层:
z_text = h_text × W_text
最终得到文本语义向量:
z_text = 0.10, -0.31, 0.78, ..., 0.20
如果这段文字准确描述了输入图片,那么图片向量和文本向量应该比较接近。
七、模型参数和特征向量的区别
这是理解 CLIP 时最重要的区别之一。
1. 模型参数是什么
模型参数包括:
- 卷积核权重;
- Transformer Attention 的 Q、K、V 权重;
- 全连接层权重;
- LayerNorm 参数;
- 图片投影层权重;
- 文本投影层权重;
- 温度缩放参数。
模型参数的作用是:
决定如何把图片或者文本转换成语义向量。
可以理解为:
模型参数 = 计算特征向量的方法和规则
2. 特征向量是什么
特征向量是输入数据经过模型参数计算后得到的结果。
例如:
图片 + 图片编码器参数 -> 图片向量
文字 + 文本编码器参数 -> 文本向量
可以写成:
图片向量 = image_encoder(图片;图片模型参数)
文本向量 = text_encoder(文字;文本模型参数)
3. 图片向量不是与模型参数比较
输入一张图片后,正确流程不是:
图片向量 -> 与模型参数比较 -> 得到概率
而是:
图片
-> 使用模型参数进行前向计算
-> 得到图片向量
-> 与候选文本向量比较
-> 得到相似度
-> 转换成候选类别的相对概率
因此:
模型参数负责生成向量。
真正进行相似度比较的是图片向量和文本向量。
八、CLIP 的训练数据
CLIP 使用大量图片---文本配对数据进行训练。
每条训练数据通常包含:
- 一张图片;
- 一段与图片有关的文本。
例如:
图片 1:一只狗在草地上奔跑
文本 1:a dog running on the grass
图片 2:一辆红色跑车
文本 2:a red sports car
图片 3:两个人正在打篮球
文本 3:two people playing basketball
这些文本可能来自:
- 图片标题;
- 网页中的图片说明;
- 图片附近的文字;
- 人工描述;
- 其他图文对应数据。
CLIP 不要求文本一定是严格的类别标签。
相比传统分类数据:
图片 -> 类别编号
CLIP 使用的是:
图片 -> 自然语言描述
九、CLIP 是如何训练的
1. 按 batch 读取图文对
假设一个 batch 中有 4 组正确图文对:
图片 0:猫
文本 0:a photo of a cat
图片 1:狗
文本 1:a photo of a dog
图片 2:汽车
文本 2:a photo of a car
图片 3:飞机
文本 3:a photo of an airplane
这里默认:
图片 0 和文本 0 是正确配对;
图片 1 和文本 1 是正确配对;
以此类推。
2. 计算图片特征
4 张图片分别输入同一个图片编码器,得到图片特征矩阵:
I = i0, i1, i2, i3
假设每个向量维度为 d,那么:
I 的形状 = batch_size × d
如果 batch_size = 4,d = 512,那么:
I 的形状 = 4 × 512
3. 计算文本特征
4 段文本输入同一个文本编码器,得到文本特征矩阵:
T = t0, t1, t2, t3
其形状同样为:
T 的形状 = 4 × 512
4. 对向量进行归一化
图片向量归一化:
i_normalized = i / L2_norm(i)
文本向量归一化:
t_normalized = t / L2_norm(t)
其中 L2 范数的文本公式为:
L2_norm(x) = sqrt(x1² + x2² + ... + xd²)
归一化后,每个向量长度为 1。
5. 计算图文相似度矩阵
图片特征矩阵和文本特征矩阵相乘:
similarity_matrix = I_normalized × transpose(T_normalized)
如果 batch 中有 4 对图文,那么会得到一个 4 × 4 的矩阵:
文本0 文本1 文本2 文本3
图片0 s00 s01 s02 s03
图片1 s10 s11 s12 s13
图片2 s20 s21 s22 s23
图片3 s30 s31 s32 s33
其中:
s_ij = 图片 i 与文本 j 的余弦相似度
正确配对位于主对角线上:
- s00
- s11
- s22
- s33
模型希望:
- 对角线相似度高;
- 非对角线相似度低。
十、余弦相似度
图片向量和文本向量通常通过余弦相似度进行比较。
普通文本公式为:
cosine_similarity(a, b) = dot(a, b) / (L2_norm(a) × L2_norm(b))
其中:
dot(a, b) = a1×b1 + a2×b2 + ... + ad×bd
如果 a 和 b 已经完成 L2 归一化,那么:
cosine_similarity(a, b) = dot(a, b)
也就是说,归一化向量之间的点积就等于余弦相似度。
余弦相似度通常位于:
-1 到 1 之间
基本含义:
- 接近 1:方向很接近,语义相似度较高;
- 接近 0:语义关系较弱;
- 接近 -1:方向相反。
在实际 CLIP 中,最终用于 Softmax 的通常不是未经处理的余弦相似度,而是经过温度缩放后的分数。
十一、温度系数和 logit scale
CLIP 会对余弦相似度进行缩放。
一种写法是:
logit_ij = similarity_ij / temperature
另一种等价写法是:
logit_ij = exp(logit_scale) × similarity_ij
其中:
exp(logit_scale) = 1 / temperature
如果温度较小,相似度差异会被放大,Softmax 输出会更加集中。
例如,原始相似度为:
狗:0.31
猫:0.28
汽车:0.12
如果不缩放,三者差异可能并不明显。
乘以较大的缩放系数后:
狗:31
猫:28
汽车:12
再经过 Softmax,模型会更加明确地偏向"狗"。
需要注意:
温度不是用于改变图片和文本的语义关系,而是用于调节分类分布的尖锐程度和训练梯度。
十二、CLIP 的损失函数
CLIP 使用双向对比学习。
它不仅要求:
给定一张图片,在所有文本中找到正确文本;
还要求:
给定一段文本,在所有图片中找到正确图片。
1. 图片到文本损失
对于图片 i,正确文本是文本 i。
图片到文本损失可以写成:
loss_image_to_text = average over i of:
-negative log(
exp(logit_ii)
/
sum over j of exp(logit_ij)
)
更直观地说:
对相似度矩阵的每一行做交叉熵。
例如,第一行表示:
图片 0 与所有文本的匹配分数。
它的正确答案是文本 0。
2. 文本到图片损失
对于文本 i,正确图片是图片 i。
文本到图片损失可以写成:
loss_text_to_image = average over i of:
-negative log(
exp(logit_ii)
/
sum over j of exp(logit_ji)
)
更直观地说:
对相似度矩阵的每一列做交叉熵。
例如,第一列表示:
文本 0 与所有图片的匹配分数。
它的正确答案是图片 0。
3. 最终损失
最终 CLIP 损失为:
clip_loss = (loss_image_to_text + loss_text_to_image) / 2
这是一种对称对比损失,也可以理解为双向 InfoNCE 损失。
十三、正样本和负样本
假设 batch 中有 N 对图文数据。
相似度矩阵一共有:
N × N
个图文组合。
其中正确配对数量为:
N
非对角线组合数量为:
N² - N
例如 batch_size = 4:
总组合数 = 4 × 4 = 16
正样本数 = 4
负样本数 = 16 - 4 = 12
因此,CLIP 可以直接把同一个 batch 中其他不对应的文本和图片作为负样本。
这种方式叫作:
batch 内负样本,或者 in-batch negatives。
假负样本问题
并不是所有非对角线组合在语义上都一定错误。
例如:
图片 1:一只金毛犬
文本 1:a golden retriever
图片 2:另一只狗在户外玩耍
文本 2:a dog playing outside
对于图片 1 来说,文本 2 不是它的原始配对,因此在训练目标中被当作负样本。
但从语义上看,文本 2 也可能适合图片 1。
这种情况称为假负样本。
所以 CLIP 的"负样本"更准确的含义是:
它不是当前数据中指定的原始配对项。
十四、训练时到底保存什么
这是一个非常重要的问题。
CLIP 训练时会计算当前 batch 的图片---文本相似度矩阵,但不会把所有相似度长期保存下来。
一个 batch 的流程是:
读取当前 batch
-> 编码图片和文本
-> 计算相似度矩阵
-> 计算损失
-> 反向传播
-> 更新模型参数
-> 当前特征和相似度矩阵被释放或覆盖
-> 读取下一个 batch
最终保存的主要是:
- 图片编码器参数;
- 文本编码器参数;
- 图片投影层参数;
- 文本投影层参数;
- 温度缩放参数;
- 可能还包括优化器状态等训练信息。
不会保存:
图片 1 和文本 1 的相似度是 0.85
图片 1 和文本 2 的相似度是 0.13
图片 2 和文本 3 的相似度是 0.29
换句话说:
CLIP 保存的不是所有训练样本之间的相似度表。
CLIP 保存的是如何计算语义向量的能力。
十五、CLIP 是不是一个数据库
CLIP 本身不是数据库。
CLIP 是一个神经网络模型,负责:
- 把图片转换成图片向量;
- 把文字转换成文本向量;
- 计算图片和文本之间的匹配程度。
数据库或者向量数据库则负责:
- 保存大量图片向量;
- 保存大量文本向量;
- 对向量进行近邻搜索;
- 返回最相似的数据。
因此:
CLIP = 特征提取和语义对齐模型
向量数据库 = 特征存储与检索系统
二者可以组合,但并不是同一个东西。
十六、CLIP 的零样本分类流程
假设需要识别一张图片属于哪个类别,候选类别为:
- 猫
- 狗
- 汽车
- 飞机
第一步:构造候选文本
可以使用:
- a photo of a cat
- a photo of a dog
- a photo of a car
- a photo of an airplane
第二步:计算候选文本向量
猫文本向量 = text_encoder("a photo of a cat")
狗文本向量 = text_encoder("a photo of a dog")
汽车文本向量 = text_encoder("a photo of a car")
飞机文本向量 = text_encoder("a photo of an airplane")
第三步:计算输入图片向量
图片向量 = image_encoder(输入图片)
第四步:计算图片与所有文本的相似度
猫分数 = cosine_similarity(图片向量, 猫文本向量)
狗分数 = cosine_similarity(图片向量, 狗文本向量)
汽车分数 = cosine_similarity(图片向量, 汽车文本向量)
飞机分数 = cosine_similarity(图片向量, 飞机文本向量)
第五步:温度缩放
猫 logit = 猫分数 / temperature
狗 logit = 狗分数 / temperature
汽车 logit = 汽车分数 / temperature
飞机 logit = 飞机分数 / temperature
第六步:Softmax
对于第 k 个候选类别:
probability_k = exp(logit_k) / sum(exp(all logits))
例如最终可能得到:
猫:1.2%
狗:98.5%
汽车:0.2%
飞机:0.1%
于是模型返回"狗"。
十七、CLIP 的概率是什么意思
CLIP 的 Softmax 概率通常是:
当前候选文本集合内部的相对概率。
它不是所有可能现实类别上的绝对概率。
假设输入实际是一架飞机,但候选类别只有:
- 猫
- 狗
- 汽车
CLIP 仍然必须在这三个候选中选出一个最相似的。
例如可能输出:
汽车:70%
狗:20%
猫:10%
这不能解释为:
模型真的有 70% 的绝对把握认为它是汽车。
更准确的解释是:
在当前提供的"猫、狗、汽车"三个候选项中,"汽车"的文本向量与输入图片向量最接近。
因此,在实际系统中,如果可能出现未知类别,通常需要:
- 增加"其他"候选类别;
- 设置最低相似度阈值;
- 做开放集识别;
- 使用额外的校准模型;
- 对候选类别进行合理设计。
十八、Prompt Engineering
CLIP 的结果会受到候选文本写法影响。
例如以下文本可能产生不同的向量:
- dog
- a dog
- a photo of a dog
- a close-up photo of a dog
- a blurry photo of a dog
通常完整自然语言描述比孤立类别词更接近 CLIP 的预训练文本分布。
因此,零样本分类时常使用提示模板:
a photo of a {class_name}
例如:
a photo of a cat
a photo of a dog
a photo of a car
Prompt Ensembling
可以为同一个类别准备多个模板:
- a photo of a dog
- a picture of a dog
- a close-up photo of a dog
- a blurry photo of a dog
- a photo of the dog
然后分别计算文本向量,再对它们进行平均。
普通文本公式为:
类别平均向量 = 所有模板文本向量之和 / 模板数量
随后再次进行归一化:
最终类别向量 = 类别平均向量 / L2_norm(类别平均向量)
这种方法可以降低模型对某个单一提示词模板的敏感性。
十九、零样本的真正含义
CLIP 的零样本分类不是指:
模型历史上从未看过"狗""猫"或者"汽车"。
它指的是:
没有使用当前目标数据集的标注训练样本,专门训练一个新的分类头。
例如,在某个图像分类数据集上测试时:
- 不使用该数据集训练一个固定类别分类器;
- 不微调模型;
- 只输入类别名称或者类别描述;
- 直接比较图片与类别文本的相似度。
因此,更准确的说法是:
零样本下游迁移。
预训练数据中仍然可能包含相关概念。
二十、没有候选文本时,CLIP 能否回答"图片里是什么"
纯 CLIP 不能直接回答。
如果只输入一张图片:
图片
-> 图片编码器
-> 图片特征向量
到这里,CLIP 的工作就结束了。
它只能输出类似:
0.12, -0.35, 0.76, ..., 0.08
这样的向量。
它不能自动生成:
"图片中有一只金毛犬正在草地上奔跑。"
原因是 CLIP 没有文本生成解码器。
CLIP 只有:
- 图片编码器;
- 文本编码器。
它没有:
- 自回归语言模型;
- 文本生成头;
- 按 token 逐个生成句子的能力。
因此,纯 CLIP 更像一个选择题模型:
这张图片与候选 A、B、C、D 中的哪一个最匹配?
它不是开放式问答模型:
请自由描述这张图片里有什么。
二十一、为什么有些使用 CLIP 的程序可以显示图片标签
通常有三种可能。
1. 程序内部准备了一个候选标签库
例如标签库包含:
- 猫
- 狗
- 金毛犬
- 拉布拉多犬
- 汽车
- 公交车
- 草地
- 建筑物
- 篮球运动员
输入图片后,程序把图片向量与所有标签文本向量比较,然后返回相似度最高的若干标签。
这种系统看起来像是在"回答图片里是什么",但本质上仍然是从候选库中选择。
如果标签库没有某个概念,模型就无法准确输出该标签。
2. CLIP 与图像描述模型组合
系统可能是:
图片
-> CLIP 或其他视觉编码器
-> 视觉特征
-> 文本解码器
-> 生成图片描述
这时真正生成句子的是文本解码器,而不是 CLIP 本身。
3. CLIP 与大语言模型组合
系统可能是:
图片
-> 视觉编码器
-> 视觉 token
-> Projector 或连接模块
-> 大语言模型
-> 自然语言回答
这类模型才属于完整的视觉语言大模型。
二十二、CLIP 与图像描述模型的区别
CLIP
输入:
图片 + 候选文本
输出:
图片和每段文本之间的相似度
主要任务:
- 零样本分类;
- 图文检索;
- 特征提取;
- 语义匹配;
- 数据筛选;
- 开放词汇识别。
图像描述模型
输入:
图片
输出:
自然语言描述
例如:
"一只金毛犬正在草地上奔跑。"
图像描述模型通常需要:
视觉编码器 + 文本生成解码器
CLIP 缺少文本生成解码器,所以不能直接生成图片描述。
二十三、CLIP 与 VLM 的关系
CLIP 可以看作现代视觉语言模型的重要基础之一,但 CLIP 本身不是完整的对话式 VLM。
CLIP 的主要目标
图片与文本语义对齐。
结构通常是:
图片 -> 图片编码器 -> 图片向量
文字 -> 文本编码器 -> 文本向量
图片向量与文本向量 -> 相似度
对话式 VLM 的主要目标
理解图片、接受问题、执行推理并生成自然语言答案。
典型结构是:
图片
-> 视觉编码器
-> 多个视觉 token
-> Projector 或 Q-Former
-> 大语言模型
-> 生成答案
可以概括为:
CLIP 重点是对齐和匹配。
VLM 重点是理解、推理和生成。
二十四、CLIP 的图文检索
1. 文本搜索图片
假设图库中有 100 万张图片。
可以提前执行:
图片 1 -> Image Encoder -> 图片向量 1
图片 2 -> Image Encoder -> 图片向量 2
......
图片 100 万 -> Image Encoder -> 图片向量 100 万
然后把这些图片向量保存到向量数据库。
用户输入:
"一只在雪地中奔跑的白色狗"
系统执行:
查询文本
-> Text Encoder
-> 查询文本向量
-> 与数据库中的所有图片向量比较
-> 返回最相似图片
此时比较的是:
查询文本向量与图库图片向量
2. 图片搜索文本
如果有一个固定文本库,也可以提前保存文本向量:
文本 1 -> 文本向量 1
文本 2 -> 文本向量 2
......
文本 N -> 文本向量 N
用户输入图片后:
输入图片
-> 图片编码器
-> 图片向量
-> 与文本库中的文本向量比较
-> 返回最相似文本
二十五、检索系统保存的是特征,不是全部相似度
在图文检索系统中,通常保存:
- 图片向量;
- 文本向量;
- 对应的图片路径、ID、标题等元数据。
通常不会提前保存所有图片与所有文本的两两相似度。
假设有:
100 万张图片
100 万段文本
所有两两组合数量为:
1,000,000 × 1,000,000 = 1,000,000,000,000
即一万亿个相似度。
如果每个相似度使用 FP32,占 4 字节,那么需要大约:
4 × 1,000,000,000,000 字节
即约 4 TB。
而保存 100 万个 512 维 FP32 图片向量,需要:
1,000,000 × 512 × 4 字节
约等于 2.048 GB。
所以工程上更合理的方法是:
保存特征向量,需要查询时再计算相似度或进行近似最近邻搜索。
二十六、CLIP 与传统分类器的数学关系
1. 传统线性分类器
假设图片编码器输出图片特征 h。
分类层参数为 W 和 b。
传统分类器的输出为:
logits = h × transpose(W) + b
其中 W 的每一行可以理解为一个固定类别对应的权重。
例如:
W_cat
W_dog
W_car
W_airplane
这些类别权重是训练后固定在模型参数中的。
2. CLIP 零样本分类
CLIP 的图片特征为 V。
候选文本特征为 T。
输出为:
logits = scale × V × transpose(T)
这里的 T 不是固定分类层参数,而是候选文本经过文本编码器动态计算出的向量。
因此,可以把 CLIP 理解为:
使用自然语言动态生成分类器的类别权重。
传统分类器:
类别权重由训练过程直接学习,并固定在分类层中。
CLIP:
类别权重由文本编码器根据类别描述动态生成。
这是 CLIP 与传统固定类别分类器最核心的区别之一。
二十七、CLIP 的简化训练伪代码
下面使用普通伪代码描述 CLIP 训练过程。
text
输入:
batch_images
batch_texts
步骤 1:
image_features = image_encoder(batch_images)
步骤 2:
text_features = text_encoder(batch_texts)
步骤 3:
image_features = L2_normalize(image_features)
步骤 4:
text_features = L2_normalize(text_features)
步骤 5:
logits_per_image =
exp(logit_scale)
× image_features
× transpose(text_features)
步骤 6:
logits_per_text = transpose(logits_per_image)
步骤 7:
labels = [0, 1, 2, ..., batch_size - 1]
步骤 8:
image_to_text_loss =
cross_entropy(logits_per_image, labels)
步骤 9:
text_to_image_loss =
cross_entropy(logits_per_text, labels)
步骤 10:
total_loss =
(image_to_text_loss + text_to_image_loss) / 2
步骤 11:
backward(total_loss)
步骤 12:
update_model_parameters()
标签是:
0, 1, 2, ..., N - 1
因为正确图文对位于相似度矩阵的主对角线上。
图片 0 对应文本 0。
图片 1 对应文本 1。
图片 2 对应文本 2。
二十八、一个完整数值示例
假设 batch 中有三对图文:
图片 0:猫
文本 0:a cat
图片 1:狗
文本 1:a dog
图片 2:汽车
文本 2:a car
经过编码和归一化后,得到相似度矩阵:
猫文本 狗文本 汽车文本
猫图片 0.80 0.45 0.10
狗图片 0.40 0.90 0.20
汽车图片 0.08 0.15 0.85
正确答案位于主对角线:
猫图片与猫文本:0.80
狗图片与狗文本:0.90
汽车图片与汽车文本:0.85
训练时,模型要努力:
- 提高 0.80、0.90、0.85;
- 降低其他非对角线分数。
对于猫图片这一行:
正确文本是猫文本。
图片到文本的分类目标是:
在猫文本、狗文本、汽车文本中选择猫文本。
对于猫文本这一列:
正确图片是猫图片。
文本到图片的分类目标是:
在猫图片、狗图片、汽车图片中选择猫图片。
二十九、CLIP 为什么可以泛化到新图片
CLIP 不是简单记住每张训练图片。
训练过程中,模型参数逐渐学习到:
- 视觉形状与语言概念之间的关系;
- 物体外观与名称之间的关系;
- 场景、动作、属性与自然语言之间的关系;
- 不同表达方式之间的语义关联。
例如,模型可能学习到:
- 狗通常具有某些视觉特征;
- "dog""puppy""golden retriever"在语义上有关联;
- 草地、奔跑、宠物等概念可能出现在相关图文中。
因此,面对没有在训练中原样出现的新图片时,模型仍然可以根据学习到的映射规则生成有意义的图片向量。
可以类比为:
模型没有保存每一道题的答案。
模型学习了解题方法。
三十、CLIP 的主要应用
1. 零样本图像分类
不针对目标数据集重新训练分类头,直接使用类别文本进行分类。
2. 文本搜索图片
输入自然语言,在图库中寻找语义最相符的图片。
3. 图片搜索文本
输入图片,从标题、标签或描述库中寻找最匹配文本。
4. 图片特征提取
使用 CLIP 图片编码器生成具有语言语义的视觉特征。
5. 图片聚类
根据 CLIP 特征向量对语义相似图片进行聚类。
6. 数据清洗
计算图文相似度,筛除图片与文字明显不匹配的数据。
7. 开放词汇识别
推理时动态输入新的类别名称或者类别描述。
8. 多模态模型视觉编码器
把 CLIP 或类似视觉编码器接入语言模型,为 VLM 提供视觉特征。
9. 文生图模型中的语义约束
某些生成系统会使用 CLIP 相似度评估生成图片与目标文本是否匹配。
三十一、CLIP 的局限性
1. 不能直接生成自然语言
纯 CLIP 没有语言生成解码器。
2. 依赖候选文本
做分类时,需要提供合理的候选类别或候选描述。
3. 对 Prompt 较敏感
不同提示模板可能产生不同分类结果。
4. 候选类别不完整会导致错误
真实类别不在候选集合中时,模型仍会在现有候选中选择一个最高分结果。
5. 概率不一定经过良好校准
Softmax 输出表示候选项之间的相对偏好,不一定等于现实中的绝对置信度。
6. 细粒度识别能力可能不足
例如:
- 相近型号汽车;
- 相似鸟类品种;
- 精细医学影像类别;
- 细微工业缺陷。
这些任务通常需要领域数据微调。
7. 空间关系能力有限
例如:
- 红球在蓝盒子左边;
- 红球在蓝盒子右边。
这两段文字只差一个关系词,CLIP 的全局向量可能不容易稳定区分。
8. 计数能力有限
例如:
- 图片中有三只狗;
- 图片中有四只狗。
CLIP 可能能识别"狗",但不一定准确识别数量。
9. 互联网数据中的偏差
训练数据中可能存在:
- 错误文本;
- 噪声配对;
- 文化偏差;
- 类别分布不均;
- 刻板印象;
- 长尾类别不足。
这些问题可能影响最终模型。
三十二、CLIP 的下游使用方式
1. 纯零样本
不训练任何新参数。
图片和候选文本分别编码后直接计算相似度。
优点:
- 不需要标注数据;
- 类别可以灵活变化;
- 使用简单。
缺点:
- 对领域和 Prompt 敏感;
- 精度可能不如专门训练模型。
2. Linear Probe
冻结 CLIP 图片编码器,只训练一个线性分类器。
流程:
图片
-> 冻结的 CLIP 图片编码器
-> 图片特征
-> 可训练线性分类层
-> 固定类别概率
作用:
评估 CLIP 图像特征对当前任务的可分性。
3. 全量微调
更新图片编码器、文本编码器和投影层等参数。
优点:
- 领域适应能力强;
- 可能获得更高精度。
缺点:
- 显存和计算开销大;
- 数据较少时容易过拟合;
- 可能破坏原始通用语义空间。
4. 参数高效微调
常见方式包括:
- LoRA;
- Adapter;
- Prompt Tuning;
- Visual Prompt Tuning;
- 只训练投影层;
- 只训练最后几层;
- 冻结文本编码器,仅微调视觉编码器。
三十三、CLIP 在部署中的优化
结合 ONNX、TensorRT、RKNN 或 NPU 部署,可以根据任务特点拆分 CLIP。
1. 固定类别分类
假设类别长期固定:
- person
- car
- bicycle
- dog
- cat
文本向量可以提前离线计算:
类别文本
-> Text Encoder
-> 文本向量
-> 保存到文件
例如保存为:
text_features.npy
运行时只需要:
输入图片
-> Image Encoder
-> 图片向量
-> Normalize
-> 与预计算文本向量矩阵相乘
-> Softmax
此时端侧设备不一定需要部署文本编码器。
运行时主要模块为:
- Image Encoder;
- L2 Normalize;
- Matrix Multiplication;
- Softmax;
- Top-K。
2. 文本搜索固定图库
如果图库固定,则提前计算并保存所有图片向量。
运行时只运行文本编码器,再进行向量搜索。
3. 图片搜索固定文本库
如果文本标签库固定,则提前计算并保存文本向量。
运行时只运行图片编码器。
4. 量化
可以考虑:
- FP16;
- INT8;
- 图片编码器量化;
- 文本编码器离线运行;
- 向量存储使用 FP16;
- 近似最近邻检索。
需要注意,归一化、相似度计算和温度缩放可能对量化误差较敏感,需要单独验证精度。
三十四、训练阶段与推理阶段的区别
训练阶段
大量图文对
-> 分 batch
-> 编码图片和文本
-> 计算当前 batch 的 N × N 相似度矩阵
-> 计算双向对比损失
-> 反向传播
-> 更新模型参数
训练阶段保存:
模型参数。
零样本分类阶段
输入图片
-> 图片编码器
-> 图片向量
候选类别文本
-> 文本编码器
-> 文本向量
图片向量与候选文本向量比较
-> 相似度
-> Softmax
-> 分类结果
检索阶段
固定数据提前编码
-> 保存特征向量
用户查询
-> 编码查询
-> 与数据库特征比较
-> 返回最相似结果
三十五、最容易混淆的几个问题
问题 1:CLIP 是否保存所有训练图片和文本的相似度?
不是。
当前 batch 的相似度只用于计算损失,之后会被释放或覆盖。
最终保存的是模型参数。
问题 2:输入图片后,图片向量是否与模型参数比较?
不是直接比较。
模型参数用于计算图片向量。
图片向量随后与候选文本向量或数据库中的其他向量比较。
问题 3:CLIP 是否根据模型参数直接输出类别概率?
纯 CLIP 通常先输出图片与候选文本之间的匹配分数。
只有提供候选文本以后,才能通过相似度和 Softmax 得到候选集合内的相对概率。
问题 4:没有候选文本时,CLIP 能否回答"图片里是什么"?
不能。
它只能输出图片特征向量。
要生成自然语言描述,需要文本生成解码器或者大语言模型。
问题 5:CLIP 是否等于 VLM?
不等于。
CLIP 主要负责图文对齐和相似度计算。
完整 VLM 还需要语言生成和多模态交互能力。
问题 6:CLIP 是否只能识别训练时固定的类别?
不是。
它可以通过新的文本描述动态构造候选类别。
但前提是模型在预训练中学到了相关视觉和语言概念。
三十六、用一个完整流程理解 CLIP
假设输入一张金毛犬图片,并希望在以下类别中分类:
- 猫
- 狗
- 汽车
完整流程如下。
第一步:图片编码
金毛犬图片
-> 图片编码器使用训练好的模型参数
-> 图片原始特征
-> 图片投影层
-> 图片向量 v
第二步:文本编码
"a photo of a cat"
-> 文本编码器
-> 猫文本向量 t_cat
"a photo of a dog"
-> 文本编码器
-> 狗文本向量 t_dog
"a photo of a car"
-> 文本编码器
-> 汽车文本向量 t_car
第三步:特征归一化
v = v / L2_norm(v)
t_cat = t_cat / L2_norm(t_cat)
t_dog = t_dog / L2_norm(t_dog)
t_car = t_car / L2_norm(t_car)
第四步:计算相似度
score_cat = dot(v, t_cat)
score_dog = dot(v, t_dog)
score_car = dot(v, t_car)
假设得到:
score_cat = 0.39
score_dog = 0.91
score_car = 0.08
第五步:温度缩放
logit_cat = score_cat / temperature
logit_dog = score_dog / temperature
logit_car = score_car / temperature
第六步:Softmax
prob_cat = exp(logit_cat) / total
prob_dog = exp(logit_dog) / total
prob_car = exp(logit_car) / total
其中:
total = exp(logit_cat) + exp(logit_dog) + exp(logit_car)
第七步:返回最高分候选
由于狗的概率最高,所以最终返回:
dog
三十七、CLIP 的本质总结
从训练角度看:
CLIP 使用大量图文对,通过批次内对比学习,使正确图文对的相似度提高,使错误图文组合的相似度降低。
从模型角度看:
CLIP 学习了两个映射函数:
图片 -> 统一语义空间
文本 -> 统一语义空间
从分类角度看:
CLIP 使用候选文本向量动态充当分类器权重。
从检索角度看:
CLIP 将图片和文本转换成可以直接进行近邻搜索的语义向量。
从生成能力看:
纯 CLIP 只能编码和匹配,不能自由生成自然语言回答。
三十八、关键公式汇总
1. 图片编码
image_feature = image_encoder(image; image_parameters)
2. 文本编码
text_feature = text_encoder(text; text_parameters)
3. 图片投影
image_embedding = image_feature × image_projection_matrix
4. 文本投影
text_embedding = text_feature × text_projection_matrix
5. L2 范数
L2_norm(x) = sqrt(x1² + x2² + ... + xd²)
6. 向量归一化
normalized_x = x / L2_norm(x)
7. 点积
dot(a, b) = a1×b1 + a2×b2 + ... + ad×bd
8. 余弦相似度
cosine_similarity(a, b) =
dot(a, b) / (L2_norm(a) × L2_norm(b))
9. 归一化后的余弦相似度
如果 a 和 b 均已归一化:
cosine_similarity(a, b) = dot(a, b)
10. 相似度矩阵
similarity_matrix =
normalized_image_features
× transpose(normalized_text_features)
11. 温度缩放
logit_ij = similarity_ij / temperature
或者:
logit_ij = exp(logit_scale) × similarity_ij
12. Softmax
probability_i =
exp(logit_i)
/
sum over j of exp(logit_j)
13. 图片到文本损失
loss_image_to_text =
average over i of:
-negative log(
exp(logit_ii)
/
sum over j of exp(logit_ij)
)
14. 文本到图片损失
loss_text_to_image =
average over i of:
-negative log(
exp(logit_ii)
/
sum over j of exp(logit_ji)
)
15. CLIP 总损失
clip_loss =
(loss_image_to_text + loss_text_to_image) / 2
16. 零样本分类
predicted_class =
候选类别中,使以下相似度最大的类别:
cosine_similarity(
image_encoder(image),
text_encoder(class_prompt)
)
三十九、一句话总结
CLIP 通过海量图文对比学习,把图片和文本映射到同一个语义向量空间;模型参数负责生成向量,图片向量与候选文本向量计算相似度并得到相对概率,而纯 CLIP 在没有候选文本和文本生成模块时,不能直接回答"图片里是什么"。