Files
Mujoco_WASM/training_server/PRETRAINED.md
T
chenlin 438e56bcc8
web-platform-ci / TypeScript, lint, unit, build (push) Has been cancelled
web-platform-ci / Playwright E2E (push) Has been cancelled
feat(training): release V0.9.1 避障训练与基础策略迁移
2026-09-08 10:50:13 +08:00

18 KiB
Raw Blame History

Go2 基础策略迁移(普通训练、自调参、CLI)

普通训练和自调参均可选择经服务验证的基础策略。浏览器持续导航不再因20秒截止而停用;训练/三seed评估协议不变。不新增高程图,不声称短训已学会复杂障碍导航。

前端直接上传单个文件(推荐)

已安装训练依赖后,在仓库根目录执行一条默认启动命令:

.venv/bin/python training_server/server.py
  1. 打开普通训练面板或自调参工作台,将终端显示的令牌填入访问令牌,连接http://127.0.0.1:8765
  2. 在“基础策略”勾选“确认Go2 legacy47模板”,点击“选择基础策略文件”,选择单个.pt.onnx;无需注册JSON、服务器文件路径、YAML或其他sidecars。
  3. 等待上传/验证结束;完成后自动选中该文件的内容ID,检查文件名、格式、原文件SHA及初始化说明。上传中无法启动;可取消等待,同一文件可再次选择重试。
  4. 普通训练选择Flat47或Obstacle81/97,再点击“发起本地训练”;自调参保留逐轮审批/全自动选择,点击“启动自调参”。无DeepSeek配置时必须明确勾选Optuna fallback才能启动自调参;上传本身不调用Agent。
  5. 失败、取消、切换任务或更换连接不会把旧基础策略默默清空;失效/不兼容选择会阻止启动。若要从头训练,明确选择“不选择(随机初始化)”。

.pt继承actor及其归一化/探索参数;ONNX只继承确定性推理网络,缺失的count采用合成1,000,000、探索std采用新训练默认1.0,两者critic/optimizer均全新、iteration0。不是恢复原PPO训练。旧管理员注册功能仅为可选高级入口,见下文。

HTTP与安全契约

默认启动服务即可上传,不需要管理员JSON、服务器路径或邻接文件。旧注册来源仍兼容,见下文“旧CLI/注册来源”。HTTP接口沿用Host/Origin检查及Bearer令牌:

POST /api/training/pretrained-sources/upload?format=pt|onnx&template=go2-legacy47-v1&name=<URL编码显示名>

  • body为原始文件字节,Content-Type: application/octet-stream,唯一Content-Length。不是JSON/base64/multipart/ZIP;普通JSON请求仍限制128KiB。
  • 必须显式确认模板,不能只凭47维shape自动证明物理语义。模板按Go2 FL/FR/RL/RR各hip/thigh/calf解释关节,以及本文legacy47观测、50Hz、PD/default/action_scale。文件缺失的坐标系/噪声等语义来自用户确认,不声称验证了源env.yaml。
  • .pt上限256MiB、ONNX上限64MiB;单个上传/解析槽,接收总限60秒、单次阻塞最多10秒;累计快照最多32个/2GiB(包括旧来源),额外预留16MiB派生产物。临时目录由服务随机生成,显示名去路径/控制字符。接收中断/超时/校验失败清理临时文件,不登记可选来源。崩溃遗留临时目录不列入目录且计入容量,需本机维护者清理。
  • CPU子进程解析:60秒墙钟/40秒CPU、8GiB虚拟地址、16MiB输出文件、64文件描述符、无core dump、CPU单线程。.pt只用weights_only=True,检查actor完整键/shape/dtype/有限值、normalizer var/std/count、探索std及已知嵌入语义metadata;缺actor的ZIP/任意checkpoint拒绝。不是针对本机同账户恶意写入或原生库漏洞的完整沙箱。
  • 单ONNX只支持opset17/18、自包含float32 [1,47]→[1,12] 的精确9节点链:Sub、Div、Gemm/ELU/Gemm/ELU/Gemm/ELU/Gemm。校验每条连边、算子属性、initializer、I/O、关节/观测/PD/action metadata,拒绝外部data/custom op/支路/重排/额外算子;随后CPU ORT对48个随机+物理probe对照重建actoratol=rtol=2e-5)。不承诺任意ONNX可恢复PPO。
  • .pt保留原count和探索stdONNX只有确定性网络/mean/denominator,以已知模板epsilon=.01推导std=denominator-.01>0var=std²合成count=1,000,000,探索std使用经检查的目标默认1.0。两者critic/optimizer fresh、iteration0ONNX source_iteration未知,不能称为恢复原.pt训练。
  • 成功201返回与health.pretrainedSources[]同形的单个source record。ID为SHA256(template:format:原文件SHA256),文件名不参与;同时保存原文件SHA及服务派生actor.pt SHA。manifest明确sourceFormatderived_fieldstemplate_confirmationverified_facts,不把派生artifact伪装成用户原checkpoint。
  • 后续普通job和tuning session继续只传pretrainedSourceId,复用原binding/immutable SHA/CLI初始化协议。受控actor.pt--pretrained-upload-manifest加载,不扫描邻接文件;81/97首层新增列为零、统计0/1/1且可学习。rung仍只resume自身checkpoint,保存的已更新count不会重置为1e6。
  • 上传来源及manifest原子目录发布、只读快照;无注册参数重启仍能列出。重复上传返回旧record,不改label/artifact或旧job绑定;失效快照保持显式不可用,不退回随机初始化。不要删除仍被历史session引用的快照。

两面板共用PretrainedSourceSelect/LocalTrainingClient及上传控件,accept=".pt,.onnx";成功后合并服务返回的已验证record并选择内容ID,连接/任务epoch变化会取消旧请求并忽略晚到响应,不能把旧endpoint结果写入新连接。上传状态显示上传并验证中(非百分比进度);取消只停止浏览器等待,服务可能已经完成验证,可刷新查看。

本轮真实CPU证据

两个真实文件分别在空临时根以单文件上传成功,均未要求或读取相邻.pt/ONNX/YAML。双方重建actor对原ONNX的48组eval最大误差均为1.9073486e-6。真实ONNX导入及81/97扩展、非零有限梯度、保存/恢复已更新统计通过;不是PPO收敛或安全行走证明。

来源 更新batch 更新率 物理probe最大动作漂移
ptcount=983138304 4096UI默认) 4.16623e-6 2.62260e-6
pt 16384(上限) 1.66647e-5 1.04904e-5
onnx,合成count=1e6 4096 .00407929 .00254631
onnx 16384 .01611989 .01006627

以上为一次正常统计更新的实测,后续PPO可能退化,不能用更新前数值等价保证训练稳定性。

双面板×真实.pt/ONNX均经独立默认服务空上传根的浏览器文件选择验证。额外CPU真实runner使用4环境:两来源初始化对MuJoCo实际观测的原ONNX最大误差1.19209e-7ONNX-derived仅运行1次PPO iteration,新增81维输入列更新为非零,导出对runner误差4.76837e-7,同trial恢复完整actor/optimizer且count保持1000096,未重设为1e6。该检查仅证明链路,不声称导航收敛。

旧CLI/注册来源使用(仍需配套文件;不适用于单文件上传)

先激活仓库 .venv,安装 training_server/rl/requirements.txt。CPU 身份校验依赖 onnxruntime==1.29.0

# SOURCE 是管理员认可的本地训练产物目录,不是浏览器传入的任意路径。
python training_server/rl/scripts/train.py Unitree-Go2-ObstacleAvoidance \
  --pretrained-checkpoint "$SOURCE/model_10000.pt" \
  --pretrained-allowed-roots "[\"$SOURCE\"]" \
  --agent.logger tensorboard \
  --output-dir "$OUTPUT"

目录必须有 params/env.yamlparams/agent.yamlpolicy.onnx 和明确选定的 .pt。可用 --pretrained-onnx 指定允许根内的配对 ONNX;没有对应 .pt 拒绝,不把 ONNX 当成 PPO resume。不扫描/按 mtime 自动认定 model_10000 对应 ONNX;当前实际对应关系由 CPU ORT 数值验证建立。

  • --pretrained-checkpoint--resume-checkpoint / --agent.resume 互斥。
  • warm-start:新 trial 的 iteration=0;只迁移 actorcritic 和 optimizer 保持新初始化。预算仍是新训练预算。
  • resume:既有 runner.load 和 explicit-resume 的 current+1max_iterations-current 行为完全不变;同 trial successive-halving 不应再次传 pretrained 参数。
  • 原 Flat legacy47 支持迁移;81/97 支持扩展。Rough 普通训练/原 resume 不受影响,但本轮不支持从 legacy47 warm-start 到含 height scan 的 Rough,会明确拒绝。
  • 校验发生在模拟器分配前;创建环境后另核对编译后的 joint 顺序、PD、默认位姿、观测顺序与动作 scale。成功初始化时在输出目录写 initialization.json

严格迁移契约

源 actor 必须是 RSL MLPModel47→512→256→128→12、ELU、经验归一化、Gaussian scalar std。所有 state key、dtype、shape、有限值及 std/var 一致性均验证;没有 strict=False。观测语义顺序为:

base_ang_vel(3), projected_gravity(3), command(3), phase(2), joint_pos(12), joint_vel(12), actions(12)

校验 term 函数名、参数、噪声/缩放/裁剪/延迟/history、动作配置、机器人 spec 名、默认关节状态、actuator/armature/collision 配置、decimation=4 与 dt=.005。观测 corruption 开关和命令采样分布可以因导航任务改变,但基础观测的坐标/单位/顺序不变。phase 为 .6s sin/cos,命令 norm<.1 时清零;本地与源 phase 实现只差尾空行,robot XML 逐字节相同(本次只读比对)。并非宣称训练分布和导航地形完全相同。

迁移覆盖:

参数 行为
mlp.0.weight[:, :47] 原值复制
mlp.0.weight[:, 47:] 零初始化,仍 requires_grad,可由 PPO 更新
所有 MLP bias、其余 weight、distribution.std_param 原值复制
normalizer mean/var/std 前47维及标量 count 逐值复制
normalizer 新维 mean=0、var=1、std=1
源 critic/optimizer/iter 不加载,保持全新目标 critic/optimizer/iteration

归一化策略经批准为 preserve-source-count/unit-new-features。真实源 count=983138304RSL 更新率为 batch_size / 更新后 count。清 count 会让首批覆盖旧47统计,故禁止清零。新 ray∈[0,1]、heading∈[-1,1]、distance∈[0,1] 原本有界;使用近 identity 初始化(实际除以 std+.01),继承原算法缓慢更新,不是完全冻结。不引入 split normalizer、不改变 checkpoint 格式。

初始化等价在 eval / 未更新统计时验证。统计更新后不是要求动作数学上不变,而是必须与原47 actor执行相同统计更新后的动作一致,且变化无突变。48组含分布外随机 gravity 的探针实测最大变化9.06e-5;真实4env首batch变化0。

可选旧管理员注册来源并在两种面板使用

注册JSON由管理员在本机配置,不是HTTP请求。以下直接使用本次用户提供的源目录(只读,不改原文件):

source .venv/bin/activate
export SOURCE=/home/cen/Embodied_Workspace/unitree_rl_mjlab/logs/rsl_rl/go2_velocity/2026-08-25_Go2
export SOURCE_CONFIG=/tmp/go2-pretrained-sources.json
python - <<'PYCONFIG'
import json, os
from pathlib import Path
root = Path(os.environ["SOURCE"])
Path(os.environ["SOURCE_CONFIG"]).write_text(json.dumps({
    "allowedRoots": [str(root)],
    "sources": [{"id": "go2-base", "label": "Go2已训练基础行走策略",
                 "checkpoint": str(root / "model_10000.pt"),
                 "onnx": str(root / "policy.onnx")}]
}, ensure_ascii=False, indent=2))
PYCONFIG
python training_server/server.py --trainer-python "$VIRTUAL_ENV/bin/python" \
  --pretrained-sources "$SOURCE_CONFIG" \
  --tuning-data-root "$HOME/.local/share/mujoco-go2-training"
  1. 复制服务显示的访问令牌,在普通训练面板连接服务,或在自调参工作台连接同一服务。
  2. 在“基础策略”选择已验证条目,检查model_10000.pt及checkpoint/ONNX完整SHA、兼容任务和观测维度。两面板默认不选,保留原随机训练行为。
  3. 选择Flat47或Obstacle81/97Rough显示不兼容并由服务拒绝。不兼容/失效来源须显式处理,不可静默清空后退回随机初始化。
  4. 普通训练点击“发起本地训练”;自调参选择Approval/Automatic后启动。基础策略不是LLM可调字段;每个新trial(含baseline)使用同一快照与相同session seed的新critic/optimizer初始化协议。后续rung只加载该trial自己的checkpoint,不覆盖成原基础权重。

允许根只能来自管理员JSON,不能来自浏览器;最多32注册条目。服务对路径各级使用dir_fd/O_NOFOLLOW,拒绝symlink、穿越、FIFO、目录与超限文件(pt256MiB/ONNX64MiB/env2MiB/agent128KiB)。CPU子进程只使用受限YAML与torch.load(weights_only=True)验证形状、语义和ONNX数值身份。未知object/apply、重复键、不匹配配置或缺.pt均拒绝;不逆向ONNX恢复PPO,也不按mtime猜checkpoint。

验证后原始四件产物复制到<tuning-data-root>/pretrained_sources/<source_id>/内容寻址只读快照。浏览器提交的pretrainedSourceId是目录返回的内容SHA身份,不是管理员可读别名或文件路径;同一别名重新注册了不同文件时,旧UI的内容ID会拒绝,必须刷新。注册之后原文件变化不改变已有job/session;每次启动trial都重新核验快照SHA,CLI还核验期望source_id。勿删除有历史session依赖的快照。管理员仍须保护数据根;这是常规文件/反序列化防护,不是任意ONNX计算或同账户恶意写入的完整沙箱。

session的SQLite config持久化完整无路径来源描述,旧session无该字段仍走原默认。服务重启会将queued/running/evaluating/paused/awaiting_approval标记interrupted并记录原state,不自动训练或调用Agent;必须用户显式恢复。恢复只清理不完整trial,保留完整评估/来源/约束版本/mode。遗留pending proposal以service_restart/recovery_invalidated审计拒绝(非用户拒绝),重新提案后Approval仍需审批;已批准历史不改。来源快照丢失/损坏时恢复排队前拒绝。连续resume请求不会启动两个worker。

源manifest/迁移覆盖写入initialization.jsonsource-bound rung要求父checkpoint的来源记录匹配。最佳ONNX的pretrained_initializationmetadata仅含SHA/source ID、源迭代、normalizer协议与initialIteration=0,不含本地路径或任意checkpoint infos。

持续点击导航

仅Obstacle81/97启用配套地图点击导航,不给普通Flat47增加非同构导航地图模式。浏览器没有20秒交互截止,但跌倒/越界仍安全停止;需用户重置并重新启用。设定新目标不重新加载策略、不改变单inflight/held-action机制,也不会自动启用已停止策略。面板明确显示策略未启用、仿真暂停或安全停止。训练与固定三seed/1000步(20秒)评估不变。

真实源warm-start81在WASM/ORT中21.02秒仍启用:从x=-5走到2.566;换目标使command从vx=.598/yaw=-.077变为vx=0/yaw=1。25.04秒仍启用,距新目标从2.828m降到2.243m;无teleport、脚本轨迹或constant actor。此为空旷plane单例,不证明复杂障碍泛化或导航收敛。

验证

python -m unittest discover -s training_server/tests -p test_pretrained.py -v
# 可选真实源;不硬编码用户个人目录到源码:
GO2_PRETRAINED_SOURCE="$SOURCE" \
GO2_PRETRAINED_EVIDENCE_DIR="$EVIDENCE" \
python -m unittest discover -s training_server/tests -p test_pretrained.py -v
# 可选仅4env×1iteration GPU初始化/优化/导出/重载烟测:
GO2_PRETRAINED_GPU_SMOKE=1 MUJOCO_GL=egl \
GO2_PRETRAINED_SOURCE="$SOURCE" GO2_PRETRAINED_EVIDENCE_DIR="$EVIDENCE" \
python -m unittest discover -s training_server/tests -p test_pretrained.py -v

本次真实源:checkpoint SHA d94eebd23be8b3cc998b493fe056a9e60ceaf4705900320015f30387412a4ffbONNX SHA 80150119e93ce2f656625fc3048ece43ec1281fcdfe9109e07a0157438d0df7c

  • 源 ORT vs checkpoint 48 probe 最大误差 1.9073486328125e-6
  • 47→47/81/97、不同ray/goalCPU初始化最大误差0;扩展81/97的CPU ONNX导出最大误差 1.9073486328125e-6
  • 真实4env源ONNX vs 扩展actor最大误差 3.427267074584961e-7;首batch基础mean变化 4.190951585769653e-9,动作变化0。
  • 新列梯度最大 .0273208;单iteration PPO后新列weight最大 .00291905critic/optimizer得到更新。
  • 新runner加载保存checkpoint后全部actor张量精确恢复,count=983138404;导出ONNX最大误差 4.76837158203125e-7
  • 安全失败例:越界路径/逃逸symlink、unsafe YAML、未知观测语义/phase/scale/armature、坏shape/NaN/std、错误actor身份、warmstart+resume混用。

这些是初始化和优化步骤证据,不等于导航收敛/到达率验证。完整命令日志和源manifest在本次交接的 /tmp/go2-pretrained-core-*/ 工件目录。

浏览器实产物复核(不再次训练)

本次保留的真实warm-start产物为 /tmp/go2-pretrained-integration-Yqhm9K/train/policy.onnxsource SHA及新迭代0可从同目录initialization.json核对。下列测试需Vite开发服务(动态导入真实PhysicsAdapter);另一个终端启动后运行:

npm run dev -- --host 127.0.0.1 --port 4174
# 在另一个终端:
GO2_PRETRAINED_DEV_URL=http://127.0.0.1:4174 \
GO2_PRETRAINED_NAV_POLICY=/tmp/go2-pretrained-integration-Yqhm9K/train/policy.onnx \
npx playwright test -c web_platform/playwright.config.ts web_platform/e2e/pretrainedNavigation.spec.ts

原始47维Flat UI兼容测试还可设置GO2_PRETRAINED_FLAT_POLICYGO2_PRETRAINED_FLAT_XML。后者必须是带12个有效actuator、采用既有FL_hip等绑定名称的Go2模型;裸训练XML本来不含actuator,会明确拒绝。此次/tmp/go2-pretrained-integration-Yqhm9K/go2-flat.xml由本地Entity(get_go2_robot_cfg())导出,保留源PD/armature,仅把actuator标识改为actuator.target.removesuffix('_joint')以匹配既有浏览器命名;没有修改生产模型或为Flat新增点击导航。Flat此测试只证明加载/推理兼容;持续行走/换目标证据来自上述真实81维warm-start产物。