diff --git a/docs/本机执行清单.md b/docs/本机执行清单.md new file mode 100644 index 0000000..7272f67 --- /dev/null +++ b/docs/本机执行清单.md @@ -0,0 +1,53 @@ +# 本机执行清单(给本地 AI 逐条执行) + +本文件是 Hark 对本机计算的唯一要求清单。按顺序执行,每一步把「回传」里的文件或输出原样交给用户,不要跳步,不要自行改代码。 +所有命令在仓库根目录(G:\Robot_v2\机器人手臂)的 Git Bash 里运行。完成的条目由 Hark 在下一次提交里删掉。 + +当前状态(2026-10-19 02:00):第二次预训练开环已正常(候选多样性 0.65、8 候选最好 2.9 mm),闭环仍 0% 到达 / 100% 碰撞; +DAgger 阶段曾把显存吃到约 30 GB,原因是 kin.gaps 一次几千个点、cap=40 mm,已修复(kin.gaps 自动分块),尚未实测。 + +## 第 0 步:同步代码 + +```bash +git fetch gitea && git reset --hard gitea/main +git log --oneline -1 # 应为「fix: 闭环失败定位与显存修复……」或更新 +``` + +- 训练控制台若开着,先点「停止」,确认没有 python 训练进程在跑。 +- 不要启动 DAgger / M5,等 Hark 看完第 1、2 步的结果再定。 + +## 第 1 步:gaps 显存峰值(不到 1 分钟) + +```bash +PYTHONUTF8=1 python - <<'EOF' +import torch +from ml.common.kin_torch import Kin +kin = Kin(device='cuda') +for n, cap in [(512, 40.0), (4096, 4.0), (4096, 40.0)]: + q = kin.lo + (kin.hi - kin.lo) * torch.rand(n, 6, device='cuda') + torch.cuda.empty_cache(); torch.cuda.reset_peak_memory_stats() + with torch.no_grad(): kin.gaps(q, cap) + print(f'n={n:5d} cap={cap:4.0f} peak {torch.cuda.max_memory_allocated() / 2**30:6.2f} GiB', flush=True) +EOF +``` + +- 通过:三行峰值都 ≤ 2 GiB。 +- 任务管理器里专用显存接近 24 GB 或共享显存开始上涨:立刻 Ctrl+C,回传已打印的行,不要继续第 2 步。 +- 回传:终端输出的 3 行。 + +## 第 2 步:闭环失败定位(约 2–4 分钟) + +```bash +PYTHONUTF8=1 python -m ml.eval.diag_cl --ckpt ml/runs/base/last.pt --n 256 --out ml/runs/diag_cl.json +``` + +- 运行期间看一眼任务管理器,专用显存应远低于 24 GB;超过 22 GB 就 Ctrl+C 并回传终端输出。 +- 回传:`ml/runs/diag_cl.json`、`ml/runs/replay_teacher.json`、`ml/runs/base/log.jsonl`。 + +## 回传汇总 + +| 步骤 | 回传内容 | +|---|---| +| 1 | 终端 3 行峰值 | +| 2 | ml/runs/diag_cl.json、ml/runs/replay_teacher.json、ml/runs/base/log.jsonl | +| 任一步出错 | 终端最后 30 行输出 | diff --git a/ml/common/kin_torch.py b/ml/common/kin_torch.py index 91fb176..31587a1 100644 --- a/ml/common/kin_torch.py +++ b/ml/common/kin_torch.py @@ -118,12 +118,41 @@ class Kin: return a, b # ---------------- 间隙 ---------------- + # 2026-10-19(用户实测 dagger/诊断吃满 24 GB 显存):粗筛后幸存胶囊对数随 点数 × cap 暴涨, + # 一次几千个点、cap=40 mm 时中间张量可达十几 GB(训练里 eval 峰值 15.9 GiB 也是它)。 + # 现在先按簇级粗筛估出每个点的幸存胶囊对数,按 PAIR_BUDGET 把 batch 切块逐块算,峰值与调用方的 batch 大小无关。 + PAIR_BUDGET = 2_000_000 + def gaps(self, q, cap=40.0, xf=None, max_pairs=None): """返回 dict: gm [B,49]:组对最小间隙 min(gap, cap)(gA*7+gB,gAbki', Rs[:, self.cl_g], self.cl_c.to(q.dtype)) + Ts[:, self.cl_g] + d2 = (cc[:, self.cp_a] - cc[:, self.cp_b]).pow(2).sum(-1) + per = ((d2 <= (self.cp_lim + cap).pow(2)).long() * self.cp_cnt).sum(1) # [B] 每点幸存胶囊对数 + del cc, d2 + if B <= 1 or int(per.sum()) <= self.PAIR_BUDGET: + bounds = [0, B] + else: + cs = torch.cumsum(per, 0).tolist(); bounds = [0]; base = 0 + for k, c in enumerate(cs): + if c - base > self.PAIR_BUDGET and k > bounds[-1]: + bounds.append(k); base = cs[k - 1] + bounds.append(B) + if len(bounds) == 2: + return self._gaps_one(q, cap, xf) + parts = [self._gaps_one(q[s:e], cap, (Rs[s:e], Ts[s:e])) for s, e in zip(bounds[:-1], bounds[1:])] + return {'gm': torch.cat([p['gm'] for p in parts], 0), + 'b': torch.cat([p['b'] + s for p, s in zip(parts, bounds[:-1])]), + 'i': torch.cat([p['i'] for p in parts]), 'j': torch.cat([p['j'] for p in parts]), + 'gap': torch.cat([p['gap'] for p in parts])} + + def _gaps_one(self, q, cap, xf): Rs, Ts = xf B = q.shape[0] with torch.no_grad():