
在真实项目里我经常遇到这样一类问题手头有一批标注好的训练数据但你很清楚这些标签并不是百分之百可信模型也可能写得太简单没法真正捕捉真实世界。你可能听说过 PAC 学习它说你可以在一个概念类中找到一个近似正确的假设。可是一旦真实标签不是由那个概念类产生的PAC 学习还成立吗这就引出了不可知 PACAgnostic PAC学习。所谓的“最优不可知 PAC 算法”并不是某个藏在论文里的神秘模型而是一整套关于“在数据不完美、模型不完美、分布也不知道的情况下如何以接近假设类最优结果的方式做出预测”的算法思路。它的核心候选往往就是经验风险最小化ERM但你还需要理解它的边界和前提。这篇文章我想从理论直觉讲到工程落地把这个标题拆开揉碎。1. 不可知 PAC 到底在解决什么样的问题1.1 从经典 PAC 到不可知 PAC拆掉“存在完美假设”这个前提经典的 PACProbably Approximately Correct学习框架有一个很强的假设存在一个概念 (c) 属于某个概念类 (C)真实标签恰好由这个 (c) 生成。也就是说所有训练样本 ((x, y)) 都满足 (y c(x))。学习器要做的事情是从一批样本中找出一个假设 (h)使得它和真实概念 (c) 在数据分布上的误差很小。这个设定在理论上很干净但放到真实项目里几乎不成立。举个例子在医疗诊断中一个病人的诊断结果可能取决于大量没有被采集到的变量你手上的特征很难说包含了全部信息或者标注本身存在错误不同医生对同一张影像的判断也不完全一致。在这种情况下你根本找不到一个完美解释所有标签的 (c)你甚至不知道真实标签是由什么生成的。不可知 PAC 的定义就是把“存在完美假设”这个前提拆掉。它不再要求标签由某个 (c \in C) 生成而是允许训练样本来自 (X \times Y) 上的任意分布 (D)。你的目标变成了找到一个假设 (h)让它在分布 (D) 上的误差尽量接近当前假设类 (H) 里能做到的最优误差。这个变化是本质性的。经典 PAC 关心的是“我离真实函数有多远”不可知 PAC 关心的是“我离当前假设类的最优解有多远”。前者是一个绝对目标后者是一个相对目标。真实世界大多数问题都没有一个“藏在数据里的完美函数”我们能做的只是在一个我们愿意考虑的模型族里选出最好的那一个并且保证这个“最好”是可信的。1.2 最优算法的目标不是零误差而是最小化超额风险既然不可知 PAC 不再追求零误差那“最优”到底指什么学习理论里常用的一个概念叫超额风险excess risk[ \text{超额风险} err_D(\hat h) - \min_{h \in H} err_D(h) ]其中 (\hat h) 是算法输出的假设(\min_{h \in H} err_D(h)) 是假设类 (H) 中最好但可能无法找到的那个假设的误差。算法要保证的是以至少 (1-\delta) 的概率超额风险不超过 (\epsilon)。注意这个目标并不是说 (\hat h) 的误差一定很小。如果假设类 (H) 本身很差比如你用线性模型去拟合一个非常复杂的非线性关系那么 (\min_{h \in H} err_D(h)) 本身就很大再优秀的算法也只能保证接近这个很大的底线。这是不可知 PAC 的一个重要边界它保证的是“不浪费你的假设类”而不是“假设类本身没有限制”。所以真正会在工程里反复出现的认知点在这里一个最优不可知 PAC 算法并不等于一个准确率最高的模型。它更像是一个“在给定模型族下不会因为样本有限而错过最优解”的算法。2. 为什么经验风险最小化是最优不可知 PAC 算法的天然起点2.1 经验风险最小化用一个可计算的替代目标逼近真实风险分布 (D) 是未知的所以真实误差 (err_D(h)) 无法直接计算。我们能拿到的只有一组训练样本 (S)。因此一个最自然的做法是用训练集上的平均误差来近似真实误差[ \hat{err}S(h) \frac{1}{m} \sum{i1}^m \mathbf{1}[h(x_i) \neq y_i] ]然后选一个让这个训练误差最小的假设 (\hat h)。这就是经验风险最小化也就是 ERM。你可能会觉得这个做法太简单了。但理论告诉我们在不可知 PAC 设定下ERM 在很多情况下就是最优的。原因是它天然地处理了“不知道分布”的问题真实分布是什么不重要我只需要在观测到的样本上做到最好再通过概率论控制“样本上的表现”和“真实分布上的表现”之间的差距。这背后是一个关于均匀收敛uniform convergence的结果。如果假设类足够小或者说它的复杂度可控那么训练误差和真实误差会在所有假设上以较高概率保持一致。这时候对训练误差做最小化实际上也就是在逼近真实误差的最小值。2.2 误差分解告诉我们“最优”到底是哪个最优为了更清楚地理解 ERM 为什么有用可以把误差拆成两部分[ err_D(\hat h) \le \underbrace{\inf_{h \in H} err_D(h)}{\text{近似误差}} \underbrace{\sup{h, \hat h \in H} |\hat{err}S(h) - err_D(h)|}{\text{估计误差}} ]近似误差反映的是“假设类本身的表达力够不够”。这个误差不会随着样本量增加而消失它由模型族和真实世界之间的差距决定。估计误差反映的是“只有有限样本我们对每个假设的判断有多不准确”。样本量越大、假设类越简单这个误差就越小。ERM 的聪明之处在于它直接把近似误差交给了使用者。你选择一个假设类就意味着你接受了这个假设类可能带来的近似误差。算法只负责把估计误差压到尽可能小从而让你能够真正接近这个假设类的最优。很多人在实际项目里会忽略这个区分总觉得“换一个更大的模型就一定会更好”。但从不可知 PAC 的角度看扩大假设类会同时增加估计误差因为更大的模型族更容易在有限样本上展现出虚假的优势。这就是过拟合的理论来源。2.3 样本复杂度边界为什么 (d/\epsilon^2) 是硬指标在经典学习理论中有一个常见的样本复杂度结论对于一个 VC 维为 (d) 的假设类ERM 只需要[ O\left(\frac{d \log(1/\delta)}{\epsilon^2}\right) ]个样本就能以至少 (1-\delta) 的概率保证超额风险不超过 (\epsilon)。这个公式看起来有点抽象但它揭示了一个非常实用的规律误差 (\epsilon) 出现在分母的平方里。也就是说你如果想误差从 0.1 降到 0.05也就是误差减半所需样本量大约是原来的 4 倍。如果还想从 0.05 降到 0.02样本量增幅会更大。这就是为什么现实项目里模型到了后期再往上提升精度会非常吃力因为瓶颈已经从算法变成了样本量。同时假设类的复杂度和 (\log(1/\delta)) 都在分子上。(d) 的影响是线性的而置信度 (\delta) 的影响是对数关系。所以想要提高置信度不用太担心样本量但模型容量变大数据需求就会直接增加。“最优”在这个意义上指的是在最低限度的样本复杂度下达到最坏情况下的最优误差。ERM 在统计意义上通常是最优的候选算法因为你不太容易找到另一个算法在同样的假设类和同样的样本量下对所有分布都能做得更好。3. 从理论到实现代理损失、假设类复杂度与验证机制3.1 为什么要用代理损失而不用 0-1 损失来做优化理论分析里误差通常直接用 0-1 损失。但在工程实现中几乎不会有人直接优化 0-1 损失。原因很简单0-1 损失的优化是一个非常棘手的非凸问题。举个例子逻辑回归实际优化的是对数损失SVM 优化的是 hinge loss神经网络里用交叉熵回归任务用平方误差或绝对值误差。这些都是代理损失surrogate loss。它们的好处是凸性、可导性、可以使用梯度下降等高效优化方法。使用代理损失和理论中的 ERM 并不冲突。可以这样理解理论上我仍然在讨论 ERM只是风险函数从 0-1 损失换成了代理损失。如果代理损失是分类校准的classification calibrated那么在无限数据下最小化代理损失得到的结果也会朝向 0-1 损失下的最优解。但有一个工程上很容易忽略的点在有限样本下代理损失的最优解并不等于 0-1 损失的最优解。比如逻辑回归在对数损失上的最优和 0-1 损失上的最优模型可能不同。也就是说即使你的验证指标是准确率你在训练时用对数损失本质上是在解决一个和准确率不完全相同的优化问题。所以我更建议把代理解释和评估指标分开看。训练阶段使用代理损失是为了计算效率验证阶段使用真实的业务指标比如准确率、召回率、F1 或业务收益。两者可以不同但你心里要明白训练过程并没有直接优化最终指标。3.2 假设类复杂度必须靠正则化和模型选择来控制理论中的假设类 (H)在工程中通常体现为“模型架构 超参数”所覆盖的所有函数空间。比如线性回归的假设类是所有线性函数逻辑回归的假设类是线性决策边界下的条件概率函数深度神经网络的假设类则是极大的参数化函数族。假设类越小估计误差越容易控制但近似误差可能偏大。假设类越大近似误差会变小但估计误差会变大。如何在两者之间取得平衡就是结构风险最小化SRM想做的事情。实际落地时我们很难真的去遍历所有假设类所以通常用两种手段近似处理正则化给目标函数加上模型复杂度惩罚比如 L2 正则、L1 正则、dropout。这相当于在不改变模型架构的前提下缩小有效假设类。模型选择通过交叉验证比较不同模型结构、不同正则强度、不同特征组合选出验证误差最小的那一个。一个坦率的提醒正则化系数的大小本质上是在调整“你想让算法在多大程度上信任训练数据”。如果数据很干净、样本量很大正则化可以调小一点如果数据噪声明显、样本量有限正则化就应该保守一些。这不是吟诗而是经验规律。3.3 独立验证集把理论边界替换成可操作的估计理论分析可以告诉你“训练误差和真实误差的差距会随着样本量增加而缩小”但它不会告诉你具体到你的数据集上这个差距到底是多少。要获得可操作的数字必须依赖独立验证集。独立验证集的意义在于它不参与训练因此训练误差和验证误差之间的差别近似地反映了估计误差。如果模型在训练集上误差很小在验证集上明显变大这说明很可能过拟合了也就是经验风险最小化在这个假设类上并没有真正泛化。这里有一个容易被忽视的流程问题验证集只能用来评估不能反复用来选模型。如果你在同一个验证集上做了 100 次模型选择最后选出一个验证误差最低的模型那么这个验证误差已经不是一个诚实的泛化误差估计了。它已经变成了“针对验证集过拟合”的训练误差。更稳妥的做法是把数据拆成训练集、验证集和测试集三层验证集做模型选择测试集只做最终评估。4. 把最优不可知 PAC 算法落地的三步操作4.1 第一步定义假设类、损失函数和评估指标动手写代码前先回答三个问题我的假设类是什么是线性模型、树模型、还是核方法我的优化目标是什么是 0-1 损失的代理损失比如对数损失还是平方损失我的最终评估指标是什么是准确率、AUC还是业务自定义的收益这三个问题看似基础但它们其实是在定义整个不可知 PAC 框架里的 (H)、风险函数和误差度量。很多项目后面跑偏都是因为这三个问题没有从一开始对齐。比如最终业务目标是“在召回率不低于某个阈值的前提下最大化精确率”但你训练时只优化交叉熵评估时只算 AUC那就很容易出现模型在离线指标上好看、上线后却不满足业务约束的情况。评估指标不应该在实验做了一半时才加进来。更稳妥的做法是在建模之前就把它固定下来并让训练阶段的目标函数尽量和它有关联。虽然代理损失不直接等于最终指标但至少方向要一致。4.2 第二步用最小可行代码跑通 ERM 与验证误差评估在实际工程里大多数机器学习框架的默认训练流程本质上都是一个“经验风险最小化”流程。以逻辑回归为例下面这段代码就是一次典型的不可知 PAC 式操作最小化代理损失然后评估 0-1 损失。import numpy as np from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split from sklearn.metrics import zero_one_loss # 假设 X, y 来自一个带有噪声标签的数据集 X_train, X_val, y_train, y_val train_test_split( X, y, test_size0.2, random_state42 ) # 逻辑回归本质上是在最小化平均对数损失 model LogisticRegression(C1.0) model.fit(X_train, y_train) y_pred model.predict(X_val) val_err zero_one_loss(y_val, y_pred) print(fvalidation 0-1 error: {val_err:.3f})这段代码虽然简单但它包含了一个核心思想训练过程和验证过程使用的是两个不同的损失函数。训练阶段玩的是对数损失验证阶段用的是 0-1 损失。如果你想知道模型在业务上到底好不好看验证误差会比看训练误差更可靠。我建议在第一次跑通时不要急着调参。先把输入、特征、标签、训练集和验证集的划分都确认好记录下初始验证误差然后再进入下一步。4.3 第三步用四个维度判断结果是否“够接近最优”跑完一个基线模型后可以用四个维度来综合判断当前的模型是否已经比较接近“当前假设类的最优”验证误差的绝对值看它是否满足业务可接受范围。如果不满足问题可能出在假设类上也就是当前模型族表达力太差。容量检查换一个更大的假设类比如从线性模型换成带核函数的模型或更大的树模型。如果验证误差明显下降说明当前假设类没有把该学的东西学出来如果没有下降太多说明当前容量已经够用。容量缩减检查换一个更小的假设类比如减少特征或增强正则化。如果验证误差反而上升说明模型正在欠拟合不需要再压容量。评估有效性确认验证集直到现在都没有参与过训练或频繁选择。如果已经用同一份验证集选过很多轮那么最终数值可信度会下降。这四步构成一个非常小的评估框架可以避免你陷入“只盯着训练误差看”的状态。它不能给出严格的统计置信区间但在工程上足够帮助你判断模型到底是在真正学习还是在背数据。5. 从“理论最优”到“生产可用”常见的坑和排查链路5.1 最优不是免费的ERM 的样本最优和计算困难是两件事理论上的最优不可知 PAC 算法通常不关心计算复杂度。ERM 在一个有限假设类上可以直接暴力枚举但在 VC 维无限或假设类结构复杂时0-1 损失下的 ERM 会变成一个 NP-hard 问题。因此实际算法几乎都要退而求其次在代理损失上做近似最小化。这就产生了一条裂缝理论中的“最优”和代码里的“最优”不完全是一回事。代码里你追求的是代理损失的最小化或者更准确地说是优化算法在有限迭代步数内找到的一个近似最优解。比如神经网络训练中的随机梯度下降它最终停在哪里受到学习率、批次大小、初始化和随机种子等多个因素影响。所以不要把一个训练好的模型直接理解成“当前假设类的最优”。它更像是一个“在特定优化路线下找到的较好的近似解”。这种区分在做模型对比时很重要如果模型 A 比 B 验证误差低一点你先要确认两者是不是都充分训练了否则差异可能只是优化不充分导致的而不是模型真正表达力的差异。5.2 代理损失与真实风险之间的缝隙一致性并不等于零偏差代理损失在无限数据下保持分类校准不等于在有限数据下没有偏差。分类校准是说只要你能够在代理损失上找到全局最优解并且在数据集无限大时你得到的决策函数会趋向于 0-1 损失下的贝叶斯最优方向。但实际数据量有限全局最优也无法保证一致性带来的优势只能以渐进的方式体现。这在业务中可能导致一个现象训练时使用对数损失模型给出的概率输出经过了校准或未校准直接用于阈值决策时表现不佳。最优做法是单独做概率校准比如 Platt scaling 或 isotonic regression而不是默认模型输出的概率值就是真实概率。如果你在项目中只关心最终排序或分类结果代理损失和 0-1 损失之间的差异可能影响不大但如果你要输出置信度并且下游依赖这些置信度做决策那么这层差异就必须认真对待。5.3 反复使用测试集会让理论保证悄悄失效一个很容易犯的错误是把测试集当作验证集来用。假设你不断在测试集上观察效果然后回头调整模型结构和超参数那么测试集上的误差已经变成了模型选择流程的一部分。它在理论上已经不再是独立样本上的泛化误差估计而更接近一个小型的训练误差。如果真的想做一个可信的最终评估测试集应该只使用一次。更合理的操作顺序是在训练集上做训练在验证集上做模型选择。所有超参数、特征、模型结构都确定后再在测试集上跑一次。记录这次结果作为最终泛化误差估计。如果测试集已经被反复使用不要假装结果仍然具有理论保证。必要时可以重新采集数据或者承认当前数字存在一定乐观偏差。5.4 排查顺序分布、输入、模型容量、评估方式当模型在验证集上表现不佳时不要急着加大模型或调整学习率。我建议按下面的顺序排查先看数据分布训练集和验证集是否同分布采样时间、用户群体、特征生产逻辑是否发生了变化数据泄露、重复样本、时间顺序错乱都会让理论前提失效。再看输入质量特征是否有缺失值或异常值标签是否明显有误样本量是否足以支持当前模型复杂度再看模型容量训练误差和验证误差的差值是多少训练误差高说明模型容量不够训练误差低但验证误差高说明容量过大需要正则化或增加样本。最后看评估方式验证集是否被多次使用评估指标是否和训练目标偏离太远切分方式是否合理这个排查顺序不一定能保证解决所有问题但可以避免最常见的错误归因。很多模型效果差问题根本不在算法而在分布假设、数据质量和评估流程上。6. 这个算法真正长期影响的不是模型而是工作方式6.1 不可知 PAC 改变了我们怎么描述“学习成功”在经典 PAC 的语境下你会觉得“学习成功”意味着找到了一个接近真实函数的概念。这个说法在现实里几乎不成立因为没有哪种真实场景会给你一个藏在某个模型族里的真相。不可知 PAC 把问题重新定义为“在一个给定的假设类里找到一个接近该假设类最优解的假设”。它不再谈“真相”而是谈“相对最优”。这样定义的好处是即使你面对的是噪声标签、信息不完整、模型族不匹配你仍然可以明确地讨论“算法有没有充分利用数据和假设类”。这种视角会直接影响工作方式。当你在做机器学习项目时你的核心任务不应该是“寻找一个正确的模型”而应该是“选择一个合理的假设类并让训练过程在这个假设类里逼近最优解”。模型选择、特征工程、超参数调优本质上都是在调整假设类。6.2 适用边界何时你应该用何时你其实不需要最优不可知 PAC 算法并不是所有场景都非要套用。如果你的问题满足可实现假设也就是说你确信真实函数确实属于你的假设类那么经典 PAC 会更直接样本复杂度也更乐观。但现实里这种场景非常少见可能只存在于信号处理等有明确物理模型的领域。如果你的目标只是快速上线一个效果不错的分类器不是写研究论文也不需要对泛化性能做严格证明那么你不需要真的去推导样本复杂度边界。你只需要把理论中的“假设类”“代理损失”“独立验证”等原则转变成一套工程实践控制模型复杂度、使用代理损失优化、用独立验证集评估。这已经能让大部分项目受益。如果你的问题本身是开放性的比如用大模型处理开放域问答那你通常不会遇到传统意义的假设类因为模型本身已经是巨大的函数族理论和实践之间的对应关系会更模糊。这时候不可知 PAC 框架更多是一种思想背景而不是可直接操作的算法选择指南。6.3 实际建议先跑通最小流程再把复杂度梯度加回来如果让我给一个最简单的落地建议我会说从一个小而稳定的假设类开始用 ERM 跑出一个基线记录训练误差和独立验证误差然后再逐步扩大模型容量直到验证误差不再明显下降。这不是一个高深的技巧但它背后的逻辑和不可知 PAC 完全一致。小假设类意味着估计误差容易控制基线结果可信度高。逐步扩大假设类是为了找到近似误差和估计误差之间的平衡点。整个过程的核心指标只有一个就是独立验证集上的风险估计而不是训练曲线上的漂亮数字。最优不可知 PAC 算法真正让人印象深刻的地方不在于它的数学复杂度而在于它把一个很容易被口号化的目标——“学得好”——变成了一个可以量化、可以比较、可以判断的工程问题。你不需要真的去推导 VC 维也可以借用这种思维方式让机器学习项目从混沌走向可控。