能训,但不能「直接加进去」。 lerobot 0.6.2 不支持多数据集训练,所以合并要在训练前做好(两个合并集本机已做好;202 集那份已推 Hub,sameview 待推)。租 GPU 后一条命令:./train_smolvla_lr.sh。配方和现役模型 b16-3cam-u20k 完全一致,这次唯一变的变量是数据。
一次约 1.3 小时、约 $1(4090 @ $0.75/h)。建议跑两个变体各一次,共约 $2.5。
| # | 事实 | 出处 | 后果 |
|---|---|---|---|
| 1 | 昨天那批是左臂数据,现役模型是右臂 | meta/stats.json action.std:sep3 只有第 0–5 维动,6–11 维全 0;0826 反过来 · 实测 | 不是「多了 60 集同样的数据」,是另一个任务。任务串不同(…with the left arm. / …with the right arm.),SmolVLA 靠语言区分 |
| 2 | --dataset.repo_id 传列表不行 | lerobot/datasets/factory.py:128 直接 raise NotImplementedError("The MultiLeRobotDataset isn't supported for now.") · 源码 | configs/default.py:30-33 的注释说「可以传列表」——那是过时注释,别信。必须先合并成一个数据集 |
| 3 | 不要传 rename_map | 现役 checkpoint config.json 输入名是 observation.images.head / right_arm_wrist / left_arm_wrist(train_config.json 里 rename_map={});推理端 run_policy_trials.py:415-417 按这套原名喂 · 源码 | REMOTE-GPU-SMOLVLA-4090.md §6/§7 那行 camera1/2/3 映射如果加上,新模型的输入名和机器人喂的对不上 |
换爪之后的全部 13 个数据集,特征签名完全一致(17 维 action/state、三路相机分辨率、30 fps、v3.0)——可以直接合并。
| 批次 | 数据集 | 臂 | 集 | 帧 | 头部视角 |
|---|---|---|---|---|---|
| 0826 | right-pick-cup-20260826-0042 | 右 | 40 | 16,487 | 低头看桌 (pan 1985 / tilt 2332) |
| sep2 | right-pick-cup-sep2-* ×4 | 右 | 51 | 14,103 | 抬头 ~6°(tilt 2261),看到对面椅子 |
| sep2 | left-pick-cup-sep2-* ×2 | 左 | 51 | 14,293 | 同上 |
| sep3(昨天) | left-pick-cup-sep3-* ×6 | 左 | 60 | 15,581 | 低头看桌 (pan 1985 / tilt 2333) —— 和 0826 一样 |
头部视角这一列是逐帧看过的(各解一帧头相机画面对比),不只是读数字。sep2 那批录制时头抬高了,画面里杯子在最下面、背景是椅子和墙 —— 和部署视角不一致。部署用的标准视角由操作者定为 cup-grasp-v0(预置位 trial = pan 2003 / tilt 2619);数据集里记的头部 state 读出来是 tilt≈2332,两者差 287 tick —— 这条差异记在这里,训练完跑测如果视角敏感,先回来看这一行。
所以做了两个合并集:
| 变体 | 内容 | 集 | 帧 | Hub | 用途 |
|---|---|---|---|---|---|
| sameview(默认) | 0826 + sep3 | 100 | 32,068 | xlerobot-team/xlerobot-pick-cup-lr-sameview-20260904 | 主跑。视角与部署一致,左右各半 |
| all | 全部 13 个 | 202 | 60,464 | xlerobot-team/xlerobot-pick-cup-lr-merge-20260904 | 对照。多一倍数据,但混了一个视角 |
两句任务串都在 meta/tasks.parquet 里:索引 0 = 右臂句,索引 1 = 左臂句。
# 在 Jetson 上,lerobot 环境。封装的是 lerobot 自带的 datasets/aggregate.py。
cd ~/Robotic_challenge/03-software/scripts
O=xlerobot-team
~/miniconda3/envs/lerobot/bin/python aggregate_datasets.py --json \
--out $O/xlerobot-pick-cup-lr-sameview-20260904 \
--repo-ids $O/xlerobot-right-pick-cup-20260826-0042 \
$O/xlerobot-left-pick-cup-sep3-20260903-{1824,1853,1906,1927,2015,2054}
顺手修了一个 bug:第一次跑直接失败——aggregate_datasets 在 roots=None 时优先走 $HF_LEROBOT_HOME/hub/datasets--*/snapshots/<sha>/ 那个「按 revision 的缓存」,那里只有 meta(24 KB),没视频,于是元数据校验 13/13 全过、复制视频时 FileNotFoundError。现在 aggregate_datasets.py 显式传 roots 和 aggr_root,指向本地完整目录。面板上的「合并」按钮走的也是这个脚本,所以一起修好了。
推送:LeRobotDataset(...).push_to_hub(private=<和参考集一致>),本机上传约 9 MB/s,1 GB 两分钟。
Pod 规格(沿用 REMOTE-GPU-SMOLVLA-4090.md §2 已验证过的):1× RTX 4090 24 GB · ≥8 vCPU · ≥32 GB RAM · 40 GB 容器盘 · RunPod PyTorch 2.8 / CUDA 12.8 模板 · ~$0.75/h。
# ① 进 pod,先开 tmux —— 家里网断了训练不会死,但 pod 照样计费
tmux new -s train
# ② 环境(§3 原样)
nvidia-smi
pip install -U "lerobot[dataset,training,smolvla]" huggingface_hub
hf auth login # 用有 xlerobot-team 读权限 + Suyang99 写权限的 token
hf auth whoami
# ③ AV1 解码后端必须是 torchcodec,否则 data_s 飙高、GPU 空转(§4 原话)
python -c "import torch, torchcodec; print(torch.__version__, torchcodec.__version__)"
ffmpeg -decoders | grep -E "av1_cuvid"
# torchcodec 报 undefined symbol → pip install "torchcodec==0.7.0"
# ④ 把脚本放进去(从 Jetson scp,或者直接粘贴,就一个文件)
mkdir -p /workspace && cd /workspace
# scp robomates@100.107.145.111:~/Robotic_challenge/05-training/train_smolvla_lr.sh .
chmod +x train_smolvla_lr.sh
# ⑤ 40 步烟测(一分钟)。看 step/s≈4-5、data_s<0.07、loss 在降、grdn 有限
BENCH=1 ./train_smolvla_lr.sh
# ⑥ 正式跑(默认 sameview;约 67-83 分钟)
./train_smolvla_lr.sh
# 对照: VARIANT=all ./train_smolvla_lr.sh
# Ctrl-B D 脱开 tmux,tmux attach -t train 回来
# ⑦ 传 checkpoint(先建仓库,再传;先确认传上去了再 Terminate pod)
hf repo create xlerobot-smolvla-lr-sameview-b16-u20000 --repo-type model --private --exist-ok
hf upload Suyang99/xlerobot-smolvla-lr-sameview-b16-u20000 \
/workspace/outputs/train/smolvla_lr-sameview_b16_u20000/checkpoints/020000 checkpoints/020000 \
--repo-type model
脚本里每个值的出处:B_EFF=16 / MICRO_BATCH=16 / UPDATES=20000 / WARMUP=1000 / LR=1e-4 / AUG=1(含 affine) / eval_split=0 / seed=1000 全部逐项抄自现役模型 checkpoints/020000/pretrained_model/train_config.json。改任何一个 = 改了第二个变量。
顺带一条之前没人写下来的:现役模型的 affine 增强是开着的(train_config.json → tfs.affine.weight=1.0)。REMOTE-GPU 文档 §10 担心 affine 的 ±0.05 平移会抹掉杯位线索——那个担心可能成立,但现役模型就是带着它训出来的。这次保持一致;要不要关是下一个实验。
# Jetson 上。面板从 05-training/*/checkpoints/*/pretrained_model 列模型(robot_server.py:2511),
# 所以目录结构照现役模型的来。checkpoint 1.3 GB,根分区还剩 ~30 GB。
cd ~/Robotic_challenge/05-training
hf download Suyang99/xlerobot-smolvla-lr-sameview-b16-u20000 \
--local-dir xlerobot-smolvla-lr-sameview-b16-u20000
跑测必须明说用哪只臂。 run_policy_trials.py 以前从数据集自动取任务串——它取的是第一句。合并集第一句是右臂。今天加了守卫(run_policy_trials.py:_dataset_task_sentence):数据集里多于一句时拒绝自动选并把两句打印出来,必须传 --task,逐字:
--task "Pick up the cup with the left arm."
--task "Pick up the cup with the right arm."
面板/现场控制台走 /api/trials/control 的 task 字段,同一条规则。发错句子 = 换了任务,bartender_tasks.py:14 记着上次这么错了 31 次两天没发现。
| 事项 | 状态 |
|---|---|
train_smolvla_lr.sh 在 4090 上实际跑起来 | 未测。本机没有可用于此的 GPU。bash -n + DRY=1 过了;每个参数都是现役模型用过的,只换了 repo_id、去掉 rename_map |
| 合并后 SmolVLA 真能按任务句区分左右臂 | 未测 —— 这正是这次训练要回答的问题。风险:起始画面下左右臂 episode 的观测几乎一样,只有语言不同 |
| 左臂的安全地板 | teleop_safety.yaml:59 有 arms.left 包络(z 0.061–0.35),但俯仰补偿的爪长/腕距只校过右臂(yaml 注释在 right 块下)。跑左臂前要看拒帧率 |
| sep2 那批「视角不一致」对训练的影响有多大 | 未测。sameview vs all 两个变体跑完对比就知道 |
| sameview 合并集 | 本机已完成(100 集 / 32,068 帧,实测)。202 集那份已推 Hub;sameview 还没推——推之前 VARIANT=sameview 在 pod 上拉不到,先用 VARIANT=all 或让远程推一下 |
| 项 | 时间 | 费用 |
|---|---|---|
| pod 设置 + 烟测 | ~15 min | ~$0.2 |
| sameview 正式 | 67–83 min | ~$1.0 |
| all 对照 | 67–83 min | ~$1.0 |
| 上传 + 收尾 | ~10 min | ~$0.1 |
| 合计 | ~2.5 h | ~$2.5 |
05-training/train_smolvla_lr.sh —— 训练脚本(本文的可执行版)05-training/train_smolvla_v2.sh —— 上一版,默认仍指旧数据集,留作参考05-training/REMOTE-GPU-SMOLVLA-4090.md —— pod 设置、torchcodec 排障、上传流程(本文引用其 §2–§4、§11;其 §6/§7 的 rename_map 行不要用)03-software/scripts/aggregate_datasets.py —— 合并(今天修了 roots)03-software/scripts/run_policy_trials.py —— 今天加了多任务守卫