想象你站在一个巨大的国际航站楼里,广播正在焦急地喊:“穿红色外套、背蓝色双肩包、戴圆框眼镜,身高约一米七,请听到后到服务台。” 一个真人听完这句话,目光会在人流中扫来扫去。但机器没有“目光”,它面前只有两种完全不同的东西:一段文字、一堆照片像素。怎么让机器也能“扫一眼就知道找谁”?答案是把所有模态都翻译成同一种“世界语”——也就是嵌入向量。文字变成一串数字,图片也变成一串数字,它们终于能放在同一把尺子下比较。这篇文章要讲的就是这把尺子本身:余弦相似度、欧氏距离、马氏距离各有各的脾气;温度系数像寻人专员的“置信门槛”,决定多像才算同一个人;困难负样本挖掘则像故意安排替身演员来锻炼系统的火眼金睛。最后,我们还会看看这套“寻人系统”是空降到新航站楼直接上岗,还是先实习一阵子再工作——零样本检索与微调检索的差别就在于此。

岗位关联

掌握相似度度量与训练技巧的搭配逻辑,是落地多模态检索的必修课——它能帮你快速定位检索精度瓶颈,让产品从“勉强能用”走向“真正好用”。

目录
  1. 可视化演示
  2. 检索基础
  3. 余弦相似度
  4. 欧氏距离
  5. 马氏距离
  6. 度量选型
  7. 温度系数
  8. 难例挖掘
  9. 效果分析
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

动态演示跨模态检索相似度计算方法的核心机制,通过入门/进阶/实战/优化四种模式展示关键概念与交互流程。

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

跨模态检索相似度计算方法:跨模态检 跨模态检索的基本流程与架构 相似度度量函数的对比与选择 核心机制可视化 跨模态检索相似度计算方法整体架构与关键组件

检索基础

航站楼里要找人,第一件事不是拿尺子测量,而是把所有信息统一成同一种“档案卡”。照片上的红外套、目击者口述的“红色外套”、监控里的像素块,形态完全不同,但填进一张标准档案卡后,就有了可比项。在多模态检索里,这张档案卡就是嵌入向量:CLIP、ALIGN 这类模型用两个编码器,一个把文字变成向量,一个把图片变成向量,两者被训练到同一个高维空间里。这个空间的奇妙之处在于:意思相近的文字和图片,向量方向也会靠近。比如“一只柴犬在草地上”这句话,和一张柴犬照片的向量,会比它和一张拖拉机照片的向量挨得更近。

这个过程技术上叫“双塔架构”。左侧的文本塔负责把句子编码成向量 e,右侧的图像塔负责把图片编码成向量 p。两个塔输出的东西长度相同、维度相同,才能放进同一个坐标系。训练时,模型拿大批量配对的图文对一起优化,让匹配对在空间里靠近、不匹配对互相远离。所谓“共享空间”,本质就是一个把语义翻译成几何位置的翻译器。

有了档案卡,寻人专员才能掏出各种尺子来打分。但请注意:不同尺子量出来的“像不像”结论可能截然不同,这正是接下来三节要讲的分歧点。在航站楼里,同样的两个人,有人觉得“穿得方向一致就像”,有人觉得“身高必须差不多才像”——度量函数的选择,就是给 AI 定下这样的“性格”。

ei=ftext(ti),pj=gimage(vj)\displaystyle \boldsymbol{e}_i = f_{\text{text}}(\boldsymbol{t}_i), \quad \boldsymbol{p}_j = g_{\text{image}}(\boldsymbol{v}_j)
文本和图像分别经过各自的编码器,输出同维度的向量,从此可以在同一个坐标系里比较远近。
  1. 文本编码器把一句自然语言描述压成一个紧密的高维向量。
    ftext(ti)\displaystyle f_{\text{text}}(\boldsymbol{t}_i)
  2. 图像编码器把一张图片压缩成与文本同维的向量。
    gimage(vj)\displaystyle g_{\text{image}}(\boldsymbol{v}_j)
  3. 共享空间两个向量落在同一个 d 维坐标系里,语义越近方向越一致。
    ei,pj∈Rd\displaystyle \boldsymbol{e}_i, \boldsymbol{p}_j \in \mathbb{R}^{d}

余弦相似度

航站楼里有一种寻人风格叫“方向派”:不看身高体重,只看风格方向。档案卡记录了一个人的“穿衣风格方向”——偏红色系还是蓝色系,偏运动还是正式。余弦相似度就是这种风格:它只比较两个向量的方向夹角,完全忽略向量的长度。即使一份档案写满了 1000 个特征,另一份只有 50 个特征(模长不同),只要方向一致,余弦就会给出接近 1 的高分。

技术上讲,余弦相似度计算的是两个向量的内积除以它们各自的模长。内积衡量“共同分量”的多寡,模长归一化则把“数量级”抹掉。结果范围在 -1 到 1 之间:1 代表方向完全一致,0 代表垂直无关,-1 代表方向相反。在多模态检索中,CLIP 类模型默认就用余弦相似度来排序候选结果,因为它对文本长度、图片亮度这一类“尺度”因素天生不敏感。

但方向派也会翻车:如果一个人穿红袄但身高方向偏了 30 厘米,描述文字和监控照的方向一致度很高,余弦会热情推荐——而实际上那是另一个人。这就是为什么航站楼管理员还需要备一把“绝对尺”。

cos⁡(a,b)=a⊤b∥a∥2∥b∥2\displaystyle \cos(\boldsymbol{a}, \boldsymbol{b}) = \frac{\boldsymbol{a}^{\top} \boldsymbol{b}}{\|\boldsymbol{a}\|_2 \|\boldsymbol{b}\|_2}
分子是内积,分母是模长乘积——把长度的影响约掉,只剩方向信息。
  1. 内积两个向量逐维相乘再累加,衡量“同方向分量”的多少。
    a⊤b\displaystyle \boldsymbol{a}^{\top} \boldsymbol{b}
  2. 模长积各自长度相乘,充当归一化除数。
    ∥a∥2∥b∥2\displaystyle \|\boldsymbol{a}\|_2 \|\boldsymbol{b}\|_2
  3. 比值得到夹角余弦,严格落在 [-1,1],方向越一致越接近 1。
    cos⁡(a,b)∈[−1,1]\displaystyle \cos(\boldsymbol{a}, \boldsymbol{b}) \in [-1, 1]

欧氏距离

方向派看风格,绝对派看差距。欧氏距离就是绝对派的尺子:它把档案卡当成地图上的坐标点,直接量两点之间的直线距离。穿红袄但身高差 30 厘米,坐标差就在“身高”这个维度上体现出来,距离不达标就是不像。这把尺子的优点是直观、好算、符合直觉;缺点是它把所有维度一视同仁,且对尺度极其敏感——如果“身高”以毫米为单位、“步幅”以米为单位,毫米那个维度会彻底主导距离。

在多模态检索中,欧氏距离适合那些模长本身携带语义的场景。比如两个特征向量不仅要方向对,还要“强度”也对:一段文本描述“非常愤怒”和“有点生气”,在情感维度上的长度差异就有意义。但要注意,使用欧氏距离前通常要做特征缩放或标准化,否则大尺度特征会淹没小尺度特征,就像拿米尺量头发丝,数据稍一抖动,结果就上天入地。

绝对派的问题在于:它假设所有维度彼此独立、量纲一致。但人的“身高”和“步幅”本来就相关,高个子通常步幅大。如果有个档案是高个子配小步幅,这其实是异常信号——欧氏距离却把它当成普通偏差。要处理这种相关性,就得请出第三把尺子。

d(a,b)=∥a−b∥2=∑k=1d(ak−bk)2\displaystyle d(\boldsymbol{a}, \boldsymbol{b}) = \|\boldsymbol{a} - \boldsymbol{b}\|_2 = \sqrt{\sum_{k=1}^{d} (a_k - b_k)^2}
逐维做差后平方求和,再开方还原成实际距离。
  1. 差向量两个向量逐维相减,得到各维度上的偏差。
    a−b\displaystyle \boldsymbol{a} - \boldsymbol{b}
  2. 平方和把每个维度的偏差平方后相加,避免正负抵消。
    ∑k=1d(ak−bk)2\displaystyle \sum_{k=1}^{d} (a_k - b_k)^2
  3. 开方对平方和开根号,得到便于解释的直线距离。
    ∥a−b∥2\displaystyle \|\boldsymbol{a} - \boldsymbol{b}\|_2

马氏距离

马氏距离是一位更聪明的测量师:它不拿直尺量,而是先观察整个航站楼的人群分布,再问“这个人在人群里算不算异常”。高个子配大步伐是常见的组合,所以这个方向上的偏差可以被容忍;但高个子配小步幅在人群中极少见,马氏距离会把这种偏差放大。它通过协方差矩阵 \(\boldsymbol{\Sigma}\) 来学习特征之间的相关模式,再用协方差矩阵的逆去“矫正”原始坐标,相当于先把数据旋转到互不相关的坐标系,再按各自方差归一化。

协方差矩阵的逆 \(\boldsymbol{\Sigma}^{-1}\) 是这个方法的核心。它编码了“哪些方向是常见方向,哪些方向是稀有方向”。常见的联合变化方向权重小,稀有的异常方向权重大。因此马氏距离能消除维度间的相关性,也能自适应每个维度的尺度差异。代价是:需要足够的数据来估计协方差矩阵,计算复杂度也更高。

马氏距离听起来最“科学”,但航站楼管理员不会每层楼都扛一台协方差计算器。尺子没有绝对的优劣,只有合适不合适。下一节我们就聊聊:什么时候用直尺,什么时候用方向仪,什么时候请出统计学家。

dM(a,b)=(a−b)⊤Σ−1(a−b)\displaystyle d_M(\boldsymbol{a}, \boldsymbol{b}) = \sqrt{(\boldsymbol{a} - \boldsymbol{b})^{\top} \boldsymbol{\Sigma}^{-1} (\boldsymbol{a} - \boldsymbol{b})}
用协方差矩阵的逆给差向量做“白化”校正,再计算加权距离。
  1. 差向量先求两个向量在各维度上的偏差。
    a−b\displaystyle \boldsymbol{a} - \boldsymbol{b}
  2. 协方差逆矩阵记录特征间相关结构,是校正系数的来源。
    Σ−1\displaystyle \boldsymbol{\Sigma}^{-1}
  3. 二次型偏差经过矩阵加权相乘,完成尺度与相关的消除。
    (a−b)⊤Σ−1(a−b)\displaystyle (\boldsymbol{a} - \boldsymbol{b})^{\top} \boldsymbol{\Sigma}^{-1} (\boldsymbol{a} - \boldsymbol{b})
  4. 开方得到符合分布规律的标准化距离。
    (a−b)⊤Σ−1(a−b)\displaystyle \sqrt{(\boldsymbol{a} - \boldsymbol{b})^{\top} \boldsymbol{\Sigma}^{-1} (\boldsymbol{a} - \boldsymbol{b})}

度量选型

航站楼里三把尺子摆在桌上,管理员必须回答一个问题:“你眼里的'像'到底是什么?” 如果答案是“风格相似就行”,选余弦;如果答案是“绝对特征不能差太多”,选欧氏;如果答案是“要考虑人群的正常组合模式”,选马氏。这个选择会直接影响检索排序的结果,因为训练时损失函数用的度量和检索时排序用的度量如果不一致,模型等于“训练时说一套,上线时做另一套”。

一个重要的数学事实能帮你做判断:当所有向量都做了 L2 归一化(模长等于 1)之后,欧氏距离和余弦相似度在排序意义上是等价的。因为距离平方展开后,模长项变成常数,唯一变量就是内积(余弦的分子)。这意味着很多 CLIP 类模型在归一化嵌入后,无论用哪个度量,给候选排序的结论都一样——差异只在数值范围不同。但当模长未被归一化时,两者结论就会分道扬镳。

选尺子的同时,管理员还要决定一个关键参数:这个系统到底“多挑剔”才算匹配。同样的相似度分数,有人在 0.7 就放行,有人非要 0.95 才点头——这就是温度系数登场的时刻。

∥a−b∥22=∥a∥22+∥b∥22−2a⊤b\displaystyle \|\boldsymbol{a} - \boldsymbol{b}\|_2^2 = \|\boldsymbol{a}\|_2^2 + \|\boldsymbol{b}\|_2^2 - 2 \boldsymbol{a}^{\top} \boldsymbol{b}
模长固定时,欧氏距离的大小完全由内积决定,此时它和余弦排序等价。
  1. 平方展开把差的平方拆成三项,距离与模长、内积建立联系。
    ∥a−b∥22\displaystyle \|\boldsymbol{a} - \boldsymbol{b}\|_2^2
  2. 交叉项交叉项恰好是内积的 -2 倍。
    −2a⊤b\displaystyle -2 \boldsymbol{a}^{\top} \boldsymbol{b}
  3. 归一化后模长项变成常数,排序只由内积决定。
    ∥a∥22+∥b∥22=2\displaystyle \|\boldsymbol{a}\|_2^2 + \|\boldsymbol{b}\|_2^2 = 2

温度系数

寻人专员的性格可以被一个旋钮调节:旋到“严格”,他要求证据极其充分才认定是同一个人,哪怕漏报也不愿错报;旋到“宽松”,他看着有点眼熟就放行,找回人的概率高了,但误认的几率也上升。这个旋钮在对比学习里就是温度系数 \(\tau\)。它出现在 softmax 结构里:所有的相似度分数先除以 \(\tau\),再做指数归一化,变成“哪个候选是正确匹配”的概率分布。

当 \(\tau\) 很小时,分数差异被放大:正样本与负样本的分数差 0.1,除以 0.01 后变成差了 10 倍的巨大鸿沟,softmax 输出接近 one-hot,模型会狠命盯住最难分的样本;当 \(\tau\) 很大时,所有分数差距被压平,概率分布趋于均匀,梯度信号也变得平淡,模型学不到精细区分。实际训练中,\(\tau\) 往往被设为一个较小的值(如 0.01 到 0.1),让模型对难负样本保持“紧张感”。

旋钮调好了,系统有了性格,但光有性格还不够。航站楼管理员深知:要让专员练出火眼金睛,光让他在好人堆里找人没用,必须故意安排一些“长得几乎一样的替身”混在人群里——这就是困难负样本挖掘。

Li=−ln⁡e sii/τe sii/τ+∑j≠ie sij/τ\displaystyle \mathcal{L}_{i} = -\ln \frac{e^{\, s_{i i} / \tau}}{e^{\, s_{i i} / \tau} + \sum_{j \neq i} e^{\, s_{i j} / \tau}}
正样本分数在分子,所有负样本分数在分母,温度决定这两者的差距被放大还是压平。
  1. 负对数似然把“正确匹配的概率”取负对数,概率越接近 1,损失越小。
    −ln⁡e sii/τZ\displaystyle -\ln \frac{e^{\, s_{i i} / \tau}}{Z}
  2. 温度缩放相似度先除以温度再指数化,改变分数间的相对差距。
    sij/τ\displaystyle s_{i j} / \tau
  3. 负样本分母所有负样本指数化后参与归一化竞争。
    ∑j≠ie sij/τ\displaystyle \sum_{j \neq i} e^{\, s_{i j} / \tau}
  4. 极限行为温度趋近 0 时分布趋近独热;温度趋近无穷时分布趋近平滑。
    lim⁡τ→0+esi/τ∑kesk/τ→1[ i=arg⁡max⁡ksk ]\displaystyle \lim_{\tau \to 0^{+}} \frac{e^{s_i/\tau}}{\sum_k e^{s_k/\tau}} \to \mathbf{1}[\, i = \arg\max_k s_k \,]

难例挖掘

训练寻人专员时,如果负样本全是金发碧眼的外国人,而目标是亚洲面孔,专员很快就能蒙混过关——因为区分太容易了。真正考验他的是:目标穿红外套背蓝书包,人群里恰好有另一个穿红外套背蓝书包的人,只是鞋子颜色不同。这类“几乎匹配”的负样本,就是困难负样本。多模态检索的对比学习中,每个批次内除了一个正样本,其他全部当作负样本;其中相似度最高的那些负样本,对梯度的贡献最大。

在线难例挖掘(OHEM)的做法是:每个训练步都动态计算当前批次内所有负样本的相似度分数,挑出分数高于某个阈值 \(\gamma\) 的样本作为难例,只对它们计算损失。这样模型不会再把精力浪费在明显不匹配的易负样本上,而是集中火力攻下“最像的干扰项”。不过要小心:如果批次里全是难例,训练会变得剧烈震荡。所以工业界常用“随机负样本 + 困难负样本”的混合策略,既保证稳定又保证精度。

训练完成,寻人专员要上岗了。但有两种上岗方式:直接空降到陌生航站楼,还是先在新航站楼实习几天。这两种方式的检索效果差异,就是零样本检索与微调检索的核心区别。

Lhard=−ln⁡e sii/τe sii/τ+∑j∈H(i)e sij/τ,H(i)={j≠i:sij>γ}\displaystyle \mathcal{L}_{\text{hard}} = -\ln \frac{e^{\, s_{i i} / \tau}}{e^{\, s_{i i} / \tau} + \sum_{j \in \mathcal{H}(i)} e^{\, s_{i j} / \tau}}, \quad \mathcal{H}(i) = \{ j \neq i : s_{i j} > \gamma \}
分母只保留相似度超过阈值的困难负样本,让训练火力集中在最易混淆的区域。
  1. 难例集合把相似度高于阈值的负样本挑出来作为训练目标。
    H(i)={j≠i:sij>γ}\displaystyle \mathcal{H}(i) = \{ j \neq i : s_{i j} > \gamma \}
  2. 正样本分子正对分数经温度缩放后仍作为分子。
    e sii/τ\displaystyle e^{\, s_{i i} / \tau}
  3. 难例分母归一化项只包含正样本和被选中的难例。
    e sii/τ+∑j∈H(i)e sij/τ\displaystyle e^{\, s_{i i} / \tau} + \sum_{j \in \mathcal{H}(i)} e^{\, s_{i j} / \tau}
  4. 损失聚焦难例主导梯度方向,迫使模型区分最像的干扰项。
    Lhard=−ln⁡e sii/τe sii/τ+∑j∈H(i)e sij/τ\displaystyle \mathcal{L}_{\text{hard}} = -\ln \frac{e^{\, s_{i i} / \tau}}{e^{\, s_{i i} / \tau} + \sum_{j \in \mathcal{H}(i)} e^{\, s_{i j} / \tau}}

效果分析

零样本检索,相当于寻人专员拿着标准世界语档案卡,直接空降到任何一个航站楼,不学当地语言就开始找人。它的优点是大规模部署成本低、换领域不用重新训练;缺点是遇到预训练时没见过的新场景(比如医疗影像、工业零件),精度会明显掉。微调检索,则是让专员先在新航站楼实习一阵子,用一些本地配对数据做小规模训练,把嵌入空间稍微“校偏”到新领域的语义上。通常微调用很小的学习率,避免把预训练学到的通用语义全部覆盖掉。

衡量检索效果的标准指标是 Recall@K。它统计:对每个查询,正确答案排在前 K 名之内的比例。K=1 时最严格,要求排第一;K=5 时宽容一些,允许出现在前五个候选里。实战中,跨模态检索系统通常先做零样本评估拿一个基线,再判断瓶颈在度量选择、温度调节还是负样本设计,最后决定是否需要微调。三条路各有成本,效果也各有取舍——这正是“系统设计”的魅力所在。

回到航站楼:档案卡准备好了,三把尺子摆好了,旋钮调好了,替身也练过了。真正的考验永远是“在真实人流里,能不能又快又准地找到那个人”。理解每种度量、每个超参的语义,你就不再是只会调库的工程师,而是能诊断系统瓶颈的设计师。

Recall@K=1N∑i=1N1 ⁣[rank(i)≤K]\displaystyle \text{Recall@}K = \frac{1}{N} \sum_{i=1}^{N} \mathbf{1}\!\left[ \text{rank}(i) \leq K \right]
对所有查询求平均,统计正确结果排进前 K 名所占的比例。
  1. 排名位置查询得到所有候选的分数排序,找出正确结果的位次。
    rank(i)\displaystyle \text{rank}(i)
  2. 指示函数位次小于等于 K 记 1,否则记 0。
    1 ⁣[rank(i)≤K]\displaystyle \mathbf{1}\!\left[ \text{rank}(i) \leq K \right]
  3. 平均对所有 N 个查询取平均,得到检索精度的整体描述。
    1N∑i=1N1 ⁣[rank(i)≤K]\displaystyle \frac{1}{N} \sum_{i=1}^{N} \mathbf{1}\!\left[ \text{rank}(i) \leq K \right]

AI 应用场景

安防监控的跨模态寻人

阶段:多模态表示学习 + 检索排序

解决的问题:传统监控找人靠人工盯屏,效率极低;当目击者只有一段文字描述(“红外套、蓝背包、圆框眼镜”)时,无法直接搜索视频帧。AI 将文本描述与视频帧分别编码到同一空间,用余弦相似度排序候选画面,几秒钟就能从几万帧中锁定目标。

具体案例:某园区安防系统接入 CLIP 风格的双塔模型,巡逻人员用对讲机说一句特征描述,系统返回按相似度倒序排列的监控截图,命中率(Recall@5)达 92%,处警时间从 20 分钟缩短到 1 分钟。

电商平台的以图搜衣与图文互搜

阶段:特征编码 + 相似度度量 + 召回精排

解决的问题:用户看到一张街拍图想买同款,或想搜“红色泡泡袖连衣裙”却不愿翻几十页列表。传统标签检索依赖人工打标,覆盖不全。AI 将图、文统一编码,以余弦相似度为粗排、马氏距离为精排,同时支持图搜文和文搜图。

具体案例:某电商平台的拍照搜同款功能,上线图文双塔模型后,SKU 召回率提升 18%,用户点单转化率提升 6%。困难负样本挖掘让系统能分辨“看起来像但扣子细节不同”的近似款,误推率显著下降。

医疗影像与诊断报告双向检索

阶段:多模态对齐 + 检索评估

解决的问题:医生看到一张疑难 CT 片,想找历史病例中“影像相似且已确诊”的报告;反过来,输入一段描述“右肺上叶磨玻璃影伴分叶”也要能召回对应影像。传统方法依赖关键词标签,丢信息严重。AI 用双塔模型对齐影像与报告嵌入,配合温度调节和难例挖掘,在冷门病种上也能保持稳定召回。

具体案例:某三甲医院试点影像-报告互检系统,医生点开 CT 即可看到相似度最高的既往确诊案例,辅助初诊准确率提升 12%。系统在零样本情况下对新设备厂商的影像也能直接运行,无需重新标注。

Python 演示

python61 行
"""跨模态检索相似度对比小实验用随机向量模拟 CLIP 风格的双塔嵌入对比余弦相似度 / 欧氏距离 在召回率上的差异""" import numpy as np  class CrossModalSearch:    def __init__(self, img_embeds, txt_embeds, normalize=True):        if normalize:            img_embeds = img_embeds / np.linalg.norm(img_embeds, axis=1, keepdims=True)            txt_embeds = txt_embeds / np.linalg.norm(txt_embeds, axis=1, keepdims=True)        self.img_emb = img_embeds        self.txt_emb = txt_embeds     def search(self, query, metric="cosine"):        if metric == "cosine":            scores = self.img_emb @ query        else:            diff = self.img_emb - query            scores = -np.sqrt((diff * diff).sum(axis=1))        return np.argsort(scores)[::-1]     def recall_at_k(self, txt_idx, metric="cosine", k_list=(1, 5)):        query = self.txt_emb[txt_idx]        order = self.search(query, metric=metric)        hit_rank = int(np.where(order == txt_idx)[0][0]) + 1        return {k: int(hit_rank <= k) for k in k_list}  def make_data(n_pairs=200, dim=128, noise=0.35):    rng = np.random.default_rng(42)    semantic = rng.normal(size=(n_pairs, dim))    img = semantic + noise * rng.normal(size=(n_pairs, dim))    txt = semantic + noise * rng.normal(size=(n_pairs, dim))    return img, txt  def evaluate(normalize):    img_emb, txt_emb = make_data()    model = CrossModalSearch(img_emb, txt_emb, normalize=normalize)    n = txt_emb.shape[0]    acc = {}    for metric in ("cosine", "euclidean"):        sums = np.zeros(2)        for i in range(n):            r = model.recall_at_k(i, metric=metric)            sums[0] += r[1]            sums[1] += r[5]        acc[metric] = sums / n    return acc  if __name__ == "__main__":    for norm in (True, False):        acc = evaluate(norm)        print("归一化=%s 余弦 R@1=%.3f R@5=%.3f | 欧氏 R@1=%.3f R@5=%.3f" % (            norm,            acc["cosine"][0], acc["cosine"][1],            acc["euclidean"][0], acc["euclidean"][1]))
目的:用随机向量模拟双塔嵌入,验证“归一化后余弦与欧氏排序等价、不归一化时结论分道扬镳”这一核心结论。
  1. img_embeds / np.linalg.norm(..., axis=1, keepdims=True)把所有图像嵌入拉回单位球面,抹掉模长影响。
  2. self.img_emb @ query一次矩阵乘法完成全库余弦打分,向量化极快。
  3. np.argsort(scores)[::-1]分数降序排列,得到候选排名。
  4. hit_rank = int(np.where(order == txt_idx)[0][0]) + 1找到正确匹配落在第几位。
  5. semantic + noise * rng.normal(...)每对图文共享同一语义向量,再加独立噪声模拟模态差异。
  6. evaluate(normalize)控制是否归一化,对比两种度量在不同条件下的召回表现。

常见误区

误区反正都是算“像不像”,归一化之后结果都一样,那我直接在代码里用 `np.dot` 手动实现一个,干嘛还要纠结选哪个度量?

正解归一化之后两者排序确实等价,但很多真实系统并不会对全部特征做 L2 归一化,尤其是模长本身携带语义或者特征各维尺度差异很大的时候。把模长当作噪声丢掉,或把模长当作关键信息,会得到完全不同的检索结果。训练时用的损失度量和上线时排序用的度量如果不一致,模型学到的区分能力就发挥不出来。

为何常见:因为现有教程常常只讲“归一化后等价”的结论,却省略了前提条件,小白很容易把这个特例当成普遍规律。

误区温度 τ 设为 0.001,损失把正负样本差距放大 1000 倍,模型肯定会学得更快更好?

正解τ 极小会使得 softmax 分母里除了最大项外几乎全为 0,梯度被最难的单个负样本绑架,训练剧烈震荡甚至发散。τ 极大则梯度过于平滑,模型失去对细微差异的敏感性。好的做法是在 0.01~0.1 范围内做小规模调参,观察验证集 Recall 曲线来确定。

为何常见:人们容易把“严厉”等同于“有效”,忽略了对比学习中梯度需要合理的尺度才能稳定传播。

误区既然难例能逼模型进步,我干脆把每个批次里相似度最高的 80% 的负样本全当难例,模型一定更鲁棒。

正解全是难例的训练集等于让寻人专员永远在双胞胎堆里找人,他会被极端情况带偏,对普通样本反而失去识别力。工业界常用混合策略:一部分随机负样本维持分布稳定,一部分困难负样本逼出区分力。这个比例本身也是要调的。

为何常见:看到论文里“难例挖掘带来精度提升”就以为越多越好,忽略了论文里难例的筛选阈值和采样比例都是精心调过的。

误区既然叫“零样本”,那预训练模型下载下来,输一句话就能完美检索,一切参数都不用动。

正解零样本只是指“不需要为下游任务重新训练”,但相似度度量、温度系数、检索阈值这些仍然影响结果。CLIP 在自然图片上表现不错,换到医疗、卫星图等新域,零样本精度会明显下降,通常需要评估后在度量选择和阈值上做适配,甚至做轻量微调。

为何常见:术语里的“零”容易让人误以为“什么都不用做”,忽略了零样本的假设是“测试分布与预训练分布足够接近”。

面试题

Q1. 跨模态检索中,将文本与图像映射到同一向量空间的主要目的是什么?

单选题 · easy

  • A.减少模型参数量
  • B.统一相似度比较← 正确答案
  • C.加速数据加载
  • D.提升显存利用率

答案:B。只有把不同模态都变成同一空间里的向量,才能用统一的度量函数打分排序。减少参数量、加速加载、提升显存都不是“映射到同一空间”的目的。

Q2. 余弦相似度对下列哪一项不敏感?

单选题 · mid

  • A.向量的长度← 正确答案
  • B.向量的维度
  • C.向量的方向
  • D.向量的稀疏度

答案:A。余弦相似度在分母中用模长做了归一化,所以向量长度(模长)不影响结果。它敏感的是方向;维度、稀疏度都在几何结构中,不是“长度”本身。

Q3. 特征各维尺度差异较大时,哪种度量最容易被大尺度维度主导?

单选题 · mid

  • A.余弦相似度
  • B.欧氏距离← 正确答案
  • C.马氏距离
  • D.曼哈顿距离

答案:B。欧氏距离对每一维平方求和,量纲大的维度贡献的平方项更大,会淹没小尺度维度。马氏距离能用协方差校正尺度,余弦也有一定归一化作用,但欧氏不设防。

Q4. 马氏距离相对欧氏距离的主要优势是什么?

单选题 · hard

  • A.考虑特征相关结构← 正确答案
  • B.计算速度更快
  • C.无需估计协方差
  • D.对异常值不敏感

答案:A。马氏距离用协方差矩阵的逆消除特征维度间的相关性,并自适应各维方差;代价是需要估计协方差矩阵,计算也更贵,所以 B、C 是错误描述。

Q5. 对比损失中温度系数趋于零时,softmax 分布会怎样?

单选题 · easy

  • A.变得平滑均匀
  • B.接近独热分布← 正确答案
  • C.保持完全不变
  • D.出现梯度消失

答案:B。温度趋近零时,分数差距被无限放大,最大项概率趋近 1,其余项趋近 0,所以分布接近 one-hot。此时梯度通常不是消失而是可能爆炸,因此 D 不对。

Q6. 下列哪些场景下,余弦相似度可能不是最佳选择?

多选题 · mid

  • A.向量模长携带重要语义← 正确答案
  • B.所有特征已做 L2 归一化
  • C.各维度尺度差异极大← 正确答案
  • D.检索需要比较绝对距离← 正确答案

答案:ACD。余弦丢掉了模长,所以模长携带语义(A)时不适合;各维度尺度差异大时,余弦的内积也会被大尺度维主导(C);需要绝对距离排序时余弦只给方向(D)。已做 L2 归一化的场景余弦表现稳定,不是问题场景。

Q7. 困难负样本挖掘中,选取的负样本通常是哪一类?

单选题 · mid

  • A.与正样本完全不相关的样本
  • B.与锚点相似度最高的错误样本← 正确答案
  • C.从数据集中随机抽取的样本
  • D.与锚点距离最远的负样本

答案:B。难例挖掘要挑“几乎匹配但其实是错”的样本,因为它们对梯度贡献大,才能逼模型学会精细区分。距离最远或完全不相关的样本太容易排除,训练收益低。

Q8. 关于零样本检索与微调检索,下列说法正确的是哪些?

多选题 · hard

  • A.零样本检索直接使用预训练模型推理← 正确答案
  • B.微调检索通常用配对数据继续训练← 正确答案
  • C.微调会覆盖全部预训练参数
  • D.零样本检索完全不受训练数据影响

答案:AB。零样本意味着不做下游训练直接推理,所以 A 对;微调就是用下游配对数据以小学习率继续训练,B 对。微调通常用低学习率保留通用语义,不会“全部覆盖”,C 错。零样本的精度上限由预训练分布决定,D 错。

Q9. Recall@5 的含义是什么?

单选题 · easy

  • A.正确结果排进前五名的比例← 正确答案
  • B.模型在五个数据集上的平均精度
  • C.需要五次检索才能收敛
  • D.负样本数量占总样本五成

答案:A。Recall@K 是统计所有查询中,正确答案排名不超过 K 的比例。K=5 就是“前五个结果里能找对”的比例,与数据集数量、收敛速度、负样本比例无关。

Q10. 一个已冻结文本编码器的跨模态检索系统要提升图文匹配精度,可采取哪些有效措施?

多选题 · extreme

  • A.调整温度系数与挖掘难负例← 正确答案
  • B.改用马氏距离度量嵌入关系← 正确答案
  • C.随机打乱批次内样本顺序
  • D.在训练中只保留最难的负样本

答案:AB。温度系数和难例挖掘影响训练分布和梯度,能有效提升匹配精度;度量函数替换直接影响排序,B 也可行。打乱样本顺序不改变数据内容和损失,C 无效;只保留最难负样本会导致训练失衡,D 是常见陷阱。