迁移学习(三):域适应
域适应实战指南:协变量偏移、标签偏移、DANN 梯度反转、MMD 对齐、CORAL、自训练、AdaBN,以及一份可运行的 DANN 完整实现。
你的自动驾驶模型在加州的晴天里跑得无懈可击。然后一进西雅图就开始下雨,Top-1 准确率从 95% 跌到 70%。模型本身没有变差——是数据分布变了,而你的训练集从未告诉它"傍晚的湿沥青"长什么样子。
这就是**域适应(domain adaptation)**要解决的日常问题:源域有大量标注数据,目标域只有未标注数据,但模型必须在目标域上跑出业务可接受的性能。本文从理论第一原理一路推到一份可运行的 DANN 实现。
你将学到
- 三种分布偏移——协变量偏移、标签偏移、概念偏移——以及各自的标准修正方法
- Ben-David 上界:为什么域适应有理论可能性,以及它确切告诉我们要去最小化哪个量
- DANN:用梯度反转层在一次反向传播里完成对抗对齐
- MMD 与 CORAL:两种非对抗的、显式的分布对齐损失
- 自训练、AdaBN、CycleGAN、ADDA——现代工具箱里的其他常用件
- 一份完整的 PyTorch DANN 实现
- 一棵方法选择决策树,以及 Office-31 / DomainNet 上的对比数字
**前置:**本系列第 1、2 章;对 GAN 式对抗训练有基本了解。
1. 分布偏移的三种面孔
**域(domain)**由特征空间 $\mathcal{X}$ 和边缘分布 $P(X)$ 构成;**任务(task)**由标签空间 $\mathcal{Y}$ 和条件分布 $P(Y \mid X)$ 构成。域适应研究的就是源域和目标域在其中某一项上不一致时该怎么办。
| 设定 | 源域 $\mathcal{D}_S$ | 目标域 $\mathcal{D}_T$ | 目标 |
|---|---|---|---|
| 数据 | 大量带标注 $(x_i, y_i)$ | 大多无标注 $x_j$ | 学到 $f: \mathcal{X} \to \mathcal{Y}$,在 $\mathcal{D}_T$ 上工作 |

整张图就是问题的全部:适应之前,源域学到的判别边界穿过了目标域几乎没有数据的空白区;适应之后,两个域共享同一个特征流形,同一条边界对两边都成立。
1.1 协变量偏移——输入分布变了
$$P_S(X) \neq P_T(X), \qquad P_S(Y \mid X) = P_T(Y \mid X)$$标注规则没变,只是观测到的东西不一样了:
- 用 2020 年邮件训练的垃圾邮件分类器在 2026 年部署:主题在变,但"什么是垃圾邮件"的判断标准没变。
- 西门子 CT 上训练的模型在 GE CT 上推断:成像特性不一样,但放射科医生看片子的诊断标准是一样的。
标准做法——重要性加权。给每个源样本乘上密度比 $w(x) = P_T(x) / P_S(x)$,加权后的源域 ERM 就在估计目标域风险:
$$\mathbb{E}_{P_T}[\ell(f(X), Y)] = \mathbb{E}_{P_S}\!\left[\frac{P_T(X)}{P_S(X)}\,\ell(f(X), Y)\right].$$高维下直接估密度无望,所以工程上直接估比值——KLIEP、uLSIF,或者训练一个分类器区分源/目标,贝叶斯最优分类器的 logit 等价于这个比值。
1.2 标签偏移——类别先验变了
$$P_S(Y) \neq P_T(Y), \qquad P_S(X \mid Y) = P_T(X \mid Y)$$类别条件下的样本长得没变,只是类别比例变了:
- ICU 病人数据训练的模型部署到门诊,疾病流行率天差地别。
- 在年轻用户里做 A/B 测出来的推荐模型,铺到全年龄段用户。
**标准做法。**用 EM(BBSE / RLLS)在无标注目标数据上估 $P_T(Y)$,然后把源域模型的输出概率按 $P_T(y) / P_S(y)$ 重新加权再归一化。
1.3 概念偏移——规则本身变了
$$P_S(Y \mid X) \neq P_T(Y \mid X)$$最难的一种。“sick” 在音乐评论里是褒义(“这段 beat 太 sick 了”),在产品评论里是贬义——同一个词,不同的标签。如果完全没有目标域标签,没人能解开这个绳结,必须至少有少量目标域标注(半监督 DA)。
2. 理论:Ben-David 上界
为什么"对齐分布"这件事在理论上行得通?经典答案是 Ben-David 等人 (2010) 的上界。对任意假设 $h \in \mathcal{H}$:
$$ \epsilon_T(h) \;\leq\; \epsilon_S(h) \;+\; \tfrac{1}{2}\, d_{\mathcal{H}\Delta\mathcal{H}}(\mathcal{D}_S, \mathcal{D}_T) \;+\; \lambda^{*}. $$| 项 | 含义 | 你能做什么 |
|---|---|---|
| $\epsilon_S(h)$ | 源域风险 | 把源域训得更好 |
| $d_{\mathcal{H}\Delta\mathcal{H}}$ | 两个域的对称差散度 | 这一项就是域适应在压缩的东西 |
| $\lambda^{*}$ | 联合最优预测器的误差 | 不可压缩——它若大,无解 |
两条结论:
- **域适应被一个 oracle 上界卡死。**如果源域和目标域的任务在本质上不一样($\lambda^*$ 大),任何方法都救不了你——你需要的是新标注,不是更花的损失函数。
- **域散度有一个能跑的代理。**训练一个二分类器区分源域和目标域特征,如果它的准确率接近 50%,说明你的特征已经域不变了。这正是 DANN 自动化的机制。
3. DANN:一次反向传播完成的对抗对齐
域对抗神经网络(Ganin 等,2016)是最有影响力的对抗式方法,也是对"压缩域散度代理"这一思想最干净的实现。

3.1 三个子网共享一个主干
| 子网 | 角色 | 训练数据 |
|---|---|---|
| 特征提取器 $G_f$ | $x \mapsto f = G_f(x)$ | 源 + 目标 |
| 标签预测器 $G_y$ | $f \mapsto \hat{y}$ | 源域标签 |
| 域判别器 $G_d$ | $f \mapsto$ 源/目标 | 源 + 目标 |
目标函数是一个 minimax:
$$ \min_{G_f,\, G_y}\; \max_{G_d}\quad \mathcal{L}_y(G_y \circ G_f) \;-\; \lambda\, \mathcal{L}_d(G_d \circ G_f). $$$G_d$ 想把两个域分开,$G_f$ 想糊弄 $G_d$ 同时让 $G_y$ 把源域分类做好。
3.2 梯度反转层(GRL)
朴素地解 minimax 需要交替优化,又脆弱又难调(早期 GAN 的痛)。DANN 的关键贡献是用梯度反转层把整套系统拆成一次反向传播:
$$ \text{前向:}\; \text{GRL}(x) = x, \qquad \text{反向:}\; \frac{\partial\,\text{GRL}}{\partial x} = -\lambda\, I. $$GRL 装在"特征 → 域判别器"这条路径上。反传时,判别器的梯度在到达 $G_f$ 之前先翻号,所以同一次 loss.backward() 就能:
- 用正常梯度更新 $G_y$(分类做得更好);
- 用正常梯度更新 $G_d$(判别做得更准);
- 用反向后的梯度更新 $G_f$(让 $G_d$ 越来越分不清域),同时仍接收 $G_y$ 传回的正常梯度。
不需要交替训练、不需要两个优化器、不需要手动冻结。
3.3 对抗权重的退火表
DANN 不会一上来就把 $\lambda$ 拉满——那样会摧毁早期学习。它走一条 sigmoid 曲线:
$$\lambda_p = \frac{2}{1 + \exp(-\gamma p)} - 1, \qquad \gamma \approx 10,$$其中 $p \in [0, 1]$ 是训练进度。早期 $\lambda \approx 0$,模型先专心学到好的源域特征;后期 $\lambda \to 1$,域对齐才真正发力。省掉这个退火,是 “DANN 跑了但反而比 source-only 还差"的最常见原因,没有之一。
4. MMD:在 RKHS 里对齐均值
对抗式很强,但训练不稳定。非对抗替代方案是:显式定义一个分布距离,然后直接最小化它。最大均值差异(Gretton 等,2012)是该方向的标准选择。

4.1 想法
核函数 $k(x, y) = \langle \phi(x), \phi(y) \rangle_{\mathcal{H}}$ 隐式地把样本映到一个(可能无限维的)再生核希尔伯特空间 $\mathcal{H}$。分布 $P$ 的核均值嵌入是其特征均值
$$\mu_P = \mathbb{E}_{X \sim P}[\phi(X)] \;\in\; \mathcal{H}.$$对于特征核(高斯 RBF 是经典代表),映射 $P \mapsto \mu_P$ 是单射的——两个分布相等 当且仅当 它们的核均值相等。所以分布距离就是核均值在 RKHS 里的距离:
$$\text{MMD}^2(P_S, P_T) = \|\mu_{P_S} - \mu_{P_T}\|_{\mathcal{H}}^2.$$图示给出了直观感受:哪怕原始直方图有点重叠,核均值嵌入会把"差距"显式画出来,阴影面积正是 $\text{MMD}^2$。
4.2 真正能算的估计量
嵌入是隐式的,把平方范数展开后内积就变成核值评估:
$$ \widehat{\text{MMD}}^2 = \frac{1}{n_s^2}\sum_{i,j} k(x_i^s, x_j^s) + \frac{1}{n_t^2}\sum_{i,j} k(x_i^t, x_j^t) - \frac{2}{n_s n_t}\sum_{i,j} k(x_i^s, x_j^t). $$它对特征可微,可以直接当一项额外损失加进深度网络:
$$\mathcal{L} = \mathcal{L}_{\text{task}} + \lambda \cdot \widehat{\text{MMD}}^2\!\big(G_f(X_S),\, G_f(X_T)\big).$$这就是 DAN / DDC(Long 等,2015;Tzeng 等,2014)。
4.3 工程提示
- **用多核 MMD。**多个不同带宽的高斯核线性组合 $k = \sum_u \beta_u k_{\sigma_u}$,对带宽误设鲁棒。
- **带宽选择用 median heuristic。**取一个 batch 内成对距离的中位数——便宜、鲁棒,绝大多数情况够用。
- **对靠后的层做 MMD。**底层带域特异性纹理;要对齐的是顶部的抽象表示。
4.4 MMD 与 DANN 一图对比
| MMD | DANN | |
|---|---|---|
| 距离 | 核 RKHS 范数 | Jensen–Shannon(通过判别器) |
| 优化 | 直接最小化 | 对抗 minimax(GRL) |
| 稳定性 | 非常稳定 | 偶尔震荡 |
| 表达力 | 受核选择限制 | 更灵活 |
| 适合场景 | 中小差距、数据少 | 差距大、数据足 |
合理的默认工作流:先 MMD 试一把;不够再上 DANN。
5. CORAL:对齐二阶统计量
如果对齐均值是好事,那么同时对齐均值和协方差通常更好。CORAL(Sun & Saenko,2016)就这么做。

设源、目标特征的协方差矩阵分别为 $C_S$、$C_T$,CORAL 损失为
$$\mathcal{L}_{\text{CORAL}} = \frac{1}{4 d^2} \|C_S - C_T\|_F^2.$$**直觉——白化 + 重新着色。**给源特征左乘 $C_S^{-1/2} C_T^{1/2}$,先把源协方差"擦掉”,再"涂上"目标协方差。Deep CORAL 把上面这个损失加到深度网络里,让梯度隐式完成同样的事。
CORAL 极其便宜(每个 batch 一次矩阵和一次 Frobenius 范数)、完全确定性,在轻度偏移下出奇地能打。在掏出 MMD/DANN 之前,它是非常值得一试的基线。
6. AdaBN:永远第一个尝试的免费午餐
最简单的一招:在目标数据上重新统计 Batch Norm 的均值和方差。
标准 BN 在测试时用的是训练期间累计的 running mean/variance。如果目标分布不一样,这些统计量就是错的,而它们坐在每一个卷积层和下一个非线性之间。AdaBN(Li 等,2017):
- 正常在源域上训练。
- 冻结权重,把无标注目标数据正向跑一遍,重新算每一层 BN 的 $\mu_T, \sigma_T^2$。
- 部署时用目标域的统计量替换源域的。
成本:几分钟。代码改动:几个 BatchNorm 的 running stats。效果:在协变量偏移下常能拿回 2–10 个点的准确率。任何更花的方法之前先做这一步。
7. GAN 式与像素级适应
有时候差距是视觉性的——合成 vs. 真实、白天 vs. 黑夜——光对齐特征已经太晚了,你需要直接翻译输入。
- CycleGAN 同时学两个生成器 $G: \mathcal{X}_S \to \mathcal{X}_T$ 和 $F: \mathcal{X}_T \to \mathcal{X}_S$,加上循环一致性 $F(G(x)) \approx x$。把源图像翻译到目标风格,再用原来的源标签训练分类器。注意:循环一致性不保证语义不变,配合感知损失或身份损失更安全。
- ADDA 把源、目标两个编码器解耦。第 1 阶段:正常训练源编码器 + 分类器;第 2 阶段:从源编码器初始化一个目标编码器,对抗一个域判别器适应它,分类器冻结;第 3 阶段:测试时目标输入走目标编码器 + 源分类器。这种不对称给了 ADDA 比 DANN 更大的容量,代价是多一个训练阶段。
8. 自训练:在目标上自举出标签
对抗式和统计式对齐都把目标当成一团没差别的云。自训练(也叫伪标注)更进一步:用当前模型给目标打标签,然后训练它自己。

循环很简单:
- 在源域上训练 $f$。
- 对每个目标样本预测,只保留 $\max_y f(x)_y > \tau$ 的那些(高置信度阈值)。
- 把保留下来的 (输入, 预测) 对当成新标注数据,重训。
- 反复迭代。
自训练强大但被低估,最臭名昭著的失败模式叫确认偏差:错但自信的预测被反复喂回训练,越来越固化。标准缓解措施:
- 把阈值 $\tau$ 调高(通常 0.9 以上);
- 类别平衡选择(每类伪标签数量设上限);
- 增广下的一致性正则(FixMatch 风格);
- 每轮重新从源模型出发,而不是从上一轮的自训练模型出发。
9. 决策树:什么时候用什么方法
1. 你有没有任何目标域标注?
├─ 有 → 半监督 DA:fine-tune + 重要性加权
└─ 没有 → 第 2 步
2. 偏移在哪?
├─ 只 P(X) 不同 → 第 3 步
├─ 只 P(Y) 不同 → 标签偏移修正(BBSE / EM)
└─ P(Y|X) 不同(概念) → 必须有少量目标标注
3. 视觉/特征差距多大?
├─ 极小 → AdaBN(永远先试)
├─ 小 → AdaBN + Deep CORAL
├─ 中 → MMD(DAN)或 DANN
├─ 大 → DANN / CDAN,或像素级(CycleGAN、ADDA)
└─ 巨大(仿真→真实)→ CycleGAN + ADDA + 自训练
实战中,强 pipeline 经常组合多种方法:AdaBN 拿走容易的几个点,MMD/DANN 做特征对齐,最后跑一轮自训练拿走最后那几个点。
10. Benchmark:到底有多大用?

数字是 ResNet-50 主干下的代表性文献平均。两点值得注意:
- **从"什么都不做"到"做点什么",跨度最大。**哪怕只用 AdaBN,差距也能补回相当一截。做点什么远比挑到完美的方法重要。
- **DomainNet 比 Office-31 困难得多。**DomainNet 上 40% 的准确率对应的方法相当强——这数据集有 345 类,跨 6 种风格迥异的视觉风格。读 DA 准确率永远要相对于 source-only 基线读,不要只看绝对值。
11. 域适应在哪里真正值钱
- 医学影像——西门子 vs. GE、1.5T vs. 3T MRI、A 医院 vs. B 医院。
- 自动驾驶——晴 → 雨、城市 A → 城市 B、仿真 → 真实。
- 推荐系统——国与国、年与年、网页 → 移动。
- NLP——电影评论 → 商品评论、新闻 → 社交、正式 → 口语。
- Sim-to-real——机器人和自动驾驶里把合成数据迁到真实传感器。
共同模式:源域标注便宜、目标域标注昂贵或不可能、模型还非得发版。
12. 把效果画出来——t-SNE 前后对比
训完一个 DA 模型后的标准检查:把源、目标特征都过一遍 t-SNE。适应之前样本按域聚成簇;适应之后按类别聚成簇。

如果"之后"图里仍然能看到两个域块,说明对齐失败了;如果只有一个块、按类别分开,说明对齐成功了。这一张图比任何单一数字都更能诊断问题。
13. 完整实现:DANN
| |
这段代码到底在做什么
| 组件 | 作用 |
|---|---|
GradientReversalLayer | 前向恒等、反向取反——把 minimax 折叠成一次反向传播。 |
_adaptive_lambda | sigmoid 退火 $\frac{2}{1+e^{-\gamma p}} - 1$:先学特征,再加对抗。 |
class_loss | 标准交叉熵,只用源域标签(目标域无标注)。 |
domain_loss | BCE,源 = 1、目标 = 0,训练域判别器。 |
| GRL + 域分支 | 反向传播时梯度翻号回到 $G_f$,让特征"藏起"域信息。 |
evaluate(alpha=0) | 测试时把 $\lambda$ 设 0,GRL 失活,只用分类头。 |
总结
域适应面对的是迁移学习里最实战的问题:训练数据和上线数据来自不同分布。工具箱按"动手成本递增"大致排序:
- AdaBN——在目标域上重算 BN 统计量;零成本、零重训、永远先试。
- CORAL——对齐源和目标的协方差矩阵;便宜、确定性。
- MMD(DAN)——对齐核均值嵌入;稳定、有理论支撑、默认用多核。
- DANN——通过梯度反转层做对抗对齐;一次反向传播搞定。
- CDAN / ADDA——更灵活的变种,应对更大差距。
- CycleGAN——特征对齐不够时,去做像素级翻译。
- 自训练——置信度阈值守门的伪标签;榨出最后那几个点。
Ben-David 上界告诉你哪些事可能:把源域误差和域散度压小,目标误差就会跟着压小——前提是联合最优误差本身就小。如果它本身就大,再多对齐也救不了你;那时你需要的是新标注。
下一章 第 4 篇——Few-Shot Learning ,我们把"源域数据充足"这个假设也丢掉,研究每类只有 1–5 个样本时该怎么学。
参考文献
- Ganin et al. (2016). Domain-Adversarial Training of Neural Networks. JMLR. arXiv:1505.07818
- Long et al. (2015). Learning Transferable Features with Deep Adaptation Networks. ICML. arXiv:1502.02791
- Sun & Saenko (2016). Deep CORAL: Correlation Alignment for Deep Domain Adaptation. ECCV. arXiv:1607.01719
- Zhu et al. (2017). Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks (CycleGAN). ICCV. arXiv:1703.10593
- Tzeng et al. (2017). Adversarial Discriminative Domain Adaptation (ADDA). CVPR. arXiv:1702.05464
- Long et al. (2018). Conditional Adversarial Domain Adaptation (CDAN). NeurIPS. arXiv:1705.10667
- Ben-David et al. (2010). A Theory of Learning from Different Domains. Machine Learning.
- Li et al. (2017). Revisiting Batch Normalization for Practical Domain Adaptation (AdaBN). arXiv:1603.04779
- Gretton et al. (2012). A Kernel Two-Sample Test (MMD). JMLR. paper
- Lipton et al. (2018). Detecting and Correcting for Label Shift with Black Box Predictors. ICML. arXiv:1802.03916
- Sohn et al. (2020). FixMatch: Simplifying Semi-Supervised Learning with Consistency and Confidence. NeurIPS. arXiv:2001.07685
系列导航
| 部分 | 主题 |
|---|---|
| 1 | 基础与核心概念 |
| 2 | 预训练与微调 |
| 3 | 域适应(本文) |
| 4 | 小样本学习 |
| 5 | 知识蒸馏 |
| 6 | 多任务学习 |
| 7 | 零样本学习 |
| 8 | 多模态迁移 |
| 9 | 参数高效微调 |
| 10 | 持续学习 |
| 11 | 跨语言迁移 |
| 12 | 工业应用与最佳实践 |