5986 字
30 分钟
AI 相册识别原理,一句话搜图是怎么做到的

AI 相册识别原理,一句话搜图是怎么做到的#

1 序言:先看它解决了什么问题#

自部署相册(Immich、MT Photos、飞牛相册)这两年集体上线了一个能力:不用翻文件夹、不用记文件名,输入一句话就能把照片捞出来。

  • 在搜索框输入「灯火通明的街道」,能返回对应照片;

  • 输入「海边看日落」,能跨过所有相册把场景找齐;

  • 相册自动把同一个人的照片聚合在一起,生成「人物相册」,点开就是 TA 从小到大的记录。

这套能力背后不是某个单一模型,而是两类模型 + 一套检索基础设施的分工:

能力用的模型回答的问题
语义搜图CLIP 双塔模型一句话和一张图「像不像」
人物相册人脸检测 + 人脸识别 + 聚类两张脸是不是同一个人
向量检索pgvector / VectorChord 等百万向量里怎么快速找最近的

先说一个很多人会问的问题:这背后是信号系统还是傅里叶变换? 答案在第三章,都不是 —— 真正的主角是线性代数里的向量内积和机器学习里的对比学习。傅里叶在这条链路里确实存在,但它管的是 JPEG 压缩,不负责「理解」。

2 全局架构:三套件各司其职#

先看一张总图,把整条链路串起来:

┌────────────────────────────────────┐
│ 本地推理服务 │
照片入库 │ │
│ 扫描 + 生成预览图 │ CLIP 图像编码器 ──► 图像向量(512维) │
▼ │ 人脸检测/对齐/特征 ─► 人脸向量(512维) │
图片库 ─────────────►│ │
└──────────────┬─────────────────────┘
│ 写入
▼
向量存储(pgvector 等)
▲
用户输入「海边看日落」 │ 查询
──► CLIP 文本编码器 ──► 文本向量 ─┘
│
▼
余弦相似度排序,取 top-k 返回

两个要点:

  • 离线阶段把图「翻译」成向量。照片入库时先跑一遍推理,把每张图变成一串数字(embedding),存进数据库。用户搜索时不用再碰原图,只做向量计算。
  • 全程本地推理。三个产品的模型都跑在 NAS 自己的 CPU/GPU 上,照片不出内网 —— 这是自部署相册相对 iCloud/Google Photos 的核心差异。

3 数学内核:不是信号系统,也不是傅里叶变换#

先直接回答标题里的问题。 AI 相册的数学核心不是傅里叶变换,也不是经典信号处理,而是四件事:向量内积、对比学习、仿射变换、密度聚类。 它们恰好分布在链路的不同环节:

数学工具用在哪管什么
余弦相似度 / 向量内积语义检索、人脸对比「像不像」的量化度量
对比学习(InfoNCE 损失)CLIP 模型训练学出一个「语义即距离」的向量空间
仿射 / 相似变换人脸对齐把歪着的脸几何摆正
密度聚类(DBSCAN)人物相册聚合无监督地把人脸自动分组
DCT(离散余弦变换,傅里叶家族)JPEG/WebP 压缩、缩略图频域压缩,不参与语义理解
卷积(CNN 内部)图像编码器可学习的局部特征提取
下面把每个公式讲透,都是从「一张图 = 一个向量」这个起点推导出来的。

3.1 余弦相似度:相册里出现频率最高的公式#

一切的起点是:把图、句子、人脸都表示成向量。有了向量,相似度就有了统一的度量 —— 夹角余弦:

cos⁡(θ)=a⋅b∥a∥⋅∥b∥=∑iaibi∑iai2⋅∑ibi2\cos(\theta) = \frac{a \cdot b}{\|a\| \cdot \|b\|} = \frac{\sum_i a_i b_i}{\sqrt{\sum_i a_i^2} \cdot \sqrt{\sum_i b_i^2}}

其中 a⋅b=∑iaibia \cdot b = \sum_i a_i b_i 是内积(对应分量相乘再求和),∥a∥=∑iai2\|a\| = \sqrt{\sum_i a_i^2} 是 L2 范数(向量的长度)。

几何含义:两个向量夹角的余弦。方向越一致,值越接近 1;方向越正交,越接近 0;方向相反,接近 -1。它天然在 [−1,1][-1, 1],不随向量长度变化 —— 这正是我们要的:判断「语义像不像」只关心方向,不关心图的亮度、对比度这类幅度信息。

举个 3 维的数值例子(真实系统是 512 维,道理一样)。两张同一个人的人脸向量:

a=(0.8, 0.5, 0.2)b=(0.7, 0.6, 0.1)a = (0.8,\ 0.5,\ 0.2) \qquad b = (0.7,\ 0.6,\ 0.1)

a⋅b=0.8×0.7+0.5×0.6+0.2×0.1=0.56+0.30+0.02=0.88a \cdot b = 0.8 \times 0.7 + 0.5 \times 0.6 + 0.2 \times 0.1 = 0.56 + 0.30 + 0.02 = 0.88

∥a∥=0.82+0.52+0.22=0.93≈0.964\|a\| = \sqrt{0.8^2 + 0.5^2 + 0.2^2} = \sqrt{0.93} \approx 0.964

∥b∥=0.72+0.62+0.12=0.86≈0.927\|b\| = \sqrt{0.7^2 + 0.6^2 + 0.1^2} = \sqrt{0.86} \approx 0.927

cos⁡(θ)=0.880.964×0.927≈0.880.894≈0.98\cos(\theta) = \frac{0.88}{0.964 \times 0.927} \approx \frac{0.88}{0.894} \approx 0.98

再来一个不同人的人脸向量:

a=(0.8, 0.5, 0.2)c=(0.1, −0.3, 0.9)a = (0.8,\ 0.5,\ 0.2) \qquad c = (0.1,\ -0.3,\ 0.9)

a⋅c=0.8×0.1+0.5×(−0.3)+0.2×0.9=0.08−0.15+0.18=0.11a \cdot c = 0.8 \times 0.1 + 0.5 \times (-0.3) + 0.2 \times 0.9 = 0.08 - 0.15 + 0.18 = 0.11

∥c∥=0.12+0.32+0.92=0.91≈0.954\|c\| = \sqrt{0.1^2 + 0.3^2 + 0.9^2} = \sqrt{0.91} \approx 0.954

cos⁡(θ)=0.110.964×0.954≈0.110.920≈0.12\cos(\theta) = \frac{0.11}{0.964 \times 0.954} \approx \frac{0.11}{0.920} \approx 0.12

设判定阈值 0.50.5:0.98>0.50.98 > 0.5 → 同一个人;0.12<0.50.12 < 0.5 → 不同人。「对比人物图片」在数学上就是这么一句话:算内积,比阈值。

工程上还有个常用技巧 ——L2 归一化:先把每个向量除以自己的长度,让 ∥a^∥=1\|\hat{a}\| = 1,再算内积:

a^=a∥a∥,b^=b∥b∥\hat{a} = \frac{a}{\|a\|}, \qquad \hat{b} = \frac{b}{\|b\|}

cos⁡(θ)=a^⋅b^\cos(\theta) = \hat{a} \cdot \hat{b}

归一化后,内积直接等于余弦相似度。归一化有两个好处:一是所有向量落在同一个单位球面上,距离比较公平;二是省一次除法—— 模型直接输出归一化向量,查询时一个点积完事。insightface 的 normed_embedding 就是这个东西。

3.2 对比学习:CLIP 是怎么「学」出这个空间的#

余弦相似度只是尺子,尺子本身是训练出来的。CLIP 的核心不是模型结构,而是它的训练目标 —— 对比学习(contrastive learning)。

取一个 batch 的 NN 对图文(图 IiI_i 配文 TiT_i),算 N×NN \times N 的相似度矩阵,对角线是正确配对。损失用带温度系数的 InfoNCE(也叫多类 NCE):

sij=cos⁡(Ii,Tj)τs_{ij} = \frac{\cos(I_i, T_j)}{\tau}

Li=−log⁡[exp⁡(sii)∑jexp⁡(sij)]L_i = -\log\left[ \frac{\exp(s_{ii})}{\sum_j \exp(s_{ij})} \right]

L=12N(∑iLi+∑jLj)L = \frac{1}{2N}\left( \sum_i L_i + \sum_j L_j \right)

其中 τ\tau 是温度系数。这个式子等价于:对第 行做 softmax,目标是对角线位置概率为 1。逐项看:

  • 分子 exp⁡(sii)\exp(s_{ii}):正确配对要尽量相似,分数越高越好;

  • 分母 ∑jexp⁡(sij)\sum_j \exp(s_{ij}):所有配对(含错误的)一起归一化,逼着模型把负样本的分数压低;

  • 温度 τ\tau:缩放整个相似度分布。τ\tau 越小,softmax 越尖锐,模型对「难分」的负样本越敏感,训练越激进;τ\tau 太大则梯度消失,学不动。

文本1 文本2 文本3
图1 ✓ ✗ ✗
图2 ✗ ✓ ✗ ← 对角线为正确配对(InfoNCE 拉近)
图3 ✗ ✗ ✓ 非对角线为负样本(推远)

训练完成后,模型学到了一个嵌入函数 **** :任何图、任何句子,经过它都映射成 512 维向量,并且语义相近的对象在向量空间里距离近。这整套思路在机器学习里叫度量学习(metric learning)—— 不直接学「这是猫」,而是学「猫和猫的向量该靠多近」。

3.3 傅里叶变换到底在哪:它管压缩,不管理解#

既然你问到傅里叶,那就把它在相册链路里的位置讲清楚 ——它真实存在,但负责的是图像压缩,不是语义识别:

  • JPEG / WebP 的 DCT(离散余弦变换):DCT 是离散傅里叶变换(DFT)的实值变体。压缩时把图像切成 8×8 的像素块,每个块做 DCT,得到 64 个频域系数 —— 低频在前、高频在后,然后丢掉人眼不敏感的高频分量,实现几倍到几十倍的压缩。你在相册里看到的预览图、缩略图,全都经过这一层;

  • 清晰度 / 模糊检测:模糊照片在频域上就是高频能量衰减,可以用频域指标评估;

  • CNN 卷积与傅里叶的联系:卷积定理 F(f∗g)=F(f)⋅F(g)F(f \ast g) = F(f) \cdot F(g) 说「时域卷积 = 频域相乘」,理论上可以用 FFT 加速卷积。但 ONNX Runtime 实际推理用的是直接卷积和 Winograd 算法,不依赖 FFT—— 这是实现细节,不是设计思想。

一句话总结:傅里叶管「像素的频域结构」,深度学习管「像素的语义」。CLIP 和人脸模型要回答的是「画面里有什么、这是谁」,这种高层语义没有固定的频域特征,只能靠数据驱动学出来。而信号系统(滤波、卷积)在 CNN 内部确实存在 —— 每个卷积核就是一组可学习的滤波器,但它只是构建特征的手段,不是相册系统设计的主线数学。

4 语义搜索:CLIP 双塔模型#

4.1 为什么不能用「打标签」#

传统图片搜索是给每张图人工打标签(海滩、日落、人),再按标签匹配。这条路在个人相册场景直接死掉:

  • 标签穷举不完。「灯火通明的街道」这种描述,事前根本想不到要打这个标签;

  • 组合语义没法枚举。「海边看日落」是「海 + 日落 + 人在场」的语义组合,不是三个标签的简单叠加;

  • 召回靠运气。标签没打准,照片就永远搜不到。

CLIP 的思路完全不同:不生成任何标签,直接把图和句子映射到同一个向量空间,让「一张图」和「一句描述它的话」在空间里离得足够近。

4.2 双塔编码器#

CLIP(Contrastive Language–Image Pre-training)由两个独立编码器组成:

  • 图像编码器:用 ViT(如 ViT-B/32)或 ResNet 系列,把图片编码成向量;

  • 文本编码器:基于 Transformer,把句子编码成向量。

两个编码器的输出经过投影层对齐到同一维度(如 512 维)。训练目标就是 3.2 节的 InfoNCE:「猫的图片」和「一只猫」这两个向量在空间里距离很近,而与「一辆车」的向量距离很远。这样一来,图片和文字就被统一到了同一把「尺子」上。

4.3 对比学习训练#

训练数据是海量「图文对」(OpenAI 原始版本用了约 4 亿对网络图文)。流程:

  1. 取一个 batch 的 NN 对图文,图像、文本分别过两个编码器,得到 N×NN \times N 相似度矩阵;

  2. 对角线是「正确配对」(图 1 ↔ 文 1),其余是负样本;

  3. 按 3.2 节的 InfoNCE 损失反向传播,拉近对角线、推远非对角线。

训练完成后,CLIP 天然获得零样本分类能力:把候选类别写成句子(a photo of a dog),与图片向量算相似度,最高者即预测类别。

4.4 推理:一句话变向量#

搜索时只做两件事:

  1. 把用户输入的一句话(如「夕阳下的沙滩」)过文本编码器,得到一个文本向量;

  2. 用这个向量和库里所有图片向量算余弦相似度(3.1 节公式),按分数从高到低排序,取 top-k 返回。

关键点:CLIP 匹配的是「语义」而不是「关键词」。图片里没有「夕阳」这个字的标签,但只要画面语义接近,向量距离就近。Immich 官方 FAQ 也明确说明:系统不会生成任何 tags、labels 或 descriptions,搜索完全靠向量相似度。

4.5 三家用的 CLIP 模型#

产品默认语义模型特点
ImmichCLIP ViT-B-32(可切换其他 CLIP 变体)开源、社区模型多,官方提供切换列表
MT PhotosXLM-Roberta-Base-ViT-B-32(LAION-5B 训练)多语言文本编码器,中文理解更好;官方说明该模型「解决了不认识颜色的问题」
飞牛相册智能识别模型(基础 / 增强两档)按硬件推荐,增强模型理解更精准、更占资源

中文用户选模型时要注意:CLIP 的文本编码器决定它「懂不懂中文」。用英文训练集的原始 ViT-B-32 搜中文,效果会明显打折;MT Photos 之所以换多语言模型,就是为了修这个问题。

5 向量检索:从「全库遍历」到「最近邻」#

向量算出来了,接下来是检索问题:几十万张照片,怎么快速找出与查询向量最接近的一批?

5.1 存哪、怎么查#

最简单的方式是全库暴力遍历 ——512 维向量的余弦计算非常快,十几万条也只是毫秒级,小相册完全够用。规模再大,就需要专门的向量存储:

  • pgvector:PostgreSQL 的向量扩展,把 embedding 当普通列存,SQL 里直接做最近邻查询。Immich 早期版本用它;

  • VectorChord:pgvector 的磁盘优化重写版(解决向量膨胀和写入放大)。Immich 新版文档明确说明语义搜索由 VectorChord 驱动;

  • 更大规模还可以上 HNSW / IVF 这类近似最近邻索引,用一点精度换数量级速度。

数学上,最近邻问题就是:给定查询向量 qq,在集合 DD 里找

arg⁡max⁡x∈Dcos⁡(q,x)⟺arg⁡min⁡x∈D(1−cos⁡(q,x))\arg\max_{x \in D} \cos(q, x) \qquad \Longleftrightarrow \qquad \arg\min_{x \in D} \big( 1 - \cos(q, x) \big)

距离和相似度只是互为 1 的补:d=1−cos⁡(θ)d = 1 - \cos(\theta)。距离越小越像,这个换算在后面飞牛阈值那里还会用到。

5.2 一行 SQL 的事#

pgvector 风格的真实查询长这样:

-- <=> 是余弦距离算子,按距离升序取最近的 100 个
SELECT asset_id
FROM asset_embedding
ORDER BY embedding <=> $1
LIMIT 100;

对用户来说这是「一句话搜图」;对系统来说,这就是一次向量距离排序。整个搜索过程没有碰任何图片文件。

6 人脸识别:检测、对齐、特征、聚类#

「人物相册」和「对比两张图是不是同一个人」是同一套流水线的两个阶段,完整链路是:

图片 ─► 人脸检测(找脸+关键点) ─► 对齐(摆正) ─► 特征提取(512维向量)
│
├─ 两张图:算余弦相似度 → 阈值判断「是不是同一人」
└─ 全库:聚类 → 生成人物相册

6.1 检测:先找到脸在哪#

第一步从图片里找出人脸框(bounding box)和 5 个关键点(两眼、鼻尖、两口角),并给出置信度。

Immich 和 MT Photos 都用 insightface 家族的 buffalo_l 模型包:检测器是 SCRFD(RetinaFace 一脉的轻量高效检测器),在 CPU 上也能跑得动。飞牛官方把它称为「人脸识别 - 标准模型」。

这一步还负责过滤:检测置信度低于阈值就当作「没有人脸」,直接跳过。飞牛的人脸设置里那个 置信度阈值(默认 0.65) 管的就是这个环节。

6.2 对齐:把脸摆正(几何变换)#

侧脸、低头、仰角都会让特征提取质量下降。用检测出的 5 个关键点做一次几何变换,把眼睛、鼻子、嘴巴「转」到标准位置,再裁出人脸区域。对齐是特征稳定的前提,跳过这一步,同一张脸在不同角度下特征会漂移。

数学上是标准的相似变换(旋转 + 等比缩放 + 平移,保形不变),矩阵形式:

[x′y′1]=[scos⁡α−ssin⁡αtxssin⁡αscos⁡αty001][xy1]\begin{bmatrix} x' \\ y' \\ 1 \end{bmatrix} = \begin{bmatrix} s\cos\alpha & -s\sin\alpha & t_x \\ s\sin\alpha & s\cos\alpha & t_y \\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} x \\ y \\ 1 \end{bmatrix}

其中 ss 是缩放、α\alpha 是旋转角、tx/tyt_x/t_y 是平移。用标准 5 点(左右眼、鼻尖、左右口角)和检测出的 5 点解这个方程,求出 ss、α\alpha、tt,把原图像素按矩阵映射到标准位置即可。insightface 内部做的就是这件事。

6.3 特征:512 维人脸指纹#

对齐后的人脸图送入识别模型(buffalo_l 内是 ArcFace 系的 w600k_r50),输出一个 512 维的归一化向量—— 相当于这张脸的「数字指纹」。同一个人不同照片的指纹相似,不同人差异大。

为什么是 512 维?这是经验与工程权衡的结果:维度越高,容纳的区分信息越多,但存储、计算、过拟合风险也同步上升。人脸领域在 128–1024 维之间都有人用,ArcFace 论文验证 512 维在精度和速度上平衡最好。

insightface 官方 API 的用法就是直白的「取向量、算点积」:

from insightface.app import FaceAnalysis
import cv2
app = FaceAnalysis(name="buffalo_l")
a = app.get(cv2.imread("a.jpg"))[0].normed_embedding # 人脸A的512维向量
b = app.get(cv2.imread("b.jpg"))[0].normed_embedding # 人脸B的512维向量
score = a @ b # 归一化向量的点积 = 余弦相似度,0~1
is_same = score > 0.5 # 超过阈值判定为同一人

6.4 对比:两张图是不是同一个人#

这就是「对比人物图片」的原理,数学版本:

提取两张脸各自的 512 维特征向量,按 3.1 节公式算余弦相似度

超过阈值

就是同一个人。

阈值是召回与误判的平衡点:

  • 阈值调低 → 更容易把不同的人判成同一人(漏放行);

  • 阈值调高 → 更严格,但同一个人可能被拆成多个相册。

这里有个容易混淆的点要拆开:相似度阈值和距离阈值是互补的。距离 d=1−cos⁡(θ)d = 1 - \cos(\theta),所以「差异阈值」和「相似度门槛」互为补数:

sth=1−dths_{\text{th}} = 1 - d_{\text{th}}

飞牛默认差异阈值 0.360.36 ⇒ 相似度门槛 =1−0.36=0.64= 1 - 0.36 = 0.64;差异阈值调到 0.200.20 ⇒ 相似度门槛 =0.80= 0.80(更严格)。飞牛官方说明「调低差异阈值,相似度要求会提高」—— 按这个公式看就完全自洽了:差异阈值越低,门槛越高,只有长得更像的才会被并进同一个人物相册。

6.5 聚类:自动生成人物相册(DBSCAN)#

相册里可能有几千张脸,不可能两两人工对比。系统把这步交给无监督聚类:把所有 512 维向量丢进聚类算法,让「距离近」的脸自动归成一组,一组就是一个人物相册。

Immich 官方说明其聚类算法是 DBSCAN 的变体。DBSCAN 是纯密度聚类,不需要预知有多少个人,数学定义很干净:

Nε(p)={ q∈D∣dist⁡(p,q)≤ε }N_\varepsilon(p) = \{\, q \in D \mid \operatorname{dist}(p, q) \le \varepsilon \,\}

核心点:∣Nε(p)∣≥MinPts\text{核心点:} \left| N_\varepsilon(p) \right| \ge \mathrm{MinPts}

逐条拆开:

  • Nε(p)N_\varepsilon(p) 是 pp 的 ε\varepsilon 邻域:以 pp 为圆心、ε\varepsilon 为半径内的所有点;

  • 核心点:邻域内至少有 MinPts\mathrm{MinPts} 个点;

  • 密度直达:q∈Nε(p)q \in N_\varepsilon(p) 且 pp 是核心点;

  • 密度可达:存在一条核心点链 p→⋯→qp \to \dots \to q;

  • 噪声:不属于任何簇的点(孤立点)。

直观理解:把每个人脸当成空间里的一个点,凡是「周围挤得够密」的区域各自成一簇;稀稀拉拉的点直接判为噪声—— 正好对应「只出现过一次的路人甲不生成人物相册」。

对照飞牛的设置就更好懂了:「生成人物的最少照片数(默认 2)」≈ MinPts\mathrm{MinPts} —— 一个人至少出现几次才配拥有人物相册;「相似度差异阈值(默认 0.36)」≈ ε\varepsilon —— 脸像到什么程度算同一人(半径内算邻居)。

聚类只是初筛,最后一步永远是人类兜底:命名、合并(同一个人被拆开)、移除(混入陌生人)。飞牛和 Immich 都提供这些手动修正操作。

7 三家实现横向拆解#

维度ImmichMT Photos飞牛相册
语义搜图CLIP(默认 ViT-B-32,可换)CLIP(多语言模型,中文友好)智能识别模型(基础 / 增强)
人脸识别insightface buffalo_linsightface buffalo_l人脸识别 - 标准模型
OCR支持(本地 OCR)PP-OCRv5_mobile未单列
向量存储Postgres + pgvector → VectorChord服务端内置索引本地存储
架构形态server + 独立 machine-learning 容器服务端进程 / 可接外部 API相册应用内置模块
任务调度队列 + 后台任务后台任务列表(人脸特征、CLIP、场景识别)安装模型后自动执行,可手动补扫
开源✅ 开源❌ 商业(免费)❌ 闭源(随 fnOS 提供)

几个值得注意的差异:

  • MT Photos 把流程拆成了可见的后台任务:人脸特征识别 → 人脸特征对比(生成人物相册)→ CLIP 识别 → 照片场景识别。场景识别还基于 CLIP 识别结果二次加工,比如识别出「室内 / 户外」这类粗分类;

  • 飞牛把「增强识别」做成了选项:视频默认只做基础识别,开启「视频增强识别」后对视频内容加深理解,搜索能捞到更多视频项,代价是计算资源占用上升;

  • Immich 的开源生态最灵活:模型可换、向量库可换、还能用外部 ML API 替代本地推理。

8 部署与性能:模型跑在哪#

三个产品的模型都跑在本地,技术栈高度一致:ONNX Runtime + 预训练模型文件(insightface、CLIP 都是 ONNX 格式),好处是 CPU 可跑、有 GPU 时自动加速。

硬件门槛以飞牛官方给的最低要求为准(三家量级接近):

项目要求
内存最低 2 GB;智能识别 - 增强模型需 8 GB
模型占用空间预留 20 GB 以上
GPU人脸识别支持 Intel GPU 与 NVIDIA(GeForce 700 以上);智能识别同样支持
CPU 兜底无 GPU 也能跑,只是慢

性能上还有三条通用优化手段:

  1. 送缩略图,不送原图。推理输入的是预览图(几百像素),不是原尺寸照片,推理速度与内存占用差一个数量级;

  2. 视频抽帧。视频先抽关键帧 / 间隔帧,只对帧做人脸与内容识别,识别结果回挂到整个视频;

  3. 任务队列分批执行。入库高峰时排队跑,避免推理服务把 NAS 的 CPU 打满。

9 局限与优化方向#

原理清楚了,也该说清楚它的边界:

  • CLIP 是「语义近似」不是「精确理解」。「红色车子左边的那个人」这类空间 / 数量关系,CLIP 表现很弱;它擅长的是「整体像不像」,不是「逻辑对不对」;

  • 聚类永远是启发式的。同一个人被拆成多个相册、路人被聚成「人物」,是常态,必须有手动合并 / 移除兜底;

  • 阈值是玄学。检测阈值、相似度阈值、最少照片数,每个都影响结果,改完还得重置重跑;

  • 视频识别计算量大。全量视频增强识别,小内存 NAS 会明显卡顿;

  • 中文语义模型的差距。用英文 CLIP 搜中文描述会明显变差,选模型时优先多语言版本(如 MT Photos 默认款)。

可以预见的方向:CLIP 往 SigLIP 这类更高效的双塔演进、向量库往更省磁盘的方向走(VectorChord 已经是这个方向)、人脸模型针对亚洲面孔持续微调(MT Photos 选 insightface 的理由之一就是「对亚洲人脸准确率更高」)。

10 总结#

  • 一句话搜图 = CLIP 双塔模型把图和句子映射到同一向量空间 + 向量检索按余弦相似度取 top-k;

  • 人物相册 = 人脸检测(找脸)→ 相似变换对齐(摆正)→ ArcFace 提取 512 维特征 → DBSCAN 密度聚类自动分组;

  • 对比两张图是不是同一个人 = 两个 512 维向量算余弦相似度,超阈值即同一人;

  • 数学内核不是傅里叶:向量内积(余弦相似度)、对比学习(InfoNCE)、仿射变换(对齐)、密度聚类(DBSCAN)才是主角;DCT 只负责 JPEG 压缩;

  • 全程本地推理是自部署相册与云相册的分水岭,照片不出 NAS,换来的是隐私,付出的是算力。

参考#

Created with ❤️ by 张萌萌

AI 相册识别原理,一句话搜图是怎么做到的
https://zmm.nw177.cn/posts/10-技术专栏/50-ai/05ai-相册识别原理一句话搜图是怎么做到的/
作者
张萌萌
发布于
2026-10-24
许可协议
CC BY-NC-SA 4.0

分享文章

生成精美分享图或复制链接,与更多人分享本文。

继续阅读

沿着主题读

基于共同的标签与分类

换条路线

从其他文章中稳定抽取

评论

正在加载评论...