第 8 章 评估与策略导出¶
训练曲线好看,不等于策略能上真机。评估是把训练产物放到"只执行、不学习"的回路上重新量一遍,导出是把它从 Python/torch 运行时里剥出来,变成真机(或 C++/边缘设备)能直接跑的张量图。本章讲评估的 play 流程与指标口径、无头批量评估,再把策略导出成 TorchScript 与 ONNX,并给一组导出后的推理时延数据。
1. 评估:play 与指标¶
isaaclab play 载入 checkpoint、构建 get_inference_policy(去掉探索噪声的确定性动作),在向量化环境里纯 rollout。在运行环境 Newton/MJWarp 后端上,对第 5 章训好的 cartpole checkpoint 跑一次离屏评估可正常加载并持续步进:
uv run isaaclab play \
--rl_library rsl_rl \
--task Isaac-Cartpole-Direct-v0 \
--checkpoint logs/rsl_rl/cartpole_direct/<时间戳>/model_299.pt \
--num_envs 256 --viz none \
physics=newton_mjwarp
一个关键口径:play 本身不打印训练那种每代指标表,它只是把策略跑起来(有可视化时看行为,无头时步进直到终止)。真正要"量得出"的聚合指标,来源有三:
- 训练期末的
success_rate/Mean episode length(第 5 章:末代 reward≈4.95、episode 撑满 300、success 1.0)——这是收敛性的第一手证据。 - 评估期重设
play_mode:resolve_task_config(..., play_mode=True)会套用环境定义的"评估态"覆写(关探索噪声、放开ObsTerm.noise、常开终止),评估口径与训练不同,须在其下重测。 - recorder manager:
recorder_manager+isaaclab.utils.datasets的EpisodeData/HDF5 handler,把评估回合的观测/动作/成功逐条落盘,供离线批量统计。
训练收敛不等于策略可用:训练末的 reward 是在当前域配置下的均值;策略可用性要在评估态(关探索、必要时提难度/加扰动)下看回合成功率与鲁棒性,二者口径不同。
2. 无头模式与批量评估¶
无头(--viz none、或渲染关闭)是批量评估的前提——不占渲染资源,才能一次 rollout 大批环境做统计。批量评估的标准做法:固定种子、num_envs 取显存预算内的大值(第 4 章),跑足够多的回合数,用 recorder 落盘后聚合成功率/回报分布/失败原因,而非只看单条曲线。复现口径由 --seed 与 configure_seed 保证(第 5 章),注意 GPU 并行下逐位不保证一致,比对以统计量为准。
坑:递归策略的隐状态也要导出
含 LSTM/GRU 的策略由包装器的 forward_lstm/forward_gru 显式处理隐状态,导出的图带隐状态输入输出;只搬权重不搬状态,部署端序列就断了。
3. 策略导出:TorchScript 与 ONNX¶
Isaac Lab 的 RSL-RL 导出把训练好的 actor 网络单独序列化成部署格式。play 在加载 checkpoint 后会自动调用导出,落到该次日志的 exported/ 目录:
## runner.export_policy_to_jit + export_policy_to_onnx(play 内触发)
## 产出:
## exported/policy.pt # TorchScript
## exported/policy.onnx # ONNX
底层是 rsl_rl 运行器的导出方法(也是 play 内调用的),它们封装 isaaclab_rl.rsl_rl.exporter 里的序列化函数:
## 由运行器提供(play 即调用以下两个方法):
runner.export_policy_to_jit(path=export_model_dir, filename="policy.pt") # TorchScript
runner.export_policy_to_onnx(path=export_model_dir, filename="policy.onnx") # ONNX
## 底层序列化函数位于 isaaclab_rl.rsl_rl.exporter:export_policy_as_jit / export_policy_as_onnx
导出用一个包装模块(_TorchPolicyExporter / _OnnxPolicyExporter)把"观测归一化 + 前向"烤进图里,因此部署端无需再挂归一化层;含 LSTM/GRU 的递归策略也在包装器里显式处理隐状态(forward_lstm/forward_gru),导出的图带隐状态输入输出。
导出产物(第 5 章 cartpole,观测维 4、动作维 1 的 MLP):exported/policy.onnx 约 8.5 KB、exported/policy.pt 约 16.5 KB——轻量网络导出的张量图很小,可直接随真机程序分发,不必携带 Python 依赖。
导出通路(play 内自动触发,落到该次日志的 exported/):
flowchart LR
play["play 加载 checkpoint"] --> exp["runner.export_policy_to_jit / _onnx"]
exp --> jit["exported/policy.pt<br/>TorchScript"]
exp --> onnx["exported/policy.onnx"]
jit --> dep["部署端<br/>归一化已烤进图,无需额外层"]
onnx --> dep
判据:轻量策略的瓶颈在观测拼装
单步前向在微秒量级,远小于典型控制周期;真机上的时间花在观测拼装与通信,优化优先级应按这条链路排。
4. 导出后推理时延¶
用 torch.jit.load 载入导出的 policy.pt,对单环境(batch=1)纯前向计时(预热后取均值,运行环境同一台 RTX 5070 Ti):
| 执行器 | 单环境每步时延 | 折算频率 |
|---|---|---|
| CPU(TorchScript) | 约 8.8 µs | 约 113 kHz |
| CUDA(TorchScript,batch=1) | 约 26.6 µs | 约 37.6 kHz |
一条与直觉相反的判据:策略很小时,GPU 推理反而比 CPU 慢——因为 batch=1 下 CUDA kernel 启动开销主导,算力用不上。结论是:单机器人、控制频率几十到几百 Hz 的部署,纯 CPU 推理余量极大(8.8 µs 对应 500 Hz 控制周期只用掉约 0.4% 的时间预算);GPU 推理要等到把许多机器人/环境攒成大批次才划算。导出时延要与仿真 dt、真机控制周期对照看:推理须远小于控制周期,才不会成为回路瓶颈。
这组数字是"判据级"的单步纯前向,不含传感器读取、通信与执行器下发——真机回路时延另需端到端测(第 9 章)。
5. 部署图与 LEAPP(一句分界)¶
除上面的 jit/onnx 导出,isaaclab export / isaaclab deploy 还挂着一套 LEAPP 部署图工作流(isaaclab.utils.leapp,把策略与前后处理编成可部署的计算图,带 --export_method、--validation_steps、图可视化)。
它面向更完整的部署打包,且 --export_method 仅对 manager-based 环境生效。LEAPP 是另一条导出线,端到端部署由 Isaac Sim 侧的运行环境承接;本节的 exported/policy.{pt,onnx} 是可复现的导出路径,二者产物形态与适用环节不同,勿混。验证要在目标设备上做而不是在训练机上:算子融合与精度路径不同,同一个 onnx 在两处的时延可相差数倍。
6. 要点¶
play载入 checkpoint 纯 rollout、不打印聚合指标;"量得出"靠训练末 success/episode、评估态play_mode覆写与 recorder 落盘三条来源。"训练收敛 = 策略可用"不成立,须评估态重测鲁棒性。- 无头(
--viz none)是批量评估前提;固定种子、大num_envs、多回合,用 recorder 聚合成功率与失败分布,GPU 并行下比对以统计量为准。 - RSL-RL 导出
export_policy_as_jit/export_policy_as_onnx,play触发写到exported/policy.{pt,onnx};包装器内联观测归一化并处理递归隐状态,产物极小(cartpole 约 8.5/16.5 KB)。 - 单环境推理时延:CPU 约 8.8 µs、CUDA 约 26.6 µs——小策略下 GPU 因启动开销反慢于 CPU;单机器人控制 CPU 余量充足,时延须对照
dt/控制周期。 isaaclab export/deploy的 LEAPP 部署图是另一条导出线(manager-based 限定),面向带前后处理的完整部署打包,与exported/policy.{pt,onnx}的产物形态不同。