diag: H 段(老师 oracle 走 rollout / 前缀消融 / 子目标越过顶点规则 / 分轴与分类别指标);训练:EMA、选模不落在 p_neq 预热、闭环分数选模、24000 步余弦、p_neq 0.5 + p_edge 0.1、子目标头切断抄输入、前缀/dq 增广;仿真:last 记真正提交的候选、碰撞与到达按每题时限、回放门禁读 pass+指纹并走 rollout;数据:动作标签按 1.25·STEP 归一化(act_scale 随 meta/ckpt/ONNX 传递,旧模型 1.0)、收回亏空结转、DAgger 带 qPrev 与起步速度、打包签名变更自动重打;ik-policy.js 同步(actScale、子目标规则、DLS 时清 lastPlan);本机执行清单与 README 更新
This commit is contained in:
@@ -5,7 +5,9 @@
|
||||
- 撞了的题:首次碰撞前 0.2 s 的状态(策略"快要撞上"的地方,最有用);
|
||||
- 另取一个 [0.3 s, 首撞前或结束] 内均匀随机时刻的状态(偏离老师的一般状态)。
|
||||
起点必须无碰且间隙 > MIN_GAP_MM(老师从碰撞态出发规划不出来,与 build_dataset 的增广接受同一地板),且离目标 > 5 mm(否则 DLS 接管,不需要老师)。
|
||||
输出 tasks_XX.jsonl(按 --parts 均分,供 gen_dataset.cjs --tasks 并行),每行 {q0, T, R, cat, src}。
|
||||
输出 tasks_XX.jsonl(按 --parts 均分,供 gen_dataset.cjs --tasks 并行),每行 {q0, qPrev, T, R, cat, src}。
|
||||
2026-10-19(审查 F7 / C10):同时记录策略在该时刻的上一帧 qPrev;老师重规划的时间律从当前速度(v0)起步,
|
||||
t=0 样本的 dq 特征用真实上一帧——原来一律按静止起步标注,DAgger 样本不是策略真正到过的 (q, dq) 状态。
|
||||
为什么需要:纯行为克隆在闭环里会偏出老师分布(首次 21850 步闭环到达 0%),原方案指望 APG/挖错修,但它们没法从 0% 起步。
|
||||
老师只用于训练标注,部署仍然无老师。"""
|
||||
import argparse, json, os, random
|
||||
@@ -30,9 +32,9 @@ def main():
|
||||
gap_min = float(os.environ.get('MIN_GAP_MM') or 3)
|
||||
os.makedirs(a.out, exist_ok=True)
|
||||
kin = Kin(device=a.device)
|
||||
ck = torch.load(a.ckpt, map_location=a.device)
|
||||
from ml.common.ckpt import load_policy # 2026-10-19:EMA 权重 + act_scale
|
||||
model, ck = load_policy(a.ckpt, a.device)
|
||||
assert ck.get('fp') in (None, kin.fp), '碰撞模型指纹与 checkpoint 不符'
|
||||
model = build(ck['cfg']).to(a.device); model.load_state_dict(ck['model']); model.eval()
|
||||
pool = [t for t in load_tasks(a.samples[:1]) if t['split'] == 'train' and t.get('cat') not in ('D',)]
|
||||
rng = random.Random(a.seed); rng.shuffle(pool); tasks = pool[:a.n]
|
||||
out, stat = [], {'tasks': len(tasks), 'collided': 0, 'states': 0, 'rej_gap': 0, 'rej_near': 0}
|
||||
@@ -61,10 +63,10 @@ def main():
|
||||
if c - 1 > lo: cand.append(rng.randint(lo, c - 1))
|
||||
for k in cand:
|
||||
if g[b, k] <= gap_min: stat['rej_gap'] += 1; continue
|
||||
q = tr[b, k:k + 1]
|
||||
q = tr[b, k:k + 1]; qprev = tr[b, max(0, k - 1)]
|
||||
e, oe = goal_err(kin, q, T[b:b + 1], R[b:b + 1])
|
||||
if e.item() < 5 and (not t.get('R') or oe.item() < 5): stat['rej_near'] += 1; continue
|
||||
out.append({'q0': [round(v, 3) for v in q[0].tolist()], 'T': t['T'], 'R': t.get('R'), 'cat': t.get('cat', 'A'),
|
||||
out.append({'q0': [round(v, 3) for v in q[0].tolist()], 'qPrev': [round(v, 3) for v in qprev.tolist()], 'T': t['T'], 'R': t.get('R'), 'cat': t.get('cat', 'A'),
|
||||
'src': {'tid': t['tid'], 'k': k, 'col': bool(hit.numel())}})
|
||||
del tr, g, per
|
||||
if a.device.startswith('cuda'): torch.cuda.empty_cache()
|
||||
|
||||
+7
-3
@@ -8,6 +8,9 @@
|
||||
# 最终模型路径写进 ml/runs/<tag>_dagger.ckpt(m5 读它)。
|
||||
# 断点续跑:采集以 collect.json 为完成标记;老师 shard 先写 .part 再改名、未写完的从断点续写;打包以 .tasks.jsonl 为完成标记;
|
||||
# 微调用该轮 last.pt 续训;整轮完成打 ml/runs/<tag>_dag<k>/done。
|
||||
# 2026-10-19(审查 review_model_train P0-2):每轮起点 = python -m ml.common.ckpt pick <目录>:best.pt 的闭环 success > 0 才用它,
|
||||
# 否则用 last.pt(success 全 0 时 best.pt 只由开环误差决定、可能落在 p_neq 预热期);train.py --init 载入 EMA 权重,
|
||||
# 只有起点已走过自己的 p_neq 预热时才不再预热。微调的 val 只取主数据(DAgger 样本全部算 train)。
|
||||
set -e -o pipefail
|
||||
cd "$(dirname "$0")/../.."
|
||||
PY=${PYTHON:-python}
|
||||
@@ -19,7 +22,7 @@ SAMPLES="ml/data/samples"
|
||||
for ((r=1; r<=R; r++)); do
|
||||
D=ml/data/dag_${TAG}_r$r; SD=ml/data/samples_dag_${TAG}_r$r; OUT=ml/runs/${TAG}_dag$r
|
||||
SAMPLES="$SAMPLES $SD"
|
||||
if [ -f $OUT/done ]; then echo "[dagger] 第 $r 轮已完成,跳过"; CK=$OUT/best.pt; continue; fi
|
||||
if [ -f $OUT/done ]; then echo "[dagger] 第 $r 轮已完成,跳过"; CK=$($PY -m ml.common.ckpt pick $OUT); continue; fi
|
||||
if [ -f $D/collect.json ]; then echo "[dagger] 第 $r 轮起点已采集,跳过"
|
||||
else echo "[dagger] 第 $r 轮:用 $CK 闭环采起点($N 题)"; $PY -m ml.dagger.collect --ckpt $CK --samples ml/data/samples --n $N --seed $r --parts $P --out $D; fi
|
||||
cat $D/collect.json
|
||||
@@ -49,13 +52,14 @@ for ((r=1; r<=R; r++)); do
|
||||
done
|
||||
fi
|
||||
mkdir -p $SD
|
||||
todo=(); for sh in $D/shard_dag_*.jsonl; do [ -e "$sh" ] || continue; b=$(basename $sh .jsonl); [ -f $SD/$b.tasks.jsonl ] || todo+=("$sh"); done
|
||||
SIG=$(node ml/prep/build_dataset.cjs --sig) # 2026-10-19:与主数据同一套打包签名,参数变了重打(见 run_prep.sh)
|
||||
todo=(); for sh in $D/shard_dag_*.jsonl; do [ -e "$sh" ] || continue; b=$(basename $sh .jsonl); grep -qF "\"sig\":\"$SIG\"" $SD/$b.meta.json 2>/dev/null && [ -f $SD/$b.tasks.jsonl ] || todo+=("$sh"); done
|
||||
[ ${#todo[@]} = 0 ] || printf '%s\n' "${todo[@]}" | xargs -P "$P" -I{} node ml/prep/build_dataset.cjs {} $SD
|
||||
$PY -m ml.data --index $SD | tail -n 3
|
||||
res=""; [ -f $OUT/last.pt ] && res="--resume $OUT/last.pt"
|
||||
echo "[dagger] 第 $r 轮:微调 $STEPS 步(样本:$SAMPLES)"
|
||||
$PY -m ml.train --samples $SAMPLES --out $OUT --config $CFGF --init $CK --steps $STEPS --lr $LR --warmup 500 $res
|
||||
touch $OUT/done; CK=$OUT/best.pt
|
||||
touch $OUT/done; CK=$($PY -m ml.common.ckpt pick $OUT)
|
||||
done
|
||||
echo "$CK" > ml/runs/${TAG}_dagger.ckpt
|
||||
echo "[dagger] 完成:后续阶段使用 $CK"
|
||||
|
||||
Reference in New Issue
Block a user