Download docs/USAGE.zh.md from Duoia/duotactic: direct link, hf CLI and curl.
- Browser
- Download file 10.3 kB
-
https://huggingface.co/Duoia/duotactic/resolve/main/docs/USAGE.zh.md
- Command line
-
hf download hf://Duoia/duotactic/docs/USAGE.zh.md
-
curl -L -o USAGE.zh.md https://huggingface.co/Duoia/duotactic/resolve/main/docs/USAGE.zh.md
使用说明(中文)
本包是 DuoTactic —— 一个 Lean 4 证明搜索 harness —— 连同它可选的候选生成器:39.58 M 参数的
tactic 模型(leanoar-schemec-40m)。
- 跑 harness(第 3 节起)需要 Lean
4.35.0-rc2与带预编译.lake缓存的 mathlib4(约 10 GB)。 miniF2Ftest32.8% /valid34.8% 就是它跑出来的:每题 45 s,每条被接受的证明都经内核重编译。 - 加载/采样模型(第 0–2 节)不需要 Lean。注意
SchemeC不是标准transformers模型:它定义在code/leanoar/model.py,权重是普通的lit_model.pth/model.safetensors,每次调用只产一条 Lean tactic,没有AutoModelForCausalLM.from_pretrained这种入口。下面所有命令都可以在包根目录 直接复制运行。
duotactic/
├── code/eval_minif2f.py DuoTactic 本体:端到端搜索 harness
├── code/leanoar/ 搜索 + 批量验证器 + 40M 模型
├── checkpoints/e6/ 模型权重(dev top-1 最高)
├── checkpoints/stage3-e3/ 模型权重,端到端最佳变体(同样通过率,快 16%)
├── data/dev/ dev 协议数组(1024 行)
├── data/minif2f/ miniF2F valid/test 题目 + .lean 文件
├── data/whitelist/ 搜索用首 token 白名单的种子文件
├── examples/dev_sample.jsonl 16 条真实 dev 状态 + mathlib 真实用过的 tactic
├── config.json metrics.json tokenizer_v1.json special_tokens_v1.json SHA256SUMS
└── README.md README.zh.md docs/USAGE.md docs/USAGE.zh.md
0. 安装与验证
pip install -r code/requirements.txt # torch>=2.4, tokenizers>=0.19, numpy>=1.26, safetensors>=0.4
python -c "import torch; print(torch.__version__, torch.cuda.is_available())"
python code/verify_package.py # 完整校验,1024 行(GPU 约 1 分钟)
python code/verify_package.py --quick # 128 行,CPU 也能跑
verify_package.py 打印四段,最后给出 PASS / FAIL:
- 参数数量——从
config.json重建SchemeC,两个变体都必须是 39,582,595; - dev 协议——在包内 1024 行上复算 top-1/top-5/CE 并与
metrics.json对比(容差 5e-4)。 这一步让公开数字是可审计的; - 推理连通性——拿包内示例状态跑一遍采样(同时显示模型首选首 token 是否与 mathlib 一致; 不一致是正常的,不影响判定);
- 校验和——逐文件对照
SHA256SUMS。
只有 1、2、4 全过才返回 0。只有权重时可用 --skip-sums。
1. 独立推理(不需要 Lean)
python code/generate.py # 包内真实 dev 样本 #0
python code/generate.py --example 3 --k 8 # 另一条真实 dev 状态
python code/generate.py --state-file state.txt # 你自己的状态(格式见下)
python code/generate.py --ckpt checkpoints/stage3-e3 # 换变体
状态就是 Lean 打印目标时的那段文本——先是假设,然后 ⊢ 目标:
n m : ℕ
h : n < m
⊢ n ≤ m
可以在证明里用 trace_state 拿到,或从 unsolved goals 报错里抠出来。在自己的代码里调用:
import json, os, sys, torch
sys.path.insert(0, 'code')
from common import load_model, load_tokenizer, encode_state, specials, whitelist
from generate import propose
net, cfg, device = load_model('checkpoints/e6') # 或 'checkpoints/stage3-e3'
tok, wl = load_tokenizer(), whitelist()
for tactic, avg_logprob in propose(net, tok, wl, state, k=16, device=device):
... # 交给 Lean 验证
四条必须遵守的规则:
- 首个 token 必须限制在
first_token_whitelist.json(64 个 id,覆盖训练集 97.6% 的首 token)。propose()已经做了这件事;不做的话多数候选会以无意义 token 开头,编译通过率会崩。 - 一条候选 = 一条 tactic。模型用双空格分隔它想表达的两步;被截断的 tactic 可能以悬挂连接词结尾,
propose()两种都会切掉。 - 截断规则:超过
ctx − 4 − max_new_tokens个 token 的状态,会保留头部 60% + 尾部 40% (⊢ 目标在最后)。总输入绝不能超过context_length。 - 只有 Lean 内核能判对错。请多要候选 + 逐个验证,不要相信任何单条输出。整条 tactic 的精确匹配率是 0/200,而且「通过编译(valid)」也不等于「证明成立」。
2. 复算 dev 指标
python code/eval_dev.py --all --compare # 两个变体 × 1024 行,并与 metrics.json 对比
python code/eval_dev.py --ckpt checkpoints/e6 --rows 256
预期(容差 5e-4):
| 变体 | top-1 | top-5 | CE |
|---|---|---|---|
checkpoints/e6 |
0.3076 | 0.7090 | 2.5494 |
checkpoints/stage3-e3 |
0.2891 | 0.7246 | 2.4971 |
协议:取 data/dev/dev_ids.npy 中第二个 token 为 <|FORWARD|> 的前 1024 行,读 mask_start − 1
位置的 logits,对 mask_start 处的 token 打分。不要拿它跟训练器打印的 dev 数字比——后者按长度
分桶重排过,不是同一批样本。
3. miniF2F 端到端搜索(需要 Lean + mathlib)
3.1 前置条件
- Lean 4.35.0-rc2 工具链(例如
elan toolchain install leanprover/lean4:v4.35.0-rc2)。 注意这是 release candidate;换 Lean 版本后 mathlib 的展开方式与状态文本都会变。 - 带预编译
.lake缓存的 mathlib4 检出(本项目用 2026-09 的快照;发布包里没有钉死 commit, 所以换 revision 时状态文本可能有轻微漂移)。在检出目录里执行lake exe cache get拿 olean 缓存—— 本地全量编译要数小时,缓存只要几分钟、约 7 GB。 - 用
--lean-parallel 6时建议 ≥16 GB 内存(每个lean --json进程都要加载 mathlib; 实测单候选 0.4 s、6 路并行后 0.034 s/候选)。
export LEANOAR_LEAN_BIN=/path/to/lean-4.35.0-rc2-linux/bin/lean
export LEANOAR_MATHLIB=/path/to/mathlib4
$LEANOAR_LEAN_BIN --version # 自检
3.2 复现公开成绩的那条命令
python code/eval_minif2f.py --split valid --n 89 --start 0 \
--k 16 --beam 4 --depth 6 --budget 45 --round-budget 30 \
--force --force-set v2 --force-depth 99 --lean-parallel 6 \
--ckpt checkpoints/stage3-e3 --tag mine
预期:**30/89 = 33.7%,RTX 4060 Laptop 上约 52 分钟(换成 e6 变体也是同样 30 题,约 60 分钟)。
全量 valid 已用这份完全相同的配置跑完:85/244 = 34.8%**,约 2.3 小时(分段 33.7% / 40.4% / 28.8%;
85 条解出里 78 条只有一条 tactic)。想再快就动两处:每次 lean --json 调用的固定成本约 6.6 s
的 import Mathlib(而每条候选只要约 0.03 s),所以墙钟全花在并行度和导入裁剪上。
各参数的含义——成绩其实来自这里:
| 参数 | 含义 |
|---|---|
--k 16 |
每个状态提 16 条候选(白名单内 top-16 首 token + 贪心续写) |
--beam 4 |
每轮扩展 4 个开放状态 |
--depth 6 |
证明长度上限(以 tactic 计)。实测:30 条解出里有 25 条是 depth 1 |
--budget 45 |
每题墙钟预算 45 秒;--round-budget 30 限制单轮 |
--force --force-set v2 |
在每一层注入导出的自动化表(rfl、ring、simp_all、omega、…、simp_all ; ring、gcongr)。这是最大的杠杆:带它前 89 题是 30/89;不带它的全量 244 题只有 8/244 |
--lean-parallel 6 |
6 路并发验证候选(纯工程收益:墙钟 2.07×) |
--narrow-imports |
每题把全量 Mathlib 导入换成 #min_imports + Mathlib.Tactic(实测每次 lean --json 从 3.41 s 降到 1.74 s)。命中「未知标识符/tactic」的候选会自动用全量导入重验,所以窄导入不可能丢证明(已验:85/85 条已验证证明仍可编译) |
--no-model |
对照开关:只验证注入表、不提模型候选。在 valid 前 10 题上它与带模型的结果完全一致(2/10、同题、同证明项),而墙钟减半 |
引用任何通过率之前,请先读 README.zh.md 的「这个成绩是怎么来的」:这些是系统成绩
(注入的自动化表 + 搜索 + 内核验证),随包模型的贡献是 0 条。
3.3 看结果与续跑
结果按行追加到 reports/search_eval_valid_mine.jsonl(每个题目一个 JSON:solved、depth、
seconds、verified、proof、confirmed、reason),同时实时打印累计进度与 ETA。因为是追加写入,
中断后用 --start <已写入行数> 续跑即可,或者直接重跑同一条命令。
3.4 疑难排查
- 某题报
initial-state-failed:它的陈述在你的 mathlib revision 上根本编译不过。有 2 道 miniF2F 题对所有人都不通过(mathd_numbertheory_711、imosl_2007_algebra_p6)。 - 报
No such file or directory: .../bin/lean:设LEANOAR_LEAN_BIN。 - Lean 报缺 olean /
unknown module prefix 'Mathlib':把LEANOAR_MATHLIB指向已编译 (.lake/build/lib/lean与.lake/packages/*齐备)的检出目录,验证器会据此拼LEAN_PATH。 verified数特别低:确认首 token 白名单生效、切词器用的是tokenizer_v1.json。- 旧版本在超长状态上会让上下文溢出 1 个 token;本包内的
search.py已按ctx − 4 − max_new_tokens计算预算并在ctx处硬停。如果你改采样器,请保持这个不变式。
4. 扩展
- 换自己的权重:把
lit_model.pth(和model.safetensors)放进一个目录,给generate.py/eval_dev.py/eval_minif2f.py传--ckpt <目录>。config.json必须与架构一致; 词表与 ctx 是固定的。 - 往
code/eval_minif2f.py的FORCE_SETS里加自动化 tactic——本项目所有实测收益几乎都来自这张表 与搜索/验证器侧,而不是模型。 - Value 头虽然随包发出但不可用(AUC 0.5201,低于策略自身置信度)。不要拿它做重排。
code/leanoar/data.py只是因为搜索代码要用里面的load_specials才包含进来;训练流水线不在本包内。