开动
强烈推荐张老师系列:张伟楠老师的动手学强化学习- PPO
目前完成了基于宇树rl_lab的RL仿真训练复现,踩了一些比较低级错误的坑后,发现纯RL的效果比预期的要好,算是pipeline流程通了,开始了解实现原理。
在智驾中,RL也已经实现了量产落地,能够在专家数据基础上实现性能拓展,效果还是很显著的。
拿unitree_rl_lab作为学习入口:
RSL-RL 做什么、PPO 和 Distillation 两条训练链路怎么跑、它如何接入 Unitree/Isaac Lab 任务,以及应该从哪些文件开始读。
好家伙:用的GPT5.5直出的图,很奈斯
1. 一句话理解 RSL-RL
extern/rsl_rl 是一个面向机器人强化学习的轻量 PyTorch 训练库。它不负责创建机器人环境、写奖励函数或管理仿真资产;这些由 Isaac Lab、Unitree RL Lab、Legged Gym 等环境库负责。RSL-RL 的职责是:
- 从环境批量采样交互数据。
- 把采样结果存入 rollout buffer。
- 用 PPO 或蒸馏算法更新策略网络。
- 记录日志、保存 checkpoint、导出 JIT/ONNX 策略。
换句话说:
text
环境库负责"机器人世界"
RSL-RL 负责"怎么学习"
2. 训练系统总览:两条主线
RSL-RL 不只有 PPO。当前源码里最重要的两条主线是:
| 主线 | 算法 | 典型用途 |
|---|---|---|
| On-policy RL | PPO |
直接通过环境 reward 学策略,例如 locomotion 速度跟踪 |
| Student-Teacher | Distillation |
让 student 模仿 teacher,把 privileged policy 压到可部署观测上 |
PPO 主流程:
#mermaid-svg-SeiKSSRzgJVUGTHr{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-SeiKSSRzgJVUGTHr .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-SeiKSSRzgJVUGTHr .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-SeiKSSRzgJVUGTHr .error-icon{fill:#552222;}#mermaid-svg-SeiKSSRzgJVUGTHr .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-SeiKSSRzgJVUGTHr .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-SeiKSSRzgJVUGTHr .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-SeiKSSRzgJVUGTHr .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-SeiKSSRzgJVUGTHr .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-SeiKSSRzgJVUGTHr .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-SeiKSSRzgJVUGTHr .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-SeiKSSRzgJVUGTHr .marker{fill:#333333;stroke:#333333;}#mermaid-svg-SeiKSSRzgJVUGTHr .marker.cross{stroke:#333333;}#mermaid-svg-SeiKSSRzgJVUGTHr svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-SeiKSSRzgJVUGTHr p{margin:0;}#mermaid-svg-SeiKSSRzgJVUGTHr .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-SeiKSSRzgJVUGTHr .cluster-label text{fill:#333;}#mermaid-svg-SeiKSSRzgJVUGTHr .cluster-label span{color:#333;}#mermaid-svg-SeiKSSRzgJVUGTHr .cluster-label span p{background-color:transparent;}#mermaid-svg-SeiKSSRzgJVUGTHr .label text,#mermaid-svg-SeiKSSRzgJVUGTHr span{fill:#333;color:#333;}#mermaid-svg-SeiKSSRzgJVUGTHr .node rect,#mermaid-svg-SeiKSSRzgJVUGTHr .node circle,#mermaid-svg-SeiKSSRzgJVUGTHr .node ellipse,#mermaid-svg-SeiKSSRzgJVUGTHr .node polygon,#mermaid-svg-SeiKSSRzgJVUGTHr .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-SeiKSSRzgJVUGTHr .rough-node .label text,#mermaid-svg-SeiKSSRzgJVUGTHr .node .label text,#mermaid-svg-SeiKSSRzgJVUGTHr .image-shape .label,#mermaid-svg-SeiKSSRzgJVUGTHr .icon-shape .label{text-anchor:middle;}#mermaid-svg-SeiKSSRzgJVUGTHr .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-SeiKSSRzgJVUGTHr .rough-node .label,#mermaid-svg-SeiKSSRzgJVUGTHr .node .label,#mermaid-svg-SeiKSSRzgJVUGTHr .image-shape .label,#mermaid-svg-SeiKSSRzgJVUGTHr .icon-shape .label{text-align:center;}#mermaid-svg-SeiKSSRzgJVUGTHr .node.clickable{cursor:pointer;}#mermaid-svg-SeiKSSRzgJVUGTHr .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-SeiKSSRzgJVUGTHr .arrowheadPath{fill:#333333;}#mermaid-svg-SeiKSSRzgJVUGTHr .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-SeiKSSRzgJVUGTHr .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-SeiKSSRzgJVUGTHr .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-SeiKSSRzgJVUGTHr .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-SeiKSSRzgJVUGTHr .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-SeiKSSRzgJVUGTHr .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-SeiKSSRzgJVUGTHr .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-SeiKSSRzgJVUGTHr .cluster text{fill:#333;}#mermaid-svg-SeiKSSRzgJVUGTHr .cluster span{color:#333;}#mermaid-svg-SeiKSSRzgJVUGTHr div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-SeiKSSRzgJVUGTHr .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-SeiKSSRzgJVUGTHr rect.text{fill:none;stroke-width:0;}#mermaid-svg-SeiKSSRzgJVUGTHr .icon-shape,#mermaid-svg-SeiKSSRzgJVUGTHr .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-SeiKSSRzgJVUGTHr .icon-shape p,#mermaid-svg-SeiKSSRzgJVUGTHr .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-SeiKSSRzgJVUGTHr .icon-shape .label rect,#mermaid-svg-SeiKSSRzgJVUGTHr .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-SeiKSSRzgJVUGTHr .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-SeiKSSRzgJVUGTHr .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-SeiKSSRzgJVUGTHr :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} get_observations
obs
Actor 采样 action
obs, reward, done, extras
更新 Actor / Critic
Isaac Lab / Unitree 环境
OnPolicyRunner
PPO.act
PPO.process_env_step
RolloutStorage
PPO.compute_returns
GAE
PPO.update
Logger / checkpoint / export
Distillation 主流程:
#mermaid-svg-f4WGP0sBJXljIk6t{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-f4WGP0sBJXljIk6t .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-f4WGP0sBJXljIk6t .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-f4WGP0sBJXljIk6t .error-icon{fill:#552222;}#mermaid-svg-f4WGP0sBJXljIk6t .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-f4WGP0sBJXljIk6t .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-f4WGP0sBJXljIk6t .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-f4WGP0sBJXljIk6t .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-f4WGP0sBJXljIk6t .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-f4WGP0sBJXljIk6t .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-f4WGP0sBJXljIk6t .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-f4WGP0sBJXljIk6t .marker{fill:#333333;stroke:#333333;}#mermaid-svg-f4WGP0sBJXljIk6t .marker.cross{stroke:#333333;}#mermaid-svg-f4WGP0sBJXljIk6t svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-f4WGP0sBJXljIk6t p{margin:0;}#mermaid-svg-f4WGP0sBJXljIk6t .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-f4WGP0sBJXljIk6t .cluster-label text{fill:#333;}#mermaid-svg-f4WGP0sBJXljIk6t .cluster-label span{color:#333;}#mermaid-svg-f4WGP0sBJXljIk6t .cluster-label span p{background-color:transparent;}#mermaid-svg-f4WGP0sBJXljIk6t .label text,#mermaid-svg-f4WGP0sBJXljIk6t span{fill:#333;color:#333;}#mermaid-svg-f4WGP0sBJXljIk6t .node rect,#mermaid-svg-f4WGP0sBJXljIk6t .node circle,#mermaid-svg-f4WGP0sBJXljIk6t .node ellipse,#mermaid-svg-f4WGP0sBJXljIk6t .node polygon,#mermaid-svg-f4WGP0sBJXljIk6t .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-f4WGP0sBJXljIk6t .rough-node .label text,#mermaid-svg-f4WGP0sBJXljIk6t .node .label text,#mermaid-svg-f4WGP0sBJXljIk6t .image-shape .label,#mermaid-svg-f4WGP0sBJXljIk6t .icon-shape .label{text-anchor:middle;}#mermaid-svg-f4WGP0sBJXljIk6t .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-f4WGP0sBJXljIk6t .rough-node .label,#mermaid-svg-f4WGP0sBJXljIk6t .node .label,#mermaid-svg-f4WGP0sBJXljIk6t .image-shape .label,#mermaid-svg-f4WGP0sBJXljIk6t .icon-shape .label{text-align:center;}#mermaid-svg-f4WGP0sBJXljIk6t .node.clickable{cursor:pointer;}#mermaid-svg-f4WGP0sBJXljIk6t .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-f4WGP0sBJXljIk6t .arrowheadPath{fill:#333333;}#mermaid-svg-f4WGP0sBJXljIk6t .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-f4WGP0sBJXljIk6t .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-f4WGP0sBJXljIk6t .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-f4WGP0sBJXljIk6t .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-f4WGP0sBJXljIk6t .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-f4WGP0sBJXljIk6t .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-f4WGP0sBJXljIk6t .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-f4WGP0sBJXljIk6t .cluster text{fill:#333;}#mermaid-svg-f4WGP0sBJXljIk6t .cluster span{color:#333;}#mermaid-svg-f4WGP0sBJXljIk6t div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-f4WGP0sBJXljIk6t .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-f4WGP0sBJXljIk6t rect.text{fill:none;stroke-width:0;}#mermaid-svg-f4WGP0sBJXljIk6t .icon-shape,#mermaid-svg-f4WGP0sBJXljIk6t .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-f4WGP0sBJXljIk6t .icon-shape p,#mermaid-svg-f4WGP0sBJXljIk6t .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-f4WGP0sBJXljIk6t .icon-shape .label rect,#mermaid-svg-f4WGP0sBJXljIk6t .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-f4WGP0sBJXljIk6t .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-f4WGP0sBJXljIk6t .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-f4WGP0sBJXljIk6t :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} get_observations
obs
student action
teacher target action
obs, reward, done, extras
只更新 student
Isaac Lab / Unitree 环境
DistillationRunner
Distillation.act
RolloutStorage
Distillation.process_env_step
Distillation.update
behavior cloning loss
这个图对应的核心源码是:
| 职责 | 文件 | 应先读的方法 |
|---|---|---|
| 训练主循环 | extern/rsl_rl/rsl_rl/runners/on_policy_runner.py |
OnPolicyRunner.__init__()、learn() |
| PPO 算法 | extern/rsl_rl/rsl_rl/algorithms/ppo.py |
act()、process_env_step()、compute_returns()、update() |
| 蒸馏 Runner | extern/rsl_rl/rsl_rl/runners/distillation_runner.py |
learn() |
| 蒸馏算法 | extern/rsl_rl/rsl_rl/algorithms/distillation.py |
act()、process_env_step()、update() |
| Rollout 缓冲区 | extern/rsl_rl/rsl_rl/storage/rollout_storage.py |
add_transition()、mini_batch_generator() |
| 默认 MLP 网络 | extern/rsl_rl/rsl_rl/models/mlp_model.py |
__init__()、forward()、get_latent() |
| 环境接口 | extern/rsl_rl/rsl_rl/env/vec_env.py |
VecEnv.get_observations()、VecEnv.step() |
3. RSL-RL 的目录结构
text
extern/rsl_rl/
├── rsl_rl/
│ ├── algorithms/ # PPO、Distillation 等算法
│ ├── runners/ # 训练入口和主循环
│ ├── storage/ # rollout buffer
│ ├── models/ # MLP / RNN / CNN 模型封装
│ ├── modules/ # MLP、分布、归一化、RNN 等网络积木
│ ├── env/ # VecEnv 抽象接口
│ ├── extensions/ # RND、Symmetry 等扩展
│ └── utils/ # 日志、配置解析、导出辅助
├── docs/ # 官方文档
├── tests/ # 单元测试
├── pyproject.toml # Python 包定义
└── README.md
初学者先不要从 modules/ 开始读。PPO 推荐路径是:
text
OnPolicyRunner.learn()
-> PPO.act()
-> PPO.process_env_step()
-> RolloutStorage.add_transition()
-> PPO.compute_returns()
-> PPO.update()
-> MLPModel.forward()
Distillation 推荐路径是:
text
DistillationRunner.learn()
-> OnPolicyRunner.learn()
-> Distillation.act()
-> Distillation.process_env_step()
-> RolloutStorage.add_transition()
-> Distillation.update()
-> MLPModel.forward()
4. RSL-RL 需要环境提供什么
RSL-RL 只依赖一个抽象环境接口:VecEnv。
环境必须提供这些属性:
text
num_envs 并行环境数量
num_actions 动作维度
max_episode_length episode 最大长度
episode_length_buf 每个环境当前 episode 长度
device 环境所在设备
cfg 环境配置
环境必须实现两个方法:
python
obs = env.get_observations()
obs, rewards, dones, extras = env.step(actions)
其中 obs 不是普通 Tensor,而是 TensorDict。它通常包含多个 observation group,例如:
text
obs["policy"] # actor 可见观测
obs["critic"] # critic 可见观测,通常包含特权信息
RSL-RL 再通过 obs_groups 决定 actor 和 critic 各自读取哪些组:
python
obs_groups = {
"actor": ["policy"],
"critic": ["critic"],
}
这是理解 Isaac Lab 接入 RSL-RL 的关键点:环境产生多个观测组,RSL-RL 的模型按配置选择并拼接这些观测组。
5. Runner:训练总控
OnPolicyRunner 是 RSL-RL 的通用 on-policy 训练入口;DistillationRunner 继承它,只额外检查 teacher 参数是否已经加载。创建 runner 时,它会:
- 保存环境、训练配置和训练设备。
- 读取一次
env.get_observations(),用来推断观测维度。 - 根据配置创建算法、模型和 rollout storage。PPO 创建 actor/critic,Distillation 创建 student/teacher。
- 创建 logger。
主循环在 learn() 中:
#mermaid-svg-MVoj8SdV31YUYz90{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MVoj8SdV31YUYz90 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MVoj8SdV31YUYz90 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MVoj8SdV31YUYz90 .error-icon{fill:#552222;}#mermaid-svg-MVoj8SdV31YUYz90 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MVoj8SdV31YUYz90 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MVoj8SdV31YUYz90 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MVoj8SdV31YUYz90 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MVoj8SdV31YUYz90 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MVoj8SdV31YUYz90 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MVoj8SdV31YUYz90 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MVoj8SdV31YUYz90 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MVoj8SdV31YUYz90 .marker.cross{stroke:#333333;}#mermaid-svg-MVoj8SdV31YUYz90 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MVoj8SdV31YUYz90 p{margin:0;}#mermaid-svg-MVoj8SdV31YUYz90 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-MVoj8SdV31YUYz90 .cluster-label text{fill:#333;}#mermaid-svg-MVoj8SdV31YUYz90 .cluster-label span{color:#333;}#mermaid-svg-MVoj8SdV31YUYz90 .cluster-label span p{background-color:transparent;}#mermaid-svg-MVoj8SdV31YUYz90 .label text,#mermaid-svg-MVoj8SdV31YUYz90 span{fill:#333;color:#333;}#mermaid-svg-MVoj8SdV31YUYz90 .node rect,#mermaid-svg-MVoj8SdV31YUYz90 .node circle,#mermaid-svg-MVoj8SdV31YUYz90 .node ellipse,#mermaid-svg-MVoj8SdV31YUYz90 .node polygon,#mermaid-svg-MVoj8SdV31YUYz90 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MVoj8SdV31YUYz90 .rough-node .label text,#mermaid-svg-MVoj8SdV31YUYz90 .node .label text,#mermaid-svg-MVoj8SdV31YUYz90 .image-shape .label,#mermaid-svg-MVoj8SdV31YUYz90 .icon-shape .label{text-anchor:middle;}#mermaid-svg-MVoj8SdV31YUYz90 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MVoj8SdV31YUYz90 .rough-node .label,#mermaid-svg-MVoj8SdV31YUYz90 .node .label,#mermaid-svg-MVoj8SdV31YUYz90 .image-shape .label,#mermaid-svg-MVoj8SdV31YUYz90 .icon-shape .label{text-align:center;}#mermaid-svg-MVoj8SdV31YUYz90 .node.clickable{cursor:pointer;}#mermaid-svg-MVoj8SdV31YUYz90 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MVoj8SdV31YUYz90 .arrowheadPath{fill:#333333;}#mermaid-svg-MVoj8SdV31YUYz90 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MVoj8SdV31YUYz90 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MVoj8SdV31YUYz90 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MVoj8SdV31YUYz90 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MVoj8SdV31YUYz90 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MVoj8SdV31YUYz90 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MVoj8SdV31YUYz90 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MVoj8SdV31YUYz90 .cluster text{fill:#333;}#mermaid-svg-MVoj8SdV31YUYz90 .cluster span{color:#333;}#mermaid-svg-MVoj8SdV31YUYz90 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MVoj8SdV31YUYz90 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MVoj8SdV31YUYz90 rect.text{fill:none;stroke-width:0;}#mermaid-svg-MVoj8SdV31YUYz90 .icon-shape,#mermaid-svg-MVoj8SdV31YUYz90 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MVoj8SdV31YUYz90 .icon-shape p,#mermaid-svg-MVoj8SdV31YUYz90 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MVoj8SdV31YUYz90 .icon-shape .label rect,#mermaid-svg-MVoj8SdV31YUYz90 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MVoj8SdV31YUYz90 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MVoj8SdV31YUYz90 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MVoj8SdV31YUYz90 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 开始一个 iteration
循环 num_steps_per_env 次
PPO.act 采样动作
env.step 执行动作
PPO.process_env_step 写入 transition
PPO.compute_returns
PPO.update
log / save
关键配置:
python
num_steps_per_env = 24
save_interval = 100
max_iterations = 50000
在 Unitree RL Lab 的 G1 locomotion PPO 配置中,这些值位于:
text
extern/unitree_rl_lab/source/unitree_rl_lab/unitree_rl_lab/tasks/locomotion/agents/rsl_rl_ppo_cfg.py
Isaac Lab 也提供 Distillation 配置示例:
text
extern/isaac_lab/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/anymal_d/agents/rsl_rl_distillation_cfg.py
6. PPO:一次训练迭代内部发生了什么
PPO 在 RSL-RL 中分成四个核心步骤。
6.1 act():采样动作并记录旧策略信息
PPO.act(obs) 做四件事:
- actor 根据当前 obs 采样动作。
- critic 估计当前状态价值
V(s)。 - 记录动作在旧策略下的
log_prob。 - 记录 actor 分布参数,供后续 PPO ratio/KL 使用。
示意:
text
obs
├─ actor -> action, log_prob, distribution params
└─ critic -> value
注意:PPO 更新时需要比较"采样动作时的旧策略"和"当前更新后的新策略",所以 rollout 阶段必须存 old_log_prob 和旧分布参数。
6.2 process_env_step():处理环境返回
process_env_step(obs, rewards, dones, extras) 在每次 env.step() 后执行,主要负责:
- 更新 actor/critic 的 observation normalizer。
- 记录 reward 和 done。
- 如果启用 RND,加入 intrinsic reward。
- 如果
extras中有time_outs,对时间截断做 bootstrap。 - 将 transition 写入
RolloutStorage。 - 根据 done 重置 actor/critic 的 recurrent state。
time_outs 很重要:如果 episode 是因为时间上限结束,而不是机器人摔倒或任务失败结束,那么理论上不应该把它当作真实 terminal。RSL-RL 会用 critic value 对 reward 做补偿:
text
reward += gamma * V(s) * time_out
6.3 compute_returns():计算 GAE
rollout 收集完成后,PPO 从最后一步往前计算:
text
delta_t = r_t + gamma * V(s_{t+1}) - V(s_t)
adv_t = delta_t + gamma * lambda * adv_{t+1}
return = adv_t + V(s_t)
其中:
| 参数 | 含义 |
|---|---|
gamma |
折扣因子,越接近 1 越看重长期回报 |
lam |
GAE 平滑系数,控制 bias/variance 权衡 |
Unitree G1 默认配置一般是:
python
gamma = 0.99
lam = 0.95
6.4 update():PPO 多轮小批量更新
PPO 更新时会把 rollout buffer 展平:
text
[num_steps_per_env, num_envs, ...]
-> [num_steps_per_env * num_envs, ...]
然后分成 num_mini_batches,重复 num_learning_epochs 轮。
核心 loss:
text
ratio = exp(new_log_prob - old_log_prob)
surrogate_1 = -advantage * ratio
surrogate_2 = -advantage * clamp(ratio, 1 - clip, 1 + clip)
actor_loss = max(surrogate_1, surrogate_2)
value_loss = MSE(V(s), return)
loss = actor_loss + value_coef * value_loss - entropy_coef * entropy
这就是 PPO 的"保守更新":如果新策略相对旧策略变化太大,clip_param 会限制收益,避免一步把策略推坏。
7. Distillation:学生-老师蒸馏
Distillation 是 RSL-RL 的第二条重要训练链路。它不是通过 reward 优化策略,而是让 student 模仿 teacher 的动作。典型用途是:先训练一个能看到 privileged observation 的强 teacher,再把行为蒸馏到只看部署可用观测的 student 上。
核心关系:
text
obs
├─ student -> action,用于 env.step
└─ teacher -> privileged_actions,作为监督目标
loss = mse(student_action, teacher_action)
# 或 huber loss
7.1 Distillation.act():student 行动,teacher 给标签
Distillation.act(obs) 做三件事:
- student 根据当前 obs 生成动作,并用这个动作推进环境。
- teacher 根据当前 obs 生成目标动作
privileged_actions。 - 把 obs、student action、teacher target 暂存在 transition 中。
这里的关键约束是:环境里真正执行的是 student action,teacher 只提供监督信号。
7.2 process_env_step():记录 transition
Distillation 仍然会接收 rewards、dones、extras,但它不使用 reward 来计算 return 或 advantage。reward 主要用于日志和环境侧统计;done 用来重置 student/teacher 的 recurrent state。
RolloutStorage 在 distillation 模式下会额外保存:
text
privileged_actions # teacher 输出的动作标签
7.3 compute_returns():空操作
Distillation 不做 GAE,也不需要 critic value target,所以 compute_returns() 是 no-op。
7.4 update():行为克隆更新 student
更新阶段从 storage 按时间步取数据:
text
student_actions = student(observations)
behavior_loss = mse(student_actions, privileged_actions)
然后只更新 student。teacher 保持 eval mode,不参与梯度更新。
关键参数:
| 参数 | 作用 |
|---|---|
num_learning_epochs |
每批采样数据重复训练几轮 |
gradient_length |
累积多少步 loss 后做一次反向传播,常用于 recurrent student |
learning_rate |
student 优化器学习率 |
loss_type |
mse 或 huber |
max_grad_norm |
student 梯度裁剪 |
7.5 teacher 从哪里来
DistillationRunner.learn() 会先检查 teacher 是否加载。如果没有加载 teacher checkpoint,会直接报错。
Distillation.load() 支持两种来源:
- 加载 distillation checkpoint:读取
student_state_dict和teacher_state_dict。 - 加载 PPO checkpoint:读取
actor_state_dict作为 teacher。
因此常见流程是:
text
先用 PPO 训练 teacher policy
再用 Distillation 加载 PPO actor 作为 teacher
最后导出 student policy 用于部署
Distillation 不兼容 RND 和 Symmetry 扩展;源码会显式检查并报错。
8. Actor、Critic、Student、Teacher 与 Observation Groups
RSL-RL 默认使用 MLPModel。它的输入不是环境给出的全部 obs,而是按 obs_groups 选择指定 group 后拼接:
python
latent = torch.cat([obs[obs_group] for obs_group in self.obs_groups], dim=-1)
PPO 典型配置:
python
actor = MLPModel(obs_set="actor")
critic = MLPModel(obs_set="critic")
Distillation 典型配置:
python
student = MLPModel(obs_set="student")
teacher = MLPModel(obs_set="teacher")
含义:
| 网络 | 所属训练方式 | 训练时输入 | 部署时是否需要 |
|---|---|---|---|
| actor | PPO | policy observation | 需要,PPO 导出的就是 actor |
| critic | PPO | privileged / critic observation | 不需要,只训练时评估 value |
| student | Distillation | 部署可用 observation | 需要,蒸馏导出的就是 student |
| teacher | Distillation | policy 或 privileged observation | 不需要,只训练时提供动作标签 |
机器人强化学习里常见做法是:critic 或 teacher 训练时看更多真值信息,比如 base linear velocity;actor 或 student 只能看部署时真实可获得的信息,比如 IMU、关节状态、命令、上一帧动作。
9. Unitree G1 29DOF 接入示例
Unitree 训练入口:
text
extern/unitree_rl_lab/scripts/rsl_rl/train.py
关键接入链路:
#mermaid-svg-kjPS0wpjDfXtpRoX{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-kjPS0wpjDfXtpRoX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-kjPS0wpjDfXtpRoX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-kjPS0wpjDfXtpRoX .error-icon{fill:#552222;}#mermaid-svg-kjPS0wpjDfXtpRoX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kjPS0wpjDfXtpRoX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-kjPS0wpjDfXtpRoX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kjPS0wpjDfXtpRoX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kjPS0wpjDfXtpRoX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-kjPS0wpjDfXtpRoX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kjPS0wpjDfXtpRoX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kjPS0wpjDfXtpRoX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kjPS0wpjDfXtpRoX .marker.cross{stroke:#333333;}#mermaid-svg-kjPS0wpjDfXtpRoX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kjPS0wpjDfXtpRoX p{margin:0;}#mermaid-svg-kjPS0wpjDfXtpRoX .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-kjPS0wpjDfXtpRoX .cluster-label text{fill:#333;}#mermaid-svg-kjPS0wpjDfXtpRoX .cluster-label span{color:#333;}#mermaid-svg-kjPS0wpjDfXtpRoX .cluster-label span p{background-color:transparent;}#mermaid-svg-kjPS0wpjDfXtpRoX .label text,#mermaid-svg-kjPS0wpjDfXtpRoX span{fill:#333;color:#333;}#mermaid-svg-kjPS0wpjDfXtpRoX .node rect,#mermaid-svg-kjPS0wpjDfXtpRoX .node circle,#mermaid-svg-kjPS0wpjDfXtpRoX .node ellipse,#mermaid-svg-kjPS0wpjDfXtpRoX .node polygon,#mermaid-svg-kjPS0wpjDfXtpRoX .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kjPS0wpjDfXtpRoX .rough-node .label text,#mermaid-svg-kjPS0wpjDfXtpRoX .node .label text,#mermaid-svg-kjPS0wpjDfXtpRoX .image-shape .label,#mermaid-svg-kjPS0wpjDfXtpRoX .icon-shape .label{text-anchor:middle;}#mermaid-svg-kjPS0wpjDfXtpRoX .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-kjPS0wpjDfXtpRoX .rough-node .label,#mermaid-svg-kjPS0wpjDfXtpRoX .node .label,#mermaid-svg-kjPS0wpjDfXtpRoX .image-shape .label,#mermaid-svg-kjPS0wpjDfXtpRoX .icon-shape .label{text-align:center;}#mermaid-svg-kjPS0wpjDfXtpRoX .node.clickable{cursor:pointer;}#mermaid-svg-kjPS0wpjDfXtpRoX .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-kjPS0wpjDfXtpRoX .arrowheadPath{fill:#333333;}#mermaid-svg-kjPS0wpjDfXtpRoX .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-kjPS0wpjDfXtpRoX .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-kjPS0wpjDfXtpRoX .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kjPS0wpjDfXtpRoX .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-kjPS0wpjDfXtpRoX .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kjPS0wpjDfXtpRoX .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-kjPS0wpjDfXtpRoX .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-kjPS0wpjDfXtpRoX .cluster text{fill:#333;}#mermaid-svg-kjPS0wpjDfXtpRoX .cluster span{color:#333;}#mermaid-svg-kjPS0wpjDfXtpRoX div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-kjPS0wpjDfXtpRoX .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-kjPS0wpjDfXtpRoX rect.text{fill:none;stroke-width:0;}#mermaid-svg-kjPS0wpjDfXtpRoX .icon-shape,#mermaid-svg-kjPS0wpjDfXtpRoX .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kjPS0wpjDfXtpRoX .icon-shape p,#mermaid-svg-kjPS0wpjDfXtpRoX .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-kjPS0wpjDfXtpRoX .icon-shape .label rect,#mermaid-svg-kjPS0wpjDfXtpRoX .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kjPS0wpjDfXtpRoX .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-kjPS0wpjDfXtpRoX .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-kjPS0wpjDfXtpRoX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Hydra task config
gym.make 创建 Isaac Lab 环境
RslRlVecEnvWrapper
OnPolicyRunner
runner.learn
对应代码逻辑:
python
env = gym.make(args_cli.task, cfg=env_cfg, ...)
env = RslRlVecEnvWrapper(env, clip_actions=agent_cfg.clip_actions)
runner = OnPolicyRunner(env, agent_cfg.to_dict(), log_dir=log_dir, device=agent_cfg.device)
runner.learn(num_learning_iterations=agent_cfg.max_iterations, init_at_random_ep_len=True)
G1 29DOF locomotion 的 actor observation 通常包括:
text
base_ang_vel
projected_gravity
velocity_commands
joint_pos_rel
joint_vel_rel
last_action
并设置:
python
history_length = 5
enable_corruption = True
concatenate_terms = True
critic observation 通常额外包含:
text
base_lin_vel
这说明 critic 使用训练时特权信息,actor 保持部署可用输入。
10. 最快上手命令
10.1 确认 Python 实际 import 的 RSL-RL
如果想使用本工作区源码版本,先在对应 Python 环境中安装 editable 包:
bash
python -m pip install -e extern/rsl_rl
验证 import 路径:
bash
python -c "import rsl_rl, inspect; print(inspect.getfile(rsl_rl))"
期望输出应指向:
text
/home/nio/wangbin/unitree_workspace/extern/rsl_rl/rsl_rl/__init__.py
如果输出在 site-packages 下,说明当前环境用的是 pip 安装版本,而不是工作区源码。
10.2 Unitree RL Lab 训练入口
常见入口在:
text
extern/unitree_rl_lab/scripts/rsl_rl/train.py
具体任务名需要从 Unitree RL Lab 注册的 gym task 中选择。脚本会读取 task 对应的 rsl_rl_cfg_entry_point,创建 env 和 runner。
10.3 回放与导出
常见入口:
text
extern/unitree_rl_lab/scripts/rsl_rl/play.py
extern/unitree_rl_lab/scripts/rsl_rl/play_keyboard.py
RSL-RL 自身也提供导出接口:
python
runner.export_policy_to_jit(path, filename="policy.pt")
runner.export_policy_to_onnx(path, filename="policy.onnx")
PPO 部署时通常只需要 actor,不需要 critic。Distillation 部署时通常只需要 student,不需要 teacher。
11. 常用调参入口
Unitree locomotion PPO 配置:
text
extern/unitree_rl_lab/source/unitree_rl_lab/unitree_rl_lab/tasks/locomotion/agents/rsl_rl_ppo_cfg.py
Isaac Lab Distillation 配置示例:
text
extern/isaac_lab/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/anymal_d/agents/rsl_rl_distillation_cfg.py
常调参数:
| 参数 | 作用 | 现象与调参方向 |
|---|---|---|
num_steps_per_env |
每轮每个环境采样步数 | 太小可能估计不稳,太大更新滞后 |
num_learning_epochs |
每批数据重复训练轮数 | 太大可能过拟合旧数据 |
num_mini_batches |
每轮分多少 mini-batch | 影响梯度噪声和显存 |
learning_rate |
学习率 | 不稳定先降学习率 |
schedule |
学习率调度 | adaptive 会根据 KL 自动调 |
desired_kl |
目标 KL | KL 太大策略变化激进,太小学习慢 |
clip_param |
PPO ratio 裁剪范围 | 常用 0.2 |
entropy_coef |
探索强度 | 探索不足可增大,动作抖可减小 |
gamma |
长期回报折扣 | locomotion 常见 0.99 |
lam |
GAE 平滑 | 常见 0.95 |
max_grad_norm |
梯度裁剪 | 防止梯度爆炸 |
网络结构配置:
python
actor.hidden_dims = [512, 256, 128]
critic.hidden_dims = [512, 256, 128]
activation = "elu"
Distillation 常调参数:
| 参数 | 作用 | 现象与调参方向 |
|---|---|---|
gradient_length |
累积多少步再反传 | RNN 蒸馏常需要关注,太长显存压力更大 |
loss_type |
mse 或 huber |
动作标签有异常值时可考虑 huber |
student.hidden_dims |
student 容量 | 部署算力有限时先压 student |
teacher.hidden_dims |
teacher 结构 | 通常要匹配已加载 checkpoint |
student.obs_groups |
student 输入 | 必须只包含部署可用观测 |
teacher.obs_groups |
teacher 输入 | 可包含 privileged observation |
观测和奖励配置通常在机器人任务文件中,例如 G1 29DOF:
text
extern/unitree_rl_lab/source/unitree_rl_lab/unitree_rl_lab/tasks/locomotion/robots/g1/29dof/velocity_env_cfg.py
12. Debug 时优先看什么
12.1 训练直接 NaN
优先检查:
- 环境返回的
obs、rewards、dones是否有 NaN。 - reward 权重是否过大。
- action scale 或 PD gain 是否过激。
learning_rate是否过大。
OnPolicyRunner.learn() 中默认会执行 check_nan(obs, rewards, dones)。
12.2 策略学不会走路
优先检查:
- actor observation 是否包含命令、关节状态、上一帧动作。
- critic 是否有合理 privileged information。
- reward 中 tracking 项和姿态/能耗惩罚是否失衡。
- command curriculum 或 terrain curriculum 是否太难。
12.3 训练能走,部署不行
优先检查:
- actor 是否使用了部署拿不到的观测。
- 训练观测归一化是否正确导出。
- joint order、action scale、default joint pose 是否和部署端一致。
- history buffer 拼接顺序是否一致。
13. 建议阅读顺序
第一遍读 PPO 主干:
text
1. extern/rsl_rl/rsl_rl/runners/on_policy_runner.py
2. extern/rsl_rl/rsl_rl/algorithms/ppo.py
3. extern/rsl_rl/rsl_rl/storage/rollout_storage.py
4. extern/rsl_rl/rsl_rl/models/mlp_model.py
5. extern/rsl_rl/rsl_rl/env/vec_env.py
第二遍读 Distillation 主干:
text
1. extern/rsl_rl/rsl_rl/runners/distillation_runner.py
2. extern/rsl_rl/rsl_rl/algorithms/distillation.py
3. extern/rsl_rl/rsl_rl/storage/rollout_storage.py
4. extern/rsl_rl/rsl_rl/models/mlp_model.py
5. extern/isaac_lab/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/anymal_d/agents/rsl_rl_distillation_cfg.py
第三遍结合 Unitree:
text
1. extern/unitree_rl_lab/scripts/rsl_rl/train.py
2. extern/unitree_rl_lab/source/unitree_rl_lab/unitree_rl_lab/tasks/locomotion/agents/rsl_rl_ppo_cfg.py
3. extern/unitree_rl_lab/source/unitree_rl_lab/unitree_rl_lab/tasks/locomotion/robots/g1/29dof/velocity_env_cfg.py
第四遍再看扩展能力:
text
extern/rsl_rl/rsl_rl/extensions/rnd.py
extern/rsl_rl/rsl_rl/extensions/symmetry.py
extern/rsl_rl/rsl_rl/runners/distillation_runner.py
extern/rsl_rl/rsl_rl/algorithms/distillation.py
14. 版本注意事项
当前子模块源码的 pyproject.toml 中包版本为 5.4.1。但 extern/unitree_rl_lab/scripts/rsl_rl/train.py 里对分布式训练有最低版本检查,要求 rsl-rl-lib >= 2.3.1。
因此:
- 单卡训练通常重点确认实际 import 路径即可。
- 分布式训练前必须确认当前环境安装版本和 Unitree RL Lab 脚本要求一致。
- 如果修改了
extern/rsl_rl源码,记得在训练环境中使用 editable install,否则改动不会生效。
15. 最小心智模型
把 RSL-RL 压缩成一句话:
text
OnPolicyRunner / DistillationRunner 负责循环;
PPO / Distillation 负责算法;
RolloutStorage 负责存数据;
Model 负责把 obs 变成 action/value;
VecEnv 是环境和算法之间的接口。
把 PPO 压缩成一句话:
text
先用旧策略采一批数据,再用裁剪后的目标函数小步更新新策略,避免策略变化过猛。
把 Distillation 压缩成一句话:
text
student 负责行动,teacher 负责给动作标签,训练时只更新 student。
