2. 特征提取基础:图像特征(CNN/ViT)、文本特征(BERT/)、音频特征(MFCC/CLAP)

跨模态检索的核心,说白了就是让不同模态的数据在同一个特征空间里“对话”。而特征提取,就是给每种模态的数据“翻译”成机器能理解的向量。这一步做不好,后面的对齐和检索全是空中楼阁。我这些年调过的系统里,至少有一半的性能问题,根子都出在特征提取上。

2.1 图像特征:从 CNN 到 ViT

图像特征提取,过去十年基本是 CNN 的天下。但这两年,ViT 开始抢班夺权了。咱们得两手都抓。

2.1.1 CNN 特征:ResNet 的“残差”哲学

CNN 通过卷积核滑动窗口提取局部特征,层数越深,感受野越大。但层数一深,梯度消失问题就来了。ResNet 的解决方案很巧妙——引入残差连接。

核心公式:输出 = F(x) + x

让网络直接学习“残差”F(x),而不是完整的映射。这样梯度可以直通浅层,训练 100 层以上的网络也不怕。

我在项目中常用的是 ResNet-50 或 ResNet-101,在 ImageNet 上预训练后,去掉最后的全连接层,取倒数第二层的 2048 维向量作为图像特征。效果稳定,部署也方便。

我的经验:如果你做细粒度检索(比如不同款式的鞋子),建议用 ResNet-101。如果是粗粒度场景(比如区分猫和狗),ResNet-50 就够了,还能省一半显存。

2.1.2 ViT 特征:把图像当句子看

ViT 的思路很直接:把图像切成 16x16 的 patch,每个 patch 拉平后当成一个“词”,然后扔给 Transformer 处理。它天然能捕捉全局依赖,不像 CNN 要靠堆叠层数来扩大感受野。

ViT 输出的 [CLS] 对应的向量,通常作为整张图的全局特征。我个人习惯用 ViT-B/16 作为基线,特征维度 768,比 ResNet 的 2048 小不少,但检索精度往往更高。

模型 特征维度 参数量 适用场景
ResNet-50 2048 25.6M 通用检索、移动端部署
ResNet-101 2048 44.5M 细粒度分类、高精度检索
ViT-B/16 768 86M 全局语义理解、跨模态对齐
ViT-L/16 1024 307M 高精度、大算力场景

避坑指南:ViT 需要大量数据预训练才能发挥威力。如果你只有几千张图,直接用 ViT 效果可能还不如 ResNet。我曾经在一个小数据集上硬上 ViT,结果 mAP 掉了 8 个点。后来换成 ResNet-101 才救回来。

2.2 文本特征:BERT 与 的“双向”与“单向”

文本特征提取,现在基本是预训练语言模型的天下。BERT 和 是两大流派,各有各的脾气。

2.2.1 BERT:双向编码,理解为王

BERT 用 Masked Language Model 做预训练,随机遮住 15% 的词,让模型根据上下文去猜。这种双向机制让它特别擅长“理解”语义。

提取特征时,我通常取 BERT 最后一层的 [CLS] 向量,或者对所有 做平均池化。维度一般是 768(base 版本)。

代码示例:BERT 特征提取

from transformers import BertTokenizer, BertModel

tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertModel.from_pretrained('bert-base-uncased')

text = "A dog is running in the park"
inputs = tokenizer(text, return_tensors='pt', padding=True, truncation=True)
outputs = model(**inputs)

# 取 [CLS] 向量作为文本特征
text_feat = outputs.last_hidden_state[:, 0, :]  # shape: [1, 768]

2.2.2 :单向生成,表达为王

用自回归方式预训练,从左到右逐个预测下一个词。它擅长“生成”而不是“理解”。在跨模态检索里, 的特征通常用于生成式任务,比如图像描述生成。

提取特征时,取最后一层的最后一个 的隐状态。维度也是 768( base)。

模型 预训练方式 特征维度 擅长任务
BERT-base 双向 MLM 768 文本理解、检索、分类
BERT-large 双向 MLM 1024 高精度理解、NLI
单向自回归 768 文本生成、图像描述
单向自回归 12288 少样本生成、对话

我的建议:做文本到图像的跨模态检索,首选 BERT。做图像到文本的生成,可以考虑 。但如果你资源有限,BERT 是更稳妥的选择——它在下游任务上的泛化能力更强。

2.3 音频特征:MFCC 与 CLAP

音频特征提取,传统方法用 MFCC,深度学习时代用 CLAP 这类预训练模型。

2.3.1 MFCC:经典手工特征

MFCC 模拟人耳听觉特性,把音频信号转换成 13-40 维的系数序列。提取流程大致是:预加重 → 分帧 → 加窗 → FFT → Mel 滤波器组 → 对数运算 → DCT。

我一般取 40 维 MFCC,加上一阶和二阶差分,得到 120 维特征。然后做时间维度的平均池化,得到一个固定长度的向量。

MFCC 特征维度:40(静态)+ 40(一阶差分)+ 40(二阶差分)= 120 维

2.3.2 CLAP:跨模态音频预训练

CLAP 是 推出的音频-文本对比学习模型,类似 CLIP 但用于音频。它把音频和文本映射到同一个特征空间,直接输出 512 维或 1024 维的向量。

用 CLAP 提取音频特征,不需要手工设计滤波器,直接输入原始波形或 Mel 频谱图就行。效果比 MFCC 好一大截,尤其在跨模态检索场景下。

方法 特征维度 是否需要标注数据 检索精度
MFCC + 均值池化 120 否 低
CLAP (base) 512 是(预训练) 高
CLAP (large) 1024 是(预训练) 很高

避坑指南:MFCC 对采样率敏感。我曾经用 16kHz 的音频提取 MFCC,换到 44.1kHz 后特征分布全变了,检索结果一塌糊涂。后来统一重采样到 16kHz 才解决问题。如果你用 CLAP,记得把音频重采样到 48kHz,这是它预训练时用的采样率。

2.4 本章知识结构图

下面这张图梳理了三种模态的特征提取路径,以及它们最终汇聚到统一特征空间的过程。

跨模态特征提取知识结构图 跨模态特征提取知识结构 图像模态 CNN (ResNet) ViT 输出: 2048d / 768d 向量 文本模态 BERT 输出: 768d / 1024d 向量 音频模态 MFCC CLAP 输出: 120d / 512d 向量 统一特征空间(对齐与检索) 文本→图像检索 图像→文本检索 音频→文本检索 不同模态的特征维度不同,需要通过投影层映射到同一维度空间才能做对齐

2.5 特征提取的通用原则

不管用哪种模型,有几个原则是通用的:

  • 维度匹配:不同模态的特征最终要映射到同一维度,通常是 256、512 或 768。我习惯用 512 维,平衡了精度和计算开销。
  • 归一化:特征向量一定要做 L2 归一化,否则检索时欧氏距离会被维度高的模态主导。我见过有人没做归一化,结果图像特征总是占主导,文本特征基本没起作用。
  • 预训练权重:尽量用在大规模数据上预训练好的权重,不要从头训练。除非你的数据量超过百万级。
  • 特征存储:提取好的特征建议用 FAISS 或 Milvus 建索引,不要每次检索都重新提取。离线提取、在线检索,这是工业界的标准做法。

我的习惯:每次提取特征后,我都会随机抽 1000 条做一次 t-SNE 可视化,看看不同模态的特征分布是否合理。如果同类样本在空间里散成一团,那说明特征提取有问题,得回去调模型。