做医学图文预训练的人应该都有过这种体验:同一套对比学习框架,放到自然图像-文本对上效果还行,一换成胸片、病理切片加临床报告,表现就明显缩水。我梳理相关工作时反复碰到同一个原因——噪声。医学图像-文本配对数据里的噪声不是简单的标注错误,而是结构化、系统性的:一份报告里大量重复的模板句、一张图像对应着与影像无关的描述段落、小病灶的漏报、随访患者影像被当成负样本强行推开。这些问题叠加起来,会直接破坏预训练的对齐信号。MIRAGE这个工作的核心价值,就是把“嘈杂环境下的鲁棒性”从训练目标的边缘位置提到了核心位置。这篇笔记,我会拆解它的三条技术主线,也会给出我在复现和迁移类似方法时踩过的坑和沉淀下来的经验,覆盖从数据清洗、训练配置到下游评估的完整链路。
1. 医学图文预训练为什么怕“吵”:噪声的来源与危害
1.1 报告文本里的“无效信息”有多严重
医学影像报告是一种高度结构化、模板化的文体。写报告的人为了效率,几乎每份报告都会重复类似的阴性描述,“心影大小形态未见异常”“双肺野清晰”“膈面光滑”这类句子在正常样本报告中的占比常常超过六成,个别模板风格极重的场景甚至接近八成。一批训练对里,不同患者的报告共享了大量完全相同的短语,这是医学多模态数据顶着“图文配对”光环下隐藏最深的坑。
这对对比学习是致命的。CLIP式图文对齐想让图像编码器和文本编码器在语义空间里互相靠近,如果两个编码器花费大量容量去对齐那些“哪份报告都在说”的模板句,那么学到的表示就会被“这份报告长什么样”主导,而不是“这个患者的影像到底有什么异常”。我见过不少直接用通用图文权重在医学数据上继续训练的案例,检索指标看着还行,但下游分类阴性和阳性时全靠句子风格做决策,换到另一家医院的报告风格就当场失灵。这不是玄学,是信号被噪声淹没的必然结果。
更隐蔽的问题是,异常描述往往被淹没在长篇的阴性描述里。一份报告可能包含上千个字,真正描述关键病灶的只有几十个字。全局图文对比时,异常信息在表示平均化的过程中被稀释,模型学会了模仿报告文风,却没学会真正看图说话。我个人的建议是,拿到一份数据集别急着训练,先做词频统计和句子聚类,你会直观看到模板句占了多少比例,这能帮你判断后续要去偏的力度。这个习惯帮我省下了大量无效实验。
1.2 图文不对齐和“同一患者”带来的错位问题
除了文本内部的模板噪声,图文之间还存在系统性错位。胸片往往一个患者拍了两张甚至多张视图,报告却是一段整体描述,模型无法从全局匹配中得知“这张图该对应哪一句”;病理切片更极端,一张全切片图像的描述覆盖整个样本的主要发现,而某一小块区域对应的具体改变,报告里可能根本没有展开。这种图文对齐不完全,会直接限制模型学到细粒度关联。
如果在这种情况下硬做全局表示对比,模型学到的是“这个患者的多张图平均起来约等于这份报告”,而不是“这个异常区域可能对应这个异常短语”。对检索任务还能将就,对于需要定位、解释、生成的下游任务就非常不利。MIRAGE这类工作之所以强调鲁棒性,就是因为它瞄准的不只是检索指标,而是要让跨模态表示在现实数据条件下仍然可信。
另一个容易被忽视的问题是false negatives。对比学习会把batch内其他样本当作负样本,但医学图文配对数据里,同一患者不同时期的多次影像、同一病变类型的不同病例,在语义上其实高度相关。如果把它们统统当作负样本去推开,等于强迫模型抹掉有意义的共性。很多鲁棒方法都在这个点上做文章,MIRAGE的思路也离不开这里。理解了这个背景,后面看技术设计会顺很多。
2. MIRAGE解决噪声的三条主线:局部对齐、文本注意力加权和鲁棒对比学习
2.1 从“整图-整文”到“区域-短语”的局部对齐
MIRAGE这类工作一个核心动作是把对齐粒度往下沉。视觉侧不再只输出单一全局向量,而是把图像分成patch序列后聚合出若干个区域级表示;文本侧也不对整段报告做平均,而是先切句,再抽取出潜在的异常描述短语。然后让区域和短语在细粒度空间里做对比,而不是全局向量硬碰。
这么做的好处很直接:它天然绕开了模板句。模板句几乎不和任何特定区域强相关,在和所有区域都比较“泛泛相近”的情况下,其影响会被加权机制进一步压低。而真正的病灶短语,比如“右上肺野见片状高密度影”,会和图像里对应位置的patch形成高相似度,模型能学到真实的视觉-语言对应关系,而不是报告风格层面的浅层匹配。
实现上常见两种路径。一种是像ViT那样把图像切成固定大小patch,再用分组注意力或聚类把patch聚成少量区域token;另一种是更早引入目标检测或分割模块,先圈出候选区域再提取区域特征。前者省事,后者区域质量更高。MIRAGE的设定更接近前者加一个轻量级的区域提议头。如果你想在自己流程里复现,先跑固定patch分组是完全可行的,区域数取16到32个之间比较实用,太少丢空间细节,太多显存吃不消。
2.2 用文本注意力给“有意义片段”加权
局部对齐降低了模板句对视觉特征的影响,但文本侧仍然需要告诉模型“哪些词值得对齐”。MIRAGE的做法是让文本编码器输出token级注意力权重,再在损失计算时按权重重新加权。直观理解就是模型学到一个门控,把“未见异常”“大小正常”“位置如常”这类token的贡献压下去,把“渗出”“结节”“磨玻璃影”这类token的贡献提上来。
这部分训练起来有个技巧:不能只靠自监督隐式学习,可以在预训练头旁边加一个弱监督的句子重要性预测头,用规则生成的伪标签做辅助信号。比如按句子里是否包含异常词表、是否包含否定词、是否出自结论段,标一个粗糙的权重,让预测头去拟合。伪标签不用很准,只要给噪声模型一个先验方向,就能显著加速收敛。我在实际复现中的体验是,这个辅助任务几乎不影响主loss的收敛速度,但对下游零样本分类的稳定性帮助很明显。
这层注意力还有个额外价值:可解释性。训练完成后把报告里的token按权重排序,你能看到模型认为最重要的句子,基本就是真正描述异常的那几句。在医学场景里,“能解释”这件事对临床接受度影响极大,哪怕只是把注意力热力图展示出来,也比黑盒输出一个分数更有说服力。很多工作只把注意力当作内部机制,忽略了它本身就是可用的产品能力,这一点值得做落地的人留心。
2.3 损失函数层面的鲁棒设计
第三条主线在损失函数。标准InfoNCE假设batch内非配对图文都是负样本,医学数据里这个假设很脆弱。针对这一点,鲁棒对比损失通常会做两个修改:一是给可能的false negatives一个软权重,二是给难负样本更高的学习权重。
软权重可以来自图-图相似度。Batch内两张图如果视觉特征过于接近,说明很可能来自同一患者或同一病变类型,那么它们的语义距离不应被强行拉远,损失里相应降低这对样本的负贡献。难负样本挖掘则是从另一个方向入手:一个报告确实是异常描述,但和错误的图片形成了暂时的假高相似度,这种样本恰恰是模型最容易混淆的,应该加大梯度。我在实现里通常用队列维护近期的旧特征,避免每步只用当前batch算,效果更稳。
还有一个常被忽略的参数是温度系数τ。医学数据模态差异大、噪声多,表示空间往往比较拥挤,τ太小时对噪声样本极度敏感,损失震荡;τ太大时又分不开类别。我自己的经验是医学图文预训练里τ取0.05到0.1之间,比自然图像常见的0.01到0.05略大一点,配合软权重使用,整体更稳。具体数值还是得在你的数据集上扫几轮,但方向大概是这样。
3. 训练配置与复现中的关键细节:从数据清洗到评测搭建
3.1 数据清洗与配对策略
预训练数据质量直接决定上限,这块值得花大力气。第一步是报告预处理:按句子拆分,过滤过短的句子和纯标点句子,对高频模板句做统计并选择性剔除或降权。我见过有人直接把出现频率排前5%的句子整句删掉,效果意外地好,因为那些基本都是“心肺膈未见异常”级别的套话。这类处理表面上是删文本,实际上是在降低视觉编码器被无效文本带偏的概率。
第二步是图文对去错配。公开数据集往往存在id混乱、重复采样、前后视野颠倒等问题,最好按患者维度检查配对关系,剔除同一患者内部出现多次的“伪新样本”。如果不做这一步,对比学习会在同一个个案上反复扩充权重,模型对特定患者的记忆会掩盖对真实医学语义的学习,测试时稍微换个分布就崩。
第三步是类别均衡考虑。纯自监督阶段不会显式用到标签,但如果你有粗粒度的数据集级标签,可以用它来约束batch采样,保证每个batch内阳性样本有一定比例。这能明显缓解“异常样本被正常样本淹没”的问题。MIRAGE方向的工作多数都在自监督阶段用到了此类采样约束,只是权重分配方式有所不同。这一步操作不复杂,但很多团队会漏掉,值得写进checklist。
3.2 训练超参与显存取舍
图文预训练最大的卡点通常是显存。局部对齐意味着图像侧要保留区域级特征,文本侧要保留token级特征,两个高分辨率张量做对比,batch size一上来显存立刻吃紧。常用的破解办法是梯度累积加混合精度:用较小batch size跑多个accumulation step再更新一次,能模拟较大batch的效果;混合精度bf16在医学图像这类对数值范围比较敏感的任务上,比fp16更稳一些。
区域数量选择上,前面说的16到32个区域是经验值。再一个容易被忽略的是文本最大长度:很多模板报告很长,但有效信息集中在前半部分和结论段,把max length从512压到256通常没什么损失,显存却省下不少。比起堆batch size,这个方向往往更划算。
温度系数、软权重、区域数这些超参,建议每次只动一个变量,且在小规模子集上做预实验。图文预训练一个周期动辄数天,最忌讳一次性改三个超参,出了问题根本没法归因。我在早期吃过这个亏,三个超参一起调,模型效果变好了都不确定是谁的功劳,换数据后又复现不了,教训很深。
3.3 评测协议怎么搭
跑预训练模型,评测问题比训练更讲究。不少团队只用零样本图文检索指标R@K判断模型好坏,这在医学场景下很容易失真:检索正样本的困难程度和报告模板的重复度高度相关,一个“更会模仿报告风格”的模型可能检索分数不错,但下游分类能力一塌糊涂。所以评测协议应该分层设计。
我的习惯是三层评测。第一层是零样本图文检索,观察整体对齐是否work;第二层是冻结特征做线性探测,把医学图像映射到报告语义空间后,用少量标签训练一个线性分类头,看特征线性可分性;第三层是少量样本微调,比如给出8张、16张带标签样本做全模型微调,看迁移效率。只有前两层通过,第三层才有参考意义。
MIRAGE这类鲁棒预训练方法最明显的优势不是检索指标爆表,而是线性探测和小样本分类的稳定性,尤其是换成多中心数据评测时。如果你复现完发现检索指标和基线差不多,不用担心,重点看下游迁移表现有没有拉开差距。评测时把随机种子固定三组、结果取均值,这个习惯也建议养成,医学数据小而偏,单次实验结果很容易带偶然性。
4. 从预训练到下游任务:场景适配与落地坑点
4.1 零样本分类、检索与生成的适用边界
鲁棒预训练模型最直接的应用是医学图文检索:输入一段报告描述去找最匹配的影像,或者反过来给一张影像找历史报告。这在临床辅助决策、教学案例库管理、科研病例筛选场景里都很实用。其次是零样本分类,用“是否存在胸腔积液”这样的文本prompt视图做相似度比大小,不需要训练标签就能给出可用的预测,在小样本科室场景下可以作为辅助筛选工具。
再往下是报告生成。预训练得到的跨模态对齐可以作为encoder,再套一个自回归decoder生成报告文本。由于预训练阶段学过区域-短语对应关系,生成时能更好地把视觉发现落实到文字描述,而不是像一些纯视觉模型那样生成一堆模板套话。医学VQA也同理,答案生成时可以通过图文对齐检索相关证据,降低幻觉。
不过要提醒一句:零样本和二分类问题上效果好的模型,不代表可以在复杂任务上直接替代专业判断。我在实际使用中反复确认过一件事,鲁棒预训练改善的是表示质量,而不是推理能力。它能让模型更准确地看到“有异常”和“哪里有异常”,但“这是什么病、怎么处理”仍然需要专门的监督数据和临床规则来兜底。把预训练模型当成一个更可靠的底座,而不是一个完整产品,落地预期会更健康。
4.2 部署时几个容易踩的坑
第一个坑是冻结骨干直接上生产。预训练模型在下游复杂任务时通常需要微调,直接冻结encoder时,区域级特征会被平均池化掉,等于把预训练阶段最值钱的精细对齐浪费了。如果算力允许,尽量微调整个文本编码器和视觉骨干,至少把最后的跨模态融合层放开,差距往往非常明显。
第二个坑是类别不平衡造成的假阳性泛滥。医学异常样本天然稀少,微调数据里阳性样本如果只有个位数,模型很容易退化成“永远输出正常”。一个可行办法是小样本阶段用加权损失,并在验证时单独看阳性类别的召回率,不要只盯着整体准确率。很多团队的失败不是模型不行,而是评估指标选得太乐观。
第三个坑是prompt改写不稳定。零样本分类时,同一个描述改几个字,结果可能有明显波动。这本质是模板噪声在推理阶段的体现。建议把prompt做成固定的标准表达,多写几个变体做预测平均,能显著提升稳定性。这算是零成本获得鲁棒性的一个土办法,但实测下来很有效。
5. 我对这类鲁棒预训练路线的一点实践体会
5.1 数据清洗的优先级比换模型结构更高
读MIRAGE这条线的工作,再结合自己的复现体验,我最大的感受是:预训练模型鲁不鲁棒,数据侧的清理往往比模型侧的改造贡献更大。局部对齐和鲁棒损失确实有效,但如果你拿一份充满重复、错位、低信息量的数据直接训练,任何精巧的机制都会被噪声淹没。
先把数据词频统计做了、把患者维度去重做了、把模板句降权做了,再上复杂的训练目标,每一步的收益都会更清楚。这也是为什么我在前面反复强调数据预处理步骤,因为这是最容易做、又最容易被跳过的一环。实际操作里,我甚至建议把清洗后的数据单独存一份版本,标记清楚每一步的规则,方便效果波动时回查。数据处理这块工作,投入产出比远高于改loss。
5.2 小规模验证,再上大规模训练
我还有一个习惯:任何新的预训练方案,先拿几百对父子样本跑一个缩略版本,对比基线看趋势,再决定要不要上全套大规模训练。缩略版本不需要跑完整个epoch,一般几百个step就能看出表示是否在收敛、注意力权重是否有区分度。这一步花不了多少GPU时间,但能帮你筛掉大半不靠谱的冲动。
最后再分享一个小技巧:如果你要做医学多模态预训练但数据量不够大,可以冻结在自然图像上预训练的视觉骨干,只训练文本侧和跨模态对齐头。这样视觉侧已经有不错的底层特征,文本侧专门学习医学语义,参数量小,不易过拟合。这个策略在只有几千对配对数据的场景里非常实用,我自己在这个配置下做过实验,比完全从头训练稳定得多,收敛也快很多。等数据量积累上来之后,再逐步解冻视觉骨干做端到端精调,过渡会非常平滑。