完整工程复盘:从 550 条轨迹到线上 T4
1. 这次复盘要回答什么
这次参赛经历里,最容易误判的地方有三个:
- 训练 loss 看起来正常,不代表 closed-loop manipulation 能完成三层堆叠;
- 本地 fresh3 的一次成功,不代表线上私有 seed 通过;
- “上传成功”和“进入队列”也不是一回事,更不是“官方成绩通过”。
因此本文按证据链记录:数据身份 -> 训练 lineage -> 本地官方评测 -> 提交包 -> 线上结果。每一层都单独判断,不用下一层的结果倒推上一层正确。
2. 数据集身份
本次 T4 主线固定为 canonical official layout 数据集:
| 项目 | 值 |
|---|---|
| 轨迹数量 | 550 |
| 分片归属 | C2=186,C3=182,C4=182 |
| 原始总字节 | 67,546,203,544 |
| 来源结构 | stock=290,alignment retry=3,rescue=257 |
| canonical manifest SHA256 | eeca954a7e64dda818a0cca86534e34f6ffa1a8055bd37810f9781a264199901 |
| processed 维度 | 16-D |
| 相机 | cam_high、cam_left_wrist、cam_right_wrist |
| next-state 校验 | max_error=0 |
这不是一个“纯 stock 550”数据集。rescue 数量较高,说明数据工程的目标是把官方 layout 覆盖补齐,而不是只保留最容易成功的轨迹。它有助于完成数据闭环,但也会带来分布、动作模式和专家 profile 混合的风险。这里把它作为需要继续验证的假设,不把 rescue 比例直接宣布为线上低分的唯一原因。
另外准备过一个 clean50 诊断集:
- raw manifest SHA256:
7918bc860c595add91c37db8b01a27ea08849b5426955e2c1ba5cd3f7ada051f; - processed audit SHA256:
3f5fef447a4dfc47cd6209867560d94091238ec3770fedf4bcbee82caafa7b60; - 50 条、16-D、三相机、next-state max error 为 0。
clean50 只用来判断“最干净子集是否能更快闭环”,不能直接当作 exact550 或线上榜单证据。
3. 主线 ACT 配置
主线是从零训练的官方兼容 ACT,约 83.9M 参数:
textbackbone ResNet18
encoder layers 4
decoder layers 7
hidden dim 512
feed-forward dim 3200
attention heads 8
chunk size 50
KL weight 10
batch size 8
learning rate 1e-5
backbone learning rate 1e-5
state/action dim 16
seed 120
action shift 0
gripper loss weight 1
augmentation off
save frequency every 250 epochs
target horizon 6000 epochs
为了提升吞吐,曾在兼容环境中使用较大 batch、TF32 和多 worker 作为训练工程优化,但这些优化不应改变模型结构、数据语义或评测 wrapper。所有吞吐变化都需要单独记录,不能把“更快”误写成“更好”。
4. 训练与评测时间线
4.1 第一阶段:exact550 训练到 global e1250
第一段训练从 global e250 继续到 e1250,共正常完成 1000 个新增 epoch。日志显示是人为设置的阶段上限,不是 OOM、崩溃或 checkpoint 损坏。之后因为硬件资源和截止时间压力,主线没有自然地跑完官方 6000 epoch。
这段经历暴露出一个计划问题:如果目标是官方 6000 epoch,就必须在开赛前预留完整计算窗口,并把每 250 epoch 的验签、评测和回滚做成自动化。临近截止才把 e1250 继续堆到 e2000,无法替代完整训练成熟度。
4.2 global e1250 的正式 fresh3
在官方 runner、固定公开 seed 和干净配置下:
sr=0/3;- mean graded=
1/9; - 逐层反推为 0 层=2、1 层=1、2 层=0、3 层=0;
- 三条 rollout 均走到 1200/1200 步,没有完整三碗成功。
这次结果说明模型能加载、环境能跑、轨迹能结束,但没有完成任务目标。不能只看“没有报错”就把它标成可提交。
4.3 global e1500 的正式 fresh3
从 e1250 best 继续训练到 global e1500 后:
sr=0/3;- mean graded=
2/9; - 相比 e1250 有一层累计进步,但完整三碗仍为
0/3; - 普通 runner 的 aggregate 无法唯一反推出逐 seed 层数,因此没有伪造逐层分布。
随后使用同权重的 trace 版本补充失败阶段。trace 是诊断工具,不覆盖普通 runner 的正式结果。它显示三条 seed 的层数为 0、1、1,仍没有三层成功。
4.4 global e1750 的正式 fresh3
global e1750 的正式结果仍为:
sr=0/3;- mean graded=
2/9; - 三条均完成 rollout,但没有完整三碗成功。
这意味着 e1500 到 e1750 的增加没有在小样本正式门禁上带来可观察提升。这里应该触发“诊断数据/对齐/闭环拓扑”的检查,而不是只盲目加 epoch。
4.5 clean50 e6500 对照
clean50 分支训练到 e6500 后出现两种结果:
- 普通官方 runner:fresh3 为
0/3,graded=1/3; - trace/诊断 runner:fresh3 为
1/3,graded=5/9,层数分布为 0 层=1、1 层=0、2 层=1、3 层=1。
这两次运行使用同权重和公开 seed,但 runner 拓扑不同,且 trace 版本对正式评测函数做了诊断性包装。因此只能把它们记录为“运行间差异与可达性证据”,不能挑高分提交,也不能把 5/9 宣称为官方成绩。
4.6 提交与线上结果
截止前最后采用的是历史普通官方 runner 中证据最强的控制候选,而不是 clean50 trace,也不是 exact550 e1750/e2000 主线:
- 本地 fresh3:
sr=1/3; - 本地 graded:
2/3; - 正确账号尾号:
a40Cbw; - 官方回执:
#719 T4; submit_exit=0。
第二版 exact550 e2000 上传虽然在截止前启动,但最终在截止后收到服务端 403,后端说明已截止;它没有形成第二个队列 ID。
线上最终榜单:
textT1: 0.60 (达标)
T2: 0.67 (达标)
T3: 0.54 (达标)
T4: 0.2533333333333333 = 25.3/100
线上结果明显低于本地控制候选的 2/3,说明公开 3 条 seed 的可达性并不等价于私有 100 seed 的泛化稳定性,也说明提交边界、环境和私有场景覆盖必须在赛前被当成一级风险。
5. 硬件和资源迁移
这次使用过单卡 4090、RTX PRO 6000 本地资源和云端 PRO 6000 资源。核心问题不是“哪张卡绝对更快”,而是计算窗口、磁盘、环境、GPU 归属和同步链路同时受限:
- 4090 远程实例因余额不足关机,训练被迫中断;
- 临时联系充值、等待开机和同步环境占用了截止前的宝贵时间;
- 云端 PRO 6000 存在其他用户任务和根盘空间限制,不能无条件再启动一套大环境;
- 从 C3 迁移 Python 3.10 / PyTorch / SAPIEN / MPlib / cuRobo 运行时比按 requirements 重新安装更可靠,但镜像同步本身耗时且必须做断点续传与 SHA 校验;
- 评测阶段需要保持单进程和 GPU 独占,不能为了“显卡还有一点显存”就并发启动第二个 SAPIEN 任务。
最终经验:训练计划必须把机器租期和断电/欠费风险纳入版本化 runbook;大环境、原始数据和 checkpoint 应提前放到持久盘或可恢复的对象存储,不能等到最后一晚再搬。
6. 证据索引与发布边界
私有工作区中对应的证据类型包括:训练 manifest 和 processed audit、checkpoint/stats SHA、fresh3/fresh10/fresh20 JSON、submit CLI 回执、leaderboard/queue 快照和 checkpoint lineage。
发布到公共仓库时,日志应先删除个人路径、IP、PID/PGID、完整 token、SSH 私钥、服务器内部 URL 和不具备再分发许可的资产信息。不要直接把整个私有 logs/ 目录复制到 Git。