CarRacing DQN/DoubleDQN:训练改进、实验结果与可视化分析


项目概述

本项目围绕 Gymnasium CarRacing-v2 视觉控制任务,搭建并改进 DQN/DoubleDQN 训练框架,目标是把训练从“能跑通”提升到“可复现、可对比、可解释”,并以实验日志与可视化结果支撑算法迭代。

项目输出包括:

  • 可配置训练入口(DQN/DoubleDQN),支持固定随机种子与关键开关;
  • 标准化日志与对比图(reward、loss、SPS、UPS 等);
  • 模型权重与评估流程,便于复用与复现;
  • 面向后续扩展(PER、NoisyNet、n-step return 等)的工程底座。

项目目标

  1. 可复现:训练参数配置化,固定 seed,日志与产物可追溯,保证同配置可复跑。
  2. 可对比:将关键改进点做成开关,支持 baseline vs improved、消融对照与多组实验对比绘图。
  3. 可解释:不仅观察 reward,还记录 loss、回合长度与吞吐指标(SPS/UPS),让训练现象可分析。
  4. 可扩展:在不破坏训练主流程的前提下,能快速加入更多 DQN 变体或训练技巧。
  5. 可落地:在 GPU 环境下支持 AMP 等加速手段,能进行长时间稳定训练并输出可汇报结果。

核心算法原理(DQN 系列)

1. DQN:用深度网络逼近动作价值函数

强化学习中,动作价值函数 Q(s, a) 表示在状态 s 下选择动作 a 后,未来累计回报的期望。DQN 使用神经网络 Q(s, a; θ) 来逼近该函数,并通过最小化 TD 误差训练网络。

核心计算包含:

  • ε-greedy 探索:以概率 ε 随机探索,以 1-ε 选择 argmax_a Q(s, a; θ)
  • 目标值(TD Target)y = r + γ max_{a'} Q(s', a'; θ⁻)
  • 损失(TD Loss):常见为 Huber/MSE:L = E[(Q(s, a; θ) - y)^2]

为提升稳定性,DQN 通常配合两项关键机制:

  • 经验回放(Replay Buffer):从历史样本中随机采样训练,打破样本相关性,提高数据利用率。
  • 目标网络(Target Network):使用参数较慢更新的 θ⁻ 计算目标值,降低“目标漂移”带来的不稳定。

2. Double DQN:缓解 Q 值过估计

标准 DQN 的 max 操作容易引入过估计。Double DQN 将“选动作”和“评估动作”拆开:

  • 先用在线网络选动作:a* = argmax_{a'} Q(s', a'; θ)
  • 再用目标网络评估:y = r + γ Q(s', a*; θ⁻)

这通常能让学习目标更稳,减少价值函数发散风险。

3. Dueling Network:分解状态价值与动作优势

Dueling 结构将 Q(s, a) 分解为:

  • 状态价值 V(s):状态本身的价值
  • 动作优势 A(s, a):相对平均动作的优势

常用聚合方式:

Q(s, a) = V(s) + (A(s, a) - mean_a A(s, a))

这样能让网络在“动作差异不大”的状态下更高效地学习,有助于视觉任务的稳定与样本效率。

4. 本项目中的稳定性增强手段(与算法配套)

  • 观测归一化:将 uint8(0~255) 缩放到 float(0~1),改善 CNN 输入尺度。
  • 梯度裁剪:限制梯度范数,缓解训练后期梯度爆炸与震荡。
  • AMP:在 GPU 上启用混合精度,在尽量不损失稳定性的前提下提高吞吐。

项目介绍

这个项目面向一个具体问题:如何让 CarRacing-v2(图像输入的驾驶控制任务)上的 DQN/DoubleDQN 训练,从“能跑”变成“可复现、可对比、可解释”,并且能支撑后续持续迭代。

项目具体做了什么

  1. 把训练做成一条标准管线:环境预处理 → 采样与回放 → 更新网络 → 记录日志 → 画图对比 → 保存模型/评估。
  2. 把关键算法点模块化为开关double_qduelingnormalize_obsmax_grad_normamp 等都可以通过参数控制,方便做对照实验。
  3. 把“实验结果”落到文件与指标上:训练过程自动输出 CSV 日志,并对 reward、loss、SPS、UPS 做可视化与表格统计,确保结论可追溯。

项目范围(从输入到输出)

  • 任务与环境:Gymnasium CarRacing-v2,图像观测输入,离散动作空间(continuous=False)。
  • 输入状态:经过灰度化、缩放与帧堆叠后的图像序列(典型形状为 (4, 84, 84))。
  • 输出策略:离散动作(转向/加速/刹车/空动作),通过估计 Q(s, a) 选择动作。
  • 训练产物
  • 训练日志(CSV):reward、loss、epsilon、SPS、UPS、episode length;
  • 模型权重(.pt);
  • 对比曲线图(PNG)。

代码结构与关键文件(可在演讲中直接指路)

  • 训练入口
  • DQN:nn/src/car_racing/car_racing_ros/dqn_model/training_dqn.py
  • DoubleDQN:nn/src/car_racing/car_racing_ros/doubledqn_model/training_double_dqn.py
  • 核心智能体与网络
  • DQN Agent:nn/src/car_racing/car_racing_ros/dqn_model/dqn_agent.py
  • Dueling 网络结构:nn/src/car_racing/car_racing_ros/dqn_model/base_agent.py
  • DoubleDQN Agent:nn/src/car_racing/car_racing_ros/doubledqn_model/doubledqn_agent.py
  • 配置文件(复现与对比的关键)
  • nn/src/car_racing/car_racing_ros/configs/dqn.yaml
  • nn/src/car_racing/car_racing_ros/configs/double_dqn.yaml
  • 实验产物目录
  • 日志:nn/src/car_racing/car_racing_ros/training/logs/
  • 权重:nn/src/car_racing/car_racing_ros/training/saved_models/
  • 图像:nn/src/car_racing/car_racing_ros/training/*.png
  • 对比绘图工具
  • nn/src/car_racing/car_racing_ros/plot_comparison.py

项目核心亮点

  1. 不只是论文复现:把 Double DQN、Dueling Network、梯度裁剪、观测归一化等技术从“零散在代码里”变成“可开关、可对比的模块”
  2. 不只有单条 reward 曲线:补充 SPS、UPS 等工程指标与完整实验结果表格,让训练过程透明可分析;
  3. 不只有数字结果:对关键术语、表格指标逐个解释,让结果可理解、可验证;
  4. 是一个可迭代的工程底座:为后续集成 PER、NoisyNet、n-step 等更多 DQN 变体预留了统一接口。

汇报大纲

  1. 项目背景与研究动机
  2. 系统性改进方案(算法 + 工程)
  3. 实验设计与结果来源
  4. 量化结果与效果分析
  5. 关键术语与表格解读
  6. 总结与未来展望

1. 项目背景与研究动机

CarRacing-v2 是一个典型的强化学习视觉控制任务。智能体从图像观测中学习驾驶策略,目标是在赛道上尽可能稳定地前进并获得更高累计奖励。 典型难点: 1. 输入是像素图像:状态维度高,特征提取依赖 CNN,训练开销明显高于低维状态任务。 2. 奖励稀疏且波动较大:智能体在训练初期经常无法形成有效驾驶行为,reward 曲线会剧烈震荡。 3. 强化学习训练稳定性差:经验回放、目标网络、探索率衰减等细节都会显著影响结果。 4. 实验复现成本高:如果参数散落在代码中,每次做对比实验都容易引入额外变量。 因此,本项目的核心目标并不是只追求一个“更高的 reward”,而是构建一个: - 能固定随机种子、重复实验的训练框架; - 能记录 reward、loss、SPS、UPS 等关键指标的监控系统; - 能对比 baseline 与改进方案的实验平台; - 能为后续扩展 PER、NoisyNet、n-step return 等方法提供统一接口的工程底座。

2. 系统性改进方案

2.1 算法层改进

本项目并非简单替换算法名称,而是把多个稳定训练的重要机制做成了可开关、可对比的模块。

1. Double DQN 机制

Double DQN 的核心作用是缓解标准 DQN 中常见的 Q 值过估计(overestimation) 问题。 - 标准 DQN 往往使用同一个目标值过程同时“选动作”和“评估动作”,容易把某些动作价值估得过高。 - Double DQN 将这两个过程分开: - 用在线网络(policy net)选择下一个动作; - 用目标网络(target/frozen net)评估该动作对应的 Q 值。

这样做的好处是: - 学习目标更稳; - reward 曲线通常更容易上升; - 在长时间训练中更不容易出现价值函数发散。

2. Dueling Network 结构

Dueling Network 将 Q 值函数分解为两部分: - 状态价值 V(s):当前状态本身有多“好”; - 动作优势 A(s, a):在该状态下,某个动作比平均动作“好多少”。 这样做的意义在于: - 网络能先学会“这个状态值不值得继续”,再学“这个状态下哪个动作更优”; - 在很多状态下,不同动作差异不大,Dueling 结构通常能提升特征利用效率; - 对图像输入任务尤其有帮助,因为它能更好地区分“环境状态信息”和“动作偏好信息”。

3. 梯度裁剪(Gradient Clipping)

max_grad_norm 用于限制梯度范数,防止训练中出现梯度爆炸。 通俗理解: - 如果一次反向传播得到的梯度过大,参数更新会非常剧烈; - 过剧烈的更新会导致 loss 突增、Q 值震荡甚至训练崩掉; - 梯度裁剪会在梯度过大时将其缩放回安全范围。 这类机制对强化学习尤其重要,因为强化学习的目标值本身就在不断变化,比监督学习更容易不稳定。

4. 观测归一化(Observation Normalization)

环境原始图像通常是 uint8 类型,像素值范围是 0~255
normalize_obs 会把它转换为 float32 并缩放到 0.0~1.0。 这样做的好处是: - CNN 输入尺度更稳定; - 梯度传播更平滑; - 不同 batch 之间的数值范围更一致; - 通常能加快收敛并减少训练前期震荡。

5. AMP 混合精度训练

AMPAutomatic Mixed Precision 的缩写,即自动混合精度训练。 它的作用是: - 一部分计算使用半精度浮点数,降低显存压力; - 关键位置保留高精度,避免数值不稳定; - 在 GPU 环境下通常可以提升吞吐。 对于需要长时间训练的 CarRacing 图像任务,AMP 可以显著改善训练效率。

2.2 工程层改进

1. 参数化训练入口

训练脚本 training_dqn.py 已支持大量命令行参数,例如: - --episodes - --max-timesteps - --dueling - --double-q - --amp - --normalize-obs - --seed 这意味着实验不再依赖“手改代码”,而是可以通过命令行固定配置、直接复现。

2. 性能监控指标

训练日志中额外记录了两类工程指标: - SPS(Steps Per Second):每秒环境交互步数; - UPS(Updates Per Second):每秒网络更新次数。 它们可以帮助回答两个关键问题: - 训练慢是因为环境模拟慢,还是因为网络更新慢? - 新增算法模块后,性能收益是否值得吞吐开销?

3. 张量处理与设备搬运优化

代码中对经验回放采样后的 batch 做了更合理的设备搬运与形状整理,减少了细粒度张量操作带来的额外开销,也降低了训练过程中的维度错误风险。

4. 可视化脚本统一化

plot_comparison.py 支持: - 多个日志同时绘图; - reward、loss、SPS、UPS 等多个指标对比; - --smooth N 滑动平均平滑; - 服务器/无头环境下通过 MPLCONFIGDIR 规避 Matplotlib 缓存问题。

2.3 环境预处理设计

训练入口中对 CarRacing 做了标准视觉强化学习预处理: 1. GrayScaleObservation:彩色图像转灰度,降低输入复杂度。 2. ResizeObservation(84, 84):将图像统一到经典 Atari 风格尺寸。 3. FrameStack(4):堆叠连续 4 帧,让网络获得速度与运动方向信息。 4. SkipFrame(4):每 4 步执行一次同动作,减少冗余计算并提升训练效率。

这些预处理对于视觉控制任务非常关键,因为单帧图像通常不足以让智能体推断速度和方向变化。

3. 实验设计与结果来源

3.1 实验日志来源

本文中的量化结果主要来自以下日志文件: - nn/src/car_racing/car_racing_ros/training/logs/DQN_baseline_long.csv - nn/src/car_racing/car_racing_ros/training/logs/DQN_improved_long.csv 这两份日志都包含 200 个 episode 的训练记录,适合作为本次主实验对比数据。 这些文件可以作为开发阶段验证使用,但在“正式对比结论”上,*_long.csv 更有代表性。

3.2 对比组定义

为便于理解,这里将实验分为两组: | 组别 | 配置说明 | 主要特点 | | :--- | :--- | :--- | | Baseline | 较原始的 DQN 训练配置 | 作为对照组,观察未充分优化时的训练表现 | | Improved | 启用 duelingdouble_qnormalize_obsampmax_grad_norm 等改进 | 目标是提升稳定性、样本效率和最终策略性能 |

3.3 图像结果

下面给出项目中已经生成的对比图,便于从趋势上观察 reward 和 loss 的变化。 Reward 对比图(smooth=20) Loss 对比图(smooth=20)

4. 量化结果与效果分析

4.1 主实验结果表(200 Episodes)

基于 DQN_baseline_long.csvDQN_improved_long.csv 统计得到的主结果如下:

指标 Baseline Improved 变化趋势 解读
平均奖励(Mean Reward) -41.99 101.72 明显提升 从整体负回报转为正回报,说明改进配置已经学到更有效的驾驶策略
末回合奖励(Last Episode Reward) 64.06 723.53 大幅提升 训练结束时 Improved 的策略质量显著更高
最近 10 回合平均奖励 6.48 597.17 大幅提升 说明 Improved 不只是偶然跑出高分,而是在后期形成了稳定优势
最佳单回合奖励(Best Reward) 219.81 916.20 大幅提升 改进配置具备更高的性能上限
平均回合长度(Mean Episode Length) 205.38 221.40 小幅提升 智能体平均存活更久、能覆盖更多赛道步骤
平均 SPS 9.20 9.30 基本持平 改进后的训练并未明显拖慢环境交互速度
平均 UPS 2.30 2.32 基本持平 加入增强模块后,网络更新吞吐仍然保持稳定
平均 Loss 0.2504 0.3509 数值上升 在强化学习中 loss 不能单独等价为“效果变差”,需结合 reward 与训练阶段一起分析

4.2 如何理解这张表

上表中的每一个指标都有明确含义,下面逐项解释。

1. 平均奖励(Mean Reward)

这是整个训练过程中,所有 episode 奖励的平均值。 - 如果平均奖励长期为负,通常说明智能体大部分时间仍然在“乱开”或频繁偏离赛道。 - 如果平均奖励转正,说明整体策略已经从“经常失败”走向“经常能有效完成驾驶”。 本实验中,平均奖励从 -41.99 提升到 101.72,说明改进配置在整体训练质量上显著优于 baseline。

2. 末回合奖励(Last Episode Reward)

这是最后一个训练回合的 reward,用于观察训练结束时模型大致处于什么水平。 - Baseline 末回合奖励为 64.06; - Improved 末回合奖励为 723.53。 这表示在训练末期,改进配置已经学到更成熟的驾驶行为。

3. 最近 10 回合平均奖励

这个指标比“单个末回合奖励”更可靠。 原因是单次 episode 可能有偶然性,而最近 10 回合平均值更能反映训练后期是否稳定地好。 在本实验中: - Baseline 最近 10 回合平均奖励仅为 6.48; - Improved 最近 10 回合平均奖励达到 597.17。 这说明 Improved 后期性能提升并不是偶然尖峰,而是稳定趋势。

4. 最佳单回合奖励(Best Reward)

表示整个训练过程中跑出的最高单回合 reward。 它反映模型的性能上限,但不代表模型每次都能稳定达到这个水平,因此需要结合“最近 10 回合平均奖励”一起看。

5. 平均回合长度(Episode Length)

这里的 length 表示一个 episode 持续了多少步。 - 在 CarRacing 中,回合越长通常意味着智能体越不容易早早失控; - 但“回合长”并不一定等于“得分高”,仍需与 reward 一起看。 本实验中 Improved 的平均回合长度略高,说明它一般能在赛道上坚持更久。

6. SPS 与 UPS

这两个指标是工程性能指标: - SPS(Steps Per Second):每秒完成多少个环境交互步; - UPS(Updates Per Second):每秒完成多少次网络参数更新。 如果一个改进方案让 reward 提升很多,但 SPS、UPS 下降非常明显,就要重新评估“性能收益是否值得工程成本”。
本实验中这两个指标几乎持平,说明改进配置在不牺牲吞吐的前提下获得了更好的学习效果。

7. Loss 为什么没有直接下降?

这是强化学习文档里最容易误解的地方。 在监督学习中,loss 降低通常意味着模型更好;但在强化学习里,loss 是 TD 误差相关的训练信号,它会受到以下因素影响: - 当前策略是否进入了更高回报、但也更复杂的状态分布; - 目标网络是否在持续变化; - Q 值估计范围是否扩大; - 后期 episode 是否更长,包含更多高价值状态。 因此: - reward 是衡量策略表现的核心指标; - loss 更适合作为训练稳定性的辅助参考; - 不能只因为 loss 数值更大,就断言模型效果更差。 在本实验中,虽然 Improved 的平均 loss 更高,但 reward、后期均值和最佳表现都明显更好,因此应综合判断为“策略性能更优”。

4.3 一句话总结主实验

在 200 回合主实验中,改进配置实现了: - 从整体负回报到整体正回报的跃迁; - 训练末期奖励的显著提升; - 最近 10 回合稳定高分; - 几乎不增加吞吐损耗的前提下获得明显性能收益。

5. 名词解释

下面对文中核心术语做一个集中解释,方便在汇报或答辩时直接引用。 | 名词 | 解释 | | :--- | :--- | | DQN | Deep Q-Network,使用神经网络逼近动作价值函数 Q(s, a) 的经典值函数方法 | | Double DQN | 对 DQN 的改进,通过“选动作”和“评估动作”分离来降低 Q 值过估计 | | Dueling Network | 将 Q 值拆成状态价值 V(s) 和动作优势 A(s, a) 两部分建模的网络结构 | | Q 值 | 在状态 s 下执行动作 a 后,未来累计回报的估计值 | | 目标网络(Target/Frozen Net) | 用于生成训练目标的网络,参数更新较慢,用于稳定训练 | | 经验回放(Replay Buffer) | 存储历史交互样本,从中随机采样训练,打破数据相关性 | | Reward | 每个 episode 的累计奖励,是评价策略好坏的最直接指标 | | Loss | 训练时 Q 值预测与目标值之间的误差,更多反映学习过程信号,而非最终任务表现 | | Episode | 从环境重置到终止的一次完整交互过程 | | SPS | Steps Per Second,每秒环境交互步数,反映采样吞吐 | | UPS | Updates Per Second,每秒参数更新次数,反映训练吞吐 | | AMP | 自动混合精度训练,在 GPU 上可降低显存占用并提升速度 | | Gradient Clipping | 梯度裁剪,把过大的梯度限制在安全范围内,避免训练发散 | | Observation Normalization | 将输入观测从 0~255 缩放到 0~1,让网络更容易学习 | | Frame Stack | 将连续多帧图像拼接为一个状态,使模型能感知运动趋势 | | Skip Frame | 连续多步重复同一动作,减少计算量并提升训练效率 |

6. 实验结果结论

结合日志、曲线和量化表格,可以得到以下结论: 1. 改进方案有效Improved 组在 200 回合主实验中显著优于 baseline,尤其体现在后期 reward 的稳定提升。 2. 性能提升具有持续性:最近 10 回合平均奖励大幅领先,说明不是偶然波动,而是训练后期已形成稳定优势。 3. 工程开销可接受:SPS 与 UPS 基本持平,说明启用 Dueling、Double DQN、归一化与裁剪后,并未带来明显吞吐损失。 4. 评价模型不能只看 loss:强化学习中的 loss 只是过程信号,必须与 reward、回合长度和后期趋势结合分析。

7. 未来工作展望

基于当前已经完成的框架,后续可以继续扩展: 1. 更强的 DQN 变体:如 PER(Prioritized Experience Replay,优先经验回放)、Noisy Networks、n-step return。 2. 更系统的超参数搜索:利用现有参数化脚本,对 lrbatch_sizetarget_updateepsilon_decay 做网格搜索或贝叶斯优化。 3. 评估体系完善:增加固定模型检查点、独立评估脚本、均值与方差统计,让结果更适合论文或课程报告使用。 4. 迁移到更多环境:将当前框架迁移到 Atari 或机器人控制任务,验证方法的通用性。