CartPole 强化学习实验:DQN 如何根据奖励学会控制杆子
1. 为什么学习强化学习
Section titled “1. 为什么学习强化学习”前面几周的实验更多围绕监督学习展开。无论是迁移学习、主动学习、小样本学习还是联邦学习,模型通常都有明确的数据和标签。比如图像分类任务中,输入是一张图片,标签是它所属的类别,模型要学习的是输入和标签之间的对应关系。
强化学习的设定不太一样。
在强化学习中,模型一开始并不知道每个状态下应该做什么动作。它需要进入环境,通过不断尝试动作获得奖励,再根据奖励反馈逐步改进策略。这个过程中没有标准答案,只有环境给出的 reward。
这带来了一个很核心的问题:
没有人工标签,只有环境奖励时,智能体如何学会做决策?
这次实验选择 CartPole-v1 环境,使用 Stable-Baselines3 训练 DQN,并用行为克隆作为监督学习对照。实验重点不是追求满分,而是观察强化学习的训练过程,以及理解 reward 在策略学习中到底起什么作用。
2. CartPole-v1 是什么任务
Section titled “2. CartPole-v1 是什么任务”CartPole 是强化学习中非常经典的入门环境。它可以理解为一个小车平衡杆子的物理仿真任务。
画面里有一辆小车,车上竖着一根杆子。这里的 “pole” 就是杆子,“cart” 就是小车。智能体不能直接扶杆子,只能控制小车向左或向右移动,让杆子尽可能保持不倒。
可以简单想象成这样:
杆子 pole | | | ___|___ | | 小车 cart |_______|智能体每一步只能选择两个动作之一:
| 动作 | 含义 |
|---|---|
| 0 | 向左推动小车 |
| 1 | 向右推动小车 |
环境给智能体的状态是 4 个数值:
| 状态 | 含义 |
|---|---|
| cart position | 小车位置 |
| cart velocity | 小车速度 |
| pole angle | 杆子的倾斜角度 |
| pole angular velocity | 杆子的角速度,也就是杆子倒下的趋势 |
模型要学的不是“识别杆子”,而是根据这 4 个状态值判断小车下一步应该往左推还是往右推。
比如,杆子正在向右倒,小车可能需要向右移动,把杆子“接住”;杆子正在向左倒,小车可能需要向左移动。模型要通过反复试错学到这种控制规律。
3. 环境 reward 是怎么体现的
Section titled “3. 环境 reward 是怎么体现的”CartPole-v1 里的 reward 规则很简单:只要杆子没有倒下,环境每坚持一个时间步就给 +1 reward。
也就是说:
| 情况 | episode reward |
|---|---|
| 杆子坚持 20 步 | 20 |
| 杆子坚持 100 步 | 100 |
| 杆子坚持 500 步 | 500 |
代码中,reward 是由环境交互函数 env.step(action) 返回的:
obs, reward, terminated, truncated, info = env.step(action)其中 reward 就是环境在当前时间步给智能体的反馈。一个 episode 的总奖励,就是把每一步 reward 累加起来:
total_reward = 0
while not done: action = policy(obs) obs, reward, terminated, truncated, info = env.step(action) total_reward += reward done = terminated or truncated所以在这次实验中,mean_reward = 230.55 的意思是:模型平均可以让杆子保持大约 230 个时间步不倒。
这里需要注意,reward 并不是人工标注的“正确动作”。环境不会直接告诉模型:
这个状态应该向左推。这个状态应该向右推。环境只会告诉模型:
你这一步之后,杆子还没倒,所以奖励 +1。至于这个动作是不是长期来看更好,需要模型自己从大量交互经验中学习。
4. DQN 如何利用 reward
Section titled “4. DQN 如何利用 reward”DQN 是一种基于 Q-learning 的强化学习算法。它要学习的是一个 Q 函数:
Q(state, action)这个值表示:在某个状态下选择某个动作,未来大概能获得多少累计奖励。
在 CartPole 中,每个状态下有两个动作,DQN 会输出两个 Q 值:
Q(state, left)Q(state, right)如果 Q(state, right) 更高,模型就更倾向于向右推小车。
DQN 每次和环境交互时,会收集一条经验:
(state, action, reward, next_state, done)例如:
当前状态:杆子有点向右倾斜动作:向右推小车reward:+1下一个状态:杆子暂时没有倒done:False这些经验会被放入 replay buffer。训练时,DQN 从 buffer 中采样经验,用 Bellman 目标更新 Q 网络:
target = reward + gamma * max Q(next_state, next_action)直观理解就是:
这个动作的价值 = 当前拿到的奖励 + 未来还能拿到的奖励所以 DQN 并不是只看当前这一步有没有 +1,而是学习哪个动作能带来更高的长期累计 reward。
5. 行为克隆为什么是监督学习
Section titled “5. 行为克隆为什么是监督学习”为了对比强化学习和监督学习,我又做了一个行为克隆实验。
行为克隆不直接根据环境 reward 更新策略,而是模仿 expert 的动作。这里我用训练好的 DQN 作为 expert,收集它在 CartPole 环境中的轨迹数据。
每条示范数据包含:
输入:CartPole 状态标签:DQN expert 选择的动作然后训练一个 MLP 分类器,让它根据状态预测 expert 动作。
行为克隆的训练目标是:
state -> action损失函数是普通监督学习里的交叉熵:
loss = F.cross_entropy(logits, expert_action)它关心的是:
预测动作是否和 expert 动作一致而不是:
这个动作最后能不能带来更高 reward这就是行为克隆和强化学习的关键差别。行为克隆能模仿已有示范,但它不能直接通过环境奖励进行自我修正。
6. 实验设置
Section titled “6. 实验设置”本次实验使用 Stable-Baselines3 中的 DQN 实现,在 CartPole-v1 上训练智能体。
主要配置如下:
| 项目 | 设置 |
|---|---|
| 环境 | CartPole-v1 |
| 算法 | DQN |
| 策略网络 | MlpPolicy |
| 总训练步数 | 20000 |
| 评估间隔 | 每 2000 steps |
| 评估 episode 数 | 20 |
| learning rate | 1e-3 |
| replay buffer | 50000 |
| batch size | 64 |
| gamma | 0.99 |
| 对照方法 | 行为克隆 |
行为克隆部分使用 DQN 作为 expert,分别收集 5、20、100 个 episode 的示范数据,然后训练监督学习模型。
最终输出包括两张图:
DQN 奖励曲线DQN 与行为克隆奖励对比图7. DQN 奖励曲线
Section titled “7. DQN 奖励曲线”训练过程中,我每隔 2000 steps 评估一次 DQN 的平均 episode reward,结果如下:
| Timesteps | Mean Reward | Std Reward |
|---|---|---|
| 2000 | 11.35 | 1.19 |
| 4000 | 25.10 | 3.51 |
| 6000 | 133.45 | 8.37 |
| 8000 | 159.80 | 13.97 |
| 10000 | 162.15 | 23.61 |
| 12000 | 230.55 | 62.41 |
| 14000 | 155.70 | 25.40 |
| 16000 | 141.50 | 20.38 |
| 18000 | 139.70 | 17.83 |
| 20000 | 92.70 | 4.89 |
奖励曲线如下:

这条曲线很有意思。DQN 并不是一路稳定变好,而是先上升,然后又回落。
在训练早期,DQN 基本还没有学会控制杆子。2000 steps 时平均奖励只有 11.35,接近很快失败的水平。
训练到 6000 steps 后,平均奖励提升到 133.45,说明模型已经学到了一些有效动作。到 12000 steps 时,平均奖励达到本次实验中的最高值 230.55。
但是继续训练之后,奖励反而下降。到 20000 steps 时,平均奖励只有 92.70。
这说明当前超参数下,DQN 出现了策略退化。强化学习训练不一定是单调稳定的,最终 checkpoint 也不一定是训练过程中最好的策略。
8. 为什么 DQN 奖励会回落
Section titled “8. 为什么 DQN 奖励会回落”DQN 奖励回落并不是代码错误,而是强化学习训练中可能出现的现象。
首先,DQN 同时涉及探索、经验回放、目标网络和 Q 值估计。任何一个环节的变化都可能影响策略表现。
其次,replay buffer 中的数据分布会随训练过程变化。模型并不是只从当前策略产生的数据中学习,而是从经验池中采样历史经验。如果不同阶段的数据混合在一起,训练方向可能出现波动。
再次,Q-learning 本身可能有估计偏差。DQN 会根据最大 Q 值选择动作,如果 Q 值估计不准,模型可能会被错误的动作价值引导。
最后,这次实验保存的是最终 20000 steps 的模型,而不是 12000 steps 时的最佳模型。因此最终 DQN 的表现低于训练中曾经达到的峰值。
这个现象正好说明了强化学习和普通监督学习的差异。监督学习中,验证集指标通常可以通过 early stopping 选择最佳模型;强化学习中也需要类似机制,否则最终策略可能不是最优策略。
9. DQN 与行为克隆对比
Section titled “9. DQN 与行为克隆对比”使用最终 DQN 作为 expert,我分别收集 5、20、100 个 episode 的示范数据,训练行为克隆模型。最终结果如下:
| Method | Demo Episodes | Train Samples | Mean Reward | Std Reward |
|---|---|---|---|---|
| Random Policy | 0 | 0 | 21.55 | 6.70 |
| DQN | - | - | 93.30 | 5.33 |
| BC-5episodes | 5 | 464 | 131.50 | 42.15 |
| BC-20episodes | 20 | 1825 | 93.25 | 11.64 |
| BC-100episodes | 100 | 9107 | 93.15 | 6.00 |
对比图如下:

Random Policy 的平均奖励只有 21.55,说明随机左右移动基本无法稳定控制杆子。
最终 DQN 的平均奖励是 93.30,明显高于随机策略,说明它确实通过环境交互学到了一定控制能力。
BC-20episodes 和 BC-100episodes 的平均奖励都在 93 左右,基本接近最终 DQN。这说明行为克隆确实学到了 expert 的动作分布,但它的能力上限很大程度上受 expert 质量限制。
比较特殊的是 BC-5episodes,它的平均奖励达到 131.50,高于最终 DQN。但它的标准差也很大,达到 42.15,说明表现波动明显。这个结果不能简单理解为行为克隆比 DQN 更强。
10. 如何理解 BC-5episodes 高于最终 DQN
Section titled “10. 如何理解 BC-5episodes 高于最终 DQN”BC-5episodes 高于最终 DQN,是这次实验中比较容易误解的点。
首先,CartPole 评估本身存在随机性。不同 episode 的初始状态不同,20 个 episode 的平均值仍然可能出现波动。
其次,BC-5episodes 的标准差很大,说明它并不是稳定超过 DQN,而是在部分 episode 中表现较好。
第三,最终 DQN 已经发生了策略退化。DQN 在训练过程中曾经达到过 230.55 的平均奖励,但最终 checkpoint 只有 93.30。BC-5episodes 超过 final DQN,并不代表它超过了 DQN 在训练过程中的最佳策略。
所以更准确的结论是:
行为克隆可以模仿 expert,并且在简单环境中有时能取得不错表现,但它没有直接使用环境 reward,也不能像强化学习一样通过试错持续改进策略。
11. 强化学习和监督学习的本质差异
Section titled “11. 强化学习和监督学习的本质差异”这次实验最重要的收获,是更直观地理解了强化学习和监督学习的区别。
监督学习有明确标签。比如图像分类中,输入是一张图片,标签是类别,模型要学习输入和标签之间的映射。
行为克隆也是这个形式:
输入:状态标签:expert 动作模型只需要模仿 expert。
强化学习没有这样的标准答案。DQN 并不知道某个状态下“正确动作”是什么,它只能通过和环境交互,根据 reward 判断策略好不好。某一步动作的好坏,有时还要经过很多后续状态才能体现出来。
可以简单对比如下:
| 方法 | 学习信号 | 训练方式 | 优点 | 局限 |
|---|---|---|---|---|
| DQN | 环境 reward | 与环境交互,更新 Q 函数 | 能主动试错,直接优化长期奖励 | 训练不稳定,样本效率较低 |
| 行为克隆 | expert action | 监督学习分类 | 训练稳定,实现简单 | 依赖 expert,不能直接利用 reward |
| 随机策略 | 无 | 不学习 | 可作为 baseline | 表现很差 |
强化学习更像是在环境中反复尝试,通过奖励逐渐发现哪些行为能带来更高长期收益。行为克隆则更像是在看别人怎么做,然后模仿已有动作。
12. 实验中的环境问题
Section titled “12. 实验中的环境问题”这次实验中也遇到了一些环境配置问题。
一开始直接安装 stable-baselines3 时,pip 尝试下载新的 CUDA 和 PyTorch 依赖,比如 nvidia_cublas 这类几百 MB 的包。但当前环境中已经有 PyTorch,所以没必要重新下载。
最后采用的方式是先检查当前环境中的 PyTorch,再使用:
pip install stable-baselines3==2.3.2 --no-deps这样只安装 Stable-Baselines3 本体,不强制升级 PyTorch 和 CUDA。
运行时还出现了一个 warning:
Evaluation environment is not wrapped with a Monitor wrapper.这个 warning 不影响本次实验主流程。它只是提醒如果环境被额外 wrapper 修改过 episode length 或 reward,评估结果可能受影响。本次使用的是标准 CartPole 环境,可以先不处理。
13. 后续可以改进的方向
Section titled “13. 后续可以改进的方向”这次实验已经跑通了 DQN 和行为克隆对比,但还有几个可以继续扩展的方向。
第一,保存最佳 checkpoint。当前实验中,DQN 在 12000 steps 表现最好,但保存的是 20000 steps 的最终模型。后续可以在每次评估后判断 mean reward 是否提升,如果提升就保存 best model。
第二,重复多个随机种子。强化学习结果受随机性影响比较明显,只跑一个 seed 很难说明普遍规律。可以用 3 到 5 个 seed 取平均。
第三,调整 DQN 超参数。比如 learning rate、exploration fraction、target update interval、buffer size 等,都可能影响 DQN 的稳定性。
第四,加入 PPO 作为对照。DQN 属于 value-based 方法,PPO 更偏 policy-based / actor-critic 路线。两者在训练稳定性上可能会有差异。
第五,换更复杂的环境。CartPole 适合入门,但任务比较简单。后续可以尝试 MountainCar、LunarLander 等环境。
14. 小结
Section titled “14. 小结”这次实验使用 Stable-Baselines3 在 CartPole-v1 上训练 DQN,并用行为克隆作为监督学习对照。
实验结果显示,DQN 在训练早期奖励快速提升,在 12000 timesteps 时平均奖励达到 230.55,但继续训练后出现回落,最终 checkpoint 的平均奖励为 93.30。这说明强化学习训练具有明显的非单调性,策略可能在后期发生退化。
行为克隆通过模仿 DQN expert 的 state-action 数据进行监督学习。BC-20episodes 和 BC-100episodes 的平均奖励都接近最终 DQN,说明它能学习 expert 的动作分布;BC-5episodes 虽然平均奖励更高,但波动也更大,不能简单说明行为克隆优于强化学习。
整体来看,强化学习和监督学习最大的区别在于学习信号。强化学习通过与环境交互,根据延迟 reward 优化策略;行为克隆本质上是监督学习,只能模仿已有示范动作,不能直接从环境 reward 中自我修正。