Tianshou ViZDoom 实战指南:从 C51/PPO 训练到 .lmp 回放
2026/9/23 21:37:19 网站建设 项目流程
  • 人工智能
  • 机器学习
  • 深度学习
  • 强化学习

【免费下载链接】tianshou

An elegant PyTorch deep reinforcement learning library.

项目地址:https://gitcode.com/gh_mirrors/ti/tianshou
点击查看免费下载

导读

本文基于 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_skipstack_num(帧堆叠数,即res[0])、num_envsmax_episode_steps=2625use_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 可以看到该脚本的主要超参数(均为命令行可选,括号内为默认值):

参数默认值说明
--taskD1_basic地图场景名,须与maps/下的.wad/.cfg对应
--seed0随机种子
--eps_train/--eps_test1.0 / 0.005训练/测试 ε-greedy 探索率
--eps_train_final0.05训练探索率最终值
--buffer_size2000000回放缓冲区大小
--lr0.0001Adam 学习率
--gamma0.99折扣因子
--num_atoms51C51 分布 Q 值的原子数
--v_min/--v_max-10.0 / 10.0分布 Q 值的取值区间
--n_step3多步回报步数
--target_update_freq500目标网络更新频率(步数)
--epoch300训练轮数
--epoch_num_steps100000每轮环境步数
--update_per_step0.1每环境步的梯度更新数
--batch_size64训练批大小
--num_training_envs/--num_test_envs10 / 10训练/测试并行环境数
--frames_stack4帧堆叠数
--skip_num4帧跳过(frameskip)数
--loggertensorboard可选tensorboardwandb
--devicecuda/cpu 自动选择运行设备

训练流程与 Atari 场景保持一致:网络使用C51Net(卷积特征提取 + 51 个原子输出),策略为C51Policy,算法为C51;数据侧使用VectorReplayBufferbuffer_num等于并行环境数,开启save_only_last_obsstack_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共享特征提取 +DiscreteActorCategorical分布)与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.loadload_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.lmp

replay.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_basicMOVE_FORWARD / TURN_LEFT / TURN_RIGHTHEALTH简单回血收集,无死亡惩罚
D2_navigation同 D1HEALTH导航任务,无死亡惩罚
D3_battle全向移动 + TURN + ATTACK + SPEEDKILLCOUNT / AMMO2 / HEALTH战斗地图,death_penalty=100doom_skill=2
D4_battle2同 D3KILLCOUNT / AMMO2 / HEALTH战斗加强地图,同样带死亡惩罚

所有地图均设置living_reward=0episode_timeout=10500screen_format=GRAY8window_visible=false(训练时不开窗口)。动作空间由 env.py 中的按钮组合函数生成:普通地图为「前进/转向」共 6 种组合,战斗地图为「前进后退 × 左右 × 转向 × 攻击 × 加速」共 72 种组合,并以离散整数索引作为动作。

奖励设计的实践经验

文档总结了在 ViZDoom 上调试奖励的五条经验,并结合 env.py 的实现可以得到印证:

  1. living reward 有害:每步常驻奖励(living reward)不利于收敛,各 cfg 均将其设为 0;
  2. 组合动作很重要:同时按多个按钮的组合动作(如移动+转身+攻击)比单一按键的原始动作空间更利于学习;
  3. 对 health 和 ammo2 的负向奖励对 D3/D4 很有帮助:战斗地图中HEALTH的 reward_config 改为[1.0, -1.0],掉血即惩罚,AMMO2采用[1.0, -1.0]同时惩罚弹药消耗;
  4. 只对 health 施加正向奖励对 D1 很有帮助:非战斗地图HEALTH[1.0, 0.0],只有回血才获得正奖励(对应 env.py 中health > self.health才计入奖励的条件);
  5. 移除 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(单次运行)

taskbest reward运行命令
D2_navigation747.52python3 vizdoom_c51.py --task "D2_navigation"
D3_battle1855.29python3 vizdoom_c51.py --task "D3_battle"

PPO(单次运行)

taskbest reward运行命令
D2_navigation770.75python3 vizdoom_ppo.py --task "D2_navigation"
D3_battle320.59python3 vizdoom_ppo.py --task "D3_battle"

PPO with ICM(单次运行)

taskbest reward运行命令
D2_navigation844.99python3 vizdoom_ppo.py --task "D2_navigation" --icm-lr-scale 10
D3_battle547.08python3 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.pyvizdoom_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.

项目地址:https://gitcode.com/gh_mirrors/ti/tianshou
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询