AI 偏见是指机器学习系统在预测或决策中表现出系统性偏差,导致某些群体受到不公平对待。2025-2026 年,随着 AI 在招聘、信贷、医疗等高风险场景的广泛应用,偏见缓解已成为企业合规和伦理治理的核心议题。
一、偏见来源分析#
1.1 数据层面偏见#
| 偏见类型 | 描述 | 示例 |
|---|
| 历史偏见 | 训练数据反映历史歧视 | 招聘数据中女性占比过低 |
| 表示偏见 | 某些群体数据不足 | 医疗数据集中少数民族样本少 |
| 测量偏见 | 特征定义对某些群体不公平 | 用 zip code 代理信用评分 |
| 聚合偏见 | 模型对整体最优但对子群体不佳 | 整体准确率高但对老年群体差 |
1.2 模型层面偏见#
| 偏见类型 | 描述 |
|---|
| 算法偏见 | 模型结构或损失函数强化偏见 |
| 部署偏见 | 模型在不同于训练环境的数据上运行 |
| 反馈偏见 | 模型输出影响后续数据收集,形成偏见循环 |
二、公平性定义与度量#
2.1 数学定义#
# 常见公平性指标计算
import numpy as np
from sklearn.metrics import confusion_matrix
def fairness_metrics(y_true, y_pred, sensitive_attr):
"""
计算常见公平性指标
y_true: 真实标签 (0/1)
y_pred: 预测标签 (0/1)
sensitive_attr: 敏感属性 (0/1),如性别、种族
"""
group_0 = sensitive_attr == 0
group_1 = sensitive_attr == 1
# Demographic Parity Difference (DPD)
# 要求不同群体的预测正例率相同
pred_positive_rate_0 = y_pred[group_0].mean()
pred_positive_rate_1 = y_pred[group_1].mean()
dpd = abs(pred_positive_rate_0 - pred_positive_rate_1)
# Equal Opportunity Difference (EOD)
# 要求不同群体的真正例率相同
tp_0 = y_pred[group_0 & (y_true == 1)].mean()
tp_1 = y_pred[group_1 & (y_true == 1)].mean()
eod = abs(tp_0 - tp_1)
# Equalized Odds Difference (EQOD)
# 要求不同群体的真正例率和假正例率都相同
fp_0 = y_pred[group_0 & (y_true == 0)].mean()
fp_1 = y_pred[group_1 & (y_true == 0)].mean()
eqod = max(abs(tp_0 - tp_1), abs(fp_0 - fp_1))
# Disparate Impact Ratio (DIR)
dir_ratio = min(pred_positive_rate_0, pred_positive_rate_1) / \
max(pred_positive_rate_0, pred_positive_rate_1, 1e-10)
return {
"demographic_parity_diff": dpd,
"equal_opportunity_diff": eod,
"equalized_odds_diff": eqod,
"disparate_impact_ratio": dir_ratio,
"positive_rate_group_0": pred_positive_rate_0,
"positive_rate_group_1": pred_positive_rate_1,
}
2.2 指标对比#
| 指标 | 定义 | 适用场景 | 法律依据 |
|---|
| Demographic Parity | P(Ŷ | A=0) = P(Ŷ | A=1) |
| Equal Opportunity | P(Ŷ=1 | Y=1,A=0) = P(Ŷ=1 | Y=1,A=1) |
| Equalized Odds | TPR 和 FPR 均相等 | 高风险决策 | 更严格 |
| Disparate Impact | P(Ŷ | A=0) / P(Ŷ | A=1) ∈ [0.8, 1.25] |
三、数据层缓解技术#
3.1 重采样(Resampling)#
from imblearn.over_sampling import SMOTE
import pandas as pd
def fairness_aware_oversample(df, sensitive_col, label_col, target_col):
"""
基于公平性的过采样
确保每个敏感属性组合的样本比例均衡
"""
# 计算每个组合的样本数
group_counts = df.groupby([sensitive_col, label_col]).size()
target_count = group_counts.max()
resampled_dfs = []
for (sensitive_val, label_val), group_df in df.groupby([sensitive_col, label_col]):
if len(group_df) < target_count:
# 对少数群体进行 SMOTE 过采样
smote = SMOTE(sampling_strategy=target_count, random_state=42)
X = group_df.drop(columns=[label_col, sensitive_col])
y = group_df[label_col]
X_resampled, y_resampled = smote.fit_resample(X, y)
# 重新组装 DataFrame
resampled_group = pd.concat([
X_resampled,
pd.DataFrame({label_col: y_resampled}),
pd.DataFrame({sensitive_col: [sensitive_val] * len(X_resampled)})
], axis=1)
resampled_dfs.append(resampled_group)
else:
resampled_dfs.append(group_df)
return pd.concat(resampled_dfs, ignore_index=True)
3.2 重加权(Reweighting)#
def compute_fairness_weights(df, sensitive_col, label_col):
"""
计算公平性感知的样本权重
思路:调整权重使得敏感属性与标签的联合分布均匀
"""
n = len(df)
group_sizes = df.groupby([sensitive_col, label_col]).size()
weights = []
for _, row in df.iterrows():
s_val = row[sensitive_col]
y_val = row[label_col]
group_size = group_sizes[(s_val, y_val)]
# 权重 = 总样本数 / (组数 * 组大小)
n_groups = len(group_sizes)
weight = n / (n_groups * group_size)
weights.append(weight)
return np.array(weights)
# 在模型训练中使用
# sample_weight = compute_fairness_weights(train_df, "gender", "label")
# model.fit(X_train, y_train, sample_weight=sample_weight)
四、训练层缓解技术#
4.1 对抗性去偏(Adversarial Debiasing)#
import torch
import torch.nn as nn
class AdversarialDebiasing(nn.Module):
"""
对抗性去偏模型
主预测器尝试预测目标
对抗器尝试从隐藏层预测敏感属性
"""
def __init__(self, input_dim, hidden_dim, num_classes, num_sensitive):
super().__init__()
# 主预测器
self.encoder = nn.Sequential(
nn.Linear(input_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
)
self.predictor = nn.Linear(hidden_dim, num_classes)
# 对抗器(用于学习去偏表示)
self.adversary = nn.Sequential(
nn.Linear(hidden_dim, hidden_dim // 2),
nn.ReLU(),
nn.Linear(hidden_dim // 2, num_sensitive),
)
def forward(self, x, return_hidden=False):
hidden = self.encoder(x)
pred = self.predictor(hidden)
if return_hidden:
return pred, hidden
return pred
def adversary_pred(self, hidden):
return self.adversary(hidden)
def train_debiased_model(model, dataloader, sensitive_attr, epochs=10,
lambda_adv=1.0):
"""
训练对抗性去偏模型
lambda_adv: 对抗损失的权重(越大去偏越强)
"""
optimizer_pred = torch.optim.Adam(
list(model.encoder.parameters()) + list(model.predictor.parameters()),
lr=0.001
)
optimizer_adv = torch.optim.Adam(model.adversary.parameters(), lr=0.001)
criterion_task = nn.CrossEntropyLoss()
criterion_adv = nn.CrossEntropyLoss()
for epoch in range(epochs):
for batch_x, batch_y, batch_s in dataloader:
# Step 1: 更新对抗器
optimizer_adv.zero_grad()
_, hidden = model(batch_x, return_hidden=True)
adv_pred = model.adversary_pred(hidden.detach())
loss_adv = criterion_adv(adv_pred, batch_s)
loss_adv.backward()
optimizer_adv.step()
# Step 2: 更新主预测器(最小化任务损失,最大化对抗损失)
optimizer_pred.zero_grad()
pred, hidden = model(batch_x, return_hidden=True)
loss_task = criterion_task(pred, batch_y)
adv_pred = model.adversary_pred(hidden)
# 梯度反转:最大化对抗器预测敏感属性的能力
# 即让隐藏表示对敏感属性"不可预测"
loss_total = loss_task - lambda_adv * criterion_adv(adv_pred, batch_s)
loss_total.backward()
optimizer_pred.step()
return model
4.2 公平性约束优化#
# 使用 Fairlearn 进行公平性约束训练
from fairlearn.reductions import ExponentiatedGradient, DemographicParity
from sklearn.linear_model import LogisticRegression
def fair_train_with_constraint(X_train, y_train, sensitive_features,
constraint="demographic_parity", eps=0.01):
"""
使用 Fairlearn 的减少方法进行公平性约束训练
"""
# 定义基础模型
base_model = LogisticRegression(solver='liblinear', fit_intercept=True)
# 定义公平性约束
if constraint == "demographic_parity":
fairness_constraint = DemographicParity()
elif constraint == "equalized_odds":
from fairlearn.reductions import EqualizedOdds
fairness_constraint = EqualizedOdds()
else:
raise ValueError(f"不支持的约束类型: {constraint}")
# 创建约束优化器
mitigator = ExponentiatedGradient(
base_model,
constraints=fairness_constraint,
eps=eps # 容忍度
)
# 训练
mitigator.fit(X_train, y_train, sensitive_features=sensitive_features)
return mitigator
# 使用示例
# mitigator = fair_train_with_constraint(
# X_train, y_train, sensitive_features,
# constraint="demographic_parity", eps=0.01
# )
# y_pred_fair = mitigator.predict(X_test)
五、推理层缓解技术#
5.1 后处理阈值调整#
def calibrate_thresholds(y_proba, sensitive_attr, target_metric="demographic_parity"):
"""
为不同敏感群体设置不同阈值以实现公平性
"""
unique_groups = np.unique(sensitive_attr)
thresholds = {}
if target_metric == "demographic_parity":
# 目标:使各群体的正例预测率相同
target_rate = y_proba.mean() # 全局正例率作为目标
for group in unique_groups:
group_proba = y_proba[sensitive_attr == group]
# 找到使该群体预测正例率达到目标的阈值
thresholds[group] = np.percentile(group_proba,
(1 - target_rate) * 100)
elif target_metric == "equalized_odds":
# 需要迭代优化以满足 TPR 和 FPR 相等
pass # 实现略
return thresholds
def fair_predict(y_proba, sensitive_attr, thresholds):
"""
使用分组阈值进行预测
"""
predictions = np.zeros_like(y_proba, dtype=int)
for group, threshold in thresholds.items():
group_mask = sensitive_attr == group
predictions[group_mask] = (y_proba[group_mask] >= threshold).astype(int)
return predictions
5.2 模型集成去偏#
def ensemble_fairness(models, X, sensitive_attr, strategy="voting"):
"""
集成多个模型的预测结果以减少偏见
"""
predictions = np.column_stack([m.predict(X) for m in models])
if strategy == "voting":
# 简单投票
return predictions.mean(axis=1) >= 0.5
elif strategy == "fair_voting":
# 公平性加权投票:为每个群体单独调整权重
final_pred = np.zeros(len(X))
for group in np.unique(sensitive_attr):
group_mask = sensitive_attr == group
group_pred = predictions[group_mask].mean(axis=1)
final_pred[group_mask] = group_pred >= 0.5
return final_pred
elif strategy == "stacking":
# 使用元学习器学习如何组合(需额外训练)
pass
六、评估与监控#
6.1 公平性仪表盘#
# 使用 AIF360 进行全面公平性评估
from aif360.metrics import BinaryLabelDatasetMetric, ClassificationMetric
from aif360.datasets import BinaryLabelDataset
def comprehensive_fairness_eval(dataset, predictions, sensitive_attr_idx=0):
"""
全面的公平性评估
"""
# 创建评估数据集
pred_dataset = dataset.copy()
pred_dataset.labels = predictions
# 二分类指标
metric = ClassificationMetric(
dataset, pred_dataset,
unprivileged_groups=[{sensitive_attr_idx: 0}],
privileged_groups=[{sensitive_attr_idx: 1}]
)
return {
# 差异指标
"statistical_parity_diff": metric.statistical_parity_difference(),
"disparate_impact": metric.disparate_impact(),
"equal_opportunity_diff": metric.equal_opportunity_difference(),
"average_odds_diff": metric.average_odds_difference(),
# 绝对值指标
"false_positive_rate_diff": metric.difference(
metric.false_positive_rate
),
"false_negative_rate_diff": metric.difference(
metric.false_negative_rate
),
"accuracy_diff": metric.difference(metric.accuracy),
# 整体性能
"overall_accuracy": metric.accuracy(),
"balanced_accuracy": metric.accuracy(
privileged=False
) * 0.5 + metric.accuracy(privileged=True) * 0.5,
}
七、技术栈对比#
| 层次 | 工具/库 | 核心功能 | 语言 |
|---|
| 数据 | Fairlearn | 公平性重采样、权重计算 | Python |
| 数据 | AIF360 | 数据集变换、偏见检测 | Python |
| 训练 | Fairlearn | 约束优化、网格搜索 | Python |
| 训练 | TensorFlow Fairness Indicators | 模型评估 | Python |
| 推理 | AIF360 | 后处理校准 | Python |
| 监控 | Fairlearn Dashboard | 可视化仪表盘 | Python |
| 监控 | WhyLabs | 生产环境监控 | SaaS |
- Barocas, S., et al. “Fairness and Machine Learning.” 2023.
- Bellamy, R., et al. “AI Fairness 360: An Extensible Toolkit for Detecting and Mitigating Algorithmic Bias.” IBM Journal of R&D, 2024.
- Fairlearn: https://fairlearn.org
- AIF360: https://aif360.res.ibm.com
- European Union AI Act (2024), Article 10-15 on Data Governance and Bias Mitigation.
加入讨论#
这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。
碳基与硅基的智慧碰撞,认知差异创造无限可能。