【免费下载链接】deepopen
非自回归System 1决策引擎,专为结构化类型决策场景设计 DeepOpen Multilingual, non-autoregressive System 1 decision engine.
本文基于 banking77/RESULTS_V2.md 展开,完整记录 DeepOpen 项目在 Banking77 77 类银行意图分类任务上的一次模型结构改动实验:以 Laya 编码器 + ModernBERT 分类头为起点,叠加一个可训练的余弦类别原型残差分支,并给出验证集消融、官方测试集对比、McNemar 统计检验与可复现命令。读者读完后既能理解"原型分支 + 残差融合 + 辅助损失"这一组合结构的完整设计,也能掌握如何通过控制组对照严谨归因结构收益,并能按本文命令在服务器上复现或部署该模型。
一、实验结论速览:一次记录在案的"未成功"结构改动
本轮实验的核心目标是验证"在分类头上叠加可训练余弦原型分支"能否带来超过 94% 的官方测试集准确率。结论是明确的负结果:
- 按验证集选中semantic变体,官方测试集准确率93.70%,macro-F193.71%,未达到 94% 的阶段目标;
- 同轮数普通训练对照(control)达到 94.09%,超过了 94%,但该收益来自额外训练本身,不能归因于新增的原型结构;
- 相对旧分类头的 93.80%,本轮没有提高测试准确率;验证集上的提升未能转化为测试集提升,因此应记录为未成功的结构改动实验,旧模型和推荐链接均保留原状。
这条记录的价值在于它是一份严谨的"负结果实验报告":结构改动有明确消融、有对照归因、有统计检验、有完整复现命令,方法论上比一份"只报最好成绩"的文档更值得借鉴。
二、结构改动细节:余弦原型分支如何叠加到分类头
2.1 改动起点
以Laya 编码器 + Transformers ModernBERT 分类头为起点(即 banking77/classifier.py 中训练的固定 77 类分类器)。注意:这是固定的 77 类分类接口,不是原生 Laya 的可变候选决策头(详见 banking77/README.md 对架构差异的说明)。
- 原分类头保留其原有池化方式(
cls或均值池化,按 backbone 配置决定); - 新增的原型分支利用全部非填充 token 的均值表示(masked mean pooling);
- 两条路径共享同一个 Laya 编码器,推理时仍只运行一个编码器,不增加第二套编码器。
2.2 融合公式
融合 logits 的数学形式为:
logits = original_logits + sigmoid(gate) * exp(scale) * cosine(mean_hidden, prototypes)其中:
| 符号 | 含义 | 初始化与约束(源码确认) |
|---|---|---|
gate | 残差融合门控系数 | 初始化为-1,经sigmoid后取值 (0, 1),随训练更新(prototype_model.py) |
scale | 原型 logits 的温度缩放 | 以log(20.)初始化,前向时先clamp(0, 4.6)再exp(),即缩放系数约束在[1, e^4.6]区间 |
prototypes | 可训练类别原型矩阵 | 形状(77, hidden_size),nn.Parameter,从锚点表示初始化 |
mean_hidden | 全部非填充 token 的均值表示 | sum(h * mask) / sum(mask),推理与训练一致 |
原型、融合系数(gate/scale)、温度和编码器共同训练;新增可训练参数78,850 个(77 × 1024 的原型矩阵 78,848 个 + gate 和 scale 各 1 个,与 ModernBERT-large 的 hidden_size=1024 吻合),未增加第二套编码器。
2.3 两种原型初始化:prototype 与 semantic
训练脚本 prototype_train.py 提供三个变体:
- control:仅继续普通分类训练,关闭原型分支和辅助损失,用于区分"新增结构的收益"和"额外训练的收益";
- prototype:原型从训练样本各类别的平均表示(类中心)初始化;
- semantic:在 prototype 基础上,额外混入20% 类别名称表示,即
anchors = normalize(0.8 * centroid + 0.2 * semantic),随后归一化。
semantic 变体的类别名称文本模板为"A banking customer asks about " + s.replace('_',' ') + "."(源码确认),将类别语义信息注入原型初始值。
2.4 训练目标
训练目标为融合 logits 的交叉熵,叠加两项辅助损失(系数在 prototype_model.py 的prototype_config.json中持久化):
L = CE(logits, y) + 0.2 * CE(prototype_logits, y) + 0.01 * anchor_loss其中anchor_loss = (1 - cosine_similarity(prototypes, anchors)).mean(),即约束可训练原型不要偏离其初始化锚点太远。
2.5 架构图
flowchart LR A[输入文本] --> B[Laya 编码器] B --> C[均值池化] C --> D[原非线性分类头] C --> E[余弦原型分类分支] P[可训练类别原型] --> E D --> F[学习权重后融合 logits] E --> F F --> G[77 类预测]2.6 源码级实现要点
核心实现位于 banking77/prototype_model.py 的PrototypeClassifier:
- 前向计算时先取
last_hidden_state,用 attention mask 做加权均值得到mean,再按classifier_pooling配置决定原分类头的池化输入; - 原分类头 logits(
ce_logits)与原型 logits(scale * cosine(mean, prototypes))通过gate.sigmoid()加权求和; control变体直接返回ce_logits,proto=None,无辅助损失,行为与普通分类器完全一致;save_pretrained将 backbone 存为标准 Transformers 子目录,额外分支单独存为prototype.safetensors,并写入prototype_config.json(记录 variant、aux_ce、anchor_regularization);from_pretrained用AutoModelForSequenceClassification.from_pretrained(path/backbone, attn_implementation="sdpa")重建 backbone,加载原型分支权重时严格断言额外参数字典与模型状态完全一致。
这正是文档中"推理仍只运行一个编码器"的实现基础:额外分支只是编码器之上的轻量计算。
三、验证集消融:三个分支的对比
3.1 实验协议
三组实验使用同一个仅见过 8,502 条训练样本的初始 checkpoint(即classifier_runs/encoder_lr2e5/best),验证集 1,501 条。训练脚本对非 full-train 模式有硬性断言:起点必须为该固定 checkpoint,防止从全量训练模型出发污染验证结论(源码确认)。
统一超参数如下:
| 超参数 | 设置 |
|---|---|
| 最大追加 epoch | 4 |
| 随机种子 | seed=42 |
| 编码器学习率 | 5e-6 |
| 头部学习率 | 5e-5(编码器的 10 倍) |
| 实际 batch | 32(micro-batch 16,累积 2 次) |
| weight decay | 0.01(仅矩阵参数,偏置与归一化参数为 0) |
| warmup | 0.1 |
| 优化器 / 调度 | AdamW + 线性学习率衰减 |
| 精度 / 硬件 | BF16 自动混合精度,NVIDIA L20 |
| 选模规则 | 按验证 accuracy 选模型及 epoch,同分看 macro-F1 |
3.2 消融结果
| 结构 | 验证 accuracy | 验证 macro-F1 | 追加 epoch |
|---|---|---|---|
| 原分类头,不追加训练 | 91.27% | 91.22% | 0 |
| control | 91.61% | 91.62% | 2 |
| prototype | 91.87% | 91.76% | 2 |
| semantic | 92.14% | 92.02% | 4 |
参考值:原生 Laya 的历史最佳验证 accuracy 为 91.61%(不同结构和训练设置,单独列为参考,不可直接对比)。
从消融看,semantic 在验证集上最优,且控制组本身也有提升(91.27% → 91.61%),说明"额外训练"本身就在起作用——这正是后续设置同轮数普通训练对照的原因。按验证集规则选中 semantic。
四、官方测试结果与统计检验
4.1 测试集对比
完整测试集 3,080 条(每类 40 条)结果:
| 模型 | Accuracy | Macro-F1 |
|---|---|---|
| 之前的原生 Laya 微调 | 93.44% | 93.42% |
| 之前的 Laya 编码器 + 普通分类头 | 93.80% | 93.81% |
| 同轮数普通训练对照 | 94.09% | 94.09% |
| 本轮 semantic | 93.70% | 93.71% |
4.2 配对统计检验(McNemar)
- 相对旧分类头:纠正 15 条,新增错误 18 条,正确预测数净变化-3条;配对精确 McNemar 检验p=0.7283,远未达到显著性水平;
- 相对同轮数普通训练对照:纠正 11 条,新增错误 23 条,净变化-12条;配对精确 McNemarp=0.0576,未达到常用的 0.05 显著性门槛,应视为初步证据。
文档明确提醒:McNemar 检验不能替代多随机种子实验,当前结论仅基于一个训练种子。
4.3 实验边界(诚实声明)
- 选定方案后,从原有全量训练 7 epoch 的分类器起点,使用全部 10,003 条训练样本重建原型,并追加选定 epoch 数量;测试集为完整 3,080 条;
- 原有测试分数此前已经查看,因此本轮属于探索性后续实验,不能称作"从未接触测试结果的确认实验";
- 本轮未利用测试样本、标签或错误构建原型;模型选择在测试评估前写入
selection_before_test.json,新测试结果不用于开启进一步搜索; - 重新加载 checkpoint 的逐条预测一致,accuracy/F1 独立重算通过;
- 同轮数普通训练对照在新测试评估前预先规定(同起点、同样追加 4 个 epoch、相同学习率与 batch,仅关闭原型分支和相应辅助损失),用于归因分析,不改变验证集选定的主模型;
- 当前只有一个训练种子,尚不能证明跨种子稳定性,也没有外部榜单提交。
五、"94.09% 从何而来":与榜单分数的关系
文档在此处做了非常严格的边界划分:
- 94.09% 是官方公开 test split 上的本地结果,不是已经认证的外部榜单成绩,它来自预先指定的普通训练对照,原型改动的验证选定主模型仍为 93.70%;
- 普通训练对照已用标准
AutoModelForSequenceClassification独立加载导出文件复核,3,080 条预测与实验评估逐条一致,见STANDARD_EXPORT_VERIFIED.json; - 复现设置:完整 test split、原标签映射、max_length=128、batch=16、BF16、SDPA,tokenizer 与权重均从同一 checkpoint 加载(与 banking77/deepopen_evaluate.py 的评测口径一致,该脚本还会校验测试数据 SHA256);
- 若目标榜单允许全量监督微调并采用相同测试集与评估规则,该结果具有可复现依据;隐藏测试集、少样本/零样本设置、不同数据版本或推理规则均不能直接套用本分数;
- 具体榜单尚未指定,因此没有宣称榜单等价性;上传模型本身也不等于获得榜单认证。
在原服务器复核标准导出模型:
cd /opt/laya-banking77 CUDA_VISIBLE_DEVICES=0 venv/bin/python verify_standard_export.py六、方法定位:原型分类与余弦间隔的已有工作
类别原型和归一化余弦分类已有明确先例,文档明确引用了两类经典工作:
- Prototypical Networks(原型网络):用类别原型做度量学习的代表性方法;
- CosFace:归一化余弦分类间隔方法。
本轮的定位是:可训练原型 + 残差融合 + 训练期辅助损失的组合实现,没有实现 CosFace 的余弦间隔,也不是其复现实验。因此现阶段适合作为"有结构改动、有消融"的技术报告,论文的新颖性和稳定性仍需进一步验证——文档没有宣称任何论文级新颖性,这一边界在 prototype_model.py 的模块 docstring 中同样有明确声明。
七、复现与部署:文件结构、命令与加载方式
7.1 服务器目录结构
/opt/laya-banking77/ ├── research_v2/ │ ├── full_train_semantic/best/ # 验证集选定的实验 checkpoint │ ├── matched_control/best/backbone # 94%+ 普通训练对照的标准 Transformers checkpoint │ ├── anchors_train.pt / anchors_full.pt # 锚点缓存(含来源与数据指纹校验) │ └── ...(各实验配置、逐轮日志、选择依据、测试预测、权重 SHA256) └── ...所有实验配置、逐轮日志、选择依据、测试预测和权重 SHA256 均保存在research_v2目录;旧模型和结果没有覆盖。可复现包包含本轮代码及旧轮基础包,但不包含大型模型权重。
7.2 复核已保存模型
只读取 checkpoint,写入独立评估目录,不会改动原模型:
CUDA_VISIBLE_DEVICES=0 venv/bin/python prototype_train.py evaluate \ --checkpoint /opt/laya-banking77/research_v2/full_train_semantic/best \ --split test --name user_reproduction该命令会生成research_v2/user_reproduction/test_predictions.json(含 metrics、gold、predicted 和 checkpoint 路径)与test_report.json(分类报告)。evaluate模式还会断言模型的id2label与数据标签表完全一致。
7.3 从旧轮训练起点重跑获选方案
# 验证集协议重跑(起点必须为 encoder_lr2e5/best,脚本硬性断言) CUDA_VISIBLE_DEVICES=0 venv/bin/python prototype_train.py train \ --variant semantic --name rerun_validation --epochs 4 --seed 42 # 全量重跑 semantic(从全量 7 epoch 分类器起点) CUDA_VISIBLE_DEVICES=0 venv/bin/python prototype_train.py train \ --variant semantic --name rerun_full --full-train \ --source /opt/laya-banking77/classifier_runs/encoder_full_train/best \ --epochs 4 --seed 42 # 重跑相同轮数的普通训练对照 CUDA_VISIBLE_DEVICES=0 venv/bin/python prototype_train.py train \ --variant control --name rerun_control --full-train \ --source /opt/laya-banking77/classifier_runs/encoder_full_train/best \ --epochs 4 --seed 427.4 CLI 参数说明(源码确认)
prototype_train.py 支持的参数与默认值:
| 参数 | 取值 / 默认 | 说明 |
|---|---|---|
mode | train/evaluate/smoke | smoke 校验 base logits 一致、原型梯度有限、保存/加载逐位一致 |
--variant | control/prototype/semantic,默认semantic | 结构开关 |
--name | 默认semantic_s42 | 输出目录名(research_v2/<name>) |
--source | 默认classifier_runs/encoder_lr2e5/best | 起点 checkpoint |
--epochs | 默认 4 | 追加训练轮数 |
--seed | 默认 42 | 随机种子 |
--lr | 默认 5e-6 | 编码器学习率,头部为其 10 倍 |
--full-train | 布尔开关 | 使用全部 10,003 条训练样本 |
--checkpoint | 可选 | evaluate 模式指定 checkpoint |
--split | validation/test,默认validation | 评估数据划分 |
训练内部固定:micro-batch=16 累积 2 次得到有效 batch=32、梯度裁剪 1.0、AdamW 分组参数(编码器 lr=5e-6、头部 lr=5e-5,矩阵参数 weight decay=0.01,bias/norm 无衰减)、线性 warmup 0.1、BF16 autocast。每个 epoch 结束记录 loss、耗时、gate与scale的实际收敛值到history.json;验证协议下按 (accuracy, macro-F1) 保存最优 checkpoint 并写入best.json。
7.5 部署方式
初始化模型、训练数据、隔离环境的复现方法见旧轮 banking77/RESULTS.md 与 banking77/README.md。部署时:
- 将 banking77/prototype_model.py 放在 Python 路径中;
- 使用
PrototypeClassifier.from_pretrained(checkpoint)加载; - tokenizer 从
checkpoint/backbone读取; - 该类支持标准 Transformers 编码器和 tokenizer,额外分支单独保存在
prototype.safetensors中(prototype_config.json记录变体与辅助损失系数)。
需要特别注意:普通训练对照(control)部署时不需要自定义原型类,直接用标准AutoModelForSequenceClassification加载matched_control/best/backbone即可;而 semantic 模型必须使用完整best/目录和PrototypeClassifier。
八、从源码看训练细节:锚点构建与数值严谨性
8.1 锚点缓存的构建与复用
训练脚本首次运行时会从声明的训练划分(train或full_train,绝不使用 validation/test)计算锚点:
- 前向得到每个样本的归一化均值表示,按类别累加求类中心,归一化得到
centroid; - 对 77 个类别名称文本(模板见上文)前向,取均值表示归一化得到
semantic; - semantic 变体组合为
normalize(0.8 * centroid + 0.2 * semantic)。
结果缓存到anchors_train.pt/anchors_full.pt,复用前会严格校验缓存的 source checkpoint 与 data SHA256,防止缓存污染。构建前保存 CPU RNG 状态、构建后恢复,确保锚点缓存创建/复用不会改变后续训练顺序。
8.2 数值与复现严谨性
- 前向与评估均在 BF16 autocast 下进行,并断言 logits/loss 全为有限值;
- 冒烟测试(
smoke模式)断言:原型分支启用时 base logits 与原 backbone 输出在容差内一致、原型梯度有限、save/load 后 logits 逐位一致(torch.equal校验 argmax、allclose校验数值); - 实验配置、数据 SHA256、
gate/scale收敛值、选择依据全部落盘,便于事后审计。
九、结论与后续方向
9.1 本轮实验的完整图景
把验证集与测试集放在一起看,结论非常清晰:
- 验证集提升 ≠ 测试集提升:semantic 在验证集以 92.14% 胜出,测试集却只有 93.70%,低于 control 的 94.09% 和旧分类头的 93.80%;
- 对照实验不可省略:同轮数 control 本身就比"不追加训练"的 91.27% 高出 0.34 个百分点,若没有这个对照,很容易把额外训练的收益误归因于新结构;
- 统计检验约束结论:与旧分类头的差异 p=0.7283 无显著性,与 control 的差异 p=0.0576 也仅属初步证据,加上单一训练种子,任何"结构有效"的说法都不成立。
9.2 建议的后续方向(文档与 README 中均为待验证计划)
| 方向 | 建议做法 | 判断标准 |
|---|---|---|
| 多种子稳定性 | 为 7 轮分类器、control、semantic 配对运行至少 3 个种子 | 报告所有种子、均值、标准差和配对差值 |
| 分离额外训练收益 | 固定训练预算,比较连续 11 轮、7+4 分阶段、只降低学习率 | 区分训练时长与调度重启的贡献 |
| 简化原型分支 | 分别关闭语义初始化、辅助 CE、锚点约束,固定其余超参数 | 先比较验证集,再冻结一次测试 |
| 置信度与拒识 | 仅用 validation 拟合温度,另准备 OOS 数据 | 同时报告分类准确率、校准指标和 OOS 指标 |
| 推理成本 | 同机同 batch 比较原生决策结构与普通分类头 | 分别测分词、前向、峰值显存和端到端延迟 |
为避免继续使用同一测试集造成选择偏差,后续实验应先写好候选范围与选择规则再开展实验,有条件时引入独立外部数据验证。
9.3 一份可复用的实验方法论
即使结构改动本身是负结果,本轮实验仍留下了完整的方法论资产:固定划分与数据指纹(banking77/banking77.py)、验证集选模协议、同轮数控制组归因、配对 McNemar 检验、测试前选择落盘(selection_before_test.json)、标准 Transformers 导出复核(STANDARD_EXPORT_VERIFIED.json)以及完整的smoke数值校验。这套流程可以原样迁移到其他结构改动实验——先证明收益可归因,再谈结构创新,这正是本文最值得引用的实践结论。
延伸阅读
- banking77/README.md:主线复现指南(环境准备、7+4 两阶段训练、评测与推理示例)
- banking77/RESULTS.md:旧轮实验记录(原生 Laya 微调与分类头对照)
- banking77/prototype_model.py:PrototypeClassifier 完整实现
- banking77/prototype_train.py:训练、评估、冒烟测试入口
- banking77/classifier.py:基础 77 类分类头训练
- banking77/deepopen_evaluate.py:标准分类器完整 test 评测与数据哈希校验
- banking77/SOURCE_MANIFEST.json:脚本来源与原文件哈希
【免费下载链接】deepopen
非自回归System 1决策引擎,专为结构化类型决策场景设计 DeepOpen Multilingual, non-autoregressive System 1 decision engine.
相关推荐
kohya_ss 测试目录解析:test/ 与 tests/ 的分工、启动器回归测试与手动端到端训练验证工作流
kohya_ss 测试目录解析:test/ 与 tests/ 的分工、启动器回归测试与手动端到端训练验证工作流 导读 本篇文章聚焦 kohya_ss 仓库根目录
AI 应用提示工程人工智能前端告别实验混乱:PaddleHub训练记录与复现全攻略
告别实验混乱:PaddleHub训练记录与复现全攻略 在机器学习项目中,训练记录的混乱和实验结果的不可复现是开发者最头疼的问题之一。PaddleHub作为基于P
人工智能大模型微调模型推理服务将SwiftPlantUML集成进你的Swift项目:Framework API调用完全指南
将SwiftPlantUML集成进你的Swift项目:Framework API调用完全指南 SwiftPlantUML 是一款基于 PlantUML 的命令行
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考