3. 数学基础回顾(二)
聊到多模态对齐,很多人第一反应是“找个损失函数算相似度不就完了?”
嗯,如果真这么简单,那多模态感知早就被工程师们玩透了。
实际上,对齐的核心在于不确定性和信息量的度量。
说白了,你得知道两个模态之间到底共享了多少信息,又各自藏着多少噪声。
我个人习惯把概率论和信息论看作多模态对齐的“两把尺子”。
一把量关系,一把量信息。
这一章,我们就来拆开这两把尺子,看看它们到底怎么用。
3.1 贝叶斯定理:对齐的“后验”视角
贝叶斯定理,公式很简单:
P(A|B) = P(B|A) * P(A) / P(B)
但在多模态里,它的意义远不止一个公式。
你想想看,当我们看到一张图片(视觉模态),同时听到一段声音(音频模态),
大脑其实是在做贝叶斯推理——用先验知识去修正当前感知。
在多模态对齐中,贝叶斯定理的核心应用是:
- 先验 P(A):某个模态特征的分布,比如文本中“猫”这个词出现的概率。
- 似然 P(B|A):给定文本“猫”,图像中出现猫形状的概率。
- 后验 P(A|B):看到图像后,对文本“猫”的置信度更新。
关键洞察: 对齐不是简单的特征匹配,而是后验概率的融合。你越能准确估计后验,对齐就越鲁棒。
我在项目中遇到过一个问题:视频和语音的时间戳对不齐。
用贝叶斯框架,我们把时间偏移量当作隐变量,用观测到的音频特征去更新偏移量的后验分布。
效果比直接硬对齐好很多。
3.2 熵:不确定性的“温度计”
熵,衡量的是一个随机变量的不确定性。
公式:
H(X) = - Σ p(x) log p(x)
为什么在多模态对齐里要关心熵?
因为高熵意味着高不确定性,对齐时就需要更多信息来消除歧义。
举个例子:
- 一张纯色图片,熵很低。对齐时,它和任何文本的匹配度都差不多,容易误对齐。
- 一张包含复杂场景的图片,熵很高。对齐时,它需要更精确的文本描述才能唯一匹配。
我的经验: 在训练多模态模型时,我会先计算每个样本的熵。熵过低的样本,要么是噪声,要么是简单样本,可以降低它们的权重,让模型更关注高信息量的样本。
3.3 互信息:对齐的“粘合剂”
互信息(Mutual Information, MI)是信息论里我最喜欢的工具之一。
它直接度量两个变量之间共享的信息量:
I(X; Y) = H(X) - H(X|Y) = H(Y) - H(Y|X)
说白了,就是知道Y之后,X的不确定性减少了多少。
在多模态对齐里,互信息就是两个模态之间的“共同语言”。
互信息在多模态对齐中的典型应用:
| 应用场景 | 互信息的作用 | 实际效果 |
|---|---|---|
| 图文匹配 | 最大化图像和文本的互信息 | 提升跨模态检索准确率 |
| 音视频对齐 | 最大化音频和视频帧的互信息 | 改善时间同步精度 |
| 多模态融合 | 用互信息选择最相关的特征子集 | 减少冗余,提升泛化能力 |
避坑指南: 我曾经在音视频对齐任务中直接最大化互信息,结果模型学到了“静音”和“黑屏”之间的强相关性——因为训练数据里很多片段都是无声黑屏。后来我加了负样本采样,才解决了这个问题。
3.4 KL散度:对齐的“距离尺”
KL散度(Kullback-Leibler Divergence)衡量两个概率分布之间的差异:
D_KL(P || Q) = Σ p(x) log(p(x) / q(x))
在多模态对齐里,KL散度最常见的用法是约束两个模态的特征分布尽可能接近。
比如,我们希望图像特征分布和文本特征分布对齐,就可以最小化它们的KL散度。
KL散度的三个关键特性:
- 非对称性:D_KL(P||Q) ≠ D_KL(Q||P)。这意味着你要选择好方向。我个人习惯用前向KL(P是目标分布,Q是模型分布)。
- 非负性:KL散度永远≥0,当且仅当P=Q时为0。
- 对零概率敏感:如果P(x)>0但Q(x)=0,KL散度会无穷大。这在训练中会导致梯度爆炸。
实战技巧: 我在做跨模态知识蒸馏时,用KL散度让图像编码器去模仿文本编码器的输出分布。但直接算KL散度容易不稳定,我通常会加一个温度系数来软化分布,让梯度更平滑。
3.5 知识结构图:概率论与信息论在多模态对齐中的角色
下面这张图,是我自己梳理的“概率论与信息论在多模态对齐中的角色”框架。
它把贝叶斯定理、熵、互信息、KL散度串联起来,形成一个完整的对齐方法论。
3.6 实战:用互信息做图文对齐
光说不练假把式。我们来看一个具体的代码片段,用互信息做图文对齐。
import torch
import torch.nn.functional as F
def mutual_information_loss(image_features, text_features, temperature=0.07):
"""
计算图文对的互信息损失(InfoNCE变体)
image_features: [batch_size, dim]
text_features: [batch_size, dim]
"""
# 归一化
image_features = F.normalize(image_features, dim=-1)
text_features = F.normalize(text_features, dim=-1)
# 计算相似度矩阵
logits = torch.matmul(image_features, text_features.T) / temperature
# 标签:对角线是正样本
batch_size = logits.shape[0]
labels = torch.arange(batch_size, device=logits.device)
# 对称损失
loss_i2t = F.cross_entropy(logits, labels)
loss_t2i = F.cross_entropy(logits.T, labels)
return (loss_i2t + loss_t2i) / 2
为什么这样有效? InfoNCE损失本质上是在最大化正样本对的互信息下界。你想想看,当模型学会区分正负样本时,它其实就是在学习两个模态之间的共享信息。
3.7 避坑总结
最后,分享几个我踩过的坑:
- KL散度方向选错:我曾经在蒸馏任务中用了反向KL,结果模型只学到了目标分布的“模式”,忽略了多样性。后来改成前向KL才稳定。
- 互信息估计偏差:直接算高维互信息很难,容易低估。我建议用InfoNCE或MINE等变体,它们更鲁棒。
- 熵的阈值设置:用熵做样本加权时,阈值设得太低会把高信息样本也过滤掉。我一般先画个熵的分布直方图,再选分位数。
概率论和信息论不是枯燥的数学,而是多模态对齐的“眼睛”。
你越理解它们,就越能看清两个模态之间到底在“说”什么。