Composable Evidence States Research
第一阶段 MVP:在全合成符号世界中生成图像事实与文本事实/规则,训练 Evidence Extractor 将两种模态映射到可比较的 latent space。Composer 暂不在本阶段实现。
数据方案 A:全合成符号世界
每张图包含两个带颜色和形状的对象以及一条空间关系。manifest 保存完整结构化标注, 同时生成两类文本状态:
FACT:例如obj1 is red,结构为[FACT, subject, predicate, object, -, -]。RULE:例如Every red object belongs to class alpha,结构为[RULE, variable, antecedent predicate, antecedent object, consequent predicate, consequent object]。NULL:表示未被事实或规则占用的 slot。
FACT 与 RULE 共享 subject、predicate、object 分类头,但类型头明确区分二者;RULE 还有独立的 consequent predicate/object 训练目标。视觉分支只产生 FACT,文本分支同时 产生 FACT 和 RULE。因此实现不会把“事实”和“规则”当成完全相同的对象。
test_ood 使用训练集中明确排除的颜色–形状组合,并同时改变规则映射,用来检查组合泛化。
统一 latent space 的两个实验方案
方案 1(当前默认):共享分类头 + 跨模态对比学习
视觉和文本 extractor 使用相同的标签空间与同构分类头。Hungarian set matching 处理无序 slots;对比损失只把语义完全相同的视觉 FACT 与文本 FACT 拉近。RULE 保持为文本独有的 有类型状态,不参与错误的视觉规则对齐。
配置:configs/mvp.yaml,其中 prototype.enabled: false。
方案 2(已实现、默认关闭):Canonical Fact Prototype
CanonicalFactPrototype 将类型、主语、前件谓词/宾语以及后件谓词/宾语的可学习 embedding
组合成规范原型,并用 cosine loss 把 matched latent state 拉向该原型。类型 embedding 与
RULE 后件字段确保 FACT 和 RULE 的原型结构不同。
使用完整的 configs/prototype.yaml 即可单独训练和比较:
uv run python train_extractor.py --config configs/prototype.yaml --backbone tiny
运行
uv sync --extra dev
uv run python -m data.build_splits --config configs/mvp.yaml --small
uv run python train_extractor.py --config configs/mvp.yaml --backbone tiny --epochs 2
uv run python -m eval.evaluate_slots --config configs/mvp.yaml \
--checkpoint artifacts/tiny/best.pt --backbone tiny
uv run pytest
正式 GPU 实验可把 --small 去掉并改用冻结 CLIP:
uv sync --extra dev --extra hf
uv run python -m data.build_splits --config configs/mvp.yaml
uv run python train_extractor.py --config configs/mvp.yaml --backbone clip
正式 2B 级训练
正式实验使用 google/siglip2-giant-opt-patch16-384:约 2B 总参数、384 分辨率的
原生图文双塔。backbone 使用 BF16 并冻结,四层 512 维 Evidence Extractor 参与训练。
configs/siglip2_giant.yaml 定义 30,000/3,000/3,000/3,000 数据划分与 10 epochs。
Gitea 的 Formal GPU training workflow 会:
- 校验预先放在
/root/autodl-tmp/ces-models/siglip2-giant的固定版本模型; - 在
/root/autodl-tmp/ces-data/synthetic-v1复用完整数据集; - 每个 epoch 保存可恢复的
last.pt,并按验证集保存best.pt; - 将运行配置、硬件、分项 loss、每轮耗时、所有验证指标和最终 benchmark 放在
Actions 的
Detailsstep; - 将结果持久化到
/root/autodl-tmp/ces-artifacts/siglip2-giant; - 最后用六项研究门槛决定 workflow 是否通过。
为避免付费 GPU 等待 7.53 GB 权重下载,先在网络更稳定的无 GPU 服务器上执行:
python3 -m venv ces-model-download
source ces-model-download/bin/activate
python -m pip install -U "huggingface_hub[hf_xet]"
HF_ENDPOINT=https://hf-mirror.com hf download \
google/siglip2-giant-opt-patch16-384 \
--revision a713301b217d38485fb2204c808367d10bc3cc40 \
--local-dir /data/ces-models/siglip2-giant
du -sh /data/ces-models/siglip2-giant
然后从该服务器断点续传到 AutoDL(替换 SSH 主机和端口):
ssh -p <AUTODL_SSH_PORT> root@<AUTODL_SSH_HOST> \
'mkdir -p /root/autodl-tmp/ces-models/siglip2-giant'
rsync -ahP --partial --append-verify \
-e 'ssh -p <AUTODL_SSH_PORT>' \
/data/ces-models/siglip2-giant/ \
root@<AUTODL_SSH_HOST>:/root/autodl-tmp/ces-models/siglip2-giant/
如果两台服务器不能直连,使用阿里云 OSS 作为中转;目标目录保持不变。workflow 只做完整文件校验,不再从 Hugging Face 下载,因此模型传好后再手动触发正式训练。
手动等价命令为:
python -m data.build_splits --config configs/siglip2_giant.yaml --reuse-existing
python train_extractor.py --config configs/siglip2_giant.yaml --backbone siglip2
python -m eval.benchmark_extractor \
--config configs/siglip2_giant.yaml \
--checkpoint /root/autodl-tmp/ces-artifacts/siglip2-giant/best.pt \
--backbone siglip2 \
--output /root/autodl-tmp/ces-artifacts/siglip2-giant/benchmark.json \
--enforce-gates
每次训练后的独立验收
以下命令运行统一 benchmark,写出 JSON,并在任一指标未达标时返回非零退出码:
uv run python -m eval.benchmark_extractor \
--config configs/mvp.yaml \
--checkpoint artifacts/clip/best.pt \
--backbone clip \
--output artifacts/clip/benchmark.json \
--enforce-gates
| 指标 | 门槛 | 定义 |
|---|---|---|
| Text fact/rule F1 | 0.98 | IID 文本中 typed FACT 与 typed RULE 的六字段 exact-match micro F1 |
| Visual fact F1 | 0.90 | IID 图像 FACT 的四个有效字段 exact-match micro F1 |
| Cross-modal Recall@1 | 0.80 | 文本 FACT 检索全部视觉 FACT,最近邻标签完全相同 |
| Hard-negative Recall@1 | 0.75 | 候选仅含正确项与恰好错一个基础字段的视觉 FACT |
| OOD fact F1 | 0.80 | held-out 颜色–形状组合上的视觉 FACT exact-match F1 |
| NULL slot accuracy | 0.95 | permutation matching 后,应为 NULL 的空槽中预测为 NULL 的比例 |
CI 的单 epoch smoke run 会执行 benchmark 来验证整条评测管线,但不会使用
--enforce-gates,因为 smoke 模型并不代表正式实验是否达标。正式训练完成后使用上述强制命令。
AutoDL Pro 临时 Runner
项目代码始终只在本地 Git 工作区和 Gitea 中维护。阿里云服务器是持久化的算力控制器与 模型/产物中转站,AutoDL Pro 实例只是临时 Gitea Actions 执行节点。控制器不会把项目源码 复制到任何服务器;ephemeral runner 接受任务后,workflow 才从 Gitea checkout 指定 commit。
ops/autodl_pro_controller.py 实现以下生命周期:
- 调用 AutoDL Pro API 创建一张
PRO6000-96G; - 等待 SSH 就绪,将模型数据和经过 SHA-256 固定的
act_runner传入实例; - 注册只带
ces-gpu-formal:host专用标签的一次性 runner; - 可选地通过 Gitea API dispatch
gpu-train.yaml,也可保留为手动触发; - 等待 runner 完成一项任务并退出,将 checkpoint、benchmark 和 runner 日志回传阿里云;
- 无论成功或失败都调用 API 关机;默认不释放实例,避免未经确认删除系统盘。
先把示例配置复制到阿里云控制器的受限目录并填写私有镜像 UUID:
install -d -m 700 /root/.config/ces-controller/secrets
install -m 600 ops/autodl-pro.example.json /root/.config/ces-controller/config.json
AutoDL 开发者 Token、Gitea runner 注册 Token,以及可选的 Gitea API Token 必须分别放在
配置指定的 root-only 文件中,不能写进配置、仓库、命令行或 AutoDL start_command。控制器
还需要一把专用于 AutoDL 的 SSH 私钥;将其公钥预先添加到 AutoDL 账号的 SSH 公钥设置。
首次运行先检查不会产生费用的执行计划:
python3 ops/autodl_pro_controller.py plan \
--config /root/.config/ces-controller/config.json
确认镜像、GPU、系统盘扩容和是否自动 dispatch 后,再在 tmux 或 systemd 中运行付费流程:
python3 ops/autodl_pro_controller.py run \
--config /root/.config/ces-controller/config.json \
--confirm-create
run 会真实创建按量计费实例。release_after_run 默认是 false;只有确认回传产物完整并愿意
删除该 Pro 实例时才应改为 true。控制器只负责调度与数据搬运,训练步骤仍完全由
.gitea/workflows/gpu-train.yaml 定义。
正式 Runner 故意不注册 ubuntu-latest、ces-ci 或通用 gpu 标签。ephemeral runner 只会
执行一个任务;使用通用标签可能让它先领取普通 CI 或 smoke job,随后退出,导致正式训练继续
排队。普通测试 Runner 与临时正式训练 Runner 因而使用互不重叠的标签。