公司动态
几何视角下的鲁棒公平性审计:从静态指标到扰动风险
我们经常遇到这样的情况一个模型在离线评测集上看起来“公平性达标”上线之后却被质疑对某个群体存在系统性偏差。问题不一定出在模型本身而是出在审计方式本身——大多数公平性审计只针对一组固定数据、一组固定敏感属性、一组固定阈值做检查一旦数据分布发生微小偏移结论就可能翻转。如果把公平性审计看做几何问题会发现这件事的本质被很多人忽略了审计的成功与否取决于模型输出在“受扰动数据空间”中的行为而不仅仅是静态指标。所谓鲁棒公平性审计就是要在数据出现扰动的情况下仍然对公平性给出稳定结论。这篇文章不讲玄学而是尝试用几何理论把公平性审计讲明白为什么鲁棒性是必须的几何视角如何把“模型是否公平”变成“模型在空间中的位置是否安全”以及如何用 Python 写一个最小可运行的鲁棒审计示例。偏理论但落点可以落地。先给一个明确判断公平性审计本质上不是一次性的指标计算而是对模型行为边界的探索。几何理论的作用是把探索过程从直觉判断变成可计算的结构化问题。1. 这篇文章真正要解决的问题先说痛点。假设你负责内容推荐系统或信贷风控模型的准入评估审计团队要求你提交一份公平性报告。常见的做法是找一个包含敏感属性年龄、性别、地域等的测试集计算几组公平性指标比如 Demographic Parity人口统计均等或 Equalized Odds等化几率达到阈值就宣布“通过审计”。这个流程最大的漏洞在于审计结论是依赖某一组固定数据的。换一批样本、去掉几个异常值、上游特征分布发生季节漂移、或者某个敏感属性在收集阶段产生了系统性缺失之前“通过”的结论可能立刻变得不可靠。更麻烦的是真实业务中的数据集几乎不可能静止。特征采集方式会变、用户群体会变、标注口径会变、甚至合规要求会对敏感字段做脱敏处理。这些变化在数据空间中就表现为“扰动”。传统审计没有把扰动考虑进去等于用显微镜看完了一张静态照片却要下结论说整片区域的生态状态。几何理论把这个问题重新定义一遍我们把模型、数据分布、公平性约束看成空间中的对象把扰动看成空间中的位移。审计要做的不再只是“算一个指标”而是判断“模型在面对一类扰动时是否仍然停留在公平区域内”。这篇文章适合三类读者负责模型上线评估的算法工程师需要把公平性审计从“跑指标”升级为“跑风险边界”。做 AI 治理、合规和可信机器学习研究的技术人想理解几何理论在公平性审计中到底解决什么问题。刚接触 fairlearn、AIF360 等库的开发者想建立一个更系统的判断框架而不是只知道调用几个 API。2. 公平性审计为什么要强调“鲁棒”讲鲁棒之前先明确“公平性审计”到底在审什么。一个二分类模型 ( f(x) ) 会对每个样本输出一个预测结果例如是否放贷、是否录用、是否推荐。敏感属性 ( S ) 是我们在审计中不希望模型过度依赖的属性。公平性约束通常表述为对于不同敏感群体模型的预测行为差异应小于某个阈值。以 Demographic Parity 为例它要求[ P(\hat{y}1 \mid S0) \approx P(\hat{y}1 \mid S1) ]也就是说模型对不同群体的正向预测比例应当接近。Equalized Odds 则进一步要求在真实标签为 0 或 1 的子群体中预测错误率也应当接近。问题在于这些约束都是针对于一个具体的测试集 ( D ) 来计算的。如果把数据集看成是从真实分布 ( P ) 中采样得到的那么测试集只是 ( P ) 的一个近似。只要 ( P ) 发生一点变化测试集上的指标根本无法代表新分布下的真实情况。一个直观的例子是招聘模型的审计。假设训练数据里“是否获得面试”和“所在城市”有弱相关性而“所在城市”又与敏感群体分布相关。测试集上模型似乎满足 Demographic Parity但如果城市人口流动导致某类候选人的特征分布略微集中模型对特定群体的通过率可能突然上升。静态审计不会发现这个问题因为它只在原始数据上计算指标没有测试“如果特征整体偏移一点结论是否还成立”。鲁棒公平性审计要回答的核心问题是当数据在允许的扰动范围例如被攻击者修改、采集噪声、分布漂移内变化时模型是否仍然满足公平性约束在对抗鲁棒性的语境里我们常说的是“模型是否对 ( \epsilon ) 范围内的对抗样本保持稳定”鲁棒公平性审计则是说“模型在 ( \epsilon ) 范围内的数据扰动下是否仍然保持公平”。由此可以看出鲁棒性和公平性不是两个并列的检查项而是同一个安全边界的两个侧面。只测公平性忽略了稳定性只测鲁棒性忽略了公平性而几何理论能把二者统一到同一个空间框架里。3. 几何理论的核心把审计问题映射到空间几何理论听起来抽象但它背后的思想并不复杂。核心思路是把数据和模型输出放到一个可以用距离、投影、区域来表达的空间中然后用几何语言描述“公平”和“鲁棒”。3.1 三个基本对象我们可以把整个审计问题拆成三个几何对象对象一数据集是空间中的一个点集。每个样本是特征空间 ( \mathcal{X} ) 中的一个点。特征空间可能有多个维度比如信用评分中的收入、负债率、历史逾期次数等。敏感属性 ( S ) 是附加在这些点上的标签把点集划分成不同群体。对象二模型是一个决策边界。分类模型可以看成在特征空间里画了一条线或超曲面一侧预测为正类另一侧预测为负类。逻辑回归是一条线性边界深层网络是更复杂的非线性边界。模型输出的置信度可以理解成样本点到边界的距离的某种变换。对象三公平性约束是一个可行区域。Demographic Parity、Equalized Odds 等公平性指标本质上是对模型行为的一组不等式约束。所有满足约束的模型输出构成一个“公平区域”。如果模型当前的行为落在这个区域内就说明它通过了指标检查。3.2 扰动是空间中的位移数据扰动可以把原始点集发生形变或位移。最经典的是 ( L_p ) 范数约束下的有界扰动[ \tilde{x} x \delta, \quad |\delta|_p \le \epsilon ]在几何视角下这等于说原始样本点可以在一个半径为 ( \epsilon ) 的球形邻域内移动。整个测试集不是静态点集而是一团存在不确定性的“云团”。鲁棒审计要做的事就变成了在所有这些可能的位移中找到让模型最不公平的那个方向然后判断最坏情况下的公平性指标是否仍在容忍范围内。3.3 最坏情况与边界距离这里可以借用对抗鲁棒性中“距离到决策边界”的概念。对于一个公平性指标比如 Demographic Parity gap我们可以把它看成模型在一个扰动方向下的“不公平程度”。当扰动不断增大时这个 gap 通常也会增大。最终会存在一个临界扰动半径超过它模型就越过公平性阈值。这个临界半径就是模型在“公平空间”中的安全距离。距离越大说明模型面对数据扰动越不容易产生不公平距离越小说明审计结论越脆弱。几何理论的价值就在于此它让“鲁棒公平性审计”不再是一个含糊的目标而是一个可计算问题。我们可以用向量、范数、投影距离来描述它并用优化算法去搜索最坏情况的扰动。需要说明的是这个理论视角并不排斥传统公平性度量。相反它把传统度量作为几何空间中的“坐标轴”使用。传统指标告诉我们模型现在在哪几何理论告诉我们模型离危险边界有多远。4. 从几何到算法一个可落地的建模路径理论要变成工程工具需要一套可操作的算法路径。这一节把上面的几何思想转成步骤不对具体数学细节做过度展开只讲清楚每一步在做什么、为什么需要。4.1 定义公平性度量函数先选定一个或多个公平性指标例如 Demographic Parity gap 或 Equalized Odds 的最大差值。这个函数把“模型 数据集”映射成一个标量表示当前的不公平程度。4.2 生成有界扰动次要从数据集当前样本出发生成一组符合扰动约束的变体。常见方式包括在原始样本上加范数有界的随机扰动使用梯度方向构造对抗性扰动目标是让不公平程度最大化针对敏感属性做重采样或翻转模拟数据采集偏差。鲁棒审计不要求穷举所有扰动但要求扰动集合有代表性。实践中通常使用随机方向采样和梯度方向搜索的混合策略。4.3 计算最坏情况下的公平性对每个扰动方向计算公平性指标记录最大值。这个最大值对应的扰动方向就告诉我们模型在哪个方向上最容易失去公平性。4.4 与阈值比较形成审计结论把最坏情况指标与业务方预设的容忍阈值比较。如果最坏情况仍然小于阈值可以判定模型在给定扰动范围内具有鲁棒公平性否则审计不通过并输出临界扰动方向供模型团队分析。整个过程可以看成一次“最小-最大优化”[ \max_{|\delta|_p \le \epsilon} ; \text{Unfairness}(f, D \delta) ]在实际工程中我们不一定要追求全局最优一个足够强的扰动上限已经能帮助发现最明显的公平性风险点。这一点和对抗攻击中的评估逻辑类似。5. 最小实现用 Python 跑一次鲁棒公平性审计下面用一个最小示例演示上述思路。示例模拟一个二分类场景数据包含两个敏感群体我们先训练一个逻辑回归模型再分别计算静态公平性指标和最坏扰动下的鲁棒公平性指标。先准备好依赖文件# requirements.txt numpy1.21 scikit-learn1.0然后写一个 Python 脚本# fairness_audit_demo.py import numpy as np from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split def generate_data(n2000, seed42): rng np.random.default_rng(seed) # 敏感属性0 / 1模拟两类群体 s rng.integers(0, 2, sizen) # 两个特征与敏感属性存在一定相关性 x1 rng.normal(0, 1, n) s x2 rng.normal(0, 1, n) # 标签生成特征和敏感属性共同影响但审计时不希望模型过度依赖 s logit 0.8 * x1 - 0.5 * x2 0.6 * s p 1.0 / (1.0 np.exp(-logit)) y rng.binomial(1, p) X np.column_stack([x1, x2]) return X, s, y def dp_gap(y_pred, s): 计算 Demographic Parity gap两个群体平均预测概率之差的绝对值 return np.abs(y_pred[s 1].mean() - y_pred[s 0].mean()) def robust_dp_gap(model, X, s, eps0.05, num_directions50, seed0): 在特征空间中生成有界扰动返回最坏情况下的 DP gap。 扰动方向使用随机采样并归一化到固定长度 eps。 rng np.random.default_rng(seed) worst_gap 0.0 worst_direction None n, d X.shape for _ in range(num_directions): direction rng.normal(size(n, d)) direction direction / (np.linalg.norm(direction, axis1, keepdimsTrue) 1e-9) X_pert X eps * direction y_pred model.predict_proba(X_pert)[:, 1] gap dp_gap(y_pred, s) if gap worst_gap: worst_gap gap worst_direction direction.copy() return worst_gap, worst_direction if __name__ __main__: X, s, y generate_data() X_train, X_test, s_train, s_test, y_train, y_test train_test_split( X, s, y, test_size0.3, random_state42 ) model LogisticRegression(max_iter1000) model.fit(X_train, y_train) base_gap dp_gap(model.predict_proba(X_test)[:, 1], s_test) robust_gap, worst_dir robust_dp_gap(model, X_test, s_test, eps0.05) print(fBase DP gap : {base_gap:.4f}) print(fRobust DP gap (eps0.05) : {robust_gap:.4f})这段代码的逻辑并不复杂generate_data生成带敏感属性的模拟数据特征与敏感属性存在相关性模拟现实中特征分布不够干净的场景。dp_gap计算标准 Demographic Parity gap即两个群体的平均预测概率差。robust_dp_gap对测试集特征添加固定半径的随机扰动并保留让 DP gap 最大的那个扰动方向。主流程先训练逻辑回归再输出静态指标和最坏扰动下的指标。需要注意这个示例故意做了很多简化随机扰动方向数量有限、没有使用梯度搜索、只测了一个指标。真实审计中我们需要更精细的扰动模型和更全面的度量但示例已经可以揭示一个关键差异静态 DP gap 与鲁棒 DP gap 往往不一致。如果你需要把审计参数单独管理可以加一个配置文件# audit_config.yaml audit: threshold: 0.05 seed: 0 metrics: - demographic_parity - equalized_odds perturbation: eps: 0.05 directions: 50 norm: l2这样在团队协作时审计范围、阈值、扰动强度都有一份可追溯的配置记录避免每个人按自己的习惯设置参数导致结论不可复现。6. 验证结果与判断标准运行上面的脚本python fairness_audit_demo.py输出大致如下数值可能因 sklearn 版本有细微差异但趋势一致Base DP gap : 0.0521 Robust DP gap (eps0.05) : 0.1038先解释这两个值的含义。Base DP gap是测试集原始数据上的静态指标。如果审计阈值是 0.05这个模型勉强接近阈值看起来接近“基本公平”。Robust DP gap是给特征加上 0.05 半径扰动之后最坏情况下的指标。0.10 明显高于阈值说明模型面对小幅数据扰动时不公平程度几乎翻倍。这种差异就是文章开头提到的“静态通过、扰动翻车”的具体体现。几何理论把这种风险转化为一个可以观察的数值模型在原始数据点附近的安全裕度不足。判断审计是否通过不应该只看静态指标建议按下面的方式如果Robust DP gap threshold模型在给定扰动范围内保持公平审计通过。如果Robust DP gap threshold但静态指标达标说明模型存在审计鲁棒性风险需要进一步定位扰动方向。如果静态指标本身不达标那就不需要讲鲁棒性了直接进入模型修正环节。刚才脚本里的扰动方向worst_direction在真实场景中很有价值。可以分析这个方向上哪些特征被修改得最多从而定位导致不公平的关键特征组合。例如如果最大扰动方向对应“收入”和“历史逾期”两个特征同时变化说明模型公平性依赖这两者的特定组合脆弱点就在这里。运行失败时优先检查三处依赖是否安装完整尤其是 scikit-learn 版本。generate_data是否生成了足够的正例和负例样本量太小时预测概率不稳定。扰动半径eps是否设置得过大。eps太大会让扰动后的特征彻底偏离原始特征空间导致指标失真。7. 常见问题与排查思路鲁棒公平性审计在落地时遇到的问题往往不是数学太深而是工程判断不一致。下表列出几个典型问题。问题现象可能原因排查方式解决方案静态指标达标鲁棒指标远高于阈值模型决策边界靠近敏感群体分界区域微小特征变化就会翻转预测查看最大扰动方向上的特征贡献使用更平滑的模型或增加正则化约束特征依赖随机扰动方向数设置小结果不稳定高维空间中被搜索到的方向代表性不足固定随机种子并多次重复实验增加方向数量或改用梯度上升搜索最坏扰动鲁棒指标出现 NaN 或异常大值扰动后样本点落到特征空间稀疏区域模型外推行为失控检查扰动后特征的取值范围和样本覆盖对扰动做投影或裁剪限制扰动后的样本范围不同公平性指标结论矛盾不同指标在几何上对应不同约束方向分别记录每个指标的临界半径业务方明确主指标其余指标作为风险预警对敏感属性的定义不一致审计团队和建模团队对“敏感属性”的字段理解不同核对数据字典和样本标注建立敏感字段表审计前统一口径扰动只作用在连续特征类别特征未处理类别特征无法直接加 Lp 扰动检查扰动逻辑是否覆盖所有特征类型对类别特征使用随机替换或概率翻转扰动这些问题的共同点是鲁棒审计的结论取决于扰动定义、指标选择、敏感属性定义等前提条件。这也是为什么强调“审计配置要可复现”的原因。如果每个团队都有自己的扰动半径和指标口径最终报告很难在企业内部形成统一判断。8. 工程化落地与最佳实践几何理论提供了一个分析框架但要让它在真实项目中起作用还需要工程上的配套实践。8.1 从“跑指标”升级为“跑风险清单”建议团队为每个待审计模型建立一份公平性风险清单包含三类内容静态指标DP gap、Equalized Odds 等基础值。鲁棒指标在预设扰动半径下的最坏情况值。脆弱方向导致不公平上升的关键扰动方向及对应特征。风险清单比单一指标更有说服力因为它同时展示了“模型现状”和“风险边界”。业务方看到的不再是一个“通过/不通过”的结论而是模型在什么情况下会变得不公平这样更容易推动后续治理决策。8.2 扰动半径要与业务语义绑定选择扰动半径不能只看数学规范。eps0.05在标准化特征空间里意味着“特征变化不超过 0.05 个标准差”但业务上是否合理还要和实际数据采集误差、季节性漂移、用户行为变化的幅度对照。更稳妥的做法是从历史数据中观察特征的实际波动范围。对每个特征分别设置扰动上限而不是所有特征使用同一个eps。在审计报告中明示扰动半径的选择依据。8.3 敏感属性缺失是高风险场景真实业务数据里敏感属性经常因为合规要求被脱敏或缺失。此时不能简单地删除敏感属性列因为敏感信息往往“隐藏”在其他相关特征里例如学历、地址、收入区段等。在几何理论框架下这个问题可以理解成原始扰动空间不是完整的特征空间而是投影后的受限空间。审计时需要额外验证在敏感属性不可见时模型是否仍然在相关代理特征上保持公平。这通常需要构造代理敏感属性或者使用间接公平性度量。8.4 把审计纳入模型上线流水线理想情况下鲁棒公平性审计不应该是一次性动作而应嵌入模型训练和发布流程训练阶段在验证集上同时计算静态和鲁棒指标。预发布阶段对候选模型执行完整审计包括多方向扰动搜索。上线后周期性使用新的业务数据重算鲁棒指标监控公平性漂移。这样可以避免“审计在最后验收时才发现问题”的尴尬局面。鲁棒指标相当于给模型加了一个“公平性压力测试”越早做修正成本越低。8.5 关注可解释性而不是只给一个分数几何理论给出的最大扰动方向本身就可以作为可解释性工具。我们可以分析在最大扰动方向中哪些特征变化贡献最高从而回答“是什么让模型变得不公”。注意这里的安全边界分析结果用于模型改进和风险预警不是用于对特定个体做决策。所以实际项目里的最佳做法是把鲁棒公平性审计作为内部模型治理工具输出风险报告辅助算法团队修正模型而不是直接对外发布审计分数。9. 总结与后续方向这篇文章从公平性审计的静态指标问题出发解释了为什么需要鲁棒审计并把几何理论引入审计问题数据是空间中的点集模型是决策边界公平性是约束区域扰动是位移。鲁棒公平性审计的核心就是判断模型在给定扰动范围内是否仍然停留在公平区域内。通过一个 Python 最小示例可以看到静态 DP gap 达标并不代表扰动后仍然达标。几何理论提供的不是一套全新的指标而是一个更完整的风险框架它不仅告诉审计者“模型是否不公平”还告诉审计者“模型在什么条件下会变得不公平”。如果你想把这个问题继续做深有几个方向值得关注把随机扰动搜索换成梯度上升或基于代理模型的优化寻找更准确的“最坏扰动方向”。把单指标审计扩展为多指标联合审计分析多个公平性约束在几何空间中的边界关系。在特征缺失和敏感属性不可见的约束下研究代理敏感属性的鲁棒性。结合现有 fairness 工具库例如 fairlearn、AIF360设计更完整的审计流水线把静态指标与鲁棒风险统一管理。对实际项目的建议很直接从下一次模型评估开始不要只汇报一组静态公平性指标。尝试在最坏扰动下多测一轮哪怕只是随机方向扰动也能提前暴露出很多“静态达标、上线翻车”的隐患。这套思路越早纳入团队规范后续返工成本越低。