在强化学习的训练过程中,算法需要数小时甚至数天才能收敛。如果没有系统化的日志记录与可视化手段,开发者将难以判断策略是否在进步、超参数是否合理、或者训练是否早已发散。rsl_rl 的日志系统正是为了解决这一问题而设计:它以统一的接口收集训练指标,支持同时输出到本地控制台与多种可视化后端,并针对分布式训练和多算法变体(如 AMP)进行了专门适配。本文将拆解其核心架构、数据流转路径与配置方法,帮助初学者快速掌握训练监控的完整链路。
架构概览:统一入口与多后端适配
日志系统的顶层入口是 Logger 类,它并不直接操作网络请求或文件写入,而是通过一个符合 SummaryWriter 接口的 writer 对象代理所有持久化操作。这种设计让控制台输出、本地 TensorBoard 事件文件、以及 Weights & Biases (W&B) 或 Neptune 云端实验追踪可以在同一套代码中无缝切换。
LoggerAMP 继承自 Logger,专为对抗动作先验(AMP)算法扩展了风格奖励(style reward)与总奖励(total reward)的追踪能力。而在 writer 层,WandbSummaryWriter 与 NeptuneSummaryWriter 均继承自 PyTorch 原生的 SummaryWriter,形成**“本地 TensorBoard 事件 + 云端实时同步”**的双写模式。下图展示了核心类之间的继承与组合关系。
classDiagram
class SummaryWriter {
+add_scalar(tag, value, step)
}
class Logger {
+log_dir
+cfg
+writer
+rewbuffer
+lenbuffer
+process_env_step(rewards, dones, extras)
+log(it, loss_dict, ...)
+save_model(path, it)
-_prepare_logging_writer()
-_store_code_state()
}
class LoggerAMP {
+style_rewbuffer
+total_rewbuffer
+process_env_step(... style_rewards, total_rewards)
}
class WandbSummaryWriter {
+store_config(env_cfg, train_cfg)
+add_scalar(tag, value, step)
+save_model(path, it)
}
class NeptuneSummaryWriter {
+run
+store_config(env_cfg, train_cfg)
+add_scalar(tag, value, step)
+save_model(path, it)
-_map_path(path)
}
SummaryWriter <|-- WandbSummaryWriter
SummaryWriter <|-- NeptuneSummaryWriter
Logger <|-- LoggerAMP
Logger --> WandbSummaryWriter : writer
Logger --> NeptuneSummaryWriter : writer
Logger --> SummaryWriter : writer
Sources: logger.py, wandb_utils.py, neptune_utils.py, amp_logger.py
生命周期:指标如何从环境流向仪表盘
日志系统的生命周期与训练循环紧密耦合,可拆分为环境步级累积和迭代级汇总两个阶段。在 OnPolicyRunner.learn() 中,每一次环境交互后都会调用 logger.process_env_step() 将奖励、终止信号和环境附加信息写入内存缓冲;当一整批 Rollout 收集完毕、策略更新完成后,再调用 logger.log() 将缓冲区的统计量一次性输出到控制台并写入可视化后端。这种两阶段设计避免了高频 I/O 对训练吞吐的拖累。
sequenceDiagram
participant Runner as OnPolicyRunner
participant Logger as Logger
participant Env as VecEnv
participant Writer as SummaryWriter
loop 每个环境步
Runner->>Env: step(actions)
Env-->>Runner: rewards, dones, extras
Runner->>Logger: process_env_step(rewards, dones, extras)
Logger->>Logger: 累加 cur_reward_sum / cur_episode_length
Logger->>Logger: dones>0 时移入 rewbuffer / lenbuffer
end
Runner->>Logger: log(it, loss_dict, ...)
Logger->>Logger: 计算 FPS、ETA 等性能指标
Logger->>Writer: add_scalar("Loss/...", value, it)
Logger->>Writer: add_scalar("Train/mean_reward", ..., it)
Logger->>Runner: 打印格式化日志字符串
当某条环境轨迹终止(dones > 0)时,process_env_step 会把该轨迹的累积奖励与长度从 GPU Tensor 转移到 CPU 的 deque 缓冲中。deque 设置了最大长度 100,这意味着 log() 中汇报的永远是最近 100 个已完成回合的滑动平均,而非全部历史平均值,从而对训练动态变化更加敏感。若启用了 RND(随机网络蒸馏)探索模块,系统还会额外维护外在奖励与内在奖励的独立缓冲。
Sources: logger.py, on_policy_runner.py
多后端对比与配置方式
Logger 在初始化时通过配置字典中的 logger 字段决定实例化哪种 writer。三种可选后端的特性与必要配置如下表所示。
| 后端 | 配置键 | 环境变量/额外依赖 | 本地事件文件 | 云端同步 | 模型保存 |
|---|---|---|---|---|---|
| TensorBoard | logger: "tensorboard" |
无(PyTorch 内置) | ✅ 是 | ❌ 否 | ❌ 否 |
| Weights & Biases | logger: "wandb" |
pip install wandb<br>WANDB_USERNAME |
✅ 是 | ✅ 是 | ✅ 是 |
| Neptune | logger: "neptune" |
pip install neptune<br>NEPTUNE_API_TOKEN<br>NEPTUNE_USERNAME |
✅ 是 | ✅ 是 | ✅ 是 |
无论选择哪种后端,本地都会同时生成 TensorBoard 事件文件,这意味着即使实验结束后云端项目被清理,你依然可以用 tensorboard --logdir 离线查看曲线。W&B 与 Neptune 的 writer 还会在初始化时自动调用 store_config(),将训练配置、策略配置、算法配置以及环境配置同步到云端,确保实验完全可复现。
Sources: logger.py, wandb_utils.py, neptune_utils.py
指标命名空间与含义
在 log() 方法内部,所有标量指标都按语义分组,使用斜杠分隔的层级命名(如 Loss/value)。初学者在可视化面板中搜索时,可通过前缀快速过滤。以下是各命名空间的标准含义。
| 命名空间前缀 | 来源 | 说明 |
|---|---|---|
Loss/* |
loss_dict |
策略损失、价值损失、熵损失等算法原始输出 |
Loss/learning_rate |
优化器 | 当前迭代的学习率 |
Policy/mean_noise_std |
策略网络 | 动作分布的平均标准差,反映探索强度 |
Perf/total_fps |
计时器 | 每秒处理的环境步数 |
Perf/collection_time |
计时器 | Rollout 数据收集耗时 |
Perf/learning_time |
计时器 | 策略更新耗时 |
Train/mean_reward |
rewbuffer |
最近 100 回合的平均总奖励 |
Train/mean_episode_length |
lenbuffer |
最近 100 回合的平均长度 |
Episode/* |
extras["episode"] |
环境自定义的每回合统计量 |
Rnd/* |
RND 模块 | 外在奖励、内在奖励、RND 权重(若启用) |
AMP/* |
LoggerAMP | 风格奖励、总奖励(仅 AMP 算法) |
特别需要注意的是,Train/mean_reward/time 与 Train/mean_episode_length/time 使用 tot_time(总训练秒数)作为横轴,而非迭代次数,这有助于在对比不同批量大小或不同机器上的实验时,消除迭代速度差异带来的视觉扭曲。W&B 后端由于自身机制限制,暂不提供以时间为横轴的曲线。
Sources: logger.py, amp_logger.py
分布式训练下的日志去重
在多 GPU 分布式训练中,rsl_rl 使用 torch.distributed 启动多个进程,每个进程拥有独立的 Logger 实例。若所有进程同时写入同一个 W&B 项目或同一组 TensorBoard 文件,会导致数据重复、曲线混乱。因此 Logger 在初始化时检查 is_distributed 与 gpu_global_rank:仅当全局 rank 为 0 的主进程启用日志写入,其余进程的 disable_logs 被设为 True,其 writer 为空,所有 add_scalar 与文件操作均被跳过。控制台打印同样受此保护,确保终端输出不会被打乱。
Sources: logger.py, on_policy_runner.py
代码版本追踪:自动记录 Git 差异
可复现性不仅依赖超参数,还取决于代码版本。Logger 在初始化时会调用 _store_code_state(),自动探测 rsl_rl 包所在的 Git 仓库(也支持通过 add_git_repo_to_log() 追加用户项目仓库),将 git status 与 git diff 输出到日志目录下的 git/*.diff 文件中。若使用 W&B 或 Neptune,这些 diff 文件还会被自动上传为实验附件,让你在数月后依然能精确还原实验时的代码状态。
Sources: logger.py, on_policy_runner.py
AMP 专用日志扩展
AMP(Adversarial Motion Prior)算法除了常规奖励外,还引入了风格奖励(衡量与参考动作相似度)和总奖励(任务奖励与风格奖励的插值)。LoggerAMP 继承 Logger 后重写了 process_env_step(),额外接收 style_rewards 与 total_rewards 参数,并在每个回合结束时将其存入 style_rewbuffer 与 total_rewbuffer。在 log() 中,这两个缓冲区的均值被写入 AMP/mean_style_reward 与 AMP/mean_total_reward,帮助开发者观察策略在“完成任务”与“模仿参考动作”之间的权衡。
AMPRunner 在训练循环中负责从算法对象提取这两种奖励并传递给日志器,因此使用 AMP 算法的用户无需手动干预即可获得完整的 AMP 监控面板。
Sources: amp_logger.py, amp_runner.py
下一步
掌握了日志系统的结构后,你可以继续了解训练运行器如何管理整体生命周期,或者探索模型如何在训练中被保存与恢复,以便将日志曲线与具体检查点对应起来。