简介:这份由清华大学崔鹏等研究者完成的分布外泛化综述,面向深度学习研究者及需在非独立同分布场景下提升模型鲁棒性的工程人员。论文从形式化定义、方法分类、理论联系、评估指标到未来方向系统梳理OOD泛化,重点讨论无监督表示学习、监督模型学习与优化策略三条路线,并串联因果推理、不变性学习、稳定学习及分布鲁棒优化等思路,便于读者建立从问题定义到方法选型的整体框架,对分布偏移、领域泛化与鲁棒学习等方向亦有直接参考价值。资源包共1个PDF文件,大小约5.34MB,适合作为论文精读、组会分享与课题调研的底稿。目前已有2740人学习下载,可据此了解该领域常用数据集、评价方式与研究脉络,并获取后续选题和实验设计的参考。
1. 一个在训练集上 AUC 0.95 的模型,换家医院就掉到 0.6:分布外泛化到底在解决什么
一个在训练集上把 AUC 刷到 0.95 的模型,换一批从另一家医院采来的同一类数据,AUC 直接掉到 0.6 以下,甚至偶尔低于随机猜——这种翻车现场在医疗、自动驾驶、金融风控里反复出现,不是数据脏,也不是模型没调好,而是训练分布和测试分布压根不是同一个。这就是分布外泛化(Out-of-Distribution Generalization,OOD)要处理的核心问题:测试分布 Pte(X,Y) 在训练阶段未知,且不等于训练分布 Ptr(X,Y),经典机器学习赖以成立的 i.i.d. 假设在这里直接失效。
这篇综述值得啃,不是因为它列了多少篇参考文献,而是它第一次把 OOD 问题从定义、方法到评估串成了一条完整的链:先把问题形式化,再按方法在整个学习流水线里介入的位置切成三层——表示层、模型层、优化层,最后用因果视角把这三层之间的理论联系讲清楚。读完你会明白,为什么 ERM 在分布偏移下必然抓取虚假相关、为什么有些方法看起来是玄学、以及评估 OOD 性能时哪些坑几乎人人踩过。
2. 从 i.i.d. 到 Ptr ≠ Pte:ERM 为什么在分布偏移下必然翻车
2.1 ERM 的最优性只在一个等式成立时才成立
经典监督学习的形式化很干净:给定训练分布 Ptr(X,Y) 上采样的 n 个样本,找一个参数化模型 fθ: X → Y,使它在测试分布 Pte 上的期望损失最小:
fθ* = arg min_{fθ} E_{X,Y ~ Pte}[ ℓ(fθ(X), Y) ]但注意,训练阶段你能拿到的只有 Ptr 的样本,所以实际做的是经验风险最小化(ERM):
L_ERM = (1/n) · Σ_i ℓ(fθ(x_i), y_i)i.i.d. 假设的含义是 Ptr(X,Y) = Pte(X,Y)。在这个等式下,训练误差是测试误差的一个无偏估计,泛化界可以用 Rademacher 复杂度或 VC 维来刻画,ERM 的最优解就能近似 Pte 上的最优解。这个结论漂亮,但它的全部前提都压在一个等式上。
一旦 Ptr ≠ Pte,这个界就不成立了。更具体地说,Pte 上的风险会被拆成两部分:Ptr 上的风险,加上一个衡量两个分布差异的散度项(比如 f-散度或 Wasserstein 距离)。前者可以靠训练压下去,后者在 ERM 的目标里根本没有出现,所以 ERM 没有任何动力去控制它。模型越强、训练集上拟合得越好,越倾向于把 Ptr 里所有可用的相关性都吸收进去——包括那些只在 Ptr 里成立、到了 Pte 就消失的虚假相关。这就是为什么训练集上刷得越狠的模型,换分布时往往摔得越重。
2.2 协变量偏移:只改变 X 的分布,标签机制不动
OOD 是一个大类,里面包含协变量偏移、标签偏移、概念偏移等多种形态,它们的成因和应对方式差别很大。综述聚焦的是协变量偏移,因为它最常见,也最容易在现实里被观测到。形式化定义是:
Ptr(Y|X) = Pte(Y|X) 且 Ptr(X) ≠ Pte(X)翻译成人话:输入 X 的边缘分布在训练和测试之间发生了漂移,但给定 X 之后 Y 的生成机制没变。比如同一套疾病诊断规则,在不同医院拍出来的影像由于设备、人群、拍摄习惯不同,X 的分布变了,但放射科医生的判断逻辑没变。协变量偏移相对好处理的一点是,标签机制稳定意味着存在一个跨分布不变的映射,模型只要学到它就能泛化——问题在于 ERM 没法区分哪个相关性是“不变”的,哪个是“环境特异”的。
和它相邻的另一个概念是域适应(Domain Adaptation)。域适应假设测试分布要么有标签、要么无标签可用,相当于你在训练时对 Pte 已经有了一点先验知识,所以能拿到理论保证。OOD 泛化更狠:Pte 在训练阶段完全未知,没有任何测试样本可用。这个差别决定了 OOD 方法不能直接套用域适应那一套对齐手段——你没法对齐一个你看不见的分布。
2.3 三个介入点:表示层、模型层、优化层
把监督学习拆开来看,其实只有三个可动的部件:特征表示 g(X)、从表示到标签的映射 fθ、以及优化的目标函数。综述按方法介入的位置把现有工作分成三类,这个划分不是拍脑袋,它对应着你在工程里实际能改的三个地方:
| 介入层 | 代表方法族 | 核心思路 | 典型代价 |
|---|---|---|---|
| 表示层 | 解耦表示学习、因果表示学习 | 用先验约束隐空间结构,让不变因子和变化因子分开 | 需要假设隐因子的独立性或因果结构 |
| 模型层 | 因果学习、稳定学习、域泛化 | 设计模型结构或学习策略,迫使模型依赖跨域不变的机制 | 需要多环境/多域数据或因果图先验 |
| 优化层 | 分布鲁棒优化、不变性优化 | 直接改写目标函数,在训练时显式约束最坏情况 | 需要定义分布距离,且半径选择敏感 |
三层之间不是互斥的,很多实战方法会同时动两层。但理解这个划分的价值在于:当你在实际项目里遇到分布偏移时,你能清楚自己手上的资源够你动哪一层。只有单域数据,表示层和优化层是主要抓手;有多域数据,模型层的域泛化和因果学习才有发挥空间。
3. 表示层:解耦与因果表示,把“变化的”和“不变的”拆开
3.1 解耦表示学习:让隐变量各管一件事
解耦表示学习的出发点很朴素:如果数据的真实变化因子可以被拆成若干独立维度,每个维度只控制一个语义因素(比如人脸数据里的姿态、光照、身份),那么当测试分布只在某几个因子上发生偏移时,模型只要依赖剩下的不变因子就能做出稳定预测。问题在于,无监督学习本身没有任何信号告诉模型“哪个维度该对应哪个因子”,所以需要人为注入先验。
最典型的实现是 β-VAE 这一类变分框架。它的损失由两部分组成:重构项和 KL 正则项,通过调节 β 来控制隐空间的解耦程度:
# 简化的 β-VAE 损失 recon_loss = F.mse_loss(x_recon, x) # 重构项:让隐变量保留足够信息 kl_loss = -0.5 * torch.sum(1 + logvar - mu**2 - logvar.exp()) loss = recon_loss + beta * kl_loss # beta > 1 时更强地约束隐空间这段代码里 β 是关键参数。β=1 退化成标准 VAE;β>1 会加大对隐空间分布与先验(通常是各向同性高斯)之间差异的惩罚,迫使不同维度去编码相对独立的变化方向,从而提升解耦度。代价是重构质量会下降——β 越大,解耦和保真之间的拉扯越明显。这背后是一个很现实的取舍:解耦程度和下游任务性能并不总是正相关,综述里也明确提到解耦只是“好表示”的一个候选属性,不是 OOD 泛化的充分条件。
3.2 因果表示学习:从观测分布走到干预分布
解耦表示学习有一个隐含假设:隐因子之间是独立的。但现实里的语义因子往往有因果依赖,比如“光照”会影响“阴影”,“身份”会影响“表情习惯”。如果强行假设独立,学出来的表示结构就可能和真实生成机制对不上,换一个分布就失效。因果表示学习试图把结构信息也编码进去,用结构因果模型(SCM)来刻画观测 X 和隐变量 Z 之间的关系:
X = f(Z) + ε, Z 的各个分量之间由一个有向无环图约束在这个框架下,分布偏移被理解为对 Z 的干预(intervention)或混杂(confounder)变化的结果。如果模型能学到 Z 的因果结构,那么当测试分布对应某种干预时,模型可以推理出哪些机制应该保持不变,哪些应该随干预改变,从而做出更可靠的预测。常见的实现思路是在 VAE 式的框架里加入结构约束,比如给隐变量的先验加上因果图对应的条件依赖,或者在训练目标里加入对干预分布的模拟。
这条路的理论很优雅,但工程上有一个硬骨头:因果结构本身通常不可观测,你得靠很强的假设(比如已知因果图、或者线性非高斯假设)才能从观测数据里辨识出来。综述把这部分放在表示层而不是模型层,恰恰说明它的定位是“给表示加先验”,而不是“直接给预测器加约束”。在实际项目里,如果你的领域知识足够强、能画出因果图,这条路值得走;如果画不出来,就要谨慎估计收益。
4. 模型层与优化层:因果、稳定、域泛化、DRO 与不变性优化
4.1 因果学习:找到跨域不变的因果机制
因果学习在 OOD 里的核心操作是区分“因果特征”和“虚假特征”。因果特征和标签之间的关联在所有分布下都成立,虚假特征只在训练分布里成立。如果模型能只依赖因果特征,那换分布时就不会崩。形式化地,把输入 X 拆成因果部分 Xc 和虚假部分 Xs,目标是学一个只对 Xc 敏感的预测器。
这条路的一个代表作是不变风险最小化(IRM)那一系思路,它不做显式的特征拆分,而是要求存在一个表示 Φ,使得在所有训练环境上,最优分类器 w 都相同:
min_{Φ, w} Σ_e R_e(w ∘ Φ) s.t. w ∈ arg min_{w'} R_e(w' ∘ Φ) 对所有环境 e 成立实际优化时这个约束没法直接求,通常用惩罚项来近似——要求每个环境上的风险对 w 的梯度在 w=1 处接近零。代码上大概长这样:
# IRM 的惩罚项近似 penalty = 0.0 for x_e, y_e in envs: loss_e = loss_fn(model(x_e), y_e) grad_w = torch.autograd.grad(loss_e, model.classifier.weight, create_graph=True)[0] penalty += grad_w.pow(2).sum() loss = sum(loss_fn(model(x_e), y_e) for x_e, y_e in envs) + lam * penalty这里的 lam 控制不变性约束的强度。lam 太大,模型会被压得过于保守、连正常拟合都做不好;lam 太小则退化成 ERM。IRM 的一个已知问题是它对环境划分方式很敏感——环境切得太粗,不变性约束几乎没有信号;切得太细,每个环境里的样本量又不够估计风险。
4.2 稳定学习:给样本重新加权,消除选择偏差
稳定学习的切入点和因果学习不同,它不拆分特征,也不要求多环境,而是从样本权重入手。核心观察是:训练数据里的选择偏差会让某些虚假特征和标签产生虚假相关,如果能给样本重新加权,使得加权后的特征分布中,每个特征和标签都边际独立,那么在这些特征上学到的预测器就不会依赖虚假相关。
技术上通常是一个交替优化的过程:先固定权重训练一个基础模型,再根据模型给出的特征-标签相关性去更新权重,让相关性往零的方向走,如此反复。这条路的好处是不需要多域数据、也不需要因果图先验,单域数据就能跑;代价是它对高维特征的相关性消除往往不彻底,而且交替优化本身可能不稳定——权重和模型互相拉扯,收敛性分析比 ERM 难得多。综述把它归在模型层,是因为它改的是“学习策略”而不是“目标函数的形式”。
4.3 域泛化:多源数据上的对齐与不变性
域泛化假设训练阶段可以拿到多个源域 D1,…,Dn,每个域内部的分布不同,目标是学一个在未知目标域上也表现好的模型。这条线的常见操作有两类:一类是对齐各域的特征分布,比如用对抗训练让特征提取器骗不过域判别器,或者对齐二阶统计量(CORAL);另一类是把 IRM 那一套不变性约束扩展到多域上。
域泛化和 OOD 泛化的关系需要说清楚:域泛化是 OOD 泛化的一个子集,它额外假设了“多源域可用”这个信息。这个假设在医疗(多家医院)、自动驾驶(多个城市)、推荐系统(多个场景)里很现实,但如果你的项目只有单域数据,域泛化方法就用不上。综述把它和因果学习、稳定学习并列放在模型层,是因为它们共享同一个操作逻辑——都是从数据里挖出某种跨域稳定的结构,区别只在于挖的方式。
4.4 DRO 与不变性优化:带理论保证的目标函数
优化层的方法不绕弯子,直接改写训练目标。分布鲁棒优化(DRO)的写法是:
min_θ sup_{Q: D(Q, Ptr) ≤ ρ} E_Q[ ℓ(fθ(X), Y) ]意思是:在所有和训练分布距离不超过 ρ 的分布 Q 里,找最坏的那个,让模型在最坏分布上的损失最小。这里 D 可以选 f-散度、Wasserstein 距离等,ρ 是鲁棒半径。理论上这个框架有清晰的保证:只要测试分布落在半径为 ρ 的球里,模型性能就有下界。但实操中 ρ 的选择是个玄学——ρ 太小等于 ERM,ρ 太大模型会为了应付根本不存在的极端分布而牺牲正常性能。
f-散度下内层 sup 有闭式解,计算上等效于对样本损失做重加权;Wasserstein 球下则需要求解一个对偶问题,计算量更大。另一条优化路线是不变性优化,代表是 V-REx 那类方法,直接惩罚各环境风险的方差:
risks = torch.stack([loss_fn(model(x_e), y_e) for x_e, y_e in envs]) loss = risks.mean() + beta * risks.var() # beta 控制方差惩罚强度这段代码比 IRM 的梯度惩罚简单得多,实践中也更稳,但它的理论保证比 DRO 弱——方差小不直接等价于最坏情况风险小。综述在优化层花了大量篇幅讨论这些方法的理论联系,因为这一层是唯一能给出“为什么能 work”的严格答案的地方,表示层和模型层的方法大多只有经验证据。
5. 避坑与排查:那些在 OOD 实验里翻车的血泪经验
5.1 坑一:数据划分看起来是 OOD,实际还是 i.i.d.
现象:按 8:2 随机划分训练测试集,跑出来的 OOD 实验结果比论文里的数字还漂亮,换到真实场景直接崩。
原因:随机划分保证训练集和测试集来自同一个分布,模型只是在做插值,根本没被逼着处理分布偏移。你测的是 i.i.d. 泛化,不是 OOD 泛化。
解决:划分必须按域、按时间、按人群来切。比如医疗数据按医院切,时序数据按时间点切,推荐数据按用户群体切。切完之后先验证训练分布和测试分布确实不同——可以用一个简单的域分类器来测,如果它能轻易区分两个分布,说明偏移够强;如果区分不了,说明你的 OOD 设定名不副实。
5.2 坑二:把域泛化方法套到单域数据上
现象:拿了一个域泛化方法,但项目里只有单域数据,硬造了几个“伪域”出来,结果还不如 ERM。
原因:域泛化方法的有效性依赖源域之间的差异足够大、且目标域和源域共享某些不变结构。硬造出来的伪域如果差异不够,不变性约束拿不到有效信号;差异太大,又可能把真正有用的特征也当成环境特异给扔了。
解决:先判断自己的数据形态。有多源数据再考虑域泛化;只有单域,优先考虑优化层方法(DRO、V-REx)或稳定学习的重加权路线。造伪域时至少保证伪域划分和某个真实的变化因素(时间、设备、地区)对齐,不要随机切。
5.3 坑三:DRO 的鲁棒半径拍脑袋定
现象:ρ 设大了,模型在所有域上都很平庸;设小了,和 ERM 没区别。
原因:ρ 应该对应测试分布和训练分布之间的真实距离,但这个距离在训练阶段未知。拍脑袋定 ρ,等于在赌测试偏移的幅度。
解决:用验证集上的分布偏移程度来标定 ρ,而不是在训练集上交叉验证。如果有多域数据,可以留一个域做验证,看不同 ρ 下在留出域上的表现,选一个在最坏域上表现最好的 ρ。没有多域数据时,宁可取一个偏小的 ρ,避免模型过度保守。
5.4 坑四:评估只看平均指标,不看最坏域
现象:模型在平均指标上赢了 ERM,但某个特定域上比随机猜还差。
原因:OOD 评估的核心是最坏情况,不是平均水平。平均指标会被表现好的域拉高,掩盖掉模型在某些域上的灾难性失败。
解决:评估时必须报告每个域的单独结果,重点关注最差域的性能和跨域方差。综述里提到的评估指标除了平均准确率,还包括最差域准确率、跨域标准差、以及和 ERM 基线的逐域对比。如果你只能报一个数字,报最差域。
6. 设计取舍与验证:为什么没有一个 OOD 方法能通吃
把三层方法摆在一起看,会发现一个让人不太舒服的事实:没有哪个方法在所有场景下都占优。这不是研究没做到位,而是 OOD 问题本身的性质决定的——你对测试分布假设得越多,方法能给的保证越强,但适用范围越窄。
因果学习理论最漂亮,但它要求你能定义环境、能画出因果图,这两个前提在真实项目里经常凑不齐。域泛化在多源场景下很实用,但单域项目直接出局。DRO 有严格的理论下界,但 ρ 的选择和分布距离的定义都需要额外的领域判断。解耦表示灵活,但解耦程度和下游性能的关系并不单调。稳定学习对数据要求最低,但高维下的相关性消除往往不彻底。
我的一般判断顺序是这样的:先诊断偏移类型——用域分类器或者简单的分布距离度量确认 Ptr 和 Pte 到底差在哪;再看手上有多少资源——单域还是多域、有没有因果先验、能不能承受额外的计算开销;最后选方法,而且一定保留 ERM 作为基线。ERM 在新分布上的表现经常被低估,很多花哨方法在真实数据上打不过一个调好正则的 ERM,原因就是方法引入的假设和真实偏移形态不匹配。
验证环节有一个容易忽略的点:OOD 方法的超参数不能只在训练分布上交叉验证。IRM 的 lam、V-REx 的 beta、DRO 的 ρ,这些参数控制的是模型对分布偏移的鲁棒程度,在 i.i.d. 验证集上调出来的值,到了偏移场景下很可能完全不对。正确做法是留出一个和训练分布不同的验证域,在这个域上做超参选择——这也是为什么域泛化方法通常比单域方法更稳,因为它们天然有多域数据可以用来做这件事。
从那以后我每次碰分布偏移相关的项目,都强制走一遍“先诊断偏移类型、再确认可用资源、最后用 ERM 当基线”的流程,绝不跳过诊断直接上方法。希望帮到你。
本文还有配套的精品资源,点击获取