Skip to content

云端训练与真机评测 ​

训练需要 NVIDIA GPU,Mac 做不了。本方案用 AutoDL,整条链路是:传代码和数据 → 装环境 → 训练 → 自动关机 → 取回模型 → 真机评测。下面全部是原生 scp / ssh / pip / lerobot-train 命令,不依赖任何包装脚本;把文中的 connect.westd.seetacloud.com 与 42143 换成自己实例控制台「登录指令」里的地址与端口即可。

步骤在哪跑核心命令
1 上传并解压Macscp -P … 传包 → ssh … "tar xzf …" 解压
2 装环境云端pip install -e .、conda install "ffmpeg<7"、HF_ENDPOINT
3 登录 wandb云端export WANDB_API_KEY=… 写进 ~/.bashrc
4 启动训练云端setsid nohup lerobot-train …
5 自动关机云端while pgrep …; do sleep 60; done; /usr/bin/shutdown
6 取回模型Macscp -r …/pretrained_model models/<步数>/
7 查状态Mac一条 ssh 看完 checkpoint / 进程 / 日志 / 关机守护

8.1 步骤 1 · 上传并解压(Mac 上执行) ​

bash
cd /Users/xxx/project/lerebot/autodl

# 一次传完代码包 + 数据集;远端目录必须写绝对路径(写 ~ 会被本地 shell 展开成本机家目录)
scp -P 42143 lerobot-main.tar.gz so101_demo.tar.gz \
  root@connect.westd.seetacloud.com:/root/autodl-tmp/

# 解压(在云端执行,不必先登进去)
ssh -p 42143 root@connect.westd.seetacloud.com \
  "cd /root/autodl-tmp && tar xzf lerobot-main.tar.gz && tar xzf so101_demo.tar.gz && ls -d lerobot-main so101_demo"
  • 地址与端口从 AutoDL 控制台的「登录指令」里抄。无卡模式与正常模式开机后都可能变化,连不上先核对这里。
  • 只更新代码时,把数据集从 scp 的文件列表里去掉即可(代码包通常是几百 KB,很快)。
  • scp 按整文件传输,中断了重跑会从头再传。想续传就换成 rsync -P --partial -e "ssh -p 42143" 本地文件 root@…:/root/autodl-tmp/。
  • 传完可核对完整性:本地 shasum -a 256 so101_demo.tar.gz 对比云端 sha256sum /root/autodl-tmp/so101_demo.tar.gz,一致才继续。

8.2 步骤 2 · 装环境(ssh 登进云端后按顺序执行) ​

bash
ssh -p 42143 root@connect.westd.seetacloud.com

# ① GPU 是否可见
nvidia-smi --query-gpu=name,memory.total,driver_version --format=csv,noheader

# ② 镜像源:AutoDL 预置的清华 pkgs/free 已下线(404),必须先移除
conda config --remove channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free 2>/dev/null
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

# ③ 确认镜像自带的 torch 是 2.8 + CUDA 12.8(不对就换官方 PyTorch 2.8 镜像重建实例)
python -c "import torch; print('torch', torch.__version__, 'cuda', torch.version.cuda)"

# ④ 装 lerobot(这个 fork 是 0.4.x,没有 [training] extra,依赖都在 base 里)
cd /root/autodl-tmp/lerobot-main && pip install -e .

# ⑤ GPU 视频解码:缺了会退成 CPU 软解,训练速度约减半
python -c "import torchcodec" || conda install -y -c conda-forge "ffmpeg<7"

# ⑥ HuggingFace 镜像(首次下载数据集或模型时才用得上)
grep -q hf-mirror ~/.bashrc || echo 'export HF_ENDPOINT=https://hf-mirror.com' >> ~/.bashrc

torchcodec:缺 torchcodec 会退化成 CPU 软解视频,训练速度大约减半。上面第 ⑤ 步就是用 conda install -c conda-forge "ffmpeg<7" 补齐它的依赖;若补完仍加载失败,通常是缺 libnvrtc——能训,但慢。

最后自检一遍数据集,确认云端能读、条数对得上:

bash
cd /root/autodl-tmp && python -c "
from lerobot.datasets.lerobot_dataset import LeRobotDataset
ds = LeRobotDataset('local/so101_demo', root='/root/autodl-tmp/so101_demo')
print(ds.meta.total_episodes, ds.meta.total_frames, ds.fps, ds.meta.camera_keys)
"

8.3 步骤 3 · 登录 wandb(训练前必做,缺了训练会直接失败) ​

训练命令带 --wandb.enable=true,没有凭据会报 api_key not configured,训练起不来。登录方式就是把 key 导出成环境变量——wandb.init() 会自动读它,不需要额外的登录工具,在云端敲三条命令即可:

bash
# 1. 导出到当前 shell —— 训练就靠这个变量
export WANDB_API_KEY='wandb_v1_你的key'

# 2. 写进 ~/.bashrc —— 重开机、新开终端后依然有效
echo "export WANDB_API_KEY='$WANDB_API_KEY'" >> ~/.bashrc

# 3. 验证:必须打印出 wandb_v1_ 开头的串,否则训练会失败
echo $WANDB_API_KEY

key 从 wandb.ai/authorize 拿(登录后直接显示)。key 是敏感凭据,别外发;要轮换就去 wandb.ai/settings 换新的,然后重新执行上面三条命令。

曲线在 wandb 网页上看(日志里会打印 Track this run --> 链接);不想用 wandb 的话,把训练命令里的 --wandb.enable=true 改成 false 也能跑,只是只剩终端日志了。

8.4 步骤 4 · 启动训练 ​

bash
setsid nohup /root/miniconda3/bin/lerobot-train \
  --dataset.repo_id=local/so101_demo \
  --dataset.root=/root/autodl-tmp/so101_demo \
  --policy.type=act \
  --output_dir=/root/autodl-tmp/outputs/train/act_so101_demo \
  --job_name=act_so101_demo \
  --batch_size=32 \
  --save_freq=5000 \
  --num_workers=12 \
  --policy.device=cuda \
  --wandb.enable=true \
  --policy.push_to_hub=false \
  --steps=25000 \
  > /root/autodl-tmp/so101_train.log 2>&1 < /dev/null &

# 起来了吗:5 秒后看进程,然后跟日志
sleep 5; pgrep -f '[l]erobot-train'
tail -f /root/autodl-tmp/so101_train.log

关键就在开头结尾这几样:setsid 让训练脱离当前会话、nohup 忽略挂断信号、末尾的 & 丢后台,再加上 > 日志 2>&1 < /dev/null 把输出写文件、标准输入接空——少了最后那个 < /dev/null,进程仍会被终端绑住。做完这步断开 SSH、关掉 Mac 都不影响。一次真实训练的参数与实测结果:

项目值说明
数据集local/so101_demo自录 31 集,两路相机
--steps25000步数越多越久,但不一定越好
--batch_size32显存不够就调小
--save_freq5000每 5000 步存一个 → 全程 5 个 checkpoint
--policy.devicecuda在 Mac 上会直接失败
实测速度约 3.8 it/s日志里 updt_s:0.264 → 1 / 0.264
总耗时约 1 小时 50 分跑满 25000 步
最终 loss0.031ACT 的动作 L1 损失,收敛正常
收尾标志End of training看到这行才算正常跑完

怎么判断跑完了:两个条件同时满足:① 远端 checkpoints/ 下有 5 个纯数字目录(005000 … 025000,另有软链接 last);② 日志最后一行是 End of training。训练中会周期性打印 step:25K loss:… 进度行;tqdm 进度条给出 [已用<剩余, it/s],「剩余」直接用来估算完成时刻。

8.5 步骤 5 · 训练完自动关机(省 GPU 空转的钱) ​

训练常在凌晨跑完,人不在电脑前。不用传守护脚本,直接在云端后台挂一条 bash -c 就够:先等训练进程出现(等不到就自己退出,绝不误关机)→ 每 60 秒轮询一次 → 结束后延迟 60 秒、sync 落盘再关机。

bash
cd /root/autodl-tmp
setsid nohup bash -c '
  for i in $(seq 30); do pgrep -f "[l]erobot-train" >/dev/null && break; sleep 10; done
  pgrep -f "[l]erobot-train" >/dev/null || { echo "没等到训练进程,不关机"; exit 0; }
  while pgrep -f "[l]erobot-train" >/dev/null; do sleep 60; done
  echo "训练结束,60 秒后关机"; sleep 60; sync; /usr/bin/shutdown
' > auto_shutdown.log 2>&1 < /dev/null &

# 确认守护真的在跑,以及它打出的第一行日志
sleep 5; cat /root/autodl-tmp/auto_shutdown.log
ps -eo pid,cmd | grep '[b]ash -c' | head -3

8.6 步骤 6 · 取回模型(Mac 上执行) ​

云端 checkpoints/<步数>/ 下有两部分,评测只需要前者:

目录大小用途
pretrained_model/约 206MB要下载:权重 + 配置 + 归一化参数,推理全靠它
training_state/约 412MB不用下载:优化器动量、调度器与 RNG 状态,只在断点续训时有用
bash
HOST=root@connect.westd.seetacloud.com
PORT=42143
OUT=/root/autodl-tmp/outputs/train/act_so101_demo

# ① 先看远端有哪些 checkpoint(完整训练应有 5 个纯数字目录:005000 … 025000)
ssh -p $PORT $HOST "ls -1 $OUT/checkpoints/"

# ② 在云端把各 pretrained_model 打成一个包(只打前者,training_state 不要)
ssh -p $PORT $HOST "cd $OUT/checkpoints && tar cf /root/autodl-tmp/pm.tar */pretrained_model"

# ③ 拉回本地并就地解开 → models/005000/pretrained_model … models/025000/pretrained_model
cd /Users/xxx/project/lerebot
scp -P $PORT $HOST:/root/autodl-tmp/pm.tar /tmp/pm.tar && tar xf /tmp/pm.tar -C models/
du -sh models/*

# ④ 校验:两端 model.safetensors 的字节数必须完全一致
ssh -p $PORT $HOST "stat -c '%s %n' $OUT/checkpoints/*/pretrained_model/model.safetensors"
stat -f '%z %N' models/*/pretrained_model/model.safetensors

# ⑤ 收尾:删掉云端那个大包
ssh -p $PORT $HOST "rm -f /root/autodl-tmp/pm.tar"
  • 合并成一次传输:逐个 scp 会握多次手、密码也要输多遍。先 tar 再拉只要一条连接。想再省事就把 ssh/scp 都加上 -o ControlMaster=auto -o ControlPath=/tmp/lr_cm/%r@%h:%p -o ControlPersist=600 复用连接,全程只输一次密码;或者干脆配公钥:ssh-copy-id -p 42143 root@…。
  • 不要用 expect 之类自动喂密码:容易死锁,人在终端前手输最稳。
  • 中途断了就重跑:scp 是整文件传输,会从头覆盖;云端那个 pm.tar 还在,直接重跑 ③ 即可,不必再打包。
  • 别用「文件存在」判断完成:下到一半断掉会留下半截文件,看着像成功。所以第 ④ 步一定要比字节数,不一致就把 models/<步数> 删掉重下。

8.7 真机评测 ​

和「录制数据集」其实是同一条 lerobot-record,唯一的关键区别:把 --teleop.* 换成 --policy.path——动作不再由主臂产生,而是模型实时预测。它仍然会录数据集,用来记录这次评测的过程(方便回看哪几条成功)。源码里 RecordConfig 的 teleop 与 policy 是二选一,两者都不给才报错。

bash
lerobot-record \
  --robot.disable_torque_on_disconnect=true \
  --robot.type=so101_follower \
  --robot.port=/dev/tty.usbmodem5B8E1136841 \
  --robot.id=my_awesome_follower_arm \
  --robot.cameras="{wrist: {type: opencv, index_or_path: 2, width: 640, height: 480, fps: 30}, \
environment: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
  --policy.path=/Users/xxx/project/lerebot/models/025000/pretrained_model \
  --policy.device=mps \
  --dataset.repo_id=local/eval_025000 \
  --dataset.root=/Users/xxx/project/lerebot/datasets/eval_025000 \
  --dataset.single_task="Grab the black cube" \
  --dataset.num_episodes=10 \
  --dataset.episode_time_s=30 \
  --dataset.reset_time_s=10 \
  --dataset.push_to_hub=false \
  --display_data=true

启动前必查:

项要求不符的后果
数据集名斜杠后必须以 eval_ 开头(local/eval_025000);反向也强制——不带 --policy.path 的录制反而不能用 eval_ 开头。换步数就换个名字ValueError: … does not begin with 'eval_';反向报 no policy is provided;共用名字会撞 FileExistsError 或被当成续录
--policy.path指到 …/checkpoints/<步数>/pretrained_model 这一层错一层就加载不了;加载成功时日志回显 'pretrained_path',可用它自检
相机配置键名、分辨率、fps 与训练时完全一致归一化参数对不上 → 报错或效果崩坏(input_features 应为 (3, 480, 640))
--policy.devicemps写 cuda 直接失败(Mac 没有);启动时那句 Switching to 'mps' 属正常,不是错误

以上校验都在建数据集之前完成,报错不留垃圾目录,改名重跑即可。首次执行先小批量试:--dataset.num_episodes=1 --dataset.episode_time_s=10。