# 代码实战

> 来源：https://dqn.cn/code/ ｜ 作者：DQN.CN 编辑部 ｜ 发布：2026-10-30 ｜ 更新：2026-10-30 ｜ 许可：CC BY-NC-SA 4.0（文字）/ MIT（代码）

代码实战栏目汇总了本站所有教程中的可运行代码。代码风格参考 CleanRL 的“单文件实现”理念：一个文件包含一个算法的全部逻辑，不依赖自定义框架，便于阅读和修改。所有代码都在本站环境中**实际运行过**，下表给出的是真实观测到的结果（单线程 CPU、短训练预算、通常是单个随机种子），不是论文数字，也没有挑选最好的一次。

## 环境准备

### Python 与 PyTorch 安装

```bash
python -m venv rl && source rl/bin/activate      # Windows: rl\Scripts\activate
pip install torch --index-url https://download.pytorch.org/whl/cpu   # 只用 CPU 即可
pip install gymnasium numpy
```

本站验证环境：Python 3.13、PyTorch 2.x（CPU）、Gymnasium 1.4.0、NumPy 2.x。有 GPU 的读者按 [PyTorch 官网](https://pytorch.org/get-started/locally/) 安装 CUDA 版本即可，代码会自动使用 GPU（DQN 示例）或在 CPU 上运行（其余示例的网络很小，CPU 更快）。

### Gymnasium 与 MuJoCo

```bash
pip install "gymnasium[atari]" opencv-python   # DQN 的 Atari 预处理示例
pip install "gymnasium[mujoco]"                # MuJoCo 连续控制（本站示例未用到，练习题中会用到）
pip install mpe2                               # 多智能体粒子环境 MPE（IPPO / MAPPO 示例）
```

建议在多核机器上同时运行多个实验时设置 `OMP_NUM_THREADS=1`，避免 PyTorch 线程互相争抢 CPU。

## 实现清单

代码位于仓库的 `examples/` 目录，页面中显示的就是这些文件本身。

### 入门（NumPy，表格方法）

| 文件 | 教程 | 环境 | 实测结果 |
| --- | --- | --- | --- |
| `basics/bandit.py` | [多臂老虎机](https://dqn.cn/basics/bandit) | 10 臂伯努利老虎机 | 5000 步累积懊悔（200 次平均）：汤普森 40.3、衰减 ε 132.9、ε=0.1 240.6、UCB1 276.4 |
| `basics/mdp_occupancy.py` | [MDP](https://dqn.cn/basics/mdp) | 天气 MRP / 两状态 MDP | MRP 解析价值与蒙特卡洛一致（v(雨) 5.641 对 5.646）；三种策略的 ⟨ρ,r⟩/(1−γ) 与 V(A) 完全相同 |
| `basics/bellman_solve.py` | [贝尔曼方程](https://dqn.cn/basics/bellman) | FrozenLake-v1 | 随机策略价值：解析解与迭代解最大误差 3.3e-10 |
| `basics/dp.py` | [动态规划](https://dqn.cn/basics/dynamic-programming) | FrozenLake-v1 | 策略迭代 7 轮、价值迭代 324 次扫描收敛，最优策略成功率 0.737 |
| `basics/mc_blackjack.py` | [蒙特卡洛](https://dqn.cn/basics/monte-carlo) | Blackjack-v1 | 50 万局 MC 控制后平均回报 −0.045（“≥20 停牌”策略为 −0.349） |
| `basics/td_random_walk.py` | [TD 学习](https://dqn.cn/basics/td-learning) | 5 状态随机游走 | 100 回合后 RMS 误差：TD(0) 最低 0.036，MC 最低 0.085 |
| `basics/cliff_q_sarsa.py` | [Q-learning 与 SARSA](https://dqn.cn/basics/q-learning-sarsa) | CliffWalking-v1 | 贪心路线回报：Q-learning −13.0（最短路线），SARSA −15.4（安全路线） |
| `basics/nstep_sarsa_cliff.py` | [Q-learning 与 SARSA](https://dqn.cn/basics/q-learning-sarsa) | CliffWalking-v1 | α=0.1 时前 50 回合平均回报：n=1 −209.2，n=3 −139.3，n=5 −144.9 |
| `basics/gym_frozenlake_q.py` | [Gymnasium 上手](https://dqn.cn/basics/gymnasium) | FrozenLake-v1 / CartPole-v1 | Q-learning 成功率 0.728；CartPole 随机策略 23.7 分 |
| `basics/gym_custom_env.py` | [Gymnasium 上手](https://dqn.cn/basics/gymnasium) | 自定义走廊环境 | 通过 `check_env` 检查 |

### 进阶（PyTorch）

| 文件 | 教程 | 环境 | 训练预算 | 实测结果 |
| --- | --- | --- | --- | --- |
| `advanced/dqn_cartpole.py` | [DQN](https://dqn.cn/advanced/dqn) | CartPole-v1 | 5 万步 | 贪心评估 500（3 个种子：500 / 470.9 / 500） |
| `advanced/dqn_atari_setup.py` | [DQN](https://dqn.cn/advanced/dqn) | ALE/Breakout-v5 | 不训练 | 仅验证预处理与网络形状 |
| `advanced/dqn_variants.py` | [DQN 改进](https://dqn.cn/advanced/dqn-improvements) | CartPole-v1 | 5 万步 × 5 配置 × 2 种子 | 各配置差异小于种子间波动，未观察到稳定提升 |
| `advanced/reinforce_cartpole.py` | [REINFORCE](https://dqn.cn/advanced/reinforce) | CartPole-v1 | 1000 回合 | 随机策略训练回报最高约 484；argmax 评估 289 |
| `advanced/a2c_cartpole.py` | [A2C](https://dqn.cn/advanced/actor-critic) | CartPole-v1 | 20 万步 | 训练回报在 300–480 波动；贪心评估 500 |
| `advanced/trpo_cartpole.py` | [TRPO](https://dqn.cn/advanced/trpo) | CartPole-v1 | 约 10 万步 | 4 万步后稳定在 500；贪心评估 500 |
| `advanced/ppo_cartpole.py` | [PPO](https://dqn.cn/advanced/ppo) | CartPole-v1 | 20 万步 | 约 12 万步起稳定 500；贪心评估 500（2 个种子） |
| `advanced/ppo_pendulum.py` | [PPO](https://dqn.cn/advanced/ppo) | Pendulum-v1 | 约 20 万步 × 3 种子 | 确定性评估 −206.3 / −202.8 / −226.6 |
| `advanced/ddpg_pendulum.py` | [DDPG](https://dqn.cn/advanced/ddpg) | Pendulum-v1 | 2 万步 | 确定性评估 −168.0 |
| `advanced/td3_pendulum.py` | [TD3](https://dqn.cn/advanced/td3) | Pendulum-v1 | 2 万步 | 确定性评估 −169.1 |
| `advanced/sac_pendulum.py` | [SAC](https://dqn.cn/advanced/sac) | Pendulum-v1 | 2 万步 | 确定性评估 −166.3 |
| `advanced/sac_discrete_cartpole.py` | [SAC](https://dqn.cn/advanced/sac) | CartPole-v1 | 4 万步 × 3 种子 | 贪心评估 500 / 500 / 384.7 |
| `advanced/her_point_goal.py` | [目标导向 RL 与 HER](https://dqn.cn/advanced/goal-conditioned) | 自建二维到达任务 | 600 回合 × 3 种子 | 第 100 回合成功率：DDPG+HER 1.00，DDPG 0.02–0.04；DDPG 在第 400–600 回合才到 1.00 |
| `advanced/dyna_q_maze.py` | [基于模型的 RL](https://dqn.cn/advanced/model-based) | Dyna 迷宫 | 50 回合 × 30 次 | 第 2 回合步数：n=0 为 742，n=50 为 45 |
| `advanced/mpc_pendulum.py` | [MPC](https://dqn.cn/advanced/mpc) | Pendulum-v1 | 10 回合（2000 步）× 2 种子 | 第 3–10 回合平均：随机打靶 −278.6，CEM −170.3，PETS −196.7 |
| `advanced/mbpo_pendulum.py` | [MBPO](https://dqn.cn/advanced/mbpo) | Pendulum-v1 | 5000 步 × 2 种子 | 2000 步时：MBPO 约 −100，SAC 约 −1300，同更新比 SAC×10 约 −98 |
| `advanced/offline_cartpole.py` | [离线 RL](https://dqn.cn/advanced/offline-rl) | CartPole-v1 数据集 | 离线训练 | 纯专家数据：朴素 DQN 9.4，CQL 500，BC 500 |
| `advanced/cql_pendulum.py` | [离线 RL](https://dqn.cn/advanced/offline-rl) | Pendulum-v1（SAC 回放缓冲区 6000 条） | 离线 2 万步 × 2 种子 | BC −892.9 / −821.9，朴素离线 SAC −108.5 / −108.9，CQL(α=5) −125.5 / −124.8 |
| `advanced/marl_climbing.py` | [多智能体 RL](https://dqn.cn/advanced/multi-agent) | 攀爬博弈 | 5000 轮 × 100 种子 | 独立 Q 学习 0% 找到最优，联合学习 100% |
| `advanced/ippo_mappo_spread.py` | [多智能体 RL](https://dqn.cn/advanced/multi-agent) | MPE simple_spread（N=3） | 80 万步 × 2 种子 | 平均回合回报：随机 −27.0，IPPO −16.44 / −16.31，MAPPO −16.67 / −16.36 |
| `advanced/bc_dagger_cartpole.py` | [模仿学习](https://dqn.cn/advanced/imitation-learning) | CartPole-v1 | 极少示范 | BC(10 样本) 64 → DAgger(60 样本) 310；BC(60 专家样本) 464 |
| `advanced/gail_cartpole.py` | [模仿学习](https://dqn.cn/advanced/imitation-learning) | CartPole-v1（25 对示范） | 约 20 万步 × 3 种子 | 奖励 −log(1−D)：500 / 500 / 500；奖励 log D−log(1−D)：9.2 / 37.7 / 9.2；同数据 BC：42.0 / 494.0 / 53.6 |
| `advanced/rlhf_toy.py` | [RLHF 与大模型 RL](https://dqn.cn/advanced/rlhf-llm) | 玩具“问答” | 数秒 | GRPO、DPO 均把正确回答概率从约 0.12 提升到约 1.0 |

Pendulum 的回报越接近 0 越好（随机策略约 −1200，约 −200 以上可认为学会）；CartPole 满分 500。

### 运行方式

```bash
cd examples/advanced
python ppo_cartpole.py
python dqn_variants.py --double --dueling --per --seed 0
python mpc_pendulum.py pets 0          # 部分较慢的脚本支持只跑一个“方法 + 种子”，便于并行
DQN_QUICK=1 python mbpo_pendulum.py    # 支持 DQN_QUICK=1 的脚本会只跑很短的版本，用来检查环境
```

## 如何复现与调参

- **随机种子**：代码设置了 Python / NumPy / PyTorch 和环境的种子，但 Gymnasium 中 `action_space.sample()` 有独立的随机数生成器（需 `env.action_space.seed(...)`），多线程浮点运算也存在微小的不确定性，所以重复运行的数值可能与页面略有不同。
- **多种子评估**：强化学习结果的方差很大。我们在 [DQN 改进](https://dqn.cn/advanced/dqn-improvements) 和 [PPO](https://dqn.cn/advanced/ppo) 页面中都遇到了“换一个种子或一个超参数，结论就变了”的情况。比较算法时至少使用 5 个种子，报告均值和置信区间（参考 Henderson et al., 2018, *Deep Reinforcement Learning that Matters*；Agarwal et al., 2021, *Deep RL at the Edge of the Statistical Precipice*）。
- **区分训练回报和评估回报**：训练回报包含探索噪声（ε-贪心、随机策略采样），评估时通常用确定性策略。两者可能差异很大（例如 REINFORCE 页面）。
- **先保证正确，再调参**：用最简单的环境（CartPole、Pendulum）确认代码能学会，再迁移到复杂任务。
- **常用调参顺序**：学习率 → 批量 / 采样长度 → 网络大小 → 算法特有超参数（如 PPO 的 epoch 数、SAC 的目标熵）。

## Jupyter notebook 与在线运行

`examples/` 中的每个脚本都自动生成了一个同名的 Jupyter notebook（`notebooks/` 目录，例如 `notebooks/advanced/ppo_cartpole.ipynb`）。每个使用了示例代码的教程页面顶部都有按钮：

- **下载 notebook**：直接下载 `.ipynb`，在本地 Jupyter / VS Code 中打开即可运行。第一个代码单元会检查依赖，缺什么装什么。
- **在 Colab 中打开**：打开 GitHub 仓库中的同一个 notebook（需要站点配置好 GitHub 仓库地址后才会启用）。**注意：Google Colab 在中国大陆通常无法直接访问**，国内读者建议下载后在本地运行，或使用国内的 notebook 平台（如 ModelScope 魔搭、阿里云天池、百度 AI Studio）上传运行。
- **在国内平台打开**：站点配置了国内平台入口后会显示。

notebook 的内容与 `.py` 文件完全一致：第 1 个单元是说明，第 2 个单元是环境准备，之后按函数和逻辑段落切分成若干代码单元。支持 `DQN_QUICK` 开关的脚本，可以在环境准备单元中取消注释 `os.environ["DQN_QUICK"] = "1"`，先用很短的训练确认能跑通。

本站对所有 notebook 都用 `jupyter nbconvert --execute` 实际执行过一遍（训练较久的脚本使用 `DQN_QUICK=1` 的短版本），确认可以从头运行到尾。Colab 的免费 CPU 足以运行本站的所有示例；训练最久的是 MPC（PETS）、MBPO 和多智能体示例，完整版本在单线程 CPU 上需要十几分钟到一小时。

## 参考文献

- Huang, S. et al. (2022). CleanRL: High-quality Single-file Implementations of Deep Reinforcement Learning Algorithms. *JMLR*, 23(274), 1–18. [arXiv:2111.08819](https://arxiv.org/abs/2111.08819)
- Henderson, P. et al. (2018). Deep Reinforcement Learning that Matters. *AAAI*. [arXiv:1709.06560](https://arxiv.org/abs/1709.06560)
- Agarwal, R. et al. (2021). Deep Reinforcement Learning at the Edge of the Statistical Precipice. *NeurIPS*. [arXiv:2108.13264](https://arxiv.org/abs/2108.13264)

## 下一步

不确定该用哪个算法？看 [算法对照表](https://dqn.cn/code/algorithm-comparison)。
