想象一座城市的“失物招领处”,里面存放着百万张遗失物品的照片。你急匆匆走进来,说:“我丢了一个红色双肩包,包上有白色小熊挂件,当时在长椅旁拍过照。”前台不会翻遍所有相册——这里有两台特制机器:一位“文字翻译官”,把你的话转写成一串标准符号;一位“图片翻译官”,把每张照片转写成同一种符号。两串符号都落到同一本“世界语词典”里,只要比对符号之间的距离,就能知道哪张照片最贴合你的描述。这就是“以文搜图”的内核:让机器在文本和图像之间建立一座共享的语义桥梁。从双塔编码、对比学习,到向量索引和召回排序,整条链路都围绕“把文字和图片翻译成同一语言”展开。
以文搜图是向量检索、语义搜索和多模态产品的基础能力。对 AI 从业者而言,理解 CLIP 双塔加向量检索的完整链路,是设计搜索服务、素材管理平台与视觉问答产品的关键地基。
可视化演示
展示CLIP双塔编码、对比学习训练和以文搜图检索全流程,交互切换三种模式观察文本与图像在共享嵌入空间中的匹配关系。
本节配有交互动效(进入视口后自动加载,约 3KB)。
'+captions.encode+'
双塔编码架构
失物招领处开门的第一件事,是请两位翻译官上台。文字翻译官只收描述句子,把每一句话转写成标准符号;图片翻译官只收照片,把每一帧画面也转写成同一种符号序列。两个人不会互相偷看笔记,但手里都有同一本符号手册。
在 CLIP(Contrastive Language-Image Pre-training)这类模型中,两位翻译官被实现为两个独立的编码器:文本编码器和图像编码器。它们不共享网络参数,但都把各自的输入映射到同一个 d 维向量空间,这个空间就是共享嵌入空间。文本编码器通常基于 Transformer 处理词元序列,图像编码器则基于 ViT 或 CNN 处理像素张量。
训练之后,描述文本和对应图片会在嵌入空间里占据相近位置。\(E_t\) 是查询文本的嵌入向量,\(E_i\) 是某张候选图片的嵌入向量,它们既然同处一个向量空间,就可以直接计算相似度。
有了这套符号手册,两位翻译官才能在各自的笔记堆里互相找到对方。接下来要解决的问题是:这本手册是怎么练出来的?
- 文本输入 \(x_t\)用户输入的描述句子会被分词、加位置编码,作为文本编码器的输入。
- 文本编码器映射文本编码器把词元序列编码为一个 d 维文本嵌入向量。
- 图像输入 \(x_i\)一幅图片经过缩放、裁剪等预处理,形成标准尺寸的像素张量。
- 图像编码器映射图像编码器输出与文本嵌入同维度的 d 维图像嵌入向量。
对比学习训练
训练手册靠的是海量“结对卡片”。想象桌面上堆着几十万张卡片,一面是图片,一面是描述。图片和描述本来匹配的,叫正样本对;随机把一张图片和另一段描述拼在一起的,叫负样本对。
对比学习的目标很朴素:让正样本对的向量更近,让负样本对的向量更远。CLIP 训练时每次取一批图文对,把每条文本与同批次所有图像计算相似度,然后套用 InfoNCE 损失。这个名字听起来神秘,本质就是“正确配对要在所有配对中突出重围”。
InfoNCE 的分子把匹配对的相似度用指数放大;分母则对查询向量与同批次所有图像(包含正样本和负样本)的相似度求和。模型要让正样本分数在总分中的占比越来越大。温度参数 \(\tau\) 控制分布的软硬程度:\(\tau\) 越小,惩罚越强,模型越会把相似度差距放大。
经过几百万次卡片练习,翻译官不再死记硬背,遇到新描述也能凭直觉找到对应画面。这份“直觉”最终凝固成嵌入空间的几何结构。
- 分子指数匹配图文对的相似度先除以温度再取指数,放大正样本的突出程度。
- 分母求和查询向量与同批次所有图像相似度的指数和,构成一个归一化分母。
- 负对数对整体分数取负对数,让“正样本占比越大”这一目标转化为损失值越小。
- 温度参数 \(\tau\)控制分布的陡峭程度。\(\tau\) 小则难负样本的惩罚更明显,相当于把相似度差异放大镜倍数调高。
嵌入空间映射
翻译官练成后,“世界语空间”就成形了。所有文本和图像无论来自哪个模态,都变成空间里的坐标点。语义越接近,点靠得越近;语义无关,点则相隔很远。“红色雨伞”的文字坐标和红伞照片的坐标会靠在一起,而和雪山照片相距很远。
衡量两个坐标方向是否一致,最常用的是余弦相似度。它先计算向量点积,再除以两个向量长度的乘积,结果只反映方向夹角,与向量绝对长度无关。这很符合直觉:我们关心“描述和画面在不在同一个方向上”,而不是“向量数字整体有多大”。
在具体实现中,模型一般会先对嵌入向量做 L2 归一化,再做点积。这样点积结果本身就等于余弦相似度,既方便计算,也方便聚类、索引等下游操作。
模态之间的天然差异——图像是像素阵列,文本是词元序列——在这里被压缩进同一种几何里。模态鸿沟没有消失,只是被“共享空间”这座桥临时连接起来。
- 向量点积逐维相乘再相加,衡量两个向量在同一方向上的投影强度。
- L2 范数向量自身的长度,写在分母上用于消除长度影响。
- 归一化余弦值点积除以两长度后,结果只由夹角决定。夹角为 0 时余弦为 1,夹角为 90 度时余弦为 0。
向量索引构建
假设招领处仓库里堆着一百万张照片。如果每次查询都把整库照片重新过一遍编码器并逐张比较,产品不可能扛得住。所以必须先做“离线建库”:提前用图像编码器把整库图片全部转成向量,并按空间结构建索引。
常用方案是聚类倒排。把向量空间划分成很多个簇,每一簇有一个中心向量代表;中心向量对应的“桶”里存放该簇所有向量。查询到来时,先计算查询向量与所有中心的相似度,只进最接近的若干桶里细找。这样就把“全库搜索”缩小成“局部搜索”。
为了进一步节省存储和带宽,还会做降维压缩。比如把 1024 维降到 256 维,或用乘积量化把向量分成多个子段,逐段用码本编号代替浮点数。代价是原来的“精确相似度”变成“近似相似度”,但换来的是数十倍的效率提升。
这和失物招领处给照片按拍摄地分格存放一模一样。登记造册越细致,将来查找就越快。
- 聚类中心集合 C离线阶段把所有图像向量聚成 m 个簇,每簇一个中心向量。
- 选出 TopK 中心查询向量 q 与所有中心计算相似度,保留相似度最高的那批中心的编号。
- 桶取并集把选中的若干桶中全部向量合并成候选集,后续再做更精细的排序。
召回排序流程
真正的查询流程分两步。第一步,大厅保安利用索引快速圈出几十个桶,这叫候选召回;第二步,专家鉴定师对候选细看,用更精确的相似度重新打分,这叫精排。召回阶段“宁多勿漏”,所以召回数量 \(K_1\) 往往设得很大;精排阶段“宁缺毋滥”,最终只保留前 \(K_2\) 个结果。
召回阶段常用 HNSW 图索引或倒排索引,追求毫秒级响应和足够高的召回率。精排阶段则会回到未压缩的原始向量,甚至叠加一个轻量排序模型,综合文本相关性、图像质量、点击率等信号做二次排序。
排序之外,阈值过滤是最后一道保险。任何文本查询和图像库之间都存在一个最高相似度,但这个最高值可能非常低。如果不设阈值,系统会把完全不相关的结果也当成 Top-1 返回;设了阈值,低置信度结果就被直接丢弃。
保安负责圈定楼层,鉴定师负责精挑细选,守门员再用相似度门槛拦下明显不符的结果——这就是检索闭环。
- 召回阶段用索引结构从全库 \(I\) 中快速找回 \(K_1\) 个候选,强调速度和召回率。
- 精排阶段对候选集合重新计算更准确的相似度或使用排序模型,只保留前 \(K_2\) 个。
- 最终结果 \(R_K\)返回给用户的前 K 个结果集合,也是产品页面上展示的内容。
检索应用实践
整套系统运转起来后,失物招领处才算真正营业。最常见的落地场景是素材库管理:设计师记不清文件名,只记得“穿黄色雨衣的小孩在雨中踩水”。过去靠人工打标签很难搜到,现在以文搜图直接命中。
电商视觉搜索也走同一套链路。用户说不清商品名,只描述“蓝色领口带蝴蝶结的裙子”,系统把描述向量和商品图向量比对,再用点击率模型重排。更进一步的“多模态扩展”把语音、文本、图片组合成复杂查询,例如“视频里穿红色裙子直播的片段”。
评估这套产品不能只靠感觉。工程上常用 Recall@K:看前 K 个结果里有多少是人工标注的相关图片。这个指标直接反映召回阶段有没有把真正该找的图捞回来,也决定了用户的最终体验。
故事讲到这里,失物招领处已经能高效营业。你只需要把一句话交给文字翻译官,剩下的,都在世界语空间里自动完成。
- TopK 集合系统最终返回给用户的前 K 个检索结果。
- 真实相关集合 G人工标注中确实与查询语义相符的图片集合。
- 交集与归一化用交集大小除以相关集合大小,得到“真实相关图被找回的占比”。数值越高,说明检索越不漏。
AI 应用场景
创意素材库的“用嘴找图”
阶段:检索排序阶段
解决的问题:设计师经常只记得画面氛围,说不出文件名或标签。传统素材库靠人工打关键词,覆盖少、维护贵、搜索体验差。以文搜图让用户直接用自然语言描述画面,无需任何标注也能命中。
具体案例:某设计平台接入 CLIP 向量检索后,用户输入“黄昏城市天台,霓虹灯下有人撑伞”,系统从百万张无标签图片中毫秒级返回语义匹配结果。设计师再也不用在几十个文件夹里翻来翻去。
电商视觉搜索
阶段:召回 + 重排阶段
解决的问题:用户经常说不清商品规范名称,例如“蓝色领口带蝴蝶结的裙子”。传统关键词搜索找不到,拍照搜索又依赖已有图。以文搜图把描述和商品图放进同一嵌入空间,让“模糊描述找商品”成为可能。
具体案例:电商 App 将商品主图离线做成向量索引,用户输入一段描述式文本,系统先做 ANN 召回,再用点击率模型精排,最终返回商品卡片。搜索转化率明显高于纯文本标签匹配。
多模态组合查询
阶段:特征编码阶段
解决的问题:单一文本或单一图像都不足以表达复杂意图。多模态扩展把语音、文本、图像编码到同一个空间,支持“边说边指”的混合查询,极大降低表达门槛。
具体案例:视频平台允许用户说“找一段雪山下奔跑的狗的视频”,语音转文本后与视频关键帧向量比对,返回匹配片段。这种能力也被用于短视频标签推荐和直播内容审核。
Python 演示
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}")
image_embeds = image_embeds / np.linalg.norm(image_embeds, axis=1, keepdims=True)对整张图片矩阵按行做 L2 归一化,保证点积等价于余弦相似度。query_embed = query_embed / np.linalg.norm(query_embed)查询向量同样归一化,否则后续点积不能代表余弦值。similarities = image_embeds @ query_embed矩阵乘向量的形式一次算出查询与全部图像的余弦相似度。order = np.argsort(similarities)[::-1]将相似度从高到低排序,拿到图片编号的逆序索引,便于输出 Top-K 结果。
常见误区
误区以为 CLIP 是“一个网络同时吃文字和图片”,就像同一个大脑既认字又认图。很多初学者看到“共享嵌入空间”,误以为编码器也共享。
正解CLIP 是双塔结构,文本编码器和图像编码器是两套独立网络,参数完全不共享。它们只是在输出端把向量映射到同一个 d 维空间中。共享的是“空间”,不是“网络”。类比:两位翻译官各写各的笔记,只是使用同一套符号体系,并不共用大脑。
为何常见:因为“共享嵌入空间”这个说法太有误导性,容易被理解成“共享一套参数”。
误区认为检索只要把相似度排序,取第一名返回就完成任务。即使完全不相关,也一定存在一个相似度最高的图片,于是系统常把低分垃圾结果返回给用户。
正解必须设置相似度阈值。当最高相似度仍低于阈值时,宁可返回“无结果”。这就像失物招领处不随便把一张照片塞给你——如果没有任何照片和你描述相符,前台会坦白说“没找到”。
为何常见:人们习惯把“检索”当成“排序”,只关心相对顺序,忽略了绝对置信度。
误区以为以文搜图模型必须像目标检测那样,人工标注“这只猫在哪、那辆车在哪”,才能学会图文匹配。
正解对比学习只需要“图文对”这种弱监督信号。比如一张猫的照片配一句“一只橘猫趴在窗台上”,不需要画框,也不需要语义分割。模型从海量图文对中自行学到粗粒度的跨模态对应。类比:翻译官不需要被逐字纠正发音,只听大量结对卡片就能掌握规律。
为何常见:传统监督学习训练数据必须带强标签,这种惯性思维被带入了多模态领域。
误区以为图像库添加新图后,旧索引自动包含新图;或者认为 embedding 空间固定不变,索引一劳永逸。
正解新增图片必须重新过图像编码器得到向量,再写进对应的桶中;如果长期积累导致数据分布漂移(比如从风景图变成商品图),聚类中心也需要重新训练和重建索引。类比:档案馆进了新照片,不登记造册,查档案时永远找不到。
为何常见:因为搜索产品看起来“只是查表”,让人忽略了索引背后的离线更新链路。
面试题
Q1. CLIP 的文本编码器输入是什么?
- A.一段自然语言描述← 正确答案
- B.一组像素颜色数值
- C.图像物体边界框
- D.音频波形采样点
答案:A。文本编码器接收自然语言序列,输出嵌入向量。像素、边界框、音频都属于其他模态或任务。类比:文字翻译官只听句子,不听画面。
Q2. 对比学习中“正样本对”指的是?
- A.描述与对应图片的配对← 正确答案
- B.两张任意相同的图片
- C.两个同义词文本
- D.图像分类的标签对
答案:A。正样本对是“同一语义”的图文配对,例如句子“一只橘猫”和对应的猫图片。其他选项都不构成跨模态匹配对。类比:结对卡片中描述和图片能对上才算正样本。
Q3. 将 InfoNCE 分母中的负样本数量从 10 增加到 100 时,通常会导致?
- A.对比判别能力更强← 正确答案
- B.相似度直接变为零
- C.文本维度变成一百
- D.图像分辨率自动放大
答案:A。分母中负样本越多,模型越能区分“真正的匹配”和“干扰项”,对比判别能力更强。B、C、D 与负样本数量无因果关系。类比:错配卡片越多,翻译官越能识别真伪配对。
Q4. 余弦相似度的取值区间是?
- A.从 -1 到 1 之间← 正确答案
- B.从 0 到 1 之间
- C.从 0 到 10 之间
- D.从负无穷到正无穷
答案:A。余弦相似度是两个向量夹角的余弦,角度在 0 到 180 度之间,余弦值在 -1 到 1 之间。B 只覆盖非负部分,C、D 范围不对。类比:两束方向相同的光线余弦为 1,正对着为 -1。
Q5. 下列哪些方法属于近似最近邻(ANN)检索?
- A.聚类中心倒排索引← 正确答案
- B.逐点全量暴力扫描
- C.近邻图(HNSW)搜索← 正确答案
- D.像素级逐位相减
答案:AC。聚类倒排和 HNSW 都是牺牲少量精度换取速度的 ANN 方法。全量扫描是精确检索而非近似方法;像素级差值比较既不语义化,也非索引结构。类比:按区域找失物比翻遍整个档案库快得多。
Q6. 在召回排序流程中,“召回”阶段的核心目标是?
- A.低复杂度快速圈出候选集← 正确答案
- B.对全库逐张精算相似度
- C.重新训练一个更强的模型
- D.判断图片是否经过篡改
答案:A。召回阶段用索引结构快速筛出可能相关的候选,强调速度和召回率。精算相似度属于精排阶段,训练模型属于离线阶段,篡改检测是独立任务。类比:保安先圈定楼层,鉴定师才细看。
Q7. 以下哪些策略能帮助提升以文搜图的实际检索精度?
- A.训练时增加困难负样本← 正确答案
- B.扩大对比学习批次大小← 正确答案
- C.无限降低向量压缩维度
- D.上线时设置相似度阈值← 正确答案
答案:ABD。困难负样本提供更强训练信号,大批次提供更多负样本来源,阈值过滤降低低置信度误报。无限降维只省内存但会丢失语义细节,反而可能损害精度。类比:训练多设陷阱,翻译官才更可靠。
Q8. 以文搜图在命中前,第一步要做的是?
- A.将查询文本编码为向量← 正确答案
- B.识别图中所有物体类别
- C.把库中图片全部下载
- D.对文本做标准化分词
答案:A。查询文本必须先由文本编码器转成嵌入向量,才能进入检索链路。物体识别不是以文搜图的必需步骤,D 只是编码前的中间处理。类比:文字翻译官先把你的话记成标准符号,再进档案室查找。
Q9. 向量索引中“降维压缩”主要为了节省什么?
- A.存储空间与 IO 带宽← 正确答案
- B.文本语义理解难度
- C.模型训练的总轮数
- D.图像本身的分辨率
答案:A。向量维度降低后,存储体积和读取带宽随之下降。压缩不改变文本语义、不缩短训练轮数,也不影响原始图像分辨率。类比:档案摘要写短了,省纸但可能丢细节。
Q10. 当查询与所有候选的余弦相似度均为负数时,应当如何理解?
- A.语义大概率不相关← 正确答案
- B.仍然机械返回最高分
- C.应结合阈值过滤不返回← 正确答案
- D.模型编码出现严重矛盾
答案:AC。余弦为负说明向量方向相反,语义大概率无关。产品中应结合阈值过滤直接不返回,而不是机械展示负数最高分。D 不一定成立,模型本身可能没问题,只是查询与库不匹配。类比:两串符号方向各异,不能硬说它们是同一件失物。