1. 多示例学习基础概念
第一次接触多示例学习(MIL)时,很多人会被"包"和"实例"的概念绕晕。其实可以把它想象成快递包裹:每个包裹(包)里有若干商品(实例),快递单上只标注了整个包裹的类型(比如"电子产品"),但不会告诉你里面具体哪个商品属于这个类别。这就是MIL的核心特点——我们只有包级别的标签,没有实例级别的标签。
传统监督学习和MIL的区别很明显。假设我们要判断X光片是否显示肿瘤:
- 监督学习需要医生标注每处可疑区域(实例级标签)
- MIL只需要知道整张片子是否有肿瘤(包级标签),大大降低了标注成本
MIL的标准假设(Standard MIL Assumption)是这样定义的:
- 正包:至少包含一个正实例
- 负包:所有实例均为负实例 这个假设最早由Dietterich在1997年提出,用于药物分子活性预测。后来衍生出更复杂的假设,比如:
- 集体假设(Collective Assumption):包的标签由所有实例共同决定
- 存在假设(Presence-Based):特定模式实例的出现决定包标签
2. 核心方法与技术演进
2.1 传统MIL方法
早期的MIL方法主要分为三大流派:
基于实例的方法就像侦探破案,先找出每个线索(实例)的价值,再综合判断。典型算法如:
- MI-SVM:通过迭代调整实例标签
- EM-DD:在特征空间寻找"概念点"
# MI-SVM的简化实现示例 from sklearn.svm import SVC def mi_svm(bags, labels, max_iter=10): # 初始化:将所有正包中的实例视为正例 instances = [inst for bag in bags for inst in bag] pseudo_labels = [1 if any(labels[i] for i, b in enumerate(bags) if inst in b) else -1 for inst in instances] for _ in range(max_iter): clf = SVC(kernel='rbf').fit(instances, pseudo_labels) # 调整标签:只保留正包中最可能为正的实例 new_labels = [] for bag in bags: scores = clf.decision_function(bag) if any(labels[i] for i, b in enumerate(bags) if bag is b): new_labels.extend([1 if score == max(scores) else -1 for score in scores]) else: new_labels.extend([-1]*len(bag)) pseudo_labels = new_labels return clf基于包的方法则把整个包当作一个整体来分析。比如:
- MILES:将包映射到实例特征空间
- 基于Hausdorff距离的方法:测量包之间的相似度
2.2 深度MIL方法
随着深度学习的兴起,MIL也进入了新时代。注意力机制成为关键突破点:
# 注意力MIL的PyTorch实现关键部分 import torch import torch.nn as nn class AttentionMIL(nn.Module): def __init__(self, input_dim): super().__init__() self.L = nn.Linear(input_dim, 128) # 特征变换 self.A = nn.Parameter(torch.randn(128, 1)) # 注意力机制 def forward(self, x): H = torch.relu(self.L(x)) # (n_instances, 128) A = torch.softmax(torch.matmul(H, self.A), dim=0) # (n_instances, 1) M = torch.mm(A.T, H) # (1, 128) return M, A现代MIL框架通常包含:
- 实例编码器(如ResNet)
- 注意力聚合层
- 分类/回归头
2023年出现的Transformer-MIL将自注意力引入包表示学习,在病理图像分析中实现了SOTA效果。实验表明,相比传统方法,深度MIL在MNIST-bags数据集上可将准确率从82%提升到95%+。
3. 实战代码复现
3.1 数据准备
MIL领域常用数据集包括:
- MNIST-bags:合成数据,便于调试
- MUSK1/2:经典药物活性数据集
- CAMELYON16:乳腺癌淋巴结转移检测
from torch.utils.data import Dataset import numpy as np class MILDataset(Dataset): def __init__(self, n_bags=100, mean_bag_size=10): self.bags = [] self.labels = [] for _ in range(n_bags): bag_size = np.random.randint(mean_bag_size-5, mean_bag_size+5) # 生成正包:至少包含一个正实例 if np.random.rand() > 0.5: self.bags.append(np.random.randn(bag_size, 2) + [1, 1]) self.labels.append(1) # 生成负包:全部为负实例 else: self.bags.append(np.random.randn(bag_size, 2)) self.labels.append(0) def __len__(self): return len(self.labels) def __getitem__(self, idx): return torch.FloatTensor(self.bags[idx]), torch.tensor(self.labels[idx])3.2 模型训练技巧
在复现论文代码时,这几个坑我踩过多次:
- 注意力分数归一化要用softmax而非sigmoid
- 学习率设置比常规CNN要小(建议1e-4起步)
- 正负样本不平衡时可采用加权交叉熵
def train_epoch(model, loader, optimizer, device): model.train() total_loss = 0 for data, label in loader: data, label = data.to(device), label.to(device) optimizer.zero_grad() # 处理变长包 instances = data.view(-1, data.size(-1)) bag_feat, _ = model(instances) loss = F.cross_entropy(bag_feat, label) loss.backward() optimizer.step() total_loss += loss.item() return total_loss / len(loader)4. 前沿进展与应用
4.1 增量MIL
2024年魏秀参团队提出的MICIL框架解决了增量学习问题:
- 通过注意力机制提取包特征
- 存储类别原型防止遗忘
- 知识蒸馏保留旧知识
在Text数据集上的实验结果:
| 方法 | 阶段0 | 阶段1 | 阶段2 | 阶段3 |
|---|---|---|---|---|
| FineTune | 81.36 | 56.94 | 42.98 | 31.61 |
| MICIL(ours) | 81.36 | 78.04 | 72.99 | 68.61 |
4.2 医学影像应用
在病理切片分析中,SAM-MIL框架创新性地:
- 使用Segment Anything Model获取空间上下文
- 设计组掩蔽策略缓解类别不平衡
- 生成伪包增强训练数据
实验显示其在CAMELYON-16数据集上AUC达到0.923,比传统方法提升6.2%。
实际部署时,我发现这些优化策略很实用:
- 使用混合精度训练加速
- 对大型WSI图像采用分块处理
- 集成多个注意力头提升鲁棒性
5. 学习路线建议
根据我的实践经验,推荐这样的学习路径:
第一阶段:基础夯实(1-2周)
- 精读《Multiple Instance Learning Foundations and Algorithms》
- 复现MI-SVM和MILES算法
- 跑通MNIST-bags示例
第二阶段:深度方法(2-3周)
- 实现Attention-MIL
- 研究ABMIL论文代码
- 在CAMELYON16上微调
第三阶段:前沿追踪(持续)
- 关注MICV、MIDL等会议
- 参与Medical MIL Challenge
- 复现最新SOTA方法
关键是要动手实践——我曾用三个月时间复现了20篇论文的核心算法,这个过程中积累的经验比单纯阅读论文要深刻得多。建议从简单的合成数据集开始,逐步过渡到真实场景数据,这样能更好理解MIL方法的适用边界和调优技巧。