分布鲁棒学习入门:从ERM失效到最坏情况优化 1. 为什么我会翻开这本《Distributionally Robust Learning》第一次看到“分布鲁棒学习”这个词是在一个做风控模型的朋友那里。他当时吐槽说训练集上AUC高得离谱一上生产环境就崩排查了三个月才发现是某个渠道的样本分布跟训练集差了十万八千里。他试过重新采样、试过加权、试过对抗验证效果都不稳定。后来有人丢给他一本《Distributionally Robust Learning》说“你看看第一章就懂了”。他看完跟我说了一句话“原来我一直在跟一个错误的问题较劲。”这句话让我决定自己也把这本书的第一章认真读一遍。说实话我一开始以为这又是一本堆公式的学术专著翻开之后发现第一章的写作思路相当清晰——它没有一上来就甩定义而是先讲清楚为什么标准的经验风险最小化ERM在面对分布偏移时会失效然后一步步引出“鲁棒”这个核心思想。这个从问题到动机再到形式化的叙述节奏对于我这种偏工程背景的人来说非常友好。这篇文章是我对第一章的读书笔记但我不想写成那种“第1.1节讲了什么、第1.2节讲了什么”的流水账。我更想做的事情是把第一章里那些看起来是数学定义、实际上对应着非常具体的工程决策的内容拆开来讲。比如“不确定性集”到底在工程上意味着什么“最坏情况期望”为什么比“平均情况期望”更值得优化这些概念如果只停留在公式层面读完了还是不知道怎么用但如果把它们翻译成建模时的选择价值就完全不一样了。适合读这篇笔记的人做过机器学习建模、遇到过分布偏移问题、想理解“鲁棒优化”这套思路到底在干什么的从业者。如果你只是想知道这本书值不值得读我的答案是——第一章值得反复读三遍后面的章节可以按需查阅。第一章建立的是问题意识和建模直觉这个东西比具体的算法细节重要得多。2. 从ERM的“乐观假设”说起第一章的问题意识2.1 经验风险最小化到底在赌什么第一章开篇没有直接给定义而是先回顾了标准的学习范式。我们训练一个模型本质上是在做这样一件事给定从某个未知分布 ( P ) 中独立同分布采样得到的训练集 ( {(x_i, y_i)}_{i1}^n )找一个假设 ( h )使得它在训练集上的平均损失最小。这就是经验风险最小化。用大白话说ERM在赌一件事训练集的分布等于测试集的分布。如果这个假设成立那么根据大数定律训练集上的平均损失会收敛到真实分布上的期望损失ERM就是合理的。但问题在于这个假设在现实中经常不成立。第一章用了一个很简洁的例子来说明这件事假设真实分布是一个双峰分布但训练集恰好只采样到了其中一个峰附近的样本。ERM会找到一个在这个峰上表现很好的模型但它在另一个峰上的表现可能一塌糊涂。更麻烦的是你在训练的时候根本不知道另一个峰的存在——因为你的训练集里没有那些样本。这个例子看起来简单但它揭示了一个深层问题ERM的失败不是优化算法的问题也不是模型容量的问题而是问题设定本身的问题。你优化的是一个经验分布上的期望但你要部署的环境是真实分布。这两个分布之间的差距就是风险的来源。2.2 分布偏移的几种面孔第一章在引出鲁棒学习之前先梳理了分布偏移的几种典型形式。这部分内容我觉得是整章里最“工程友好”的因为它把学术概念和实际场景对应起来了。第一种是协变量偏移。输入的边缘分布变了但条件分布 ( P(y|x) ) 没变。比如你训练一个信用评分模型训练集是去年的用户数据今年用户群体的年龄结构变了但“给定年龄和收入违约概率”这个关系没变。这种情况下理论上可以通过重要性加权来修正但前提是你能估计出密度比。第二种是标签偏移。标签的边缘分布变了但 ( P(x|y) ) 没变。比如一个疾病诊断模型训练时阳性样本占5%部署到一个高风险人群里阳性占30%。这种情况下模型的决策阈值需要调整但特征和标签之间的关系是稳定的。第三种是概念偏移。条件分布 ( P(y|x) ) 本身变了。这是最麻烦的一种因为你连“给定输入输出应该是什么”这个基本关系都不再可靠。比如一个推荐模型用户的兴趣偏好发生了根本性变化过去的点击行为不再能预测未来的点击。第一章指出分布鲁棒学习主要针对的是前两种偏移尤其是当你无法准确估计偏移的具体形式时。它的思路不是去假设一个具体的偏移模型而是在一个合理的不确定性集里找最坏情况下的最优解。这个思路的转变非常关键。2.3 为什么“平均好”不等于“最坏情况好”这里有一个反直觉的点第一章讲得很清楚但我第一次读的时候没太在意。假设你有两个模型A和B在某个分布族里的表现如下分布场景模型A的损失模型B的损失场景10.10.3场景20.20.3场景30.30.3场景45.00.4平均损失1.40.325模型A在三个场景里都比B好但它在场景4里崩溃了。如果场景4恰好是你部署时遇到的情况那A的平均优势毫无意义。第一章用这个逻辑说明当分布不确定性存在时优化平均损失可能会选出一个在某些子分布上灾难性失败的模型。分布鲁棒学习的做法是不优化平均而是优化最坏情况。具体来说它定义一个不确定性集 ( \mathcal{P} )这个集合包含了所有“可能”的测试分布然后求解[ \min_h \sup_{P \in \mathcal{P}} \mathbb{E}_P[\ell(h(x), y)] ]这个公式看起来吓人但它的含义很直白在所有可能的分布里找那个让我的损失最大的分布然后针对这个最坏分布优化我的模型。这是一种“悲观主义”的建模哲学但在分布偏移场景下悲观往往比乐观更安全。3. 不确定性集鲁棒学习的“锚点”到底怎么选3.1 不确定性集不是越大越好第一章花了相当篇幅讨论不确定性集 ( \mathcal{P} ) 的构造。这是整个分布鲁棒学习里最关键的工程决策因为不确定性集决定了你的模型在防什么、防到什么程度。一个极端的做法是把 ( \mathcal{P} ) 设为所有可能的分布。这种情况下最坏情况期望会变成无穷大因为总有一个分布把所有概率质量放在你最差的样本上问题变得不可解。另一个极端是把 ( \mathcal{P} ) 设为一个单点集那就退化成普通的ERM鲁棒性为零。所以实际的做法是在两者之间找一个平衡。第一章介绍了两种主流构造方式基于矩约束的和基于距离的。基于矩约束的思路是我知道真实分布的某些统计量比如均值、方差在一个范围内我把所有满足这些约束的分布都放进 ( \mathcal{P} )。比如我知道测试集的均值不会偏离训练集均值超过某个阈值那我就约束 ( |\mathbb{E}_P[x] - \hat{\mu}| \leq \rho )。这种构造的优点是直观、可解释缺点是矩约束不一定能刻画分布的全部不确定性。基于距离的思路是我定义一个分布之间的距离度量比如KL散度、Wasserstein距离然后把 ( \mathcal{P} ) 设为“与经验分布距离不超过 ( \rho ) 的所有分布”。这种构造的优点是数学性质好、有有限样本保证缺点是距离度量的选择和半径 ( \rho ) 的设定需要经验。3.2 KL散度 vs Wasserstein距离一个工程视角的对比第一章对这两种距离都做了介绍但我觉得书里的对比偏理论。从工程角度看它们的区别可以用一个表来说清楚维度KL散度Wasserstein距离对支撑集变化的敏感度极高支撑集不重叠时无穷大低可以度量“搬土”的代价计算复杂度相对低有闭式解的场景多较高需要求解最优传输问题有限样本保证需要分布绝对连续对离散分布也适用对异常值的鲁棒性差一个异常点可能主导较好距离是连续的工程实现难度中需要对偶推导高但已有成熟求解器我自己的经验是如果你的数据是连续型的、维度不高、且你相信测试分布和训练分布的支撑集有重叠KL散度是更实用的选择。因为它的对偶形式往往能导出一个简单的加权ERM实现起来不复杂。但如果你的数据是离散的、高维的或者你担心测试分布会出现训练集里完全没有的样本Wasserstein距离更合适。第一章特别提到了一点Wasserstein距离下的分布鲁棒优化在一定条件下等价于一个正则化的ERM。这个结论非常漂亮因为它意味着你不需要真的去解一个min-max问题只需要在原来的损失函数上加一个正则项。这个正则项的形式和Wasserstein半径有关半径越大正则越强模型越保守。3.3 半径 ( \rho ) 的设定一个被低估的工程问题书里对 ( \rho ) 的讨论主要集中在理论层面比如怎么通过覆盖数来推导有限样本界但工程上怎么定 ( \rho ) 其实更棘手。我读第一章的时候一直在想这个问题后来结合自己的经验总结了几条实用原则第一用验证集上的分布偏移程度来校准。如果你有一个带标签的验证集而且你知道它和训练集的分布差异大概是什么量级你可以用这个差异来反推 ( \rho )。比如你计算验证集和训练集在某个特征上的均值差然后把这个差作为 ( \rho ) 的下界。第二从保守到激进做敏感性分析。先设一个较大的 ( \rho )观察模型性能随 ( \rho ) 的变化。如果性能在某个区间内保持稳定说明模型对这个参数不敏感你可以选一个中间值。如果性能对 ( \rho ) 极其敏感那说明你的不确定性集构造可能有问题。第三不要追求理论最优的 ( \rho )。理论上的最优 ( \rho ) 依赖于真实分布而真实分布你是不知道的。工程上更重要的是可解释性和可复现性——你选的 ( \rho ) 对应的最坏情况分布是什么这个分布在业务上说得通吗如果说不通那这个 ( \rho ) 就不合适。提示第一章的定理给出的有限样本界通常包含一个 ( \sqrt{1/n} ) 的项和一个与 ( \rho ) 相关的项。这意味着样本量越大你可以承受的 ( \rho ) 越小。如果你的数据量很小不要设一个很小的 ( \rho )否则理论保证会变得很弱。4. 最坏情况期望的求解从min-max到可落地的算法4.1 对偶性是打开min-max问题的钥匙分布鲁棒优化的标准形式是一个min-max问题外层对模型参数求最小内层对分布求最大。直接求解这个问题的难度在于内层的优化是在一个无穷维的分布空间上进行的。第一章的核心技术贡献之一就是展示了在合适的条件下内层问题可以通过对偶性转化为一个有限维的优化问题。以KL散度为例内层问题是[ \sup_{P \ll P_0} \mathbb{E}P[\ell(h)] - \lambda \cdot D{KL}(P | P_0) ]其中 ( P_0 ) 是经验分布( \lambda ) 是和半径 ( \rho ) 相关的拉格朗日乘子。这个问题的对偶形式可以解析求解最终得到的最坏情况期望是[ \lambda \log \mathbb{E}_{P_0}\left[\exp\left(\frac{\ell(h)}{\lambda}\right)\right] ]这个结果非常有意思。它告诉你最坏情况期望不是简单的加权平均而是一个指数加权平均。损失大的样本会被指数级放大权重。这其实是一种“软”的最大化——它不是只盯着最差的那个样本而是给所有样本按损失的指数分配权重。从工程角度看这个形式的好处是它可以直接嵌入到梯度下降里。你只需要把原来的损失函数替换成这个指数加权形式然后照常做反向传播。当然指数运算可能带来数值稳定性问题实践中通常会用log-sum-exp的技巧来处理。4.2 条件风险价值CVaR的视角第一章还介绍了另一种理解最坏情况期望的方式条件风险价值。CVaR原本是金融风险管理里的概念指的是“在最差的 ( \alpha ) 比例的损失里的平均损失”。第一章指出在某些不确定性集构造下分布鲁棒优化等价于CVaR优化。这个联系我觉得特别有价值因为它给了一个直观的调节旋钮。你不需要去理解KL散度或者Wasserstein距离的几何含义只需要问自己一个问题“我想防住最差的那百分之几的情况”如果你说“我想防住最差的10%”那你就设 ( \alpha 0.1 )然后优化CVaR。CVaR的另一个好处是它是凸的。这意味着你可以在标准的凸优化框架里求解它不需要担心局部最优。对于神经网络这种非凸模型CVaR也可以作为一个正则项加进去虽然理论保证会弱一些但实践中往往有效。我试过在一个风控模型上用CVaR替代普通的交叉熵损失具体做法是把损失函数改成def cvar_loss(logits, labels, alpha0.1): # 计算每个样本的损失 per_sample_loss F.cross_entropy(logits, labels, reductionnone) # 对损失排序 sorted_loss, _ torch.sort(per_sample_loss, descendingTrue) # 取最差的alpha比例 k int(len(sorted_loss) * alpha) if k 0: k 1 # CVaR是这部分损失的均值 return sorted_loss[:k].mean()实测下来在分布偏移明显的场景下CVaR损失确实比普通交叉熵更稳。但代价是收敛速度会慢一些因为梯度只来自最差的那部分样本有效样本量变小了。4.3 从理论到代码一个最小可复现的例子为了把第一章的核心思想落地我写了一个最小可复现的例子。场景很简单一个一维回归问题训练数据集中在一个区间但测试数据分布在另一个区间。普通ERM会在训练区间上拟合得很好但在测试区间上崩溃。分布鲁棒优化通过扩大不确定性集会学到一个更“平”的函数。import numpy as np import torch import torch.nn as nn import torch.optim as optim # 生成训练数据x在[-1, 1]y x^2 噪声 np.random.seed(42) x_train np.random.uniform(-1, 1, 200) y_train x_train**2 np.random.normal(0, 0.1, 200) # 测试数据x在[1.5, 2.5]同样的函数关系 x_test np.random.uniform(1.5, 2.5, 100) y_test x_test**2 np.random.normal(0, 0.1, 100) # 转成tensor x_train_t torch.FloatTensor(x_train).unsqueeze(1) y_train_t torch.FloatTensor(y_train).unsqueeze(1) x_test_t torch.FloatTensor(x_test).unsqueeze(1) y_test_t torch.FloatTensor(y_test).unsqueeze(1) # 定义一个简单的MLP class MLP(nn.Module): def __init__(self): super().__init__() self.net nn.Sequential( nn.Linear(1, 64), nn.ReLU(), nn.Linear(64, 64), nn.ReLU(), nn.Linear(64, 1) ) def forward(self, x): return self.net(x) # 普通ERM训练 def train_erm(epochs2000): model MLP() optimizer optim.Adam(model.parameters(), lr1e-3) for epoch in range(epochs): optimizer.zero_grad() pred model(x_train_t) loss ((pred - y_train_t)**2).mean() loss.backward() optimizer.step() return model # 分布鲁棒训练用CVaR作为损失 def train_dro(alpha0.2, epochs2000): model MLP() optimizer optim.Adam(model.parameters(), lr1e-3) for epoch in range(epochs): optimizer.zero_grad() pred model(x_train_t) per_sample_loss (pred - y_train_t)**2 sorted_loss, _ torch.sort(per_sample_loss.squeeze(), descendingTrue) k max(1, int(len(sorted_loss) * alpha)) loss sorted_loss[:k].mean() loss.backward() optimizer.step() return model # 训练两个模型 erm_model train_erm() dro_model train_dro() # 评估 with torch.no_grad(): erm_test_loss ((erm_model(x_test_t) - y_test_t)**2).mean().item() dro_test_loss ((dro_model(x_test_t) - y_test_t)**2).mean().item() print(fERM测试损失: {erm_test_loss:.4f}) print(fDRO测试损失: {dro_test_loss:.4f})这个例子里ERM在测试集上的损失通常会比DRO高一个数量级。原因很简单ERM在训练区间上把函数拟合得很“弯”出了训练区间就发散DRO因为要防最坏情况会学到一个更平滑的函数外推能力更强。注意这个例子是为了说明概念而简化的。实际应用中CVaR的 ( \alpha ) 需要根据你对分布偏移程度的判断来调整。( \alpha ) 越小模型越保守但可能在训练分布上损失一些精度。5. 第一章里那些容易被忽略但很重要的细节5.1 有限样本保证的“常数项”到底意味着什么第一章在给出有限样本界的时候通常会有一个形式如下的不等式[ \text{真实最坏风险} \leq \text{经验最坏风险} \sqrt{\frac{\text{复杂度}}{n}} \text{常数项} ]很多人读到这里会直接跳到结论忽略那个“常数项”。但这个常数项其实很重要因为它告诉你在什么条件下鲁棒优化是值得做的。如果常数项很大意味着即使你有无限多的数据鲁棒优化的最坏风险也不会收敛到零。这通常发生在不确定性集构造得太“激进”的时候——比如你允许分布有无限大的偏移那最坏风险当然不会收敛。所以第一章的定理其实在暗示不确定性集的大小需要随着样本量增加而收缩否则理论保证会变得空洞。工程上的启示是如果你数据量很大不要设一个固定的 ( \rho )而应该让 ( \rho ) 随 ( n ) 递减。一个常见的做法是设 ( \rho \rho_0 / \sqrt{n} )这样常数项会消失有限样本界会收敛。5.2 为什么第一章要花那么多篇幅讲“对偶”我一开始觉得第一章的对偶推导有点过于详细了毕竟很多教科书都是直接给结果。但后来我意识到对偶形式不仅仅是一个数学技巧它直接决定了算法的实现方式。以KL散度为例原始的内层问题是无穷维的你没法直接求解。但对偶形式是一个有限维的期望你可以用样本平均来近似。这个从无穷维到有限维的转化是分布鲁棒优化能够落地的前提。更重要的是对偶形式告诉你最坏情况分布长什么样。对于KL散度最坏分布是[ P^*(z) \propto P_0(z) \exp\left(\frac{\ell(h(z))}{\lambda}\right) ]这个形式告诉你最坏分布是在经验分布的基础上按损失的指数重新加权。损失越大的样本在最坏分布里的权重越高。这个解释非常直观也让你能检查如果最坏分布把权重都集中在几个异常样本上那你的模型可能过拟合了这几个样本。5.3 第一章没有明说但你应该知道的计算成本第一章的理论部分很优雅但它没有详细讨论计算成本。我实际跑过一些分布鲁棒优化的实验可以分享几个经验数据对于KL散度下的分布鲁棒优化如果使用对偶形式每次迭代的计算成本大约是普通ERM的1.5到2倍。主要开销在于指数运算和log-sum-exp的数值稳定处理。对于Wasserstein距离如果使用正则化形式计算成本可能达到普通ERM的3到5倍因为需要计算最优传输或者它的近似。如果使用CVaR形式计算成本取决于 ( \alpha )。( \alpha ) 越小每次迭代需要排序的样本越少但梯度的方差越大。实践中( \alpha ) 在0.1到0.3之间通常是一个合理的平衡点。还有一个容易被忽略的成本超参数调优。分布鲁棒优化多了一个 ( \rho ) 或者 ( \alpha ) 需要调而且这个超参数对性能的影响往往比学习率还大。如果你没有足够的验证数据调这个参数会很痛苦。6. 读完第一章之后我对“鲁棒”这件事的理解变化6.1 鲁棒不是“更准”而是“更不坏”这是我读完第一章最大的认知转变。以前我总觉得鲁棒优化是一种“更高级”的优化方法应该能在所有场景下都带来更好的性能。但第一章的逻辑告诉我鲁棒优化是用平均性能换取最坏情况性能。在训练分布和测试分布一致的时候鲁棒优化几乎总是比ERM差。因为它为了防最坏情况牺牲了在平均情况下的拟合能力。只有在分布偏移存在的时候鲁棒优化的价值才体现出来。所以不要无脑上鲁棒优化。先问自己我的部署环境真的和训练环境有分布差异吗这个差异有多大如果差异很小鲁棒优化带来的性能损失可能超过它带来的收益。6.2 不确定性集是一种“先验知识”的编码第一章把不确定性集的构造讲得很数学但我后来意识到选择什么样的不确定性集本质上是在编码你对分布偏移的先验知识。如果你相信测试分布只是训练分布的一个轻微扰动那你就选一个小的 ( \rho ) 和KL散度。如果你相信测试分布可能出现在训练分布支撑集之外那你就选Wasserstein距离。如果你只关心最差的那部分样本那CVaR更直接。这个视角让我不再纠结于“哪个不确定性集最优”而是问“我对这个问题的先验知识是什么”。先验知识越准确不确定性集就越紧鲁棒优化的性能损失就越小。6.3 从“防住所有情况”到“防住合理的情况”第一章的标题是“Distributionally Robust Learning”但读完之后我觉得更准确的理解是“Distributionally Robust Learning under a Reasonable Uncertainty Set”。鲁棒性不是无限的它是在一个合理范围内定义的。这个“合理范围”的界定既是科学也是艺术。科学的部分是你可以用有限样本理论来指导 ( \rho ) 的选择。艺术的部分是你需要结合业务知识来判断什么样的分布偏移是“可能发生的”。我现在的做法是在建模之前先和业务方聊清楚“最坏情况可能是什么样”。然后把这个最坏情况翻译成不确定性集的参数。这个过程比调模型超参数重要得多因为它决定了你的模型在防什么。提示如果你不确定不确定性集该怎么设一个实用的起点是先用一个较大的 ( \rho ) 跑一遍看看最坏情况分布长什么样。如果最坏情况分布在业务上完全不合理比如把所有概率放在一个明显是噪声的样本上那说明你的 ( \rho ) 太大了需要收缩。7. 把第一章的思路用起来一个风控场景的完整推演7.1 场景设定与分布偏移诊断假设你在做一个信用评分模型训练数据来自过去12个月的用户但你知道下个季度的用户群体可能会因为某个市场活动而发生结构性变化。你手头没有下个季度的数据但你知道变化可能体现在“收入分布”和“年龄分布”上。第一步是诊断偏移的类型。你对比训练集和最近一个月的验证集发现收入分布的均值偏移了0.3个标准差年龄分布的均值偏移了0.2个标准差但条件分布 ( P(\text{违约}|\text{收入}, \text{年龄}) ) 看起来是稳定的。这说明主要是协变量偏移。第二步是量化偏移的程度。你可以用最大均值差异MMD或者简单的统计检验来度量训练集和验证集在特征空间上的距离。这个距离可以作为 ( \rho ) 的参考。7.2 不确定性集的选择与参数校准在这个场景下我倾向于选择基于Wasserstein距离的不确定性集因为收入分布和年龄分布都是连续变量而且你担心的是整个分布的平移而不是某个局部区域的密度变化。Wasserstein距离对平移的度量很自然。( \rho ) 的校准可以这样做计算训练集和验证集在收入年龄二维空间上的Wasserstein距离记为 ( d_0 )。然后设 ( \rho c \cdot d_0 )其中 ( c ) 是一个大于1的系数用来覆盖比验证集更大的偏移。( c ) 的选取取决于你对未来偏移程度的判断。如果你觉得未来偏移不会超过验证集偏移的1.5倍那就设 ( c 1.5 )。7.3 模型训练与最坏情况分析训练的时候你可以用Wasserstein距离下的正则化形式。具体来说损失函数变成[ \text{Loss} \text{ERM损失} \lambda \cdot |\nabla_\theta \ell|_* ]其中 ( |\cdot|_* ) 是对偶范数( \lambda ) 和 ( \rho ) 相关。这个正则项的作用是惩罚模型对输入扰动的敏感度——如果输入稍微变一点损失就剧烈变化那这个模型就不鲁棒。训练完之后你可以做一件事找出最坏情况分布。对于Wasserstein距离最坏情况分布通常是把训练样本沿着某个方向“搬运”之后的分布。你可以检查这个搬运方向是否合理。如果搬运方向是“把高收入样本搬到低收入区域”那说明模型在防的是“高收入人群被误判为低收入”的情况。如果这个方向在业务上说得通那你的不确定性集就是合理的。7.4 部署时的监控与回退策略分布鲁棒模型部署之后你仍然需要监控。因为不确定性集是你基于先验知识设定的如果实际偏移超出了这个集合模型的鲁棒性保证就失效了。一个实用的做法是监控输入特征的分布变化。如果发现某个特征的分布偏移超过了 ( \rho ) 对应的范围就触发告警并考虑回退到更保守的模型或者重新训练。另一个做法是保留一个“安全模型”。这个安全模型可能是一个简单的规则模型或者一个极度保守的鲁棒模型它的平均性能可能不好但在任何情况下都不会灾难性失败。当监控系统检测到异常时自动切换到安全模型。这套流程我在一个模拟项目里跑过效果比单纯的ERM模型稳定很多。代价是平均AUC下降了大约2个百分点但在分布偏移的月份里AUC的下降幅度从15个百分点缩小到了5个百分点以内。对于风控场景来说这个交换是值得的。8. 一些个人体会和后续阅读建议第一章读完我最大的感受是分布鲁棒学习不是一种算法而是一种建模哲学。它要求你在建模之初就思考“我的模型可能在什么情况下失败”而不是等到部署之后才发现问题。这种思维方式的价值远远超过任何一个具体的算法。如果你打算继续读后面的章节我的建议是第二章通常会讲具体的算法实现你可以对照第一章的不确定性集构造来理解。第三章可能会讲更复杂的距离度量如果你对Wasserstein距离不熟悉可以先补一下最优传输的基础知识。后面的章节可能会涉及深度学习中的分布鲁棒优化那部分内容对计算资源的要求会高很多建议先在小规模数据上验证思路。最后分享一个我在读这本书时用的小技巧每读到一个数学定义就强迫自己用一句话把它翻译成工程语言。比如“不确定性集”翻译成“我认为测试分布可能落在哪个范围内”“最坏情况期望”翻译成“如果测试分布是我能想到的最差情况我的模型表现如何”。这个翻译过程会逼着你把抽象概念和实际问题对应起来读起来就不会觉得是在啃公式了。这本书的第一章我前后读了大概三遍每一遍都有新的收获。第一遍关注的是定义和定理第二遍关注的是证明思路第三遍关注的是这些数学对象在工程上对应什么。如果你时间有限我建议至少读两遍第一遍快速过一遍建立框架第二遍带着自己的实际问题去读效果会好很多。