想象一座城市的“失物招领处”,里面存放着百万张遗失物品的照片。你急匆匆走进来,说:“我丢了一个红色双肩包,包上有白色小熊挂件,当时在长椅旁拍过照。”前台不会翻遍所有相册——这里有两台特制机器:一位“文字翻译官”,把你的话转写成一串标准符号;一位“图片翻译官”,把每张照片转写成同一种符号。两串符号都落到同一本“世界语词典”里,只要比对符号之间的距离,就能知道哪张照片最贴合你的描述。这就是“以文搜图”的内核:让机器在文本和图像之间建立一座共享的语义桥梁。从双塔编码、对比学习,到向量索引和召回排序,整条链路都围绕“把文字和图片翻译成同一语言”展开。

岗位关联

以文搜图是向量检索、语义搜索和多模态产品的基础能力。对 AI 从业者而言,理解 CLIP 双塔加向量检索的完整链路,是设计搜索服务、素材管理平台与视觉问答产品的关键地基。

目录
  1. 可视化演示
  2. 双塔编码架构
  3. 对比学习训练
  4. 嵌入空间映射
  5. 向量索引构建
  6. 召回排序流程
  7. 检索应用实践
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示CLIP双塔编码、对比学习训练和以文搜图检索全流程,交互切换三种模式观察文本与图像在共享嵌入空间中的匹配关系。

本节配有交互动效(进入视口后自动加载,约 3KB)。

'+captions.encode+'

双塔编码架构

失物招领处开门的第一件事,是请两位翻译官上台。文字翻译官只收描述句子,把每一句话转写成标准符号;图片翻译官只收照片,把每一帧画面也转写成同一种符号序列。两个人不会互相偷看笔记,但手里都有同一本符号手册。

在 CLIP(Contrastive Language-Image Pre-training)这类模型中,两位翻译官被实现为两个独立的编码器:文本编码器和图像编码器。它们不共享网络参数,但都把各自的输入映射到同一个 d 维向量空间,这个空间就是共享嵌入空间。文本编码器通常基于 Transformer 处理词元序列,图像编码器则基于 ViT 或 CNN 处理像素张量。

训练之后,描述文本和对应图片会在嵌入空间里占据相近位置。\(E_t\) 是查询文本的嵌入向量,\(E_i\) 是某张候选图片的嵌入向量,它们既然同处一个向量空间,就可以直接计算相似度。

有了这套符号手册,两位翻译官才能在各自的笔记堆里互相找到对方。接下来要解决的问题是:这本手册是怎么练出来的?

Et=ftext(xt)∈Rd,Ei=fimage(xi)∈Rd\displaystyle E_t = f_{\text{text}}(x_t) \in \mathbb{R}^{d}, \quad E_i = f_{\text{image}}(x_i) \in \mathbb{R}^{d}
这个公式说明:文本和图像虽然来自完全不同的模态,但经过各自的编码器,最终都能写成同一维度 d 的向量,让跨模态比较成为可能。
  1. 文本输入 \(x_t\)用户输入的描述句子会被分词、加位置编码,作为文本编码器的输入。
    xt\displaystyle x_t
  2. 文本编码器映射文本编码器把词元序列编码为一个 d 维文本嵌入向量。
    Et=ftext(xt)\displaystyle E_t = f_{\text{text}}(x_t)
  3. 图像输入 \(x_i\)一幅图片经过缩放、裁剪等预处理,形成标准尺寸的像素张量。
    xi\displaystyle x_i
  4. 图像编码器映射图像编码器输出与文本嵌入同维度的 d 维图像嵌入向量。
    Ei=fimage(xi)∈Rd\displaystyle E_i = f_{\text{image}}(x_i) \in \mathbb{R}^{d}

对比学习训练

训练手册靠的是海量“结对卡片”。想象桌面上堆着几十万张卡片,一面是图片,一面是描述。图片和描述本来匹配的,叫正样本对;随机把一张图片和另一段描述拼在一起的,叫负样本对。

对比学习的目标很朴素:让正样本对的向量更近,让负样本对的向量更远。CLIP 训练时每次取一批图文对,把每条文本与同批次所有图像计算相似度,然后套用 InfoNCE 损失。这个名字听起来神秘,本质就是“正确配对要在所有配对中突出重围”。

InfoNCE 的分子把匹配对的相似度用指数放大;分母则对查询向量与同批次所有图像(包含正样本和负样本)的相似度求和。模型要让正样本分数在总分中的占比越来越大。温度参数 \(\tau\) 控制分布的软硬程度:\(\tau\) 越小,惩罚越强,模型越会把相似度差距放大。

经过几百万次卡片练习,翻译官不再死记硬背,遇到新描述也能凭直觉找到对应画面。这份“直觉”最终凝固成嵌入空间的几何结构。

L=−log⁡exp⁡(sim(zt,zi+)/τ)∑j=1Nexp⁡(sim(zt,zj)/τ)\displaystyle \mathcal{L} = -\log \frac{\exp(\text{sim}(z_t, z_i^{+}) / \tau)}{\sum_{j=1}^{N} \exp(\text{sim}(z_t, z_j) / \tau)}
InfoNCE 让正确配对的相似度在分母总和中占比尽量大,等价于训练两位翻译官“在噪音中认出真正的搭档”。
  1. 分子指数匹配图文对的相似度先除以温度再取指数,放大正样本的突出程度。
    exp⁡(sim(zt,zi+)/τ)\displaystyle \exp(\text{sim}(z_t, z_i^{+}) / \tau)
  2. 分母求和查询向量与同批次所有图像相似度的指数和,构成一个归一化分母。
    ∑j=1Nexp⁡(sim(zt,zj)/τ)\displaystyle \sum_{j=1}^{N} \exp(\text{sim}(z_t, z_j) / \tau)
  3. 负对数对整体分数取负对数,让“正样本占比越大”这一目标转化为损失值越小。
    −log⁡(⋅)\displaystyle -\log (\cdot)
  4. 温度参数 \(\tau\)控制分布的陡峭程度。\(\tau\) 小则难负样本的惩罚更明显,相当于把相似度差异放大镜倍数调高。
    τ\displaystyle \tau

嵌入空间映射

翻译官练成后,“世界语空间”就成形了。所有文本和图像无论来自哪个模态,都变成空间里的坐标点。语义越接近,点靠得越近;语义无关,点则相隔很远。“红色雨伞”的文字坐标和红伞照片的坐标会靠在一起,而和雪山照片相距很远。

衡量两个坐标方向是否一致,最常用的是余弦相似度。它先计算向量点积,再除以两个向量长度的乘积,结果只反映方向夹角,与向量绝对长度无关。这很符合直觉:我们关心“描述和画面在不在同一个方向上”,而不是“向量数字整体有多大”。

在具体实现中,模型一般会先对嵌入向量做 L2 归一化,再做点积。这样点积结果本身就等于余弦相似度,既方便计算,也方便聚类、索引等下游操作。

模态之间的天然差异——图像是像素阵列,文本是词元序列——在这里被压缩进同一种几何里。模态鸿沟没有消失,只是被“共享空间”这座桥临时连接起来。

sim(u,v)=u⋅v∥u∥2∥v∥2\displaystyle \text{sim}(u, v) = \frac{u \cdot v}{\|u\|_2 \|v\|_2}
余弦相似度把“语义相近”变成“向量方向相近”。两个向量方向一致时余弦值为 1,方向相反时余弦值为 -1。
  1. 向量点积逐维相乘再相加,衡量两个向量在同一方向上的投影强度。
    u⋅v=∑k=1dukvk\displaystyle u \cdot v = \sum_{k=1}^{d} u_k v_k
  2. L2 范数向量自身的长度,写在分母上用于消除长度影响。
    ∥u∥2=∑k=1duk2\displaystyle \|u\|_2 = \sqrt{\sum_{k=1}^{d} u_k^2}
  3. 归一化余弦值点积除以两长度后,结果只由夹角决定。夹角为 0 时余弦为 1,夹角为 90 度时余弦为 0。
    u⋅v∥u∥2∥v∥2\displaystyle \frac{u \cdot v}{\|u\|_2 \|v\|_2}

向量索引构建

假设招领处仓库里堆着一百万张照片。如果每次查询都把整库照片重新过一遍编码器并逐张比较,产品不可能扛得住。所以必须先做“离线建库”:提前用图像编码器把整库图片全部转成向量,并按空间结构建索引。

常用方案是聚类倒排。把向量空间划分成很多个簇,每一簇有一个中心向量代表;中心向量对应的“桶”里存放该簇所有向量。查询到来时,先计算查询向量与所有中心的相似度,只进最接近的若干桶里细找。这样就把“全库搜索”缩小成“局部搜索”。

为了进一步节省存储和带宽,还会做降维压缩。比如把 1024 维降到 256 维,或用乘积量化把向量分成多个子段,逐段用码本编号代替浮点数。代价是原来的“精确相似度”变成“近似相似度”,但换来的是数十倍的效率提升。

这和失物招领处给照片按拍摄地分格存放一模一样。登记造册越细致,将来查找就越快。

Candidates(q)=⋃j∈TopKsim(q,C)Bucketj\displaystyle \text{Candidates}(q) = \bigcup_{j \in \text{TopK}_{\text{sim}}(q, C)} \text{Bucket}_j
这组公式表示:查询向量先和聚类中心比较,只挑最像的几簇,再把这几个桶里的图像向量都拿出来当候选。
  1. 聚类中心集合 C离线阶段把所有图像向量聚成 m 个簇,每簇一个中心向量。
    C={c1,c2,…,cm}\displaystyle C = \{ c_1, c_2, \dots, c_m \}
  2. 选出 TopK 中心查询向量 q 与所有中心计算相似度,保留相似度最高的那批中心的编号。
    TopKsim(q,C)\displaystyle \text{TopK}_{\text{sim}}(q, C)
  3. 桶取并集把选中的若干桶中全部向量合并成候选集,后续再做更精细的排序。
    ⋃j∈TopKBucketj\displaystyle \bigcup_{j \in \text{TopK}} \text{Bucket}_j

召回排序流程

真正的查询流程分两步。第一步,大厅保安利用索引快速圈出几十个桶,这叫候选召回;第二步,专家鉴定师对候选细看,用更精确的相似度重新打分,这叫精排。召回阶段“宁多勿漏”,所以召回数量 \(K_1\) 往往设得很大;精排阶段“宁缺毋滥”,最终只保留前 \(K_2\) 个结果。

召回阶段常用 HNSW 图索引或倒排索引,追求毫秒级响应和足够高的召回率。精排阶段则会回到未压缩的原始向量,甚至叠加一个轻量排序模型,综合文本相关性、图像质量、点击率等信号做二次排序。

排序之外,阈值过滤是最后一道保险。任何文本查询和图像库之间都存在一个最高相似度,但这个最高值可能非常低。如果不设阈值,系统会把完全不相关的结果也当成 Top-1 返回;设了阈值,低置信度结果就被直接丢弃。

保安负责圈定楼层,鉴定师负责精挑细选,守门员再用相似度门槛拦下明显不符的结果——这就是检索闭环。

RK=Rerank(Recall(q,I,K1),K2)\displaystyle R_K = \text{Rerank}\big(\text{Recall}(q, I, K_1), K_2\big)
这套流程先粗后精:先用便宜方法快速捞回可能相关的候选,再用昂贵方法精挑细选,最终给出可信的 Top-K。
  1. 召回阶段用索引结构从全库 \(I\) 中快速找回 \(K_1\) 个候选,强调速度和召回率。
    Recall(q,I,K1)\displaystyle \text{Recall}(q, I, K_1)
  2. 精排阶段对候选集合重新计算更准确的相似度或使用排序模型,只保留前 \(K_2\) 个。
    Rerank(…,K2)\displaystyle \text{Rerank}(\dots, K_2)
  3. 最终结果 \(R_K\)返回给用户的前 K 个结果集合,也是产品页面上展示的内容。
    RK\displaystyle R_K

检索应用实践

整套系统运转起来后,失物招领处才算真正营业。最常见的落地场景是素材库管理:设计师记不清文件名,只记得“穿黄色雨衣的小孩在雨中踩水”。过去靠人工打标签很难搜到,现在以文搜图直接命中。

电商视觉搜索也走同一套链路。用户说不清商品名,只描述“蓝色领口带蝴蝶结的裙子”,系统把描述向量和商品图向量比对,再用点击率模型重排。更进一步的“多模态扩展”把语音、文本、图片组合成复杂查询,例如“视频里穿红色裙子直播的片段”。

评估这套产品不能只靠感觉。工程上常用 Recall@K:看前 K 个结果里有多少是人工标注的相关图片。这个指标直接反映召回阶段有没有把真正该找的图捞回来,也决定了用户的最终体验。

故事讲到这里,失物招领处已经能高效营业。你只需要把一句话交给文字翻译官,剩下的,都在世界语空间里自动完成。

Recall@K=∣TopK∩G∣∣G∣\displaystyle \text{Recall@K} = \frac{| \text{TopK} \cap G |}{|G|}
Recall@K 衡量的是“与查询真正相关的图片中,有多少被系统成功找回来”,是检索产品最重要的质量指标之一。
  1. TopK 集合系统最终返回给用户的前 K 个检索结果。
    TopK\displaystyle \text{TopK}
  2. 真实相关集合 G人工标注中确实与查询语义相符的图片集合。
    G\displaystyle G
  3. 交集与归一化用交集大小除以相关集合大小,得到“真实相关图被找回的占比”。数值越高,说明检索越不漏。
    ∣TopK∩G∣∣G∣\displaystyle \frac{| \text{TopK} \cap G |}{|G|}

AI 应用场景

创意素材库的“用嘴找图”

阶段:检索排序阶段

解决的问题:设计师经常只记得画面氛围,说不出文件名或标签。传统素材库靠人工打关键词,覆盖少、维护贵、搜索体验差。以文搜图让用户直接用自然语言描述画面,无需任何标注也能命中。

具体案例:某设计平台接入 CLIP 向量检索后,用户输入“黄昏城市天台,霓虹灯下有人撑伞”,系统从百万张无标签图片中毫秒级返回语义匹配结果。设计师再也不用在几十个文件夹里翻来翻去。

电商视觉搜索

阶段:召回 + 重排阶段

解决的问题:用户经常说不清商品规范名称,例如“蓝色领口带蝴蝶结的裙子”。传统关键词搜索找不到,拍照搜索又依赖已有图。以文搜图把描述和商品图放进同一嵌入空间,让“模糊描述找商品”成为可能。

具体案例:电商 App 将商品主图离线做成向量索引,用户输入一段描述式文本,系统先做 ANN 召回,再用点击率模型精排,最终返回商品卡片。搜索转化率明显高于纯文本标签匹配。

多模态组合查询

阶段:特征编码阶段

解决的问题:单一文本或单一图像都不足以表达复杂意图。多模态扩展把语音、文本、图像编码到同一个空间,支持“边说边指”的混合查询,极大降低表达门槛。

具体案例:视频平台允许用户说“找一段雪山下奔跑的狗的视频”,语音转文本后与视频关键帧向量比对,返回匹配片段。这种能力也被用于短视频标签推荐和直播内容审核。

Python 演示

python39 行
import numpy as np # 模拟 6 张图片的 4 维归一化嵌入, 对应 CLIP 图像编码器的输出image_embeds = np.array([    [0.80, 0.55, 0.10, 0.20],  # 雪山星空    [0.10, 0.25, 0.90, 0.35],  # 沙滩日落    [0.75, 0.60, 0.15, 0.22],  # 石桥红伞    [0.20, 0.15, 0.30, 0.92],  # 城市夜景    [0.60, 0.65, 0.35, 0.30],  # 森林小鹿    [0.30, 0.85, 0.20, 0.40],  # 奔跑小猫], dtype=np.float32) # 图片文件名, 仅用于展示file_names = [    "snow_mountain.jpg",    "beach_sunset.jpg",    "bridge_red_umbrella.jpg",    "city_night.jpg",    "forest_deer.jpg",    "running_cat.jpg",] # 模拟 CLIP 文本编码器输出的查询向量query_embed = np.array([0.78, 0.58, 0.12, 0.20], dtype=np.float32) # 对向量做 L2 归一化, 这样点积就是余弦相似度image_embeds = image_embeds / np.linalg.norm(image_embeds, axis=1, keepdims=True)query_embed = query_embed / np.linalg.norm(query_embed) # 计算查询与所有图片的余弦相似度similarities = image_embeds @ query_embed # 按相似度降序排列order = np.argsort(similarities)[::-1] print("文本查询: 一座石桥, 有人撑着红伞")print("以文搜图 Top-K 结果:")for rank, idx in enumerate(order, start=1):    print(f"  top-{rank}: {file_names[idx]:<24} 相似度={similarities[idx]:+.4f}")
目的:用 NumPy 模拟 CLIP 双塔编码后的向量空间,演示“文本查询向量 vs 图像嵌入向量”的余弦相似度检索流程。
  1. image_embeds = image_embeds / np.linalg.norm(image_embeds, axis=1, keepdims=True)对整张图片矩阵按行做 L2 归一化,保证点积等价于余弦相似度。
  2. query_embed = query_embed / np.linalg.norm(query_embed)查询向量同样归一化,否则后续点积不能代表余弦值。
  3. similarities = image_embeds @ query_embed矩阵乘向量的形式一次算出查询与全部图像的余弦相似度。
  4. order = np.argsort(similarities)[::-1]将相似度从高到低排序,拿到图片编号的逆序索引,便于输出 Top-K 结果。

常见误区

误区以为 CLIP 是“一个网络同时吃文字和图片”,就像同一个大脑既认字又认图。很多初学者看到“共享嵌入空间”,误以为编码器也共享。

正解CLIP 是双塔结构,文本编码器和图像编码器是两套独立网络,参数完全不共享。它们只是在输出端把向量映射到同一个 d 维空间中。共享的是“空间”,不是“网络”。类比:两位翻译官各写各的笔记,只是使用同一套符号体系,并不共用大脑。

为何常见:因为“共享嵌入空间”这个说法太有误导性,容易被理解成“共享一套参数”。

误区认为检索只要把相似度排序,取第一名返回就完成任务。即使完全不相关,也一定存在一个相似度最高的图片,于是系统常把低分垃圾结果返回给用户。

正解必须设置相似度阈值。当最高相似度仍低于阈值时,宁可返回“无结果”。这就像失物招领处不随便把一张照片塞给你——如果没有任何照片和你描述相符,前台会坦白说“没找到”。

为何常见:人们习惯把“检索”当成“排序”,只关心相对顺序,忽略了绝对置信度。

误区以为以文搜图模型必须像目标检测那样,人工标注“这只猫在哪、那辆车在哪”,才能学会图文匹配。

正解对比学习只需要“图文对”这种弱监督信号。比如一张猫的照片配一句“一只橘猫趴在窗台上”,不需要画框,也不需要语义分割。模型从海量图文对中自行学到粗粒度的跨模态对应。类比:翻译官不需要被逐字纠正发音,只听大量结对卡片就能掌握规律。

为何常见:传统监督学习训练数据必须带强标签,这种惯性思维被带入了多模态领域。

误区以为图像库添加新图后,旧索引自动包含新图;或者认为 embedding 空间固定不变,索引一劳永逸。

正解新增图片必须重新过图像编码器得到向量,再写进对应的桶中;如果长期积累导致数据分布漂移(比如从风景图变成商品图),聚类中心也需要重新训练和重建索引。类比:档案馆进了新照片,不登记造册,查档案时永远找不到。

为何常见:因为搜索产品看起来“只是查表”,让人忽略了索引背后的离线更新链路。

面试题

Q1. CLIP 的文本编码器输入是什么?

单选题 · easy

  • A.一段自然语言描述← 正确答案
  • B.一组像素颜色数值
  • C.图像物体边界框
  • D.音频波形采样点

答案:A。文本编码器接收自然语言序列,输出嵌入向量。像素、边界框、音频都属于其他模态或任务。类比:文字翻译官只听句子,不听画面。

Q2. 对比学习中“正样本对”指的是?

单选题 · easy

  • A.描述与对应图片的配对← 正确答案
  • B.两张任意相同的图片
  • C.两个同义词文本
  • D.图像分类的标签对

答案:A。正样本对是“同一语义”的图文配对,例如句子“一只橘猫”和对应的猫图片。其他选项都不构成跨模态匹配对。类比:结对卡片中描述和图片能对上才算正样本。

Q3. 将 InfoNCE 分母中的负样本数量从 10 增加到 100 时,通常会导致?

单选题 · mid

  • A.对比判别能力更强← 正确答案
  • B.相似度直接变为零
  • C.文本维度变成一百
  • D.图像分辨率自动放大

答案:A。分母中负样本越多,模型越能区分“真正的匹配”和“干扰项”,对比判别能力更强。B、C、D 与负样本数量无因果关系。类比:错配卡片越多,翻译官越能识别真伪配对。

Q4. 余弦相似度的取值区间是?

单选题 · mid

  • A.从 -1 到 1 之间← 正确答案
  • B.从 0 到 1 之间
  • C.从 0 到 10 之间
  • D.从负无穷到正无穷

答案:A。余弦相似度是两个向量夹角的余弦,角度在 0 到 180 度之间,余弦值在 -1 到 1 之间。B 只覆盖非负部分,C、D 范围不对。类比:两束方向相同的光线余弦为 1,正对着为 -1。

Q5. 下列哪些方法属于近似最近邻(ANN)检索?

多选题 · mid

  • A.聚类中心倒排索引← 正确答案
  • B.逐点全量暴力扫描
  • C.近邻图(HNSW)搜索← 正确答案
  • D.像素级逐位相减

答案:AC。聚类倒排和 HNSW 都是牺牲少量精度换取速度的 ANN 方法。全量扫描是精确检索而非近似方法;像素级差值比较既不语义化,也非索引结构。类比:按区域找失物比翻遍整个档案库快得多。

Q6. 在召回排序流程中,“召回”阶段的核心目标是?

单选题 · hard

  • A.低复杂度快速圈出候选集← 正确答案
  • B.对全库逐张精算相似度
  • C.重新训练一个更强的模型
  • D.判断图片是否经过篡改

答案:A。召回阶段用索引结构快速筛出可能相关的候选,强调速度和召回率。精算相似度属于精排阶段,训练模型属于离线阶段,篡改检测是独立任务。类比:保安先圈定楼层,鉴定师才细看。

Q7. 以下哪些策略能帮助提升以文搜图的实际检索精度?

多选题 · hard

  • A.训练时增加困难负样本← 正确答案
  • B.扩大对比学习批次大小← 正确答案
  • C.无限降低向量压缩维度
  • D.上线时设置相似度阈值← 正确答案

答案:ABD。困难负样本提供更强训练信号,大批次提供更多负样本来源,阈值过滤降低低置信度误报。无限降维只省内存但会丢失语义细节,反而可能损害精度。类比:训练多设陷阱,翻译官才更可靠。

Q8. 以文搜图在命中前,第一步要做的是?

单选题 · easy

  • A.将查询文本编码为向量← 正确答案
  • B.识别图中所有物体类别
  • C.把库中图片全部下载
  • D.对文本做标准化分词

答案:A。查询文本必须先由文本编码器转成嵌入向量,才能进入检索链路。物体识别不是以文搜图的必需步骤,D 只是编码前的中间处理。类比:文字翻译官先把你的话记成标准符号,再进档案室查找。

Q9. 向量索引中“降维压缩”主要为了节省什么?

单选题 · mid

  • A.存储空间与 IO 带宽← 正确答案
  • B.文本语义理解难度
  • C.模型训练的总轮数
  • D.图像本身的分辨率

答案:A。向量维度降低后,存储体积和读取带宽随之下降。压缩不改变文本语义、不缩短训练轮数,也不影响原始图像分辨率。类比:档案摘要写短了,省纸但可能丢细节。

Q10. 当查询与所有候选的余弦相似度均为负数时,应当如何理解?

多选题 · extreme

  • A.语义大概率不相关← 正确答案
  • B.仍然机械返回最高分
  • C.应结合阈值过滤不返回← 正确答案
  • D.模型编码出现严重矛盾

答案:AC。余弦为负说明向量方向相反,语义大概率无关。产品中应结合阈值过滤直接不返回,而不是机械展示负数最高分。D 不一定成立,模型本身可能没问题,只是查询与库不匹配。类比:两串符号方向各异,不能硬说它们是同一件失物。