Skip to content

输入关键词开始搜索

CartPole 强化学习实验:DQN 如何根据奖励学会控制杆子


前面几周的实验更多围绕监督学习展开。无论是迁移学习、主动学习、小样本学习还是联邦学习,模型通常都有明确的数据和标签。比如图像分类任务中,输入是一张图片,标签是它所属的类别,模型要学习的是输入和标签之间的对应关系。

强化学习的设定不太一样。

在强化学习中,模型一开始并不知道每个状态下应该做什么动作。它需要进入环境,通过不断尝试动作获得奖励,再根据奖励反馈逐步改进策略。这个过程中没有标准答案,只有环境给出的 reward。

这带来了一个很核心的问题:

没有人工标签,只有环境奖励时,智能体如何学会做决策?

这次实验选择 CartPole-v1 环境,使用 Stable-Baselines3 训练 DQN,并用行为克隆作为监督学习对照。实验重点不是追求满分,而是观察强化学习的训练过程,以及理解 reward 在策略学习中到底起什么作用。


CartPole 是强化学习中非常经典的入门环境。它可以理解为一个小车平衡杆子的物理仿真任务。

画面里有一辆小车,车上竖着一根杆子。这里的 “pole” 就是杆子,“cart” 就是小车。智能体不能直接扶杆子,只能控制小车向左或向右移动,让杆子尽可能保持不倒。

可以简单想象成这样:

杆子 pole
|
|
|
___|___
| | 小车 cart
|_______|

智能体每一步只能选择两个动作之一:

动作含义
0向左推动小车
1向右推动小车

环境给智能体的状态是 4 个数值:

状态含义
cart position小车位置
cart velocity小车速度
pole angle杆子的倾斜角度
pole angular velocity杆子的角速度,也就是杆子倒下的趋势

模型要学的不是“识别杆子”,而是根据这 4 个状态值判断小车下一步应该往左推还是往右推。

比如,杆子正在向右倒,小车可能需要向右移动,把杆子“接住”;杆子正在向左倒,小车可能需要向左移动。模型要通过反复试错学到这种控制规律。


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。

至于这个动作是不是长期来看更好,需要模型自己从大量交互经验中学习。


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。


为了对比强化学习和监督学习,我又做了一个行为克隆实验。

行为克隆不直接根据环境 reward 更新策略,而是模仿 expert 的动作。这里我用训练好的 DQN 作为 expert,收集它在 CartPole 环境中的轨迹数据。

每条示范数据包含:

输入:CartPole 状态
标签:DQN expert 选择的动作

然后训练一个 MLP 分类器,让它根据状态预测 expert 动作。

行为克隆的训练目标是:

state -> action

损失函数是普通监督学习里的交叉熵:

loss = F.cross_entropy(logits, expert_action)

它关心的是:

预测动作是否和 expert 动作一致

而不是:

这个动作最后能不能带来更高 reward

这就是行为克隆和强化学习的关键差别。行为克隆能模仿已有示范,但它不能直接通过环境奖励进行自我修正。


本次实验使用 Stable-Baselines3 中的 DQN 实现,在 CartPole-v1 上训练智能体。

主要配置如下:

项目设置
环境CartPole-v1
算法DQN
策略网络MlpPolicy
总训练步数20000
评估间隔每 2000 steps
评估 episode 数20
learning rate1e-3
replay buffer50000
batch size64
gamma0.99
对照方法行为克隆

行为克隆部分使用 DQN 作为 expert,分别收集 5、20、100 个 episode 的示范数据,然后训练监督学习模型。

最终输出包括两张图:

DQN 奖励曲线
DQN 与行为克隆奖励对比图

训练过程中,我每隔 2000 steps 评估一次 DQN 的平均 episode reward,结果如下:

TimestepsMean RewardStd Reward
200011.351.19
400025.103.51
6000133.458.37
8000159.8013.97
10000162.1523.61
12000230.5562.41
14000155.7025.40
16000141.5020.38
18000139.7017.83
2000092.704.89

奖励曲线如下:

DQN 在 CartPole-v1 上的奖励曲线

这条曲线很有意思。DQN 并不是一路稳定变好,而是先上升,然后又回落。

在训练早期,DQN 基本还没有学会控制杆子。2000 steps 时平均奖励只有 11.35,接近很快失败的水平。

训练到 6000 steps 后,平均奖励提升到 133.45,说明模型已经学到了一些有效动作。到 12000 steps 时,平均奖励达到本次实验中的最高值 230.55。

但是继续训练之后,奖励反而下降。到 20000 steps 时,平均奖励只有 92.70。

这说明当前超参数下,DQN 出现了策略退化。强化学习训练不一定是单调稳定的,最终 checkpoint 也不一定是训练过程中最好的策略。


DQN 奖励回落并不是代码错误,而是强化学习训练中可能出现的现象。

首先,DQN 同时涉及探索、经验回放、目标网络和 Q 值估计。任何一个环节的变化都可能影响策略表现。

其次,replay buffer 中的数据分布会随训练过程变化。模型并不是只从当前策略产生的数据中学习,而是从经验池中采样历史经验。如果不同阶段的数据混合在一起,训练方向可能出现波动。

再次,Q-learning 本身可能有估计偏差。DQN 会根据最大 Q 值选择动作,如果 Q 值估计不准,模型可能会被错误的动作价值引导。

最后,这次实验保存的是最终 20000 steps 的模型,而不是 12000 steps 时的最佳模型。因此最终 DQN 的表现低于训练中曾经达到的峰值。

这个现象正好说明了强化学习和普通监督学习的差异。监督学习中,验证集指标通常可以通过 early stopping 选择最佳模型;强化学习中也需要类似机制,否则最终策略可能不是最优策略。


使用最终 DQN 作为 expert,我分别收集 5、20、100 个 episode 的示范数据,训练行为克隆模型。最终结果如下:

MethodDemo EpisodesTrain SamplesMean RewardStd Reward
Random Policy0021.556.70
DQN--93.305.33
BC-5episodes5464131.5042.15
BC-20episodes20182593.2511.64
BC-100episodes100910793.156.00

对比图如下:

DQN 与行为克隆在 CartPole-v1 上的奖励对比

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表现很差

强化学习更像是在环境中反复尝试,通过奖励逐渐发现哪些行为能带来更高长期收益。行为克隆则更像是在看别人怎么做,然后模仿已有动作。


这次实验中也遇到了一些环境配置问题。

一开始直接安装 stable-baselines3 时,pip 尝试下载新的 CUDA 和 PyTorch 依赖,比如 nvidia_cublas 这类几百 MB 的包。但当前环境中已经有 PyTorch,所以没必要重新下载。

最后采用的方式是先检查当前环境中的 PyTorch,再使用:

Terminal window
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 环境,可以先不处理。


这次实验已经跑通了 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 等环境。


这次实验使用 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 中自我修正。