- 人工智能
- 机器学习
- 深度学习
- 强化学习
【免费下载链接】tianshou
An elegant PyTorch deep reinforcement learning library.
导读
本文基于 Tianshou 仓库中的 examples/vizdoom/README.md 及其配套源码,系统讲解如何在经典第一人称射击游戏环境 ViZDoom 上训练深度强化学习智能体。你将掌握:用 EnvPool 大幅加速环境采样的配置方式、C51 / PPO / PPO+ICM 三类算法的训练与评估命令、四张官方地图(D1~D4)的差异与奖励设计经验,以及如何保存并回放.lmp录屏文件。读完本文后,你可以直接复现文档中报告的训练结果,并把这套「环境封装 + 高吞吐采样 + 可视化回放」的流程迁移到其他视觉类 RL 场景。
ViZDoom 场景概览
ViZDoom 是基于著名第一人称射击游戏 Doom 的强化学习环境,因其低观测维度、可控的奖励设计以及贴近真实游戏引擎的交互方式,常被用于测试视觉智能体在稀疏奖励、探索与战斗等任务上的表现。本仓库在 examples/vizdoom/ 目录下提供了完整可运行的示例,核心文件包括:
- env.py:ViZDoom 环境的 Gymnasium 封装与多进程/EnvPool 工厂函数
make_vizdoom_env; - vizdoom_c51.py:基于 C51 分布强化学习的离线(off-policy)训练入口;
- vizdoom_ppo.py:基于 PPO 的在线(on-policy)训练入口,并支持通过 ICM(内在好奇心模块)增强探索;
- replay.py:以 1024x576 窗口回放
.lmp录屏的脚本; - maps/:D1~D4 四张地图的
.wad场景文件、.cfg配置与 SPECTATOR 演示脚本。
四张地图来自 DirectFuturePrediction 项目,更多场景与配置可参考 ViZDoom 官方 scenarios 目录。环境观测为灰度帧,默认分辨率 84x84、4 帧堆叠(frames_stack=4),动作空间为离散组合动作,详见下文。
环境加速:优先使用 EnvPool
ViZDoom 的 Python 环境逐帧执行较慢,文档明确建议在 Linux 机器上优先安装 EnvPool 来运行本套实验:
pip install envpool安装完成后,env.py 中的make_vizdoom_env会自动切换为 EnvPool 的 ViZDoom 环境实现,无需修改任何训练代码。EnvPool 的纯执行速度约为 Python 向量化环境的 2~3 倍,整体 RL 训练流水线约快 1.5 倍。关于 EnvPool 的更多信息可查阅其官方 GitHub 与 ViZDoom API 文档。
从源码看,EnvPool 分支的关键配置如下(env.py):
task_id = "".join([i.capitalize() for i in task.split("_")]) + "-v1" # 例如 D3_battle -> D3Battle-v1 reward_config = { "KILLCOUNT": [20.0, -20.0], # 击杀奖励,取击杀数变化乘以 +20(损失则 -20) "HEALTH": [1.0, 0.0], # 血量增量奖励(battle 地图改为 [1.0, -1.0]) "AMMO2": [1.0, -1.0], # 弹药增量奖励 } if "battle" in task: reward_config["HEALTH"] = [1.0, -1.0] # 战斗地图掉血惩罚make_gymnasium传入frame_skip、stack_num(帧堆叠数,即res[0])、num_envs、max_episode_steps=2625与use_combined_action=True等参数。其中max_episode_steps=2625与原生环境一致:单局上限 10500 tics,配合frameskip=4后智能体实际决策步数为10500 / 4 = 2625步。
如果未安装 EnvPool,代码会回退到 Python 向量化实现:make_vizdoom_env会用ShmemVectorEnv包装多个基于原生vizdoom库的Env实例,并用os.cpu_count()限制测试环境数量为min(cpu_count - 1, num_test_envs)。两种实现共享同一套 Gymnasium 接口,因此训练脚本无需感知底层差异。
训练一个智能体
C51 训练
以文档提供的 C51(Categorical DQN)训练入口为例:
python3 vizdoom_c51.py --task {D1_basic|D2_navigation|D3_battle|D4_battle2}从 vizdoom_c51.py 可以看到该脚本的主要超参数(均为命令行可选,括号内为默认值):
| 参数 | 默认值 | 说明 |
|---|---|---|
--task | D1_basic | 地图场景名,须与maps/下的.wad/.cfg对应 |
--seed | 0 | 随机种子 |
--eps_train/--eps_test | 1.0 / 0.005 | 训练/测试 ε-greedy 探索率 |
--eps_train_final | 0.05 | 训练探索率最终值 |
--buffer_size | 2000000 | 回放缓冲区大小 |
--lr | 0.0001 | Adam 学习率 |
--gamma | 0.99 | 折扣因子 |
--num_atoms | 51 | C51 分布 Q 值的原子数 |
--v_min/--v_max | -10.0 / 10.0 | 分布 Q 值的取值区间 |
--n_step | 3 | 多步回报步数 |
--target_update_freq | 500 | 目标网络更新频率(步数) |
--epoch | 300 | 训练轮数 |
--epoch_num_steps | 100000 | 每轮环境步数 |
--update_per_step | 0.1 | 每环境步的梯度更新数 |
--batch_size | 64 | 训练批大小 |
--num_training_envs/--num_test_envs | 10 / 10 | 训练/测试并行环境数 |
--frames_stack | 4 | 帧堆叠数 |
--skip_num | 4 | 帧跳过(frameskip)数 |
--logger | tensorboard | 可选tensorboard或wandb |
--device | cuda/cpu 自动选择 | 运行设备 |
训练流程与 Atari 场景保持一致:网络使用C51Net(卷积特征提取 + 51 个原子输出),策略为C51Policy,算法为C51;数据侧使用VectorReplayBuffer(buffer_num等于并行环境数,开启save_only_last_obs与stack_num以节省内存)。ε 采用 Nature DQN 式线性衰减:前 100 万环境步内从eps_train线性降到eps_train_final(见 train_fn)。每轮结束后评估一次,达到env.spec.reward_threshold时提前停止,并把最佳策略保存为policy.pth。
文档给出的收敛参考(同一环境配置下的实际观测):
- D1(回血收集):训练约 50 万环境步(5 个 epoch)即可基本做到不死、完成训练;
- D3(战斗):可达到 1600+ 奖励,即 5 分钟内 75+ 击杀;
- D4(战斗加强):可达到 700+ 奖励。
PPO 与 PPO+ICM 训练
PPO 训练入口与 C51 类似:
python3 vizdoom_ppo.py --task {D1_basic|D2_navigation|D3_battle|D4_battle2}vizdoom_ppo.py 额外提供 PPO 专属超参数:--gae_lambda(0.95)、--vf_coef(0.5)、--ent_coef(0.01)、--eps_clip(0.2)、--max_grad_norm(0.5)、--lr_decay(默认开启,按 epoch 线性衰减学习率)、--dual_clip、--value_clip、--advantage_normalization等。其网络结构为DQNet共享特征提取 +DiscreteActor(Categorical分布)与DiscreteCritic,使用OnPolicyTrainerParams训练,每轮 1000 环境步采集、4 次重复更新。
启用 ICM 内在好奇心只需一个参数:
python3 vizdoom_ppo.py --task "D2_navigation" --icm-lr-scale 10 python3 vizdoom_ppo.py --task "D3_battle" --icm-lr-scale 10当--icm_lr_scale > 0时,脚本会用ICMOnPolicyWrapper包裹 PPO,并额外构建IntrinsicCuriosityModule(前向+反向模型,默认--icm_reward_scale 0.01、--icm_forward_loss_weight 0.2),以好奇心奖励辅助探索(vizdoom_ppo.py)。
评估与录屏回放
评估已训练策略
加载训练好的policy.pth并评估:
python3 vizdoom_c51.py --num_test_envs 100 --resume-path policy.pth --watch --task {D1_basic|D3_battle|D4_battle2}--watch表示只观看/评估预训练策略;--resume-path指定权重路径(torch.load后load_state_dict载入,见 vizdoom_c51.py);--num_test_envs控制并行评估的回合数。评估结果会以CollectStats形式打印(平均回报、回合长度等)。
保存并回放 .lmp 录屏
增加--save-lmp参数即可在评估的同时保存.lmp回放文件:
python3 vizdoom_c51.py --save-lmp --num_test_envs 100 --resume-path policy.pth --watch --task {D1_basic|D3_battle|D4_battle2}保存的.lmp文件位于lmps/目录(命名形如episode_{count}.lmp,对应 env.py 中new_episode(lmp_path)的逻辑)。回放命令为:
python3 replay.py maps/D3_battle.cfg episode_8_25.lmpreplay.py 会以RES_1024X576分辨率、可见窗口的方式重放整局,每步advance_action()并休眠1/35秒模拟实时播放,结束时打印本局击杀数。你也可以直接回放仓库文档中提供的两个最佳录屏(D3、D4 各一个,位于results/c51/目录):
python3 replay.py maps/D3_battle.cfg results/c51/d3.lmp python3 replay.py maps/D4_battle2.cfg results/c51/d4.lmp地图与奖励设计经验
四张地图的差异
各地图的.cfg见 examples/vizdoom/maps/,关键差异如下:
| 地图 | 动作按钮 | 游戏变量 | 特点 |
|---|---|---|---|
| D1_basic | MOVE_FORWARD / TURN_LEFT / TURN_RIGHT | HEALTH | 简单回血收集,无死亡惩罚 |
| D2_navigation | 同 D1 | HEALTH | 导航任务,无死亡惩罚 |
| D3_battle | 全向移动 + TURN + ATTACK + SPEED | KILLCOUNT / AMMO2 / HEALTH | 战斗地图,death_penalty=100,doom_skill=2 |
| D4_battle2 | 同 D3 | KILLCOUNT / AMMO2 / HEALTH | 战斗加强地图,同样带死亡惩罚 |
所有地图均设置living_reward=0、episode_timeout=10500、screen_format=GRAY8、window_visible=false(训练时不开窗口)。动作空间由 env.py 中的按钮组合函数生成:普通地图为「前进/转向」共 6 种组合,战斗地图为「前进后退 × 左右 × 转向 × 攻击 × 加速」共 72 种组合,并以离散整数索引作为动作。
奖励设计的实践经验
文档总结了在 ViZDoom 上调试奖励的五条经验,并结合 env.py 的实现可以得到印证:
- living reward 有害:每步常驻奖励(living reward)不利于收敛,各 cfg 均将其设为 0;
- 组合动作很重要:同时按多个按钮的组合动作(如移动+转身+攻击)比单一按键的原始动作空间更利于学习;
- 对 health 和 ammo2 的负向奖励对 D3/D4 很有帮助:战斗地图中
HEALTH的 reward_config 改为[1.0, -1.0],掉血即惩罚,AMMO2采用[1.0, -1.0]同时惩罚弹药消耗; - 只对 health 施加正向奖励对 D1 很有帮助:非战斗地图
HEALTH为[1.0, 0.0],只有回血才获得正奖励(对应 env.py 中health > self.health才计入奖励的条件); - 移除 MOVE_BACKWARD 可能收敛更快,但最终性能可能下降:这解释了为何 D1/D2 的动作组合只包含前进而不含后退。
此外,击杀奖励在 env.py 中实现为每次击杀变化量乘以 20(reward += 20 * (killcount - self.killcount)),与 EnvPool 分支的KILLCOUNT: [20.0, -20.0]保持一致。
算法配置与参考结果
文档说明 ViZDoom 的设置与 Atari 完全一致,因此可以尝试 Atari 示例中列出的更多算法(如 Rainbow、IQN、QR-DQN 等),只需按同样模式替换算法与网络。以下是文档记录的基准结果(单次运行,供参考对比,实际结果会因随机种子与硬件有所波动):
C51(单次运行)
| task | best reward | 运行命令 |
|---|---|---|
| D2_navigation | 747.52 | python3 vizdoom_c51.py --task "D2_navigation" |
| D3_battle | 1855.29 | python3 vizdoom_c51.py --task "D3_battle" |
PPO(单次运行)
| task | best reward | 运行命令 |
|---|---|---|
| D2_navigation | 770.75 | python3 vizdoom_ppo.py --task "D2_navigation" |
| D3_battle | 320.59 | python3 vizdoom_ppo.py --task "D3_battle" |
PPO with ICM(单次运行)
| task | best reward | 运行命令 |
|---|---|---|
| D2_navigation | 844.99 | python3 vizdoom_ppo.py --task "D2_navigation" --icm-lr-scale 10 |
| D3_battle | 547.08 | python3 vizdoom_ppo.py --task "D3_battle" --icm-lr-scale 10 |
可以看到,ICM 在稀疏奖励明显的战斗任务(D3)上带来了显著收益(320.59 → 547.08),而在 D2 上也有 770 → 844 的提升,说明好奇心驱动的内在奖励能有效改善探索。原文档中的完整奖励曲线图(results/c51/与results/ppo*目录下的 PNG)记录在案,可在运行实验时通过 TensorBoard/WandB 复现对比。
观察与调试技巧
- 查看观测与动作空间:env.py 内置了
__main__自测代码,可直接运行python3 env.py打印观测形状、动作数并随机步进环境,快速验证环境封装是否正常。 - SPECTATOR 模式:maps/spectator.py 演示了 ViZDoom 的 SPECTATOR 模式——以 640x480 可见窗口进入游戏,逐帧打印状态号、游戏变量、动作与奖励,适合人工体验地图与验证奖励设定:
python3 maps/spectator.py -c maps/D3_battle.cfg -w maps/D3_battle.wad - 数据收集:
vizdoom_c51.py与vizdoom_ppo.py均支持--save_buffer_name,可在--watch模式下用测试环境采集经验并save_hdf5保存为 HDF5 缓冲文件,用于后续离线学习。
小结
本文从 examples/vizdoom/README.md 出发,结合仓库源码完整梳理了 Tianshou 在 ViZDoom 上的工程实践:EnvPool 加速环境采样、C51/PPO/PPO+ICM 三套算法的一键训练与参数体系、基于.lmp的评估回放闭环,以及经过验证的地图与奖励设计经验。这套「EnvPool 高吞吐采样 + 组合动作离散化 + 结构化工件回放」的组合,同样是处理其他视觉类 RL 任务时可以复用的模板。
- 人工智能
- 机器学习
- 深度学习
- 强化学习
【免费下载链接】tianshou
An elegant PyTorch deep reinforcement learning library.
相关推荐
PaddleNLP PPO/GRPO 强化学习对齐训练实战指南:从数据协议到分布式训练
PaddleNLP PPO/GRPO 强化学习对齐训练实战指南:从数据协议到分布式训练 导读 本文以 PaddleNLP 仓库中的 PPO && GRPO 官方
人工智能大模型预训练微调LoRARLHF强化学习分布式训练模型推理服务推理引擎模型量化模型压缩本地部署NLP解决Verl PPO训练卡顿:从根源优化到实战调优指南
解决Verl PPO训练卡顿:从根源优化到实战调优指南 PPO训练时进度条停滞、GPU利用率忽高忽低、单轮迭代耗时超预期?这些卡顿问题严重影响大语言模型强化学习
人工智能大模型强化学习RLHF分布式训练微调Stable Baselines3自动驾驶训练案例:从仿真到部署的PPO实战指南
Stable Baselines3自动驾驶训练案例:从仿真到部署的PPO实战指南 引言:自动驾驶强化学习的痛点与解决方案 你是否还在为自动驾驶算法训练中的样本效
人工智能强化学习机器学习
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考