diff --git a/ml/gen/run_parallel.sh b/ml/gen/run_parallel.sh index 59cb8a7..2d2a189 100755 --- a/ml/gen/run_parallel.sh +++ b/ml/gen/run_parallel.sh @@ -31,20 +31,25 @@ while :; do done # 判定按产物而不是 wait 的退出码:2026-10-18 实测 28 个种子跑了 5 小时后全部 wait 报失败, # 但每个 .part 都是完整的 1786 行(node 打了 done、mv 却没执行)——Git Bash 长跑后 wait 的返回码不可靠。 -fail=0 +# 短产物分两种:网页点「停止」把 node 杀掉(.part 是断点,续跑接着写,不是失败)和 node 自己报错。 +# 只有日志尾部有报错特征才算失败;143 让网页显示「已停止」而不是「失败(返回码 6)」(monitor.html:508 同一口径)。 +crashed=0; stopped=0; sn=0 for k in "${!pids[@]}"; do s=${seeds[$k]}; f=ml/data/shard_$(printf %04d $s).jsonl - wait ${pids[$k]} || true + w=0; wait ${pids[$k]} || w=$? # 记下来但不当判据:长跑后 Git Bash 的 wait 返回码不可靠 if [ -f "$f" ]; then continue; fi - if [ -f "$f.part" ]; then - n=$(wc -l < "$f.part") - if [ "$n" -ge "$N" ]; then mv "$f.part" "$f" && echo "[gen] 种子 $s 产物完整($n 行),补改名" && continue; fi + n=0; [ -f "$f.part" ] && n=$(wc -l < "$f.part") + if [ "$n" -ge "$N" ]; then mv "$f.part" "$f" && echo "[gen] 种子 $s 产物完整($n 行),补改名" && continue; fi + if tail -n 4 ml/data/log_$s.txt 2>/dev/null | grep -qE '^(Error|.*Error:|.*SyntaxError|.*heap out of memory|Traceback|.*throw )'; then echo "[gen] 种子 $s 失败:.part 只有 $n/$N 行,最后几行:"; tail -n 5 ml/data/log_$s.txt || true + crashed=1 else - echo "[gen] 种子 $s 失败:没有产物,最后几行:"; tail -n 5 ml/data/log_$s.txt || true + echo "[gen] 种子 $s 已停止:写好 $n/$N 条,断点保留在 $f.part,点「继续训练」从第 $((n + 1)) 条接着写(子进程返回码 $w)" + stopped=1; sn=$((sn + n)) fi - fail=1 done -[ $fail = 0 ] || exit 6 +[ $crashed = 0 ] || exit 6 +# 全被停止时不跑 stats.cjs:分片还没改名,统计口径没变,重算一遍只会让「补量」看起来原地不动 +[ $stopped = 0 ] || { echo "[gen] 本轮是被停止的,没有报错:$stopped 个种子共保住 $sn 条,续跑不重复生成"; exit 143; } node ml/gen/stats.cjs ml/data/shard_*.jsonl > ml/data/stats.json cat ml/data/stats.json diff --git a/ml/pipeline.sh b/ml/pipeline.sh index 93e06b5..418bc25 100755 --- a/ml/pipeline.sh +++ b/ml/pipeline.sh @@ -134,8 +134,10 @@ case $stage in [ "$need" = "0" ] && break echo "样本不足目标 $TARGET_SAMPLES,补生成 $need 条任务(第 $k 次)" per2=$(( (need + NPROC - 1) / NPROC )) - old=$($PY -m ml.pstate get gen target_tasks) # 读不到直接失败(审查 N-13:此前空值会被算成 56 这类数) - $PY -m ml.pstate set gen target_tasks=$(( old + per2 * NPROC )) + # 目标 = 已写完的分片条数 + 本轮要补的;不能用 pstate 里上次的 target_tasks 累加, + # 那样每次续跑(点停止后再「继续训练」)分母都加一截,进度条会越续越少(2026-10-18 实测 67368→84728)。 + done_n=$($PY -c "import json;print(json.load(open('ml/data/stats.json', encoding='utf-8'))['tasks'])") + $PY -m ml.pstate set gen target_tasks=$(( done_n + per2 * NPROC )) run bash ml/gen/run_parallel.sh $per2 $NPROC $s0 "$extra" s0=$((s0 + NPROC)) done