核心理论解读
这篇论文的核心在于解决多模态融合时的权重分配问题。当多个模态分别从不同维度评价目标状态并给出不同结果时,如何融合这些结果?关键在于理解置信度(Confidence)及其扩展概念。
置信度与不确定性
在机器学习中,置信度表示模型对预测结果的确定程度。例如分类任务中,若模型输出正类概率为 0.92,则该值即为置信度。数学上,它通常定义为模型对预测类别的后验概率估计。
文中引入熵(Entropy)来衡量整体不确定性。熵越低,代表模型越确定;反之则不确定性越高。简单来说,高置信度对应低熵。常见的分类评价指标含义如下:
| 指标 | 一句话解释 |
|---|---|
| Accuracy | 模型整体准不准 |
| Precision | 模型说'是'的时候靠谱吗 |
| Recall | 真正'是'的有没有被找全 |
| F1 | Precision 和 Recall 的折中 |
| ROC-AUC | 正样本排在负样本前面的能力 |
信度指标体系
为了更精准地分配融合权重,论文提出了两种信度指标:
- Mono-Confidences(单模态信度):仅评估当前模态本身的可靠性。
- Holo-Confidences(全息信度):评估当前模态相对于其他模态的可靠性。
融合权重的设计原则是:当前模态越可靠,其权重越大;其他模态越不可靠,当前模态的相对权重也应越大。损失函数 $l$ 与权重 $ω$ 应呈负相关。
在此基础上,论文进一步提出 Co-Belief(协同信度),即同时考虑自身可靠性与整体模态状态,以此最终确定该模态的融合权重。
代码实战与修复
环境准备
训练环境基于 Linux 云服务器(如 Ubuntu 20.04 + Python 3.11),配合 GPU 加速即可。论文附带的开源代码包较小(约 2MB),缺失了部分预训练结构和数据集文件,需自行补充。
数据与资源
本例选用 MVSA_Single 数据集进行情绪识别任务。你需要手动下载数据集并放置到指定目录,确保训练集划分文件与数据路径一致。此外,代码依赖预训练词向量 glove.840B.300d,可通过以下命令获取:
wget https://nlp.stanford.edu/data/glove.840B.300d.zip
关键逻辑修复
在复现过程中发现原代码 forward 函数存在逻辑错误。文本和图像的 Loss 定义在了条件判断之外,导致运行失败。这主要是作者整理代码时的疏忽,算法逻辑本身无误。以下是修正后的核心函数,重点调整了 Loss 计算的位置与初始化逻辑:
def model_forward(i_epoch, model, args, criterion, optimizer, batch, mode='eval'):
txt, segment, mask, img, tgt, idx = batch
tgt = tgt.cuda()
clf_loss = 0.0
tcp_pred_loss = 0.0
# ⭐ 先初始化,避免炸
# ---------- 普通单 / 早期融合模型 ----------
if args.model == "bow":
txt = txt.cuda()
out = model(txt)
clf_loss = criterion(out, tgt)
args.model == :
img = img.cuda()
out = model(img)
clf_loss = criterion(out, tgt)
args.model == :
txt, img = txt.cuda(), img.cuda()
out = model(txt, img)
clf_loss = criterion(out, tgt)
args.model == :
txt, mask, segment = txt.cuda(), mask.cuda(), segment.cuda()
out = model(txt, mask, segment)
clf_loss = criterion(out, tgt)
args.model == :
txt, img = txt.cuda(), img.cuda()
mask, segment = mask.cuda(), segment.cuda()
out = model(txt, mask, segment, img)
clf_loss = criterion(out, tgt)
args.model == :
txt, img = txt.cuda(), img.cuda()
mask, segment = mask.cuda(), segment.cuda()
out, txt_logits, img_logits, txt_tcp_pred, img_tcp_pred = \
model(txt, mask, segment, img, )
txt_loss = criterion(txt_logits, tgt)
img_loss = criterion(img_logits, tgt)
clf_loss = txt_loss + img_loss
maeloss = nn.L1Loss(reduction=)
label = F.one_hot(tgt, num_classes=args.n_classes)
args.task_type == :
txt_pred = torch.sigmoid(txt_logits)
img_pred = torch.sigmoid(img_logits)
:
txt_pred = F.softmax(txt_logits, dim=)
img_pred = F.softmax(img_logits, dim=)
txt_tcp, _ = torch.(txt_pred * label, dim=, keepdim=)
img_tcp, _ = torch.(img_pred * label, dim=, keepdim=)
tcp_pred_loss = (
maeloss(txt_tcp_pred, txt_tcp.detach()) + maeloss(img_tcp_pred, img_tcp.detach())
)
:
args.model ==
txt, img = txt.cuda(), img.cuda()
mask, segment = mask.cuda(), segment.cuda()
out = model(txt, mask, segment, img)
clf_loss = criterion(out, tgt)
loss = clf_loss + tcp_pred_loss
loss, out, tgt


