# Final Ensemble
正式最终系统
本仓库的正式最终系统是一个 7-voter Logistic Regression Stacking 方案。它不是规则硬投票,也不是探索阶段的静态加权投票,而是基于连续分数学习出来的 stacking 模型。
正式结果入口:
results/final-system/ds13/ensemble_meta.jsonconfigs/ensemble_config.jsonresults/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。FastDetectGPT 和 Binoculars 不是单独训练出来的新分类模型,它们是零样本检测算法分支:
FastDetectGPT使用Qwen2.5-3B-Instruct与Qwen2.5-3B的对比分数。Binoculars也基于同一对 3B 模型,只是打分公式不同。- 对应实现位于
scripts/inference/run_zero_shot_detectors.py。
因此仓库不会给这两个 detector 单独保存“分类器权重目录”。它们的可交付形式是:算法说明、推理脚本、实验留档和最终分数文件。
最终权重如何确定
正式 DS13 系统的权重学习流程如下:
- 收集 7 个 voter 在 dev 上的连续输出分数。
- 构造特征矩阵,并额外加入长度特征
len_norm = length / 1000.0。 - 通过
StandardScaler标准化特征。 - 用
sklearn.linear_model.LogisticRegression(solver="lbfgs", C=1.0)拟合二分类 stacking 模型。 - 在 dev 上按 F1 搜索最优阈值,得到最终推理阈值。
对应实现可从 scripts/inference/run_logistic_regression_ensemble.py 看出,正式参数以结果文件为准,而不是以脚本默认参数猜测。
DS13 正式 LR 系数与阈值
以下数字直接来自 results/final-system/ds13/ensemble_meta.json 与 configs/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.6861943699threshold = 0.1307
可以直接把这些系数理解成“正式最终系统的权重”。如果有人去看 src/enhanced_replica/voter_registry.py,会看到 default_weight_champion 和 bucket_weights。这些值属于 E04 / E06 探索阶段的硬投票默认值,只服务于探索期脚本,不代表正式最终 DS13 ensemble 权重。
分桶方式与 DS13 的 fallback
本仓库保留的 bucket 定义为:
extreme_short = 0-75short = 76-180general = 181+
DS13 正式 bundle 虽然同时保存了 lr_global 和 lr_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.jsonconfigs/ensemble_config.json
为准。
DS13 正式最终结果
总体结果
F1 = 0.986091Accuracy = 0.986182Precision = 0.992448Recall = 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 分支,而是把 short 和 extreme_short 两个长度专门化 adapter 一起保留下来。
上游 voter 结果为什么也要保留
results/final-system/upstream-voters/ds13/ 保存了 7 个 voter 的 dev / test 输出。保留它们不是为了让人手动拼装提交,而是为了做到两件事:
- 让最终 DS13 ensemble 可追溯。
- 让后续研究者能直接看到每个 voter 的分数文件,从而复算 stacking、阈值与误差来源。
一句话区分两类“权重”
- 正式最终系统权重:看
results/final-system/ds13/ensemble_meta.json和configs/ensemble_config.json。 - 探索期硬投票默认值:看
src/enhanced_replica/voter_registry.py,只属于 E04 / E06 研究路线。