{ "cells": [ { "cell_type": "markdown", "id": "9538016c", "metadata": {}, "source": [ "# 06|跳跃:参考动作、强化学习与评估\n", "\n", "用上游已公开的跳跃参考数据与 PPO 任务,在仿真中训练和回放跳跃。结果及视频读取本专题保存的实测文件;没有运行的数据不会被写成成果。" ] }, { "cell_type": "markdown", "id": "109fdd99", "metadata": {}, "source": [ "## 运行前提\n", "\n", "本文记录的上游代码来自 [KingKongRobotics/jumper](https://github.com/KingKongRobotics/jumper),提交 `b2e58669848a3ba4f209597cd6bebdfe9d0533a4`。完整环境检查和旧实验见 [Ubuntu 工作站复现记录](../01-学习资料/Ubuntu工作站复现记录.md)。下方代码单元读取已经保存的结果并显示视频,不会自动安装依赖或启动训练。\n", "\n", "工作站代码在 `/home/ubuntu/projects/robotics_shared/repos/jumper-everyembodied`,Python 为 `/data/Data14TB/envs/jumper-everyembodied/bin/python`。下方命令在仓库根目录执行;`warp:cuda` 用于 GPU 训练,`native:cpu` 和 OSMesa 用于无窗口录像。训练日志、checkpoint、视频和评估数据来自不同步骤,应在报告中分别记录。具体版本和结果以本专题保存的证据为准。\n" ] }, { "cell_type": "markdown", "id": "c7fdf4c1", "metadata": {}, "source": [ "## 1. 开源内容和动作机制\n", "\n", "[训练任务与奖励](https://github.com/KingKongRobotics/jumper/tree/b2e58669848a3ba4f209597cd6bebdfe9d0533a4/tasks/jumper/jump) 使用仓库内 `tasks/jumper/jump/ref/high_jump_flat.npz`。策略输出是在参考关节动作上的残差;学习目标包含参考关节、机身高度、速度及接触跟踪。上游 PPO 网络与超参数见该目录的 `rl_cfg.py`。参考轨迹不等于当前训练出的策略;不要把参考动画或官方动作包当作这次 checkpoint 的结果。" ] }, { "cell_type": "markdown", "id": "24781d15", "metadata": {}, "source": [ "## 2. 列出任务并训练\n", "\n", "```bash\n", "cd /home/ubuntu/projects/robotics_shared/repos/jumper-everyembodied\n", "PY=/data/Data14TB/envs/jumper-everyembodied/bin/python\n", "\"$PY\" scripts/train.py --task jumper.jump --dry-run\n", "OMP_NUM_THREADS=4 \"$PY\" scripts/train.py --task jumper.jump --backend warp --device cuda:0 --num_envs 4096 --max-iterations 1000 --headless --no-tensorboard\n", "```\n", "\n", "以训练实际日志为准记录源码 commit、环境、任务、后端、环境数、迭代、随机种子和 checkpoint。上游默认训练可能超过此处示例的 1000 次;短训用于验证学习与运行链路,不自动表示收敛。\n", "\n", "本次计划 1000 次,但工作站与其他任务共享 GPU,在保存 model_300 后主动中止;评估使用 model_300,上游默认 10000 次。" ] }, { "cell_type": "markdown", "id": "34dd89a9", "metadata": {}, "source": [ "## 3. 阅读训练过程\n", "\n", "除了总奖励,关注 `Episode_Reward/ref_base_height`、`ref_joint_pos`、`ref_contact` 以及 `Metrics/jump/apex_rise`、`flight_s`、`takeoff_vz`。训练日志中的批量统计与单次视频指标是不同测量。需要检查机器人实际离地、落地及失败终止,才能描述回放效果。" ] }, { "cell_type": "markdown", "id": "f6922ede", "metadata": {}, "source": [ "## 4. 回放、录像与上游评估\n", "\n", "跳跃训练物理频率 400 Hz、控制频率 200 Hz;回放使用相同物理频率。观测噪声默认开启,`--stop-on-done` 避免将重置后的画面误认为连续动作。\n", "\n", "```bash\n", "CKPT=logs/jumper/jumper.jump/2026-10-29_14-48-03/model_300.pt\n", "MUJOCO_GL=osmesa OMP_NUM_THREADS=1 \"$PY\" scripts/play.py --task jumper.jump --backend native --device cpu --checkpoint \"$CKPT\" --headless --steps 700 --physics-hz 400 --stop-on-done --measure --video jump.mp4 --video-width 640 --video-height 480 --speed 0\n", "\"$PY\" tools/checks/jump_eval.py --ckpt \"$CKPT\" --num-envs 1 --episodes 3\n", "```\n", "\n", "上游评估脚本关闭观测噪声,以 1 N 接触力阈值判断全足离地,报告高度与累计腾空时间;它在自动重置后采样,且把一次 done 波计为一个 episode,本例用单环境解释其输出。训练批量指标与单次回放指标不同。\n" ] }, { "cell_type": "markdown", "id": "3fc34c8d", "metadata": {}, "source": [ "## 5. 本专题实测数据" ] }, { "cell_type": "code", "execution_count": 1, "id": "fb55cc58", "metadata": { "execution": { "iopub.execute_input": "2026-10-29T07:13:25.519381Z", "iopub.status.busy": "2026-10-29T07:13:25.518385Z", "iopub.status.idle": "2026-10-29T07:13:25.526920Z", "shell.execute_reply": "2026-10-29T07:13:25.526415Z" } }, "outputs": [], "source": [ "import json\n", "from pathlib import Path\n", "from IPython.display import Video, display\n", "\n", "evidence_dir = Path('../01-学习资料')\n", "media_dir = Path('../assets')\n" ] }, { "cell_type": "code", "execution_count": 2, "id": "8011381d", "metadata": { "execution": { "iopub.execute_input": "2026-10-29T07:13:25.530928Z", "iopub.status.busy": "2026-10-29T07:13:25.529929Z", "iopub.status.idle": "2026-10-29T07:13:25.537631Z", "shell.execute_reply": "2026-10-29T07:13:25.537631Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{\n", " \"task\": \"jumper.jump\",\n", " \"upstream_commit\": \"b2e58669848a3ba4f209597cd6bebdfe9d0533a4\",\n", " \"training\": {\n", " \"backend\": \"warp:cuda\",\n", " \"num_envs\": 4096,\n", " \"planned_iterations\": 1000,\n", " \"checkpoint_iteration\": 300,\n", " \"stopped_early\": true,\n", " \"seed\": null\n", " },\n", " \"checkpoint\": \"../02-可运行代码/checkpoints/jump-model-300.pt\",\n", " \"checkpoint_sha256\": \"03a568f4e0201bd5b1be977fbd8c94b5d9d9c88f9411cfa4e0ac9c4caeaec9bc\",\n", " \"evaluation\": {\n", " \"tool\": \"tools/checks/jump_eval.py\",\n", " \"observation_noise\": false,\n", " \"num_envs\": 1,\n", " \"episodes_reported\": 3,\n", " \"threshold\": \"All foot contact force norms <= 1 N\",\n", " \"reference_apex_z_m\": 0.235,\n", " \"reference_rise_m\": 0.141,\n", " \"reference_airborne_s\": 0.319,\n", " \"episodes\": [\n", " {\n", " \"apex_z_m\": 0.254,\n", " \"rise_m\": 0.159,\n", " \"airborne_s\": 0.325,\n", " \"push_off_vz_m_s\": 1.6\n", " },\n", " {\n", " \"apex_z_m\": 0.252,\n", " \"rise_m\": 0.158,\n", " \"airborne_s\": 0.32,\n", " \"push_off_vz_m_s\": 1.6\n", " },\n", " {\n", " \"apex_z_m\": 0.254,\n", " \"rise_m\": 0.16,\n", " \"airborne_s\": 0.325,\n", " \"push_off_vz_m_s\": 1.61\n", " }\n", " ],\n", " \"caveat\": \"Upstream script samples after auto-reset and counts done waves; these are one-environment reported episodes.\"\n", " },\n", " \"video\": {\n", " \"path\": \"../assets/jump-trained.mp4\",\n", " \"backend\": \"native:cpu\",\n", " \"physics_hz\": 400,\n", " \"control_hz\": 200,\n", " \"observation_noise\": true,\n", " \"steps\": 700,\n", " \"duration_s\": 3.5,\n", " \"termination\": \"episode ended at step 700\"\n", " }\n", "}\n" ] } ], "source": [ "result_path = evidence_dir / 'jump-result.json'\n", "if result_path.is_file():\n", " result = json.loads(result_path.read_text(encoding=\"utf-8\"))\n", " print(json.dumps(result, ensure_ascii=False, indent=2))\n", "else:\n", " print(\"尚未找到实际评估数据:\", result_path)\n" ] }, { "cell_type": "markdown", "id": "b2677c92", "metadata": {}, "source": [ "## 6. 自训策略视频\n", "\n", "下方视频和评估文件应对应同一 checkpoint 与明确的回放条件。" ] }, { "cell_type": "code", "execution_count": 3, "id": "ebb8f80c", "metadata": { "execution": { "iopub.execute_input": "2026-10-29T07:13:25.540637Z", "iopub.status.busy": "2026-10-29T07:13:25.540637Z", "iopub.status.idle": "2026-10-29T07:13:25.789840Z", "shell.execute_reply": "2026-10-29T07:13:25.789334Z" } }, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "video_path = media_dir / 'jump-trained.mp4'\n", "if video_path.is_file():\n", " display(Video(str(video_path), embed=True, width=640))\n", "else:\n", " print(\"尚未找到实际视频:\", video_path)\n" ] }, { "cell_type": "markdown", "id": "539d903b", "metadata": {}, "source": [ "## 延伸阅读\n", "\n", "- [上游教程:三种技能训练与回放](https://github.com/KingKongRobotics/jumper/blob/b2e58669848a3ba4f209597cd6bebdfe9d0533a4/docs/TUTORIAL.md)\n", "- [专题首页](../README.md) · [三足步态训练](03_动作训练与评估.ipynb) · [舞蹈任务](07_舞蹈_参考动作训练与评估.ipynb)\n", "\n", "数据和源码的第三方许可见上游 `NOTICE`。仿真效果不直接代表真机效果。" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.3" } }, "nbformat": 4, "nbformat_minor": 5 }