2026-10-17 12:08:04 +00:00
|
|
|
|
# Transformer 拟合避障轨迹规划:训练方案(审查稿)
|
|
|
|
|
|
|
|
|
|
|
|
> 2026-10-17 起草,基于 `main@3c7c814`(贴立柱修复后的规划器)。本文只是方案,代码尚未编写。
|
2026-10-17 12:26:42 +00:00
|
|
|
|
> 审查时重点看:§0 定位、§2 数据分布、§3 表示方式、§5 训练配置、§5A 后训练循环、§7 验收标准。
|
2026-10-17 12:08:04 +00:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 0. 定位与边界
|
|
|
|
|
|
|
|
|
|
|
|
| 项目 | 决定 |
|
|
|
|
|
|
|---|---|
|
|
|
|
|
|
| 模型角色 | **提议器**:给出若干条候选关节轨迹,由现有 `collideFree` + 半格复验把关,全部不合法时回落 `routeRT` / `solveDyn` |
|
|
|
|
|
|
| 不做的事 | 不让模型直接驱动电机;不替代碰撞检测;不学习动力学(速度/加速度仍由 `animTo` 时间参数化) |
|
|
|
|
|
|
| 老师 | 当前 JS 规划器(`webapp/js/ik-solver.js`):松手口径用 `S.solveDyn(T, opt)`,拖拽口径用 `S.solveRoute(T, {quick:true,...})` |
|
|
|
|
|
|
| 收益目标 | 实时拖拽重规划 P99 ≈ 321 ms → **< 50 ms**;首次全量 IK 尖峰(最差约 2 s)→ < 100 ms |
|
|
|
|
|
|
| 底线 | 「模型+验证+回落」整体的到达率、路径合法率**不得低于**现有规划器(任何基准上都不允许退化) |
|
|
|
|
|
|
|
|
|
|
|
|
为什么必须保留验证:碰撞是"硬约束",神经网络只能做到高概率满足。验证器把"偶尔撞一下"变成"偶尔慢一下"。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 1. 训练环境
|
|
|
|
|
|
|
|
|
|
|
|
| 阶段 | 在哪里跑 | 说明 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| 数据生成 | Hark 沙箱(2 vCPU / 7 GB,Node) 或 用户机器 | 纯 JS,无需 GPU;可多进程并行 |
|
|
|
|
|
|
| 训练 | **用户的 GPU 机器** | 沙箱无 GPU、无 PyTorch。最低建议 8 GB 显存(RTX 3060 级别) |
|
|
|
|
|
|
| 部署推理 | 浏览器(onnxruntime-web,WebGPU 优先,wasm 兜底) | 与现有查看器同页运行 |
|
|
|
|
|
|
|
|
|
|
|
|
Python 环境(训练机):
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
conda create -n armtf python=3.11 -y && conda activate armtf
|
|
|
|
|
|
pip install torch --index-url https://download.pytorch.org/whl/cu121 # 按本机 CUDA 版本选
|
|
|
|
|
|
pip install numpy pyarrow tqdm tensorboard onnx onnxruntime
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2. 第一步:生成数据(规划器当老师)
|
|
|
|
|
|
|
|
|
|
|
|
### 2.1 新增文件
|
|
|
|
|
|
|
|
|
|
|
|
| 文件 | 作用 |
|
|
|
|
|
|
|---|---|
|
|
|
|
|
|
| `ml/gen/gen_dataset.cjs` | 采样任务 → 调用规划器 → 校验 → 写分片 |
|
|
|
|
|
|
| `ml/gen/sampler.cjs` | 起点/目标采样器(三类分布,见 2.3) |
|
|
|
|
|
|
| `ml/gen/run_parallel.sh` | 按 CPU 核数起 N 个进程,每个进程不同随机种子 |
|
|
|
|
|
|
| `ml/data/shard_XXXX.jsonl` | 原始样本分片(每片 5000 条) |
|
|
|
|
|
|
|
|
|
|
|
|
复用 `tests/route_bench_setup.cjs` 装配求解器(关节表、`docs/travel.json`、`docs/collide.json`,无需网格)。
|
|
|
|
|
|
|
|
|
|
|
|
### 2.2 单条样本的字段
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": "s0003_000127",
|
|
|
|
|
|
"mode": "pos" | "pose",
|
|
|
|
|
|
"teacher": "dyn" | "rt",
|
|
|
|
|
|
"q0": [6 个关节角, 度],
|
|
|
|
|
|
"T": [x, y, z], // 目标 TCP 位置, mm
|
|
|
|
|
|
"R": [[3x3]] | null, // 目标姿态(pose 模式)
|
|
|
|
|
|
"tool": 0,
|
|
|
|
|
|
"path": [[6], [6], ...], // 老师给出的折线: q0 → via... → q
|
|
|
|
|
|
"q_goal": [6],
|
|
|
|
|
|
"ok": true, // 到达 (误差<1mm, pose 另需<0.5°) 且 1° 细验无干涉
|
|
|
|
|
|
"poseRelaxed": false,
|
|
|
|
|
|
"travel_deg": 123.4,
|
|
|
|
|
|
"plan_ms": 812.0,
|
|
|
|
|
|
"fp": "collide.json 指纹" // modelFingerprint(),碰撞模型变了旧数据作废
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2.3 采样分布(目标 20 万条原始任务)
|
|
|
|
|
|
|
|
|
|
|
|
关节限位(`docs/travel.json`):J1/J3/J6 连续 ±180°;J2 [-92, 9],J4 [-111, 16],J5 [-93, 34]。
|
|
|
|
|
|
|
|
|
|
|
|
| 类别 | 占比 | 采样方式 |
|
|
|
|
|
|
|---|---:|---|
|
|
|
|
|
|
| A 均匀 | 50% | 起点 q0、目标位形 b 均在限位内均匀采样且本身无干涉;目标取 `fk(b)`(pose 模式加 `orient(b)`) |
|
|
|
|
|
|
| B 直线被挡 | 30% | 同 A,但要求 q0→b 关节直线 1° 细验有干涉(route_bench 的生成口径) |
|
|
|
|
|
|
| C 贴立柱 | 15% | b 满足 `nearColumn`(J1/J2/J3 任一 ±4° 即撞立柱),q0 在立柱另一侧(near_column_bench 口径) |
|
|
|
|
|
|
| D 不可达/无安全解 | 5% | 目标在工作空间外或所有 IK 分支都撞;标签为"拒绝",教模型说"到不了" |
|
|
|
|
|
|
|
|
|
|
|
|
- `mode`:pos 与 pose 各 50%。
|
|
|
|
|
|
- 老师:每条任务用 `solveDyn` 求一次(松手口径,质量更高);其中 30% 额外用 `routeRT` 拖拽口径求一次,作为"快速路径"风格的辅助样本(`teacher:"rt"`),训练时可按需过滤。
|
|
|
|
|
|
- **测试集隔离**:用固定种子另生成 2000 条留作测试集,且排除与训练目标距离 < 5 mm 的样本;`route_bench` / `near_column_bench` / `rt_drag_bench` 的案例**不进入训练集**。
|
|
|
|
|
|
|
|
|
|
|
|
### 2.4 质量过滤
|
|
|
|
|
|
|
|
|
|
|
|
1. `ok == false` 的样本:A/B/C 类丢弃;D 类保留为"拒绝"标签。
|
|
|
|
|
|
2. 整条路径 1° 细验(`segOK`)+ 半格复验,任一段干涉即丢弃。
|
|
|
|
|
|
3. `poseRelaxed == true` 的样本单独打标签,训练时只当作 pos 模式样本用(避免模型学到"姿态随便放")。
|
|
|
|
|
|
4. 关节行程超过同任务 `routeRT` 结果 1.5 倍的视为老师绕远,丢弃(可选,先统计比例再决定)。
|
|
|
|
|
|
|
|
|
|
|
|
### 2.5 数据增广(不需要重新规划)
|
|
|
|
|
|
|
|
|
|
|
|
- **后缀切片**:合法路径的任意后半段也是合法路径。从每条路径中按弧长取 2–4 个中间点作为新 q0,得到新样本(目标不变)。约 ×3。
|
|
|
|
|
|
- **连续轴平移**:J1 绕立柱对称性**不成立**(立柱在固定位置),不做 J1 旋转增广;J6 若与碰撞无关可加 ±360° 等价表示,归一化时统一处理。
|
|
|
|
|
|
- 增广后预计约 60 万条训练样本。
|
|
|
|
|
|
|
|
|
|
|
|
### 2.6 耗时与存储估算
|
|
|
|
|
|
|
|
|
|
|
|
- `solveDyn` 约 0.7 s/条,沙箱 2 进程约 1 万条/小时 → 20 万条约 20 小时;用户机器 8 核约 5 小时。
|
|
|
|
|
|
- 每条约 1–2 KB,全部原始数据约 300 MB;转 Parquet 后约 80 MB。
|
|
|
|
|
|
|
|
|
|
|
|
### 2.7 本步检查点(审查时可看)
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] `ml/data/stats.json`:各类别数量、ok 率、平均行程、路径点数分布、规划耗时分布
|
|
|
|
|
|
- [ ] 随机抽 20 条在查看器里回放(新增 `?replay=shard_0000.jsonl#127` URL 参数)
|
|
|
|
|
|
- [ ] 测试集与 3 个基准案例和训练集无重叠
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 3. 第二步:预处理(Python)
|
|
|
|
|
|
|
|
|
|
|
|
文件:`ml/prep/build_dataset.py` → 输出 `ml/data/train.parquet`、`val.parquet`(95/5 划分)、`test.parquet`、`norm.json`。
|
|
|
|
|
|
|
|
|
|
|
|
### 3.1 路径重采样
|
|
|
|
|
|
|
|
|
|
|
|
1. 连续轴(J1/J3/J6)先做展开(`unwrapTo` 同口径),保证相邻点差 < 180°。
|
|
|
|
|
|
2. 按**加权关节空间弧长**重采样为固定 **K = 32** 个点,第 0 点 = q0,第 31 点 = q_goal。权重默认各轴 1(可改成按连杆长度加权)。
|
|
|
|
|
|
3. 记录原始弧长 `L`(模型额外回归它,用于早停与排序)。
|
|
|
|
|
|
|
|
|
|
|
|
### 3.2 条件输入(编码器一侧)
|
|
|
|
|
|
|
|
|
|
|
|
| 量 | 维度 | 编码 |
|
|
|
|
|
|
|---|---:|---|
|
|
|
|
|
|
| q0 | 6 | 每轴 (sin, cos) → 12;限位轴再加归一化值 (q−lo)/(hi−lo) → +3 |
|
|
|
|
|
|
| 目标位置 T | 3 | 除以 600 mm 归一化 |
|
|
|
|
|
|
| 目标姿态 R | 6 | 旋转矩阵前两列(6D 表示);pos 模式填 0 |
|
|
|
|
|
|
| 模式 | 2 | one-hot [pos, pose] |
|
|
|
|
|
|
| 工具号 | 1 | 目前恒 0,留位 |
|
|
|
|
|
|
| 起点 TCP | 3 | `fk(q0)` 归一化(给模型一个笛卡尔线索) |
|
|
|
|
|
|
|
|
|
|
|
|
### 3.3 输出表示(解码器一侧)——离散化
|
|
|
|
|
|
|
|
|
|
|
|
- 每个关节值相对 q0 的**增量** Δq = q_k − q0 离散化:连续轴范围 [−360, 360],限位轴范围 [lo−hi, hi−lo],均分 **512 个桶**(约 1.4°/桶)。
|
|
|
|
|
|
- 每个桶再回归一个桶内偏移 ∈ [−0.5, 0.5](细化到亚度级)。
|
|
|
|
|
|
- 序列:K−1 = 31 个路径点 × 6 轴 = **186 个 token**(第 0 点即 q0,不需要预测)。
|
|
|
|
|
|
- 额外 1 个 `[REJECT]/[OK]` 分类 token 放在序列最前:D 类样本只训练这个 token。
|
|
|
|
|
|
|
|
|
|
|
|
**为什么不用直接回归(MSE)**:立柱两侧绕行(左绕/右绕、J3 翻转/不翻转)是多峰分布,MSE 会输出两条路径的平均——恰好穿过立柱。离散化 + 自回归采样能保留多峰。
|
|
|
|
|
|
|
|
|
|
|
|
### 3.4 归一化文件 `norm.json`
|
|
|
|
|
|
|
|
|
|
|
|
记录桶边界、K、权重、碰撞模型指纹 `fp`;部署端必须校验 `fp` 一致,否则拒绝加载模型。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 4. 第三步:模型结构
|
|
|
|
|
|
|
|
|
|
|
|
文件:`ml/model/traj_transformer.py`
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
条件向量 (≈37 维)
|
|
|
|
|
|
└─ MLP → 8 个条件 token (d=256) ← 编码器:4 层 Transformer encoder
|
|
|
|
|
|
目标序列: [BOS][OK] (j1,j2,...,j6)×31
|
|
|
|
|
|
└─ 嵌入 = 桶嵌入 + 轴嵌入(6) + 路径点位置嵌入(32)
|
|
|
|
|
|
└─ 6 层 Transformer decoder(因果自注意力 + 对条件 token 的交叉注意力)
|
|
|
|
|
|
输出头:
|
|
|
|
|
|
├─ 桶分类头 (512 类 / token)
|
|
|
|
|
|
├─ 桶内偏移回归头 (1 / token)
|
|
|
|
|
|
├─ OK/REJECT 头 (2 类)
|
|
|
|
|
|
└─ 路径弧长回归头 (1)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
| 超参 | 值 |
|
|
|
|
|
|
|---|---|
|
|
|
|
|
|
| d_model | 256 |
|
|
|
|
|
|
| 头数 | 8 |
|
|
|
|
|
|
| FFN | 1024,GELU |
|
|
|
|
|
|
| 编码器/解码器层数 | 4 / 6 |
|
|
|
|
|
|
| Dropout | 0.1 |
|
|
|
|
|
|
| 参数量 | 约 7 M(fp32 约 28 MB,fp16 约 14 MB) |
|
|
|
|
|
|
|
|
|
|
|
|
备选(第一版不做):同一骨干改为 flow matching,直接输出 31×6 连续值,推理 8–16 步;在自回归版精度不够时再试。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 5. 第四步:训练
|
|
|
|
|
|
|
|
|
|
|
|
文件:`ml/train.py`,配置 `ml/configs/base.yaml`。
|
|
|
|
|
|
|
|
|
|
|
|
### 5.1 损失
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
L = CE(桶) 权重 1.0(label smoothing 0.05)
|
|
|
|
|
|
+ L1(桶内偏移) 权重 0.5
|
|
|
|
|
|
+ CE(OK/REJECT) 权重 0.5
|
|
|
|
|
|
+ L1(弧长 L) 权重 0.1
|
|
|
|
|
|
+ 平滑项 ‖q_{k+1} − 2q_k + q_{k−1}‖²(用期望桶值计算) 权重 0.05
|
|
|
|
|
|
+ 终点项 ‖q_31 − q_goal‖(期望值) 权重 0.5
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 5.2 训练配置
|
|
|
|
|
|
|
|
|
|
|
|
| 项 | 值 |
|
|
|
|
|
|
|---|---|
|
|
|
|
|
|
| 优化器 | AdamW,β=(0.9, 0.95),weight decay 0.05 |
|
|
|
|
|
|
| 学习率 | 3e-4,前 2000 步线性预热,余弦退火到 3e-6 |
|
|
|
|
|
|
| batch | 256(显存不够用梯度累积) |
|
|
|
|
|
|
| 精度 | bf16/fp16 混合精度 |
|
|
|
|
|
|
| 轮数 | 最多 40 epoch,验证集"合法率"连续 5 次不升即早停 |
|
|
|
|
|
|
| 教师强制 | 全程 teacher forcing;第 20 epoch 后 10% 概率用模型自己的预测(scheduled sampling),减轻曝光偏差 |
|
|
|
|
|
|
| 预计耗时 | RTX 3060:约 1.5–3 小时(估算,跑完第一轮后校正) |
|
|
|
|
|
|
|
|
|
|
|
|
### 5.3 训练中验证(每个 epoch)
|
|
|
|
|
|
|
|
|
|
|
|
在 `val` 抽 1000 条,**自回归采样**生成路径后用 Python 版碰撞检查器评估:
|
|
|
|
|
|
- 用 `ml/eval/collide_py.py`(从 `collide.json` 读胶囊,与 JS 同口径;先用 JS 结果对拍 1 万个位形,误差必须为 0)。
|
|
|
|
|
|
- 指标:合法率(1° 细验无干涉)、终点误差、行程比(模型/老师)、REJECT 准确率。
|
|
|
|
|
|
- 保存最优 checkpoint 依据 = **合法率**,其次终点误差。
|
|
|
|
|
|
|
|
|
|
|
|
### 5.4 一条命令运行
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
python ml/prep/build_dataset.py --in ml/data --out ml/data
|
|
|
|
|
|
python ml/train.py --config ml/configs/base.yaml --run runs/v1
|
|
|
|
|
|
tensorboard --logdir runs
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-10-17 12:26:42 +00:00
|
|
|
|
## 5A. 第四步半:后训练——验算、挑错、针对性再训练(循环)
|
|
|
|
|
|
|
|
|
|
|
|
> 2026-10-17 用户补充:一轮监督训练不够,要"模型结果逐条验算 → 挑出错的 → 针对性训练 → 周而复始"。
|
|
|
|
|
|
> 下面把它做成固定流程,每一轮都可复现、可回滚。
|
|
|
|
|
|
|
|
|
|
|
|
### 5A.1 为什么光和老师数据对比不够
|
|
|
|
|
|
|
|
|
|
|
|
监督训练只在**老师走过的状态**上学习。模型上线后会走到老师没走过的状态(自己的路径稍微偏一点,下一帧的起点就偏了),
|
|
|
|
|
|
误差会累积——这是模仿学习的"分布偏移"。所以后训练要同时做两件事:
|
|
|
|
|
|
|
|
|
|
|
|
1. **困难样本挖掘**:在新任务上让模型出结果,逐条验算,错的交给老师重新标注。
|
|
|
|
|
|
2. **DAgger(数据聚合)**:在**模型自己走到的状态**上请老师给答案,再加回训练集。拖拽场景尤其需要这一条。
|
|
|
|
|
|
|
|
|
|
|
|
### 5A.2 一轮的完整流程(第 r 轮)
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
┌──────────────────────────────────────────────┐
|
|
|
|
|
|
模型 M_r ──▶ ①出题 ──▶ ②模型作答 ──▶ ③逐条验算 ──▶ ④错题分类
|
|
|
|
|
|
│
|
|
|
|
|
|
M_{r+1} ◀── ⑦门禁 ◀── ⑥针对性微调 ◀── ⑤老师重标 + 邻域扩增 ◀┘
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**① 出题(挖掘池,每轮新抽)**
|
|
|
|
|
|
- 每轮用新种子生成 5 万条任务,分布同 §2.3,但把 B/C 类(直线被挡、贴立柱)提到 60%。
|
|
|
|
|
|
- 另跑 2000 段"模型在环"拖拽仿真(同 rt_drag_bench 口径,但每帧由模型规划、走模型给的路径),记录模型实际经过的状态,作为 DAgger 状态池。
|
|
|
|
|
|
- **挖掘池与测试集严格分开**:§2.3 的留出测试集和三个基准永远不进挖掘池,否则门禁失效。
|
|
|
|
|
|
|
|
|
|
|
|
**② 模型作答**
|
|
|
|
|
|
- 每个任务采样 B = 8 条(与部署一致:贪心 + 不同温度)。GPU 批量推理,5 万任务约几分钟。
|
|
|
|
|
|
|
|
|
|
|
|
**③ 逐条验算**(新增 `ml/eval/verify_batch.py`,GPU 批量版碰撞检查器)
|
|
|
|
|
|
- 每条候选:1° 细验 + 半格复验无干涉;终点 TCP 误差 < 1 mm(pose 另需姿态 < 0.5°);关节不越限位。
|
|
|
|
|
|
- 同一任务调用老师(已有标签或现算)得到老师行程 `L*`。
|
|
|
|
|
|
- 验算口径必须与 JS 完全一致:`verify_batch.py` 先与 JS `collideFree` 对拍 10 万个位形,0 误差才允许用于挖掘。
|
|
|
|
|
|
- 为什么要 GPU 版:5 万任务 × 8 条 × 约 100 个采样位形 = 4000 万次位形检查,JS 单核约 20 小时,GPU 批量约几分钟。
|
|
|
|
|
|
|
|
|
|
|
|
**④ 错题分类**(写入 `ml/mining/round_r/errors.parquet`)
|
|
|
|
|
|
|
|
|
|
|
|
| 类别 | 判定 | 典型原因 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| E1 全错 | 8 条全部不合法 | 没学会这一类绕行 |
|
|
|
|
|
|
| E2 部分错 | 有合法的,但贪心那条不合法 | 置信度校准差 |
|
|
|
|
|
|
| E3 绕远 | 最优合法候选行程 > 1.2 × `L*` | 选错同伦类(该左绕却右绕) |
|
|
|
|
|
|
| E4 终点偏 | 路径合法但终点误差超限 | 离散化/精修不足 |
|
|
|
|
|
|
| E5 拒判错 | 可达却判 REJECT,或不可达却给路径 | OK 头没学好 |
|
|
|
|
|
|
| E6 拖拽失稳 | 模型在环仿真中出现碰撞帧或 3 s 内未到达 | 分布偏移 |
|
|
|
|
|
|
| G 比老师好 | 合法且行程 < 0.9 × `L*` | 老师没找到更短的路 |
|
|
|
|
|
|
|
|
|
|
|
|
同时记录每个错题撞的是哪对部件(`collideDetail`),便于看是不是集中在立柱上段等特定区域。
|
|
|
|
|
|
|
|
|
|
|
|
**⑤ 老师重标 + 邻域扩增**
|
|
|
|
|
|
- E1–E5:用 `solveDyn` 重新求解(已有标签直接复用),得到正确标签。
|
|
|
|
|
|
- E6(DAgger):取模型路径**撞前最后一个安全状态**、以及拖拽中途的若干状态作为新起点 q0,请老师从这里规划到目标。
|
|
|
|
|
|
- 邻域扩增:每个错题再造 10 个邻居(目标 ±5 mm、q0 各轴 ±3°),老师标注,过滤后加入——一个错题往往代表一片区域没学会。
|
|
|
|
|
|
- G 类:模型的更短路径通过验算后**直接作为新标签**(替换老师标签),模型可以反过来超过老师。
|
|
|
|
|
|
- 老师耗时:每轮错题约 2000–5000 条 × 11(含邻居)× 0.7 s,8 核机器约 1–2 小时。
|
|
|
|
|
|
|
|
|
|
|
|
**⑥ 针对性微调**
|
|
|
|
|
|
- 从 M_r 的权重继续训练,**不从头训**。
|
|
|
|
|
|
- 训练集 = 新错题样本 50% + 历史数据回放 50%(防止学了新的忘了旧的)。
|
|
|
|
|
|
- 错题按类别加权:E1、E6 权重 2.0,E3 权重 1.5,其余 1.0。
|
|
|
|
|
|
- 学习率 1e-4,预热 500 步,余弦退火,3–5 epoch。
|
|
|
|
|
|
|
|
|
|
|
|
**⑦ 门禁(不通过就回滚)**
|
|
|
|
|
|
|
|
|
|
|
|
| 检查 | 要求 |
|
|
|
|
|
|
|---|---|
|
|
|
|
|
|
| 留出测试集模型命中率 | 比 M_r 高(≥ +0.3 个百分点) |
|
|
|
|
|
|
| 留出测试集合法率、行程比 | 不得比 M_r 差 |
|
|
|
|
|
|
| route_bench / near_column_bench / rt_drag_bench | 「模型+验证+回落」任何一项不得退化 |
|
|
|
|
|
|
| 上一轮已修好的错题(回归集) | 至少 95% 仍然正确 |
|
|
|
|
|
|
|
|
|
|
|
|
不通过:丢弃 M_{r+1},检查错题标签质量后调整权重/回放比例重做本轮。
|
|
|
|
|
|
|
|
|
|
|
|
### 5A.3 停止条件
|
|
|
|
|
|
|
|
|
|
|
|
- 连续 2 轮命中率提升 < 0.5 个百分点,或
|
|
|
|
|
|
- 达到 6 轮,或
|
|
|
|
|
|
- 达到 §7.2 全部验收标准。
|
|
|
|
|
|
|
|
|
|
|
|
### 5A.4 进阶选项(循环稳定后再考虑)
|
|
|
|
|
|
|
|
|
|
|
|
1. **验算过的自我采样微调**(expert iteration / 拒绝采样):对每个任务采样 32 条,只保留验算通过且最短的一条作为标签,不需要老师参与,适合 G 类多的时候。
|
|
|
|
|
|
2. **偏好训练**(DPO 类):同一任务的"合法路径"和"撞了的路径"组成一对,让模型提高前者概率、降低后者,直接针对"别撞"优化。
|
|
|
|
|
|
3. **碰撞惩罚项**:在损失里加可微的胶囊最小距离惩罚(从 `collide.json` 的胶囊参数计算),距离 < 安全余量时罚。
|
|
|
|
|
|
|
|
|
|
|
|
### 5A.5 新增文件
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
ml/mining/
|
|
|
|
|
|
mine_round.py ①–④ 出题、作答、验算、分类
|
|
|
|
|
|
relabel.cjs ⑤ 调老师重标 + 邻域扩增(Node)
|
|
|
|
|
|
finetune.py ⑥ 回放混合 + 加权微调
|
|
|
|
|
|
gate.py ⑦ 门禁与回滚
|
|
|
|
|
|
loop.sh 一条命令跑 N 轮:bash ml/mining/loop.sh --rounds 6
|
|
|
|
|
|
round_r/ 每轮的错题、新标签、指标、checkpoint(不入库)
|
|
|
|
|
|
ml/eval/verify_batch.py GPU 批量碰撞验算(与 JS 对拍)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
每轮输出 `round_r/report.md`:错题分布、门禁结果、命中率曲线,方便逐轮审查。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-10-17 12:08:04 +00:00
|
|
|
|
## 6. 第五步:推理与集成
|
|
|
|
|
|
|
|
|
|
|
|
### 6.1 导出
|
|
|
|
|
|
|
|
|
|
|
|
`ml/export_onnx.py`:导出带 KV cache 的解码器(opset 17),fp16 量化;输出 `webapp/models/traj_v1.onnx` + `traj_v1.norm.json`。
|
|
|
|
|
|
|
|
|
|
|
|
### 6.2 推理流程(新增 `webapp/js/ik-learned.js`,在 `routeRT` 之前调用)
|
|
|
|
|
|
|
|
|
|
|
|
1. 编码条件 → 一次 batch 采样 **B = 8** 条(温度 {0, 0.5, 0.8, 1.0} 各 2 条,0 为贪心)。
|
|
|
|
|
|
2. 若 OK 头判 REJECT 概率 > 0.9 → 直接走原规划器(不信任模型的"到不了",只用来省时间排序)。
|
|
|
|
|
|
3. 每条候选:终点用 `solveTo` 做 1–3 次牛顿精修 → 整条 `collideFree` 1° 细验 + 半格复验。
|
|
|
|
|
|
4. 选合法且行程最短的一条;**全部不合法 → 原 `routeRT` / `solveDyn` 回落**。
|
|
|
|
|
|
5. 拖拽中热启动:把上一帧路径剩余部分作为解码前缀,只重新生成后半段。
|
|
|
|
|
|
|
|
|
|
|
|
### 6.3 延迟预算(目标)
|
|
|
|
|
|
|
|
|
|
|
|
| 环节 | 目标 |
|
|
|
|
|
|
|---|---:|
|
|
|
|
|
|
| 模型推理(8 条 × 186 token,WebGPU) | < 15 ms |
|
|
|
|
|
|
| 碰撞验证(8 条) | < 15 ms(已有包围球预筛) |
|
|
|
|
|
|
| 合计(命中时) | < 30 ms |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 7. 第六步:评估与验收
|
|
|
|
|
|
|
|
|
|
|
|
### 7.1 测试集合
|
|
|
|
|
|
|
|
|
|
|
|
| 集合 | 来源 |
|
|
|
|
|
|
|---|---|
|
|
|
|
|
|
| route_bench | `tests/route_bench.cjs`,60 例 |
|
|
|
|
|
|
| near_column_bench | `tests/near_column_bench.cjs`,30 例(pos / pose / rt) |
|
|
|
|
|
|
| rt_drag_bench | `tests/rt_drag_bench.cjs`,12 例 |
|
|
|
|
|
|
| held-out | §2.3 的 2000 条留出测试集 |
|
|
|
|
|
|
|
|
|
|
|
|
新增 `tests/learned_bench.cjs`:对同一批案例分别跑 ①原规划器 ②仅模型 ③模型+验证+回落,输出对比表。
|
|
|
|
|
|
|
|
|
|
|
|
### 7.2 验收标准
|
|
|
|
|
|
|
|
|
|
|
|
| 指标 | 仅模型(参考) | 模型+验证+回落(必须) |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| 路径合法率 | ≥ 90% | = 100%(与现状一致) |
|
|
|
|
|
|
| 到达率 | ≥ 95% | ≥ 现状(route 60/60,near pos 30/30,rt 30/30) |
|
|
|
|
|
|
| 关节行程 | ≤ 老师 × 1.1 | ≤ 现状 × 1.05 |
|
|
|
|
|
|
| 拖拽重规划 P99 | — | < 50 ms(现状约 321 ms) |
|
|
|
|
|
|
| 拖拽碰撞帧 | — | 0 |
|
|
|
|
|
|
| 模型命中率(不需回落) | — | ≥ 85% |
|
|
|
|
|
|
|
|
|
|
|
|
不达标的处理:命中率低 → 加数据(重点补失败类别)/ 加大模型;行程差 → 加大行程 loss 或过滤老师绕远样本;延迟不降 → 减少 B 或改 flow matching。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 8. 风险与维护
|
|
|
|
|
|
|
|
|
|
|
|
1. **碰撞模型/立柱变动 = 重训**:`collide.json` 指纹写进数据和模型,不一致时前端自动禁用模型,回落原规划器,不会出错只会变慢。重训流程 = §2 → §5,约半天。
|
|
|
|
|
|
2. **老师的缺陷会被学走**:例如 `ci27` 姿态根枚举漏分支(姿态偏差约 97.5°)。数据里 `poseRelaxed` 样本已隔离;老师修好后再重造数据。
|
|
|
|
|
|
3. **分布外目标**:模型在工作空间边缘可能乱给;有验证+回落兜底,只影响速度。
|
|
|
|
|
|
4. **J3/J6 连续轴展开**:预处理与部署必须同一套 `unwrapTo` 口径,§3 对拍时一并验证。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 9. 目录规划
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
ml/
|
|
|
|
|
|
gen/ gen_dataset.cjs sampler.cjs run_parallel.sh
|
|
|
|
|
|
data/ shard_*.jsonl stats.json train/val/test.parquet norm.json (不入库,.gitignore)
|
|
|
|
|
|
prep/ build_dataset.py
|
|
|
|
|
|
model/ traj_transformer.py
|
|
|
|
|
|
eval/ collide_py.py eval_paths.py
|
|
|
|
|
|
configs/ base.yaml
|
|
|
|
|
|
train.py export_onnx.py README.md
|
|
|
|
|
|
webapp/js/ik-learned.js
|
|
|
|
|
|
webapp/models/traj_v1.onnx traj_v1.norm.json
|
|
|
|
|
|
tests/learned_bench.cjs
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 10. 里程碑
|
|
|
|
|
|
|
|
|
|
|
|
| # | 内容 | 产出 | 在哪跑 |
|
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
| M1 | 数据生成器 + 1000 条试跑 + stats | `ml/gen/*`、stats.json | 沙箱 |
|
|
|
|
|
|
| M2 | Python 碰撞检查器对拍 | `collide_py.py`,1 万位形 0 误差 | 沙箱 |
|
|
|
|
|
|
| M3 | 全量 20 万条数据 | Parquet | 沙箱(约 20 h)或用户机器 |
|
|
|
|
|
|
| M4 | 训练工程 + 小数据过拟合测试(1000 条能背下来) | `train.py` 等 | 沙箱 CPU 验证代码可跑 |
|
|
|
|
|
|
| M5 | 正式训练 | checkpoint、TensorBoard | **用户 GPU** |
|
2026-10-17 12:26:42 +00:00
|
|
|
|
| M5A | 后训练循环:GPU 批量验算器 + 挖掘/重标/微调/门禁,跑 3–6 轮 | 每轮 report.md | 用户 GPU(老师重标可分到沙箱) |
|
2026-10-17 12:08:04 +00:00
|
|
|
|
| M6 | 导出 ONNX + 前端集成 + learned_bench | 对比表 | 沙箱 + 浏览器 |
|
|
|
|
|
|
|
|
|
|
|
|
## 11. 需要用户确认
|
|
|
|
|
|
|
|
|
|
|
|
1. 训练机显卡型号与显存。
|
|
|
|
|
|
2. 定位:只做加速器(本文默认),还是希望最终能脱离规划器。
|
|
|
|
|
|
3. 数据生成在沙箱跑(约 20 h),还是你的机器跑更快。
|