enhanced-replica-model-pack / docs /final_ensemble.md
LUCIFerace's picture
Add files using upload-large-folder tool
7186231 verified

# Final Ensemble

正式最终系统

本仓库的正式最终系统是一个 7-voter Logistic Regression Stacking 方案。它不是规则硬投票,也不是探索阶段的静态加权投票,而是基于连续分数学习出来的 stacking 模型。

正式结果入口:

  • results/final-system/ds13/ensemble_meta.json
  • configs/ensemble_config.json
  • results/final-system/upstream-voters/ds13/

7 个 voter 包含什么

Voter 类型 仓库里保留的资产 在最终系统中的角色
qwen7b_general LoRA adapter models/qwen-adapters/general/ 通用主力分支
qwen7b_short LoRA adapter models/qwen-adapters/short/ 补强 76-180 字短文本
qwen7b_extreme_short LoRA adapter models/qwen-adapters/ultra-short/ 补强 0-75 字极短文本
bert 微调分类模型 models/bert-final/ 最终 LR 权重最高
roberta 微调分类模型 models/roberta-final/ 与 BERT 和 Qwen 分支形成互补
FastDetectGPT 零样本 detector 算法脚本 + 结果文件 提供生成痕迹分数
Binoculars 零样本 detector 算法脚本 + 结果文件 提供另一类生成痕迹分数

这里最容易被误解的是最后两个 detector。FastDetectGPTBinoculars 不是单独训练出来的新分类模型,它们是零样本检测算法分支:

  • FastDetectGPT 使用 Qwen2.5-3B-InstructQwen2.5-3B 的对比分数。
  • Binoculars 也基于同一对 3B 模型,只是打分公式不同。
  • 对应实现位于 scripts/inference/run_zero_shot_detectors.py

因此仓库不会给这两个 detector 单独保存“分类器权重目录”。它们的可交付形式是:算法说明、推理脚本、实验留档和最终分数文件。

最终权重如何确定

正式 DS13 系统的权重学习流程如下:

  1. 收集 7 个 voter 在 dev 上的连续输出分数。
  2. 构造特征矩阵,并额外加入长度特征 len_norm = length / 1000.0
  3. 通过 StandardScaler 标准化特征。
  4. sklearn.linear_model.LogisticRegression(solver="lbfgs", C=1.0) 拟合二分类 stacking 模型。
  5. 在 dev 上按 F1 搜索最优阈值,得到最终推理阈值。

对应实现可从 scripts/inference/run_logistic_regression_ensemble.py 看出,正式参数以结果文件为准,而不是以脚本默认参数猜测。

DS13 正式 LR 系数与阈值

以下数字直接来自 results/final-system/ds13/ensemble_meta.jsonconfigs/ensemble_config.json

Feature Coefficient
bert 2.0188854029
qwen7b_general 1.8788706258
roberta 1.8788624937
qwen7b_short 1.2970493780
qwen7b_extreme_short 0.8596312618
FastDetectGPT 0.2563906985
Binoculars 0.2295749248
len_norm 0.0062348417

补充参数:

  • intercept = 1.6861943699
  • threshold = 0.1307

可以直接把这些系数理解成“正式最终系统的权重”。如果有人去看 src/enhanced_replica/voter_registry.py,会看到 default_weight_championbucket_weights。这些值属于 E04 / E06 探索阶段的硬投票默认值,只服务于探索期脚本,不代表正式最终 DS13 ensemble 权重。

分桶方式与 DS13 的 fallback

本仓库保留的 bucket 定义为:

  • extreme_short = 0-75
  • short = 76-180
  • general = 181+

DS13 正式 bundle 虽然同时保存了 lr_globallr_bucket 两套结果,但 lr_bucket 在 DS13 上没有学出单独桶模型,而是全部回退到 global:

Bucket n_dev 是否回退到 global
extreme_short 1
short 0
general 9

这意味着:

  • DS13 的 bucket 流程被保留了。
  • 但因为 dev 样本极少,正式结果实际上等价于 global LR。
  • 所以 DS13 上讨论“bucket 权重”没有意义,真正需要看的就是全局 LR 系数。

为什么会回退到 DS01 dev

DS13 dev 过小,不足以稳定拟合 7-voter LR stacking。因此最终配置明确采用了 fallback 思路:用更稳定的 dev 参考来拟合 LR,再迁移到 DS13 test 评估。仓库里保留 results/final-system/ds01-reference/,是为了让这条 fallback 逻辑有一个可追溯的参考 bundle。

需要注意的是,ds01-reference 是参考证据区,不是第二个正式最终系统入口。对于 DS13 的正式最终权重,始终以:

  • results/final-system/ds13/ensemble_meta.json
  • configs/ensemble_config.json

为准。

DS13 正式最终结果

总体结果

  • F1 = 0.986091
  • Accuracy = 0.986182
  • Precision = 0.992448
  • Recall = 0.979815

子集结果

Subset N F1 Precision Recall Accuracy
normal 4000 0.997505 0.995518 0.999500 0.997500
mixed_attack 1000 0.962810 0.993603 0.933868 0.964000
paraphrase_attack 1000 0.979675 0.995868 0.964000 0.980000
perturbation_attack 1000 0.996000 0.996000 0.996000 0.996000
len_64 1000 0.940452 0.966245 0.916000 0.942000
len_128 1000 0.982880 0.989858 0.976000 0.983000
len_256 1000 0.994995 0.995992 0.994000 0.995000
len_512 1000 0.998004 0.996016 1.000000 0.998000

这里最值得保留的结论是:短文本仍然最难,len_64 明显低于长文本段。这也解释了为什么最终系统没有只保留一个通用 Qwen 分支,而是把 shortextreme_short 两个长度专门化 adapter 一起保留下来。

上游 voter 结果为什么也要保留

results/final-system/upstream-voters/ds13/ 保存了 7 个 voter 的 dev / test 输出。保留它们不是为了让人手动拼装提交,而是为了做到两件事:

  1. 让最终 DS13 ensemble 可追溯。
  2. 让后续研究者能直接看到每个 voter 的分数文件,从而复算 stacking、阈值与误差来源。

一句话区分两类“权重”

  • 正式最终系统权重:看 results/final-system/ds13/ensemble_meta.jsonconfigs/ensemble_config.json
  • 探索期硬投票默认值:看 src/enhanced_replica/voter_registry.py,只属于 E04 / E06 研究路线。