)
generalized_rates 实战指南基于三玩家框架的广义率指标约束优化NeurIPS 2019 代码复现【免费下载链接】google-researchGoogle Research项目地址: https://gitcode.com/gh_mirrors/go/google-research导读generalized_rates是 Google Research 仓库中与论文Optimizing Generalized Rate Metrics with Three PlayersHarikrishna Narasimhan、Andrew Cotter、Maya GuptaNeurIPS 2019配套的示例代码核心解决一类在公平性约束下优化非凸率指标如 F-measure、KL 散度的机器学习问题。本指南将带你完整走通环境安装、COMPAS 数据集上的 F-measure 优化实验、Adult 数据集上的 KLD 优化实验并结合仓库源码剖析约束优化问题如何建模、代理目标surrogate如何设计、随机/确定性模型如何产出使你能够将该框架迁移到自己的公平分类任务中。一、核心思想用三玩家求解广义率指标优化传统的分类器训练直接最小化可微的损失如 hinge loss、交叉熵但很多实际业务关心的指标——F-measure、覆盖度coverage、正类预测率positive prediction rate——都是基于率的、不可微甚至非凸的目标。当进一步加入组间公平性约束如两组的 F-measure 差距不能超过 ε时问题变成带约束的非凸优化普通梯度方法无法直接处理。论文提出的三玩家Three Players框架将这类问题转化为一个带约束的极小极大问题迭代求解三方博弈模型参数player 1、拉格朗日乘子player 2以及为处理不可微率指标而引入的松弛变量player 3。仓库中对应实现了论文的两个核心算法Algorithm 2适用于凸率指标如误差率约束下的 KL 散度见 kld_optimization/methods.pyAlgorithm 3适用于和之比形式的非凸率指标如带组间 F-measure 奇偶约束的 F-measure 最大化见 fmeasure_optimization/methods.py。两个算法都构建在 TensorFlow 生态之上并直接依赖 Google 的 tensorflow_constrained_optimizationTFCO 库来管理率对象与拉格朗日优化器。二、仓库结构与模块职责generalized_rates/ ├── datasets/ # 数据加载与预处理 │ ├── load_compas.py # COMPAS 原始 CSV → COMPAS.npy │ ├── load_adult.py # Adult 原始数据 → Adult.npy │ └── synthetic.npy # 预生成的合成数据可直接跑 F-measure 实验 ├── fmeasure_optimization/ # F-measure 优化Algorithm 3 │ ├── experiments.py # 实验入口对比多种方法 │ ├── methods.py # 无约束/约束优化方法实现 │ └── evaluation.py # F-measure、误差率等评估函数 ├── kld_optimization/ # KLD 优化Algorithm 2 │ ├── experiments.py │ ├── methods.py │ └── evaluation.py ├── requirements.txt # Python 依赖 └── run.sh # 一键脚本用合成数据跑 F-measure 实验两个优化子目录的结构完全对称experiments.py定义命令行入口与实验流程methods.py实现算法evaluation.py提供基于 numpy 的评估指标。这种对称设计便于读者对照学习两种算法在建模上的差异。三、环境安装仓库要求 Python 3 环境依赖项见 requirements.txtabsl-py0.7.0命令行 flags 与 app 框架numpy1.13.3tensorflow2.2.0代码内部以tensorflow.compat.v1方式使用见 methods.py 的导入语句tensorflow_constrained_optimizationTFCO 率约束优化库按 README 推荐的方式创建虚拟环境并安装virtualenv -p python3 . source ./bin/activate pip3 install -r generalized_rates/requirements.txt仓库还提供了 run.sh 一键脚本其逻辑与 README 安装步骤一致并在安装后直接使用预置的合成数据./generalized_rates/datasets/synthetic.npy运行 F-measure 实验适合快速验证环境是否就绪set -e set -x virtualenv -p python3 . source ./bin/activate pip3 install -r generalized_rates/requirements.txt python -m generalized_rates.fmeasure_optimization.experiments \ --data_file./generalized_rates/datasets/synthetic.npy四、实验一在 COMPAS 数据集上优化 F-measure4.1 准备数据集COMPAS 数据ProPublica 发布的累犯预测数据需要先下载compas-scores-two-years.csv并保存到generalized_rates/datasets文件夹然后调用 datasets/load_compas.py 完成预处理DATA_DIR./generalized_rates/datasets python -m generalized_rates.datasets.load_compas \ --data_file$DATA_DIR/compas-scores-two-years.csv \ --output_directory$DATA_DIR/预处理脚本会完成特征筛选保留 age、c_charge_degree、race、score_text、sex、priors_count 等列、样本过滤days_b_screening_arrest在 ±30 天内、is_recid ! -1、去除缺失类别、连续特征分桶priors_count按 0/50/70/80/90/100 分位切分其余连续特征按 20/40/60/80/90/100 分位切分、独热编码最终将标签设为两年内是否再犯two_year_recid受保护组设为女性被告sex_Female并按 1/3 测试、剩余 2/3 再按 1/3 验证的比例切分保存为COMPAS.npy。4.2 运行 F-measure 优化实验python -m generalized_rates.fmeasure_optimization.experiments \ --data_file$DATA_DIR/COMPAS.npy该实验求解的约束优化问题为见 experiments.py 模块 docstringmax F-measure s.t. F-measure(group1) F-measure(group0) - epsilon4.3 命令行参数说明参数类型默认值含义--data_filestring无必填预处理后.npy数据路径--loops_conint5000拉格朗日约束优化器的迭代轮数--loops_uncint2500无约束方法误差率/逻辑回归的迭代轮数--epsilonfloat0.01约束松弛量即允许 group1 的 F-measure 比 group0 低的最大幅度4.4 实验对比了哪些方法run_experiment()依次训练并对比四类模型最终在测试集上打印各自的 F-measure 与约束违例值(fm, fm0 - fm1)UncError无约束误差率优化用error_rate_optimizer最小化 hinge lossmethods.py 中为线性模型weights·x thresholdAdam 优化每 10 轮 checkpoint 一次最后用np.argmin选最优迭代点UncF1Post-shift 后移位 F1 优化先训练逻辑回归最小化交叉熵再在验证集上对预测分数做分位数阈值扫描bin_size0.001即 0.1% 粒度挑出使 F-measure 最大的平移阈值post_shift_fmeasureConstrained (Stochastic)Algorithm 3 随机模型lagrangian_optimizer_fmeasure用 TFCO 的rate_context/f_score定义整体与分组 F-measure构造RateMinimizationProblem(-fm_overall, [fm0 fm1 epsilon])用LagrangianOptimizerV1交替更新模型参数与乘子训练中每 10 轮记录目标与违例用tfco.find_best_candidate_index选最优迭代点再用tfco.find_best_candidate_distribution做收缩得到一个稀疏的迭代点概率分布作为随机模型Constrained (Deterministic)Algorithm 3 确定性模型与随机模型同一次训练中产出即find_best_candidate_index选出的单一点模型。注意约束方法使用模型参数学习率lr_range_con [0.001, 0.01, 0.1, 1.0]与乘子学习率lr_range_con做两两网格搜索在验证集上按目标 约束违例用tfco.find_best_candidate_index选出最佳超参数组合无约束方法则在lr_range_unc [0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0]中按验证集误差/交叉熵选优。五、实验二在 Adult 数据集上优化 KLD5.1 准备数据集下载 Adult 训练与测试数据文件并保存到generalized_rates/datasets文件夹然后调用 datasets/load_adult.pyDATA_DIR./generalized_rates/datasets python -m generalized_rates.datasets.load_adult \ --train_file$DATA_DIR/adult.data \ --test_file$DATA_DIR/adult.test \ --output_directory$DATA_DIR/预处理要点见 load_adult.py标签为年收入是否 50K受保护组设为女性gender_Female连续特征分桶——age按 4 分位数切分capital_gain/capital_loss/hours_per_week/education_num使用脚本内置的固定 bin训练与测试集经独热编码后自动对齐列缺失列补 0最终从测试集中按vali_fraction1/3切出验证集保存为Adult.npy。5.2 运行 KLD 优化实验python -m generalized_rates.kld_optimization.experiments \ --data_file$DATA_DIR/Adult.npy该实验求解的约束优化问题为见 experiments.py docstringmin sum_G KLD(p, hat{p}_G) s.t. error_rate eps * error_rate_unconstrained其中p为全体样本的正类比例hat{p}_G为组 G 的预测正类比例eps是乘性松弛约束的实际形式是误差率不超过无约束误差率的eps倍。由于epsilon默认值为 1.1实验会先把无约束误差率模型在训练集上的误差算出来再乘以epsilon得到加性松弛量additive_slack见run_experiment中的error_unc_train * FLAGS.epsilon传入lagrangian_optimizer_kld。5.3 命令行参数说明参数类型默认值含义--data_filestring无必填预处理后.npy数据路径--loops_conint5000拉格朗日约束优化器迭代轮数--loops_uncint2500无约束方法迭代轮数--epsilonfloat1.1乘性松弛系数相对无约束误差率5.4 实验对比了哪些方法UncErrorhinge loss 最小化的线性模型与 F-measure 实验中同一实现PostShift人口统计均等后移位先训练逻辑回归再在验证集上分别为两个组计算阈值使每组的正类覆盖率达到整体正类比例p并把组属性拼接到特征末尾、将两个阈值差并入权重post_shift_dp见 methods.py返回的是特征扩展后的数据集与后移位模型Constrained (Stochastic) / Constrained (Deterministic)lagrangian_optimizer_kld实现 Algorithm 2。KLD 实验在测试集、训练集、验证集三份数据上都打印各方法的(sum(KLD), error, error/error_unc)便于观察公平性与精度在不同数据划分上的权衡。六、源码级解析Algorithm 2 的松弛变量博弈lagrangian_optimizer_kld 是理解三玩家思想的最佳入口。KLD 目标本身涉及分组正类预测率ppr_G与负类预测率npr_G为将其转成可微目标源码做了如下设计引入四个松弛变量xi_pos0/xi_neg0/xi_pos1/xi_neg1把原始问题改写为带约束的极大极小问题docstring 中给出完整推导对-p·log(xi) - (1-p)·log(xi)形式的 KL 目标约束xi ppr/ npr松弛变量的最优响应best response有闭式解BR(xi_pos0) p / lambda_pos0BR(xi_neg0) (1-p) / lambda_neg0对两个组同理拉格朗日乘子用显式 Variable 维护lambda_pos0等四个乘子初始化为 0.5methods.py由于 TFCO 库不支持松弛变量 best response源码用tf.stop_gradient把乘子冻结在目标里使一次梯度下降同时实现对模型参数最小化、对松弛变量乘子最大化率用 hinge 凹下界代理ppr_hinge_group0 sum(1 - relu(1 - predictions)) / n0因为约束中是xi - ppr的形式乘子非负-ppr的凹下界取负后正好构成凸上界保证极小极大更新方向的正确性误差率约束交给 TFCOtfco.rate_contexttfco.error_rate构造error additive_slack约束LagrangianOptimizerV1内部自动完成误差率约束乘子的梯度上升。训练循环与 F-measure 版本一致每 10 轮记录模型权重、KLD 目标evaluation.expected_group_klds与违例量error - additive_slack最终用tfco.find_best_candidate_index与tfco.find_best_candidate_distribution分别产出确定性与随机模型。KLD 的数值计算在 evaluation.py 中使用DELTA 1e-10做平滑防止对数为零。七、评估函数速查两个evaluation.py提供了一致的指标族均支持随机模型多个迭代点按概率加权函数所在文件说明expected_error_rate两个目录均有随机模型期望误差率predicted ! labels的加权平均expected_group_errorsfmeasure按组分别计算期望误差率expected_fmeasure/expected_group_fmeasuresfmeasure用 TP/FP/FN 计算 F-measure2TP / (2TP FP FN)fmeasure_for_predictionsfmeasure给定标签与预测分数的 F-measurepost-shift 阈值扫描使用cross_entropy_loss两个目录均有数值稳定的 sigmoid 交叉熵expected_group_kldskld计算两组 KLDp·log(p/p_G) (1-p)·log((1-p)/(1-p_G))八、迁移到自有数据的关键提示数据格式实验入口统一从.npy中加载(train_set, vali_set, test_set)每份数据为(features, labels, groups)三元组groups取值为 0/1源码中按z 1/z 0区分两组。参考 load_compas.py 与 load_adult.py 可复刻完整的特征工程与切分流程TF 兼容性代码使用tensorflow.compat.v1与tf.Session()属 TF1 风格编程范式需在 TF2 环境或显式启用 TF1 行为时运行运行目录命令以python -m generalized_rates...形式执行需在仓库根目录含__init__.py的上级目录下运行确保generalized_rates包可被导入网格搜索开销约束方法默认在 4×4 的超参数网格上各跑 5000 轮F-measure 实验还叠加 2500 轮的无约束方法训练整体耗时取决于数据规模可通过调整--loops_con、--loops_unc控制。结语generalized_rates以紧凑的代码实现了 NeurIPS 2019 的三玩家率指标优化框架F-measure 与 KLD 两个实验分别对应 Algorithm 3和之比非凸目标与 Algorithm 2凸率目标完整覆盖了从数据预处理、无约束基线、post-shift 基线到约束优化的对比流程。对需要在公平性约束下优化业务率指标的工程师与研究者而言这是一个可直接运行、可逐行研读的参考实现。【免费下载链接】google-researchGoogle Research项目地址: https://gitcode.com/gh_mirrors/go/google-research创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考