7. 从原始数据到 SMPL-X¶
本章说明如何从原始录制得到带手指的 SMPL-X:7.1–7.6 使用我们训练好的模型,7.7 介绍如何重新训练。所有步骤都可以在一台机器上完成。有 NVIDIA GPU 最好,没有也能用 CPU 跑(--device cpu),只是慢很多。
一条真实录制(做三明治,30 Hz):带拖尾的五个坐标轴是 tracker 位姿,人体是解出的 SMPL-X,手上的颜色是手套测到的各区压力。
7.1 重建分三个阶段¶
每条录制依次经过三个阶段,每个阶段的结果都写到磁盘上,可以单独检查。
| 阶段 | 做什么 | 输出($WORK/out/<阶段>/<录制名>/) |
|---|---|---|
| reference | 用标定结果把五个 tracker 的位姿换算成关节位置(去掉安装参数) | references/ |
| proposal(补全) | 五 tracker 版 AvatarPoser 在 60 Hz 下给出整段全身轨迹,补出 tracker 看不到的 17 个关节 | proposals/,其中 contact_probability.npy 是左右脚着地概率,与手套触觉无关 |
| projection(约束) | 对 SMPL-X 做可微优化,同时满足三层约束:L1 骨架(tracker 位置和旋转、关节限位),L2 身体表面(不自相穿插),L3 地面(所有顶点不穿地) | projected/:smplx_profile_driven.npz 和 .json、tracker_diagnostics.npz、projection_diagnostics.json、pipeline_metadata.json |
7.2 环境与模型¶
conda create -n egoexplorer python=3.10 -y && conda activate egoexplorer
pip install torch # 按本机 CUDA 版本选择
pip install -e ".[all]" # 在工具包根目录执行
模型文件放在工具包根目录下:
| 文件 | 来源 |
|---|---|
models/smplx/SMPLX_NEUTRAL.npz |
SMPL-X 官网,需注册并遵守其许可 |
models/vposer/V02_05/ |
VPoser,同样从 SMPL-X 官网下载 |
ckpt/avatarposer_five/model.pt |
补全阶段的网络,随仓库提供 |
assets/calibration_motion_vposer_mano.npz |
标定参考动作,随仓库提供;也可以用 scripts/render_calibration_protocol.py --rebuild-motion-cache 重新生成 |
outputs/external_models/avatarposer.pth |
官方 AvatarPoser 权重,只在重新训练时需要 |
7.3 工作目录¶
以下命令都在工具包根目录下执行,并用到这几个变量:
export WORK=/path/to/egoexplorer_work
export CKPT=ckpt/avatarposer_five/model.pt
export PYTHONPATH=src:scripts
$WORK/
├── ego_data_sync/<batch>/<session>/ 原始录制(第 6 章的五个文件)
├── ego_data_lr_fixed/<batch>/<session>/ 左右修正副本(第 9.2 节自动生成)
├── input/ego_data_sync/<batch>/<session>/ 合并后的输入:有修正副本的用副本,其余用原始文件
├── profiles/<batch>.json 这一组的标定结果(第 5 章)
└── out/ 各阶段输出、30 Hz 导出、校验页、总览页
- 一个 batch 就是同一个人、同一次佩戴的一组录制,整组用同一份标定。换人或重新佩戴后的录制放进新的 batch。
ego_data_sync、ego_data_lr_fixed这两个目录名不要改,检查和修正脚本靠它们识别 batch。- 任何结果都不要写回原始录制目录。
7.4 默认配置¶
scripts/run_five_tracker_pipeline.py 的默认参数就是下面这套配置,一般不需要改:
| 项 | 值 |
|---|---|
| 补全网络 | ckpt/avatarposer_five/model.pt |
| 投影脚本 | scripts/project_sparse_tracker_baseline_l2.py |
| L1 关节限位 | 膝 125°,肘 140°,躯干前倾 90°,膝反屈权重 100,骨盆侧倾权重 100 |
| L2 身体表面 | signed_top8,权重 3000,半径 1.8 cm,采样 256 点 |
| L3 地面 | 穿地惩罚权重 50 |
| 优化 | Adam 60 步,学习率 0.004,每段 256 帧 |
其中两项不要改:
- 学习率 0.004。 用 0.008 时,约 20–35% 的真实录制会发散,报
FloatingPointError: non-finite SMPL-X parameters。 - 躯干前倾上限 90°。 上限设成 15° 时,弯腰、弓步、坐下这类动作会让整个人沉到地面以下。
7.5 运行¶
一条命令¶
WORK=/path/to/egoexplorer_work bash scripts/run_pipeline.sh all # 处理所有 batch
WORK=/path/to/egoexplorer_work bash scripts/run_pipeline.sh project <batch> # 只跑某一步、某个 batch
WORK=/path/to/egoexplorer_work bash scripts/run_pipeline.sh status # 查看各阶段进度
它依次执行左右检查、左右修正、合并输入、投影、手部融合,以及第 8、9 章的导出、校验页和总览页。每一步都跳过已完成的录制,中断后重跑即可接着做。投影发散的录制会自动用学习率 0.002 重试一次。
分步执行¶
第 1 步,左右检查与修正(第 9.1–9.2 节)。先做这一步,投影时直接用修正后的输入,就不用返工。
第 2 步,合并输入。 每个文件单独建链接(Path.rglob 不会进入链接过去的目录,所以不能直接链接整个录制目录):
for d in "$WORK"/ego_data_sync/*/*/; do
b=$(basename "$(dirname "$d")"); s=$(basename "$d")
src="$WORK/ego_data_lr_fixed/$b/$s"; [ -d "$src" ] || src="${d%/}"
mkdir -p "$WORK/input/ego_data_sync/$b/$s"
for f in "$src"/*; do ln -sfn "$(readlink -f "$f")" "$WORK/input/ego_data_sync/$b/$s/$(basename "$f")"; done
done
第 3 步,投影。 每个 batch 用自己的标定各跑一次:
B=<batch>
python scripts/run_five_tracker_pipeline.py \
--input-root $WORK/input/ego_data_sync/$B --subject-profile $WORK/profiles/$B.json \
--checkpoint $CKPT --output-root $WORK/out \
--body-model-path models/smplx --device cuda --workers 1 --skip-existing
--session <录制名>(可重复)只处理指定的录制。- 单条失败不会中断整批,失败原因记录在
$WORK/out/pipeline_report.json。 --workers是同时处理的录制数,显存或内存紧张时保持 1。进程因内存不足被系统杀掉时不会留下报错信息:状态为失败却没有原因时,先用dmesg | tail查看。- 耗时参考:3000 帧的录制在 H200 上约 25 秒,CPU 上要几分钟。
看残差,不要只看状态。 状态为 ok 不代表结果好。用 tracker_diagnostics.npz 里的 position_residual_m 筛选:好的录制在 3–12 mm;有些状态为 ok 的录制残差在几十到几百毫米。
需要严格贴合 tracker 时(动作幅度大的录制、标定录制、给训练做标签),改用严格配置:300 步、学习率 0.01、--position-weight 10000 --rotation-weight 60 --pose-prior-weight 0.5,其余不变。各动作段的残差可降到 1–4 mm,耗时约为默认配置的 5 倍。动态动作只占录制的约 5%,统计残差时要按动作段看 p99 和最大值,只看中位数会掩盖问题。
7.6 手部融合¶
手套骨架先拟合到 MANO(SMPL-X 的手部模型),再通过标定好的手腕安装参数接到解出的手臂上,手指和触觉就和身体对齐到了同一个人、同一条时间轴上。MANUS 和 Wuji 走同一条流程,按骨架的节点数选择对应关系。
python -m five_tracker_smplx.cli fuse-manus-batch \
--input-root $WORK/input/ego_data_sync/$B/<session> --body-output-dir $WORK/out/projected \
--subject-profile $WORK/profiles/$B.json --body-model-path models/smplx --device cuda \
--max-hand-frames 480 --iterations 60 --no-protocol --no-viewer
输出 projected/<录制名>/smplx_with_manus_hands.npz。身体部分与融合前完全一致,只补上 left_hand_pose 和 right_hand_pose(各 45 维,MANO 15 个关节的轴角)。关节拟合误差约 8–12 mm。
- 手套左右以
session.json里的slot为准,修正副本中已经改好。 - Wuji 骨架不含手的整体朝向,手的朝向完全由手腕 tracker 决定。
- 没有手套数据的录制,导出时
hand_pose_source为none_neutral_zero,手部是中性姿态的占位值,不是测量结果。
7.7 重新训练补全网络¶
什么时候需要。 如果某类动作在训练数据里没有出现过,补全网络会给出接近站立的姿态,例如抬腿、深蹲时膝和髋几乎不弯。投影的 60 步优化追不回超过约 15° 的偏差(每个参数最多移动约 步数 × 学习率 = 0.24 rad),这时需要重新训练。换人或重新佩戴只需要重新标定,不需要重新训练。
训练方法:
- 从官方 AvatarPoser 出发。 用
outputs/external_models/avatarposer.pth初始化,训练脚本把输入从 54 通道扩到 90 通道,新增的脚踝通道初始化为 0。不要从已经训练过的五 tracker 模型继续训练。 - 合成数据(
--synthetic-root,文件名sequence_*.npz):- VPoser 随机姿态:
scripts/generate_sparse_tracker_synthetic.py --profile <标定> --sequences 24 --frames 240 --output <目录>; - 引导姿态:
assets/guides/里的 B01–B10 全身动作,用目标采集者的标定转换成合成序列(静态姿态按"站立—做动作—保持—站立"展开,动态动作按两种时长重采样;转换脚本尚未整理进工具包); - AMASS:
scripts/generate_amass_five_tracker_synthetic.py --amass <HDM05/CMU/BMLrub …> --profile <标定> --output <目录> --frames 240(60 Hz,只取根节点和 21 个身体关节)。
- VPoser 随机姿态:
- 真实录制的标签(
--natural-root,每条一个<录制名>/smplx_profile_driven.{npz,json}):- 用严格配置(7.5 节)投影出标签,躯干前倾上限 90°;
- 加上逐帧的参考姿态先验,避免解到错误的姿态分支。
scripts/build_pose_reference.py生成参考姿态:标定录制用 01–17 的协议姿态(assets/protocol_body_poses.json)加上分段结果,测试录制用 B01–B10 引导姿态。投影时加--pose-reference <npz> --pose-reference-weight 30,只作用于髋、脊柱、膝、踝和脚,手臂仍由 tracker 决定。不加这一步,深蹲、抬腿、弓步的标签会在几个可能的姿态之间随机跳。
- 训练:
真实录制来自不同标定时,不要传
python scripts/train_avatarposer_five_tracker.py \ --checkpoint outputs/external_models/avatarposer.pth \ --synthetic-root <合成数据目录> --natural-root <标签目录> --holdout-token "" \ --max-natural-windows $((2000 * <真实录制条数>)) --hard-negative-ratio 0.3 \ --epochs 3 --batch-size 32 --learning-rate 1e-4 --device cuda --output <输出目录>--mount-reference,每条录制使用自己的安装参数。 - 评估。 在留出的测试录制上用默认配置跑投影,按动作段比较各 tracker 的残差和关节角,再挑几条旧录制确认没有变差。作为参考,重新训练后测试集的平均残差从 35 / 25 / 20 / 30 / 53 mm(头、左手、右手、左脚、右脚)降到了 8 / 2 / 2 / 3 / 5 mm。
我们的模型就是这样训练的。合成数据包括 24 条 VPoser 序列、20 条引导姿态序列和 AMASS(HDM05、CMU、BMLrub);真实数据包括 35 条带参考姿态先验的录制和 17 条按动作类别挑选的录制。
加入新的动作类型时,需要准备两样东西:每个动作的参考姿态,以及动作段的起止标注。缺少它们,投影给出的标签会在几个可能的姿态之间随机选择。