4.3 去偏见技术与落地案例 本节摘要:检测出偏见只是第一步,真正难的是消除它。本节讲三种按干预时机划分的去偏见技术:预处理(重采样、重加权,在数据进模型前改)、训练中(公平约束、对抗去偏见,改训练目标)、后处理(阈值优化,改预测阶段)。每种各有优劣,往往要组合使用。后半节用三个真实案例收尾——招聘 AI、信贷评分、司法预测(COMPAS),看偏见在真实业务里怎么被发现、被量化、被缓解,以及缓解后的代价。
本节摘要:检测出偏见只是第一步,真正难的是消除它。本节讲三种按干预时机划分的去偏见技术:预处理(重采样、重加权,在数据进模型前改)、训练中(公平约束、对抗去偏见,改训练目标)、后处理(阈值优化,改预测阶段)。每种各有优劣,往往要组合使用。后半节用三个真实案例收尾——招聘 AI、信贷评分、司法预测(COMPAS),看偏见在真实业务里怎么被发现、被量化、被缓解,以及缓解后的代价。
阅读完本节,你应当能够:
检测出模型对女性选择率只有 0.28、男性 0.45 之后,怎么办?最直觉的反应是"调阈值"——把女性的批准阈值调低一点。但这只是治标,而且可能引入新的不公平(对男性)。真正系统化的去偏见,要回到偏见产生的环节去干预。
去偏见技术按"干预发生在哪个阶段"分成三类。预处理是在数据进模型之前改(让数据本身更平衡);训练中是在模型学习时加约束(让模型优化目标里包含公平性);后处理是在模型预测完之后调(按群体设不同阈值)。这三类不是互斥的,实际项目里常常组合使用——预处理改善数据,训练中加约束,后处理微调。
要提前接受一个事实:去偏见几乎一定有代价。统计上,公平性和准确率之间存在 trade-off——你要么牺牲一点整体准确率换来群体更平等,要么追求极致准确率容忍某些群体的劣势。没有免费的午餐。关键是在这个 trade-off 上找到符合业务和伦理的平衡点,而不是假装 trade-off 不存在。
| 干预时机 | 改什么 | 优点 | 缺点 |
|---|---|---|---|
| 预处理 | 训练数据 | 模型无关,一次处理处处可用 | 可能丢失信息,效果有限 |
| 训练中 | 训练目标/约束 | 效果好,能优化特定公平指标 | 改训练流程,复杂 |
| 后处理 | 预测阈值 | 简单,不用重训 | 需要知道群体属性(部署时可能违法) |
重采样的思路是"让训练数据里各群体的分布更平衡"。如果少数群体样本太少,要么过采样(复制少数群体样本),要么欠采样(删多数群体样本)。
from imblearn.over_sampling import SMOTE import numpy as np def fair_oversample(X, y, protected_attr): """按群体分别过采样,让各群体样本量平衡""" X_resampled, y_resampled = [], [] for group in np.unique(protected_attr): mask = protected_attr == group X_g, y_g = X[mask], y[mask] # 对每个群体单独做 SMOTE 过采样到相近规模 smote = SMOTE(k_neighbors=min(5, len(X_g) - 1)) X_res, y_res = smote.fit_resample(X_g, y_g) X_resampled.append(X_res) y_resampled.append(y_res) return np.vstack(X_resampled), np.hstack(y_resampled) # 使用:平衡后的数据再训练 X_fair, y_fair = fair_oversample(X_train, y_train, train_gender) model.fit(X_fair, y_fair)
重采样会改变数据量,重加权则保留原始数据,只是给不同样本分配不同权重——少数群体或被歧视的样本给更高权重。
def compute_fair_weights(y, protected_attr): """给少数群体和被低估的样本更高权重""" weights = np.ones(len(y)) n_total = len(y) n_groups = len(np.unique(protected_attr)) for group in np.unique(protected_attr): mask = protected_attr == group group_size = mask.sum() # 权重与群体大小成反比,小群体权重大 weights[mask] = n_total / (n_groups * group_size) return weights # 训练时传入样本权重 sample_weights = compute_fair_weights(y_train, train_gender) model.fit(X_train, y_train, sample_weight=sample_weights)
💡 关键直觉:重加权比重采样轻量——不改变数据量,只是让模型在训练时"更关注"被忽视的群体。但它的效果也有限,如果偏见是算法层面的(模型主动学会了歧视模式),光改权重不够,还得在训练目标里加约束。
训练中去偏见的核心是"把公平性写进优化目标"。Fairlearn 的 ExponentiatedGradient 就是这么做的——它把一个普通分类器包起来,在训练时同时优化准确率和公平约束。
from fairlearn.reductions import ExponentiatedGradient, DemographicParity from sklearn.linear_model import LogisticRegression # 定义公平约束:统计均等 constraint = DemographicParity() # 用指数梯度下降在约束下训练 mitigator = ExponentiatedGradient( LogisticRegression(), constraints=constraint, eps=0.01, # 允许的公平性差距(越小越公平,但可能越不准) ) mitigator.fit(X_train, y_train, sensitive_features=train_gender) # 预测:得到的模型自动满足统计均等约束 y_pred_fair = mitigator.predict(X_test)
对抗去偏见用了一个高明的设计:训练两个模型,一个做预测(主任务),一个猜受保护属性(对抗者)。目标是让主模型预测得好,同时让对抗者猜不出受保护属性——也就是让模型的表示里"洗掉"了敏感信息。
import torch import torch.nn as nn class FairModel(nn.Module): def __init__(self, input_dim, hidden_dim): super().__init__() self.encoder = nn.Sequential( nn.Linear(input_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, hidden_dim), ) self.predictor = nn.Linear(hidden_dim, 1) # 主任务:预测 y self.adversary = nn.Linear(hidden_dim, 1) # 对抗:猜性别 def forward(self, x): features = self.encoder(x) pred = torch.sigmoid(self.predictor(features)) adv_pred = torch.sigmoid(self.adversary(features)) return pred, adv_pred def train_fair_model(model, X, y, protected, epochs=100): optimizer = torch.optim.Adam(model.parameters()) for _ in range(epochs): optimizer.zero_grad() pred, adv_pred = model(X) task_loss = nn.BCELoss()(pred.squeeze(), y.float()) adv_loss = nn.BCELoss()(adv_pred.squeeze(), protected.float()) # 总损失 = 主任务损失 减 对抗损失 # 减号表示:让主模型尽量让对抗者猜不准(去除敏感信息) loss = task_loss - 0.1 * adv_loss loss.backward() optimizer.step() return model
对抗去偏见的理论很优雅,但实战中调参难——对抗系数(上面的 0.1)太大主任务学不好,太小去不掉偏见。
最简单的后处理是按群体设不同决策阈值。Fairlearn 的 ThresholdOptimizer 会自动找一组阈值,让模型在满足公平约束的同时尽量保持准确率。
from fairlearn.postprocessing import ThresholdOptimizer to = ThresholdOptimizer( estimator=model, # 已训好的模型 constraints="demographic_parity", # 公平约束 objective="accuracy_score", # 优化的目标 predict_method="predict_proba", ) to.fit(X_train, y_train, sensitive_features=train_gender) # 预测时自动按群体应用不同阈值 y_pred_fair = to.predict(X_test, sensitive_features=test_gender)
⚠️ 常见坑:后处理需要知道每个样本的受保护属性才能应用阈值。如果法规禁止在决策时使用这些属性(比如贷款不能因种族用不同标准),后处理就不能直接用。这种情况下得回到预处理或训练中干预——它们的输出是个"对所有群体用相同规则"的公平模型。
某招聘 AI 检测发现男性选择率 0.45、女性 0.28,存在明显偏见。用 ExponentiatedGradient 加统计均等约束训练后,男性降到 0.38、女性升到 0.36,差距大幅缩小,整体准确率只降了 2 个百分点。
| 指标 | 去偏见前 | 去偏见后 |
|---|---|---|
| 男性选择率 | 0.45 | 0.38 |
| 女性选择率 | 0.28 | 0.36 |
| 选择率差异 | 0.17 | 0.02 |
| 整体准确率 | 0.85 | 0.83 |
信贷模型在年龄维度上有偏见——年轻群体(age<25)的差异影响只有 0.65(低于 0.8 阈值)。用 AIF360 的 Reweighing 重加权预处理后,差异影响升到 0.92,达标。
| 指标 | 去偏见前 | 去偏见后 |
|---|---|---|
| 差异影响(年轻/年长) | 0.65 | 0.92 |
| 是否达标(≥0.8) | 否 | 是 |
COMPAS 是美国广泛使用的再犯风险评估系统,被发现对非洲裔的假阳性率(FPR)远高于欧洲裔——意味着更多无辜的非洲裔被错误标记为"高风险"。用阈值优化(机会均等约束)后,两个群体的 FPR 从 1.78 倍差距降到 1.10 倍。
| 指标 | 去偏见前 | 去偏见后 |
|---|---|---|
| 非洲裔 FPR | 0.32 | 0.22 |
| 欧洲裔 FPR | 0.18 | 0.20 |
| FPR 比率 | 1.78 | 1.10 |
💡 关键直觉:从三个案例都能看到一个规律——去偏见有效,但都有代价。准确率会降一点,或者某个群体的指标会变(COMPAS 里欧洲裔 FPR 从 0.18 升到 0.20)。这不是技术的失败,而是公平性 trade-off 的必然。决策者要明白:你愿意为公平付多大代价?这个选择是价值观和业务判断,不是算法能替你做的。
第四章结束。下一章把这些技术能力映射到法规要求上——欧盟 AI 法案、中国算法备案、美国 NIST 框架,看合规到底要你做什么。
三个落地案例横向对比后,能提炼出几条跨行业的共性教训,值得单独沉淀。第一,干预时机越早成本越低,但越早越不知道该干预什么——数据预处理的成本低,可那时还看不清模型最终在哪个群体上失衡;等到上线后用后处理调阈值,又往往已经造成实际伤害。成熟做法是分两轮:先用小成本实验(重加权)探明偏见的主要来源层,再在下一版训练里做针对性干预。第二,去偏见的收益要用"最差群体的改善"来度量,而不是平均值——平均通过率恢复不代表被伤害的群体恢复了,报表里永远放分组最差值。第三,人的环节是反弹最厉害的:工具改了,审核人员的习惯没改,半年后指标悄悄漂回去,所以去偏见项目必须配月度的分组指标回顾会,把它变成和故障复盘一样的例行仪式。

补一段关于"何时该放弃自动化"的判断标准,这是落地案例里最沉痛也最少被写进教程的经验。当某个决策同时满足三个条件——错误代价高、争议群体边界模糊、法律要求可解释——自动化就不该是终审。招聘终面、信贷终审、量刑参考都属于这一类。技术上模型可以辅助排序和初筛,但终审权留在人手里,且要给被决策者留出质疑和申诉的通道。这不是技术退让,而是系统的安全设计:自动化决策出错时责任链条清晰、可追诉,反而是纯人工决策做不到的。把"保留人工"当作去偏见技术栈的最后一层,而不是失败,这个观念转变是很多团队在案例复盘中付出的学费。
关于干预效果的持久性再补一句:很多去偏见手段的初始效果会随再训练而衰减,因为新的训练数据仍带着原有的社会分布。重加权权重需要在每次数据更新后重新计算,公平约束的系数要随数据分布校准,把它们写成训练流水线里的自动步骤而不是一次性脚本,是防止半年后指标悄悄漂回去的关键。
最后补一个跨行业观察:干预手段的选择和行业的可解释性压力强相关。金融和医疗偏好预处理与后处理,因为这两类手段不改模型内部,容易向监管说明;互联网产品偏好训练中干预,因为迭代快、可解释压力小。选型时把这个维度纳入,比单纯比技术指标更贴近真实约束。
再补一个关于干预组合的事实:三种干预手段可以叠加,但收益不是线性相加。预处理降了数据偏见,后处理再调阈值,第二层的空间就小了;先做后处理再回头做预处理,可能发现后处理本身就是多余的。务实做法是按从早到晚的顺序逐层评估,每层只在还有残余差距时才上,避免为凑技术清单把三层全堆上去——堆满三层的方案,多半说明前面某一层没做扎实。