深度强化学习在车辆行为决策中的工程实践:从MDP建模到PPO训练
简介这是一份聚焦深度强化学习车辆行为决策的研究文档面向自动驾驶、人工智能和智能交通方向的研究人员、工程师及高校学生。文档以DQN与DDPG算法为主线系统梳理了驾驶员失误导致的安全问题背景、驾驶环境感知流程和策略模型设计思路。内容涵盖马尔科夫决策过程的五元组、状态值函数与贝尔曼方程等理论基础介绍了从DQN在Atari游戏中的突破到CNN端到端驾驶控制、再向连续动作空间扩展的经典研究脉络同时对比了DQN在离散动作空间中的局限以及DDPG如何通过Actor-Critic、经验回放和目标网络机制适应油门、刹车、转向等连续控制需求。资源仅含1个docx文档压缩包大小664KB结构紧凑、逻辑完整兼具理论推导和驾驶场景分析可作为论文写作、算法入门和课题设计的参考。目前已有115人学习下载。1. 车辆行为决策为什么需要深度强化学习车辆行为决策是自动驾驶系统里最容易被低估的一层。感知把道路、车辆、行人读进来规划把轨迹算出来但“接下来该跟车、加速、换道还是避让”这个瞬间判断既不能靠规则表穷举也不能把它当成纯优化问题去实时求全局最优。实际做下来你会发现规则方法在交叉口、匝道汇入这类场景会写出几千条互相对撞的条件分支而传统优化算法又被环境的不确定性拖住别人怎么开车你预测不了。深度强化学习把决策建模成“状态到动作”的映射通过和环境的交互奖励来学习策略不依赖手工设定所有场景。适合对这条路感兴趣的人包括在做决策规划模块的自动驾驶工程师研究 DRL 在连续控制上落地的算法工程师以及打算用仿真环境做学术验证的研究生。这篇文章按“建模—算法选型—训练环境—上车验证”的顺序把车辆行为决策里真正需要想清楚的事讲透。2. 车辆行为决策的MDP建模与观测设计2.1 行为决策层的输入输出边界行为决策和运动规划是两件事。行为决策的输出是驾驶意图比如“保持车道巡航”“准备换到左车道”“在停止线前停车”运动规划才把这些意图转换成具体的路径点或控制指令。很多刚开始做的人把两者混在一起让强化学习直接输出方向盘转角结果训练很难收敛因为动作空间里同时混合了离散意图和连续控制。常见的做法是决策层做离散动作规划层做连续轨迹。在这个边界下来看 MDP 建模核心是“状态转移概率不可知导致只能采样”。车辆周围其他交通参与者的意图不会写在状态里我们必须用一系列可观测变量去近似真实的隐状态。一套标准的观测设计如下def build_observation(ego, targets, road): obs np.concatenate([ # 自车状态 np.array([ego.vx, ego.vy, ego.yaw_rate, ego.acc]), # 前车相对信息 np.array([targets[0].dist, targets[0].rel_vx, targets[0].rel_lat]), # 左后方来车相对信息 np.array([targets[1].dist, targets[1].rel_vx, targets[1].rel_lat]), # 右后方来车相对信息 np.array([targets[2].dist, targets[2].rel_vx, targets[2].rel_lat]), # 当前车道限速、距下游路口距离 np.array([road.speed_limit, road.dist_to_junction]) ]) return obs.astype(np.float32)这段代码的关键在于没有把前车绝对速度放进观测里而是使用相对速度rel_vx。研究表明相对量对决策策略的泛化远好于绝对量因为决策只关心“我比前车快还是慢”而不关心绝对速度值。加入横摆角速度是感知到自车存在侧偏可能时才有的很多论文省略这个量导致换道策略在弯道区域崩掉。距离量全部归一化到 0-1 范围再输入网络避免量纲差异导致训练初期值函数更新方向被某一维特征主导。2.2 动作空间设计离散动作常见配置与参数动作空间的设计决定了问题难度。全连续动作交给决策层会引入和规划层的职责重叠常见的做法是把动作组合成意图集。注意观察动作列表中如何用不同维度组合出实际执行语义动作编号语义目标车速 m/s横向意图0匀速巡航当前速度保持车道1加速跟车前车速度保持车道2减速跟车前车速度*0.9保持车道3左换道目标车道限速换至左车道4右换道目标车道限速换至右车道动作编号 1 和 2 的区别不只是加速度大小而是目标车速参考点的差异。加速跟车把前车速度当作跟踪目标减速跟车则把前车速度乘以折减系数这样在跟车场景下策略可以表达“缓慢拉开距离”的中间语义而不是简单粗暴输出一个刹车量。参数里需要额外加一个“动作最小持续时间”约束常见做法是设 0.5 秒内不允许连续切换动作防止策略在边界处高频抖动。2.3 奖励函数中常见陷阱奖励函数是车辆行为决策里最容易被反复调的部分。稀疏奖励比如只在碰撞或到达终点给一个 -1 或 1 信号训练速度极慢但如果直接用密集奖励比如每一帧都对速度、距离进行惩罚策略会趋向于保守的原地停车因为不动就不会出错。我一般做三层奖励结构第一层是事件奖励碰撞扣 2 分、违反交通规则扣 1 分、到达目标点加 1 分优先级绝对最高第二层是效率奖励用前进距离的变化来鼓励移动单位是米乘一个小系数。不要用速度作为效率奖励的代理指标因为在弯道和拥堵中保持与车流一致比绝对速度更有意义。第三层是舒适性权重对加加速度也就是 jerk 做惩罚。这个模型写出来是reward ( - 2.0 * collision - 1.0 * rule_violation 1.0 * reach_goal 0.1 * (progress_now - progress_last) - 0.05 * abs(acc_now - acc_last) )事件奖励必须放在最后做终局性判断也就是如果碰撞发生在某一帧这一帧的即时奖励其他项全部置零避免策略在碰撞瞬间还拿到前进奖励导致对碰撞的惩罚被冲淡。jerk 系数 0.05 是从大量实验得到的经验值太大会让车辆在高速变道场景下动作犹豫太小则会产生明显顿挫感。调奖励的顺序永远是先调事件奖励的相对大小再动效率系数最后动舒适性系数反着调会浪费大量算力。3. 深度强化学习算法选型从DQN到PPO与SAC3.1 各类深度强化学习算法的适用边界算法选型的前提是识别清楚你面对的是离散动作还是连续动作。在车辆行为决策里如果完全按照上一章的离散动作表来建模那么 DQN 系算法仍然是最稳定的选择如果把换道轨迹的目标点也交给策略学习动作就是连续的此时 DQN 不适用。下面的对比表直接标出每一种算法在车辆决策上的适用位置算法动作类型样本效率训练稳定性决策场景适配度DQN离散低中换道、跟车间隙选择Double DQN离散低中高缓解过估计Dueling DQN离散低中高价值分离更稳PPO离散或连续中高最通用工程首选SAC连续高中连续动作决策规划耦合表格里体现出一个容易被忽略的点SAC 的样本效率高但是训练稳定性不如 PPO原因在于熵系数自动调节的机制在车辆高风险场景下容易让策略在训练中途变得过度随机必须额外做熵系数裁剪。DQN 系算法在纯粹离散动作的决策问题里仍然值得选因为其过估计问题可以通过 Double DQN 解决价值分解清晰可解释性更好。PPO 的好处是它对奖励尺度和超参数不敏感在换道决策这种奖励密度不一的问题里很少出现崩溃式发散。3.2 PPO在车辆决策中的关键实现细节PPO 在行为决策中的应用关键不在于网络结构多复杂而在于如何处理时序关联。车辆状态天然是时序数据但直接在 MLP 里堆叠历史帧会造成输入维度过大一个折中的方案是输入最近 5 帧的观测拼接而不是把整条轨迹交给循环网络。LSTM 版本收敛慢只在需要记忆前车 5 秒行为时才有必要多数场景不需要这种记忆能力。实现 PPO 时最大的坑在 GAE 计算的 normalize 步骤。状态价值估计的尺度如果不对优势函数的量级会被杠杆放大导致策略更新一步就坏掉。下面这段代码展示了正确的处理方式def compute_gae(rewards, values, next_value, gamma0.99, lam0.95): advantages np.zeros_like(rewards) last_gae 0.0 for t in reversed(range(len(rewards))): next_values values[t 1] if t 1 len(values) else next_value delta rewards[t] gamma * next_values - values[t] last_gae delta gamma * lam * last_gae advantages[t] last_gae returns advantages values # 优势归一化PPO训练比DQN更依赖这个操作 advantages (advantages - advantages.mean()) / (advantages.std() 1e-8) return advantages.astype(np.float32), returns.astype(np.float32)lam 0.95是 GAE 的偏差方差权衡参数车辆决策里建议不要调太高因为高 lambda 会引入远期偏差到策略梯度里换道决策里的远期回报受其他车辆行为干扰太大。归一化一定得在完整 batch 上做而不是在每一步做否则会破坏优势的相对排序。gamma 0.99对应的是约 10 秒的决策视界这是从 0.5 秒决策周期推出来的合理折扣既不过于短视也不过于远期。PPO 里 clip 参数在车辆决策里值得单独提0.2 是保守默认值如果训练中策略熵下降过快造成早熟可以把 clip 调到 0.1 试代价是更新节奏变慢。有一点是训练中期会遇到 reward 在几个小时内都是平的这是正常的因为稀疏事件奖励下策略需要大量探索才能偶然发现成功路径出现这种情况时不要急着调奖励参数应该先看策略熵是否在下降熵在降就说明在学。3.3 与粒子群等传统优化算法的定位差异做车辆行为决策研究的人常被问到一个问题为什么不用粒子群或 NSGA-II 这类优化算法来搜索轨迹参数要回答这个必须分清在线和离线的边界。粒子群算法可以在离线状态下对一个场景的轨迹参数做全局搜索给出质量很高的轨迹但它的耗时不能保证实时性。深度强化学习在离线训练时也花了大量算力进行探索但是在部署时只是一次前向推理时延通常在十毫秒级。另一个本质区别在于泛化能力。优化类算法每遇到一个新场景都要重新求解行为决策里的场景参数空间是连续的包括前车距离、相对速度、道路曲率、旁车意图各类信息组合数量多到什么程度任何在线优化都难以招架。强化学习把场景映射到策略参数里遇到相似场景直接复用。两者准确说不是替代关系而是互补优化算法可以作为 RL 训练中的专家示范数据生成器用来做模仿学习的初始化。对这个问题感兴趣的人注意这个结合方式就比单纯对比算法优劣有价值得多。4. 搭建车辆行为决策训练环境的步骤与参数4.1 仿真器选型与坐标系约定主流的车辆决策训练环境有 CARLA、SUMO 和 SMARTS 三类。CARLA 的传感器和物理仿真最完整适合做相机输入和车辆动力学耦合的决策SUMO 的微观交通流仿真能力强但动力学模型粗糙适合多车博弈的宏观策略验证SMARTS 专门为多智能体交互设计处理其他车辆是“有决策能力的学习体”的情况优于前两者。做成套行为决策研究时我一般用 SMARTS 或 CARLASUMO 更适合验证路网级别的调度策略。仿真器使用中最容易被忽略的是坐标系。CARLA 在世界坐标系下返回位置而行为决策需要的所有量都应该是自车坐标系下的相对量。在进入模型前统一做一次坐标变换def transform_to_ego(ego_pos, ego_yaw, target_pos): dx target_pos[0] - ego_pos[0] dy target_pos[1] - ego_pos[1] cos_yaw np.cos(-ego_yaw) sin_yaw np.sin(-ego_yaw) local_x dx * cos_yaw - dy * sin_yaw local_y dx * sin_yaw dy * cos_yaw return np.array([local_x, local_y], dtypenp.float32)ego_yaw取负号是因为这里想得到的是目标点在自车坐标系下的坐标而不是自车在世界坐标系下的朝向变换。很多训练不收敛的问题追到根上就是坐标系变换时正负号搞反导致前车一会儿在左一会儿在右。另一个建议是固定仿真步长不要在训练时用可变步长否则同样一条轨迹在不同步长下的观测序列没有任何意义。4.2 最小可运行的训练脚本环境建好后的最小训练闭环不依赖复杂框架直接用 gym 接口写清楚就行。以下脚本是一个可跑通的起点包含初始化、交互循环、经验存储三个关键部分import gym import numpy as np from stable_baselines3 import PPO env gym.make(vehicle-decision-v0) # 关键超参数学习率低一点车辆决策规则稀疏 model PPO( MlpPolicy, env, learning_rate3e-4, n_steps2048, batch_size128, gamma0.99, gae_lambda0.95, clip_range0.2, ent_coef0.01, # 保证一定探索度配合车辆安全性约束 max_grad_norm0.5, # 梯度裁剪防碰撞场景带来的大梯度 verbose1, ) # 训练中每5000步用固定随机种子评估一次 for i in range(20): model.learn(total_timesteps25000) obs env.reset() episode_return 0.0 for _ in range(200): action, _ model.predict(obs, deterministicTrue) obs, reward, done, _ env.step(action) episode_return reward if done: break if (i 1) % 4 0: model.save(fvehicle_decision_{i1}.zip)学习率 3e-4 是 PPO 论文里的默认值车辆决策场景如果出现奖励震荡可以降到 1e-4但不要低于 5e-5否则收敛太慢。n_steps2048对应一次策略更新收集的交互步数这个值在决策周期 0.5 秒的情况下约为 17 分钟的驾驶数据。ent_coef0.01是容易被忽略的一项熵系数太小策略会过早确定化在遇到训练时没见过的右侧超车场景时没有探索能力。评估时用deterministicTrue是合理的但注意实际部署时应该保留轻微的随机性因为真实道路上其他车辆不会完全遵循训练分布确定性策略在极端情况下反而更容易卡死。训练中途保存模型是个好习惯但要注意每轮都用同一随机种子做测评否则不同起点的评估结果之间没有可比性。4.3 训练不收敛时先查这五个参数检查项合理范围异常表现学习率1e-4 - 5e-4过大导致 loss 直接变 NaN奖励尺度事件奖励绝对值在 1-10模型只看碰撞惩罚忽略效率观测归一化所有量在 [0,1] 或标准化训练前期震荡剧烈GAE lambda0.95 - 0.99过小导致换道动作迟钝动作频率2 - 10 Hz太高则动作抖动太低则错过避让时机奖励尺度这一点值得多提。总奖励如果长期为正且数量级在 10 以上模型会变得冒险因为它发现激进驾驶的收益能覆盖碰撞的惩罚。解决方法是把碰撞惩罚系数调成效率奖励系数的十倍以上让“安全”在数值意义上是效率的前提。动作频率 2Hz 是我推荐的起点也就是每 500ms 做一次决策这样可以给底层运动控制留出足够执行时间。过高频率会导致决策层和规划层的指令互相打架低频又会让策略对突发插队反应不过来。4.4 多智能体与联邦思路做场景扩展单一车辆场景收敛之后下一步自然是多车交互。多智能体场景里其他车辆也有自己的策略这就让环境变成了非平稳的训练时的最优策略可能在部署时失效。一个常规做法是让其他车辆用规则模型和上一版本 RL 策略两者混编避免训练对手太弱或者太强。如果研究的重心在数据隐私保护与多方联合训练可以考虑联邦深度强化学习的框架每辆车在本地收集轨迹数据只上传策略梯度或模型参数服务器端聚合后下发。这个方向的难点是不同车辆的观测分布差异大简单做 FedAvg 会导致模型震荡需要对不同客户端的梯度做加权或做个性化的本地微调。5. 车辆行为决策模型上车前的验证与降级策略模型在仿真里收敛不意味着能上车。部署前要做的第一件事不是看成功率而是把策略在所有训练场景上的决策轨迹全部回放一遍检查有没有“虽然成功但动作异常”的情况。所谓异常包括在无车路段反复左右偏移、遇红灯提前 200 米就停在路中间、变道过程中频繁修正。这些行为不会在碰撞率这种指标上反映出来但会影响乘坐体验和周边车辆的安全。一个可执行的验证方法是设计固定回归场景集每个场景设置固定的起始位置、固定的周围车初始状态然后对比新旧策略的决策差异。如果新策略在某个场景上的动作和旧策略差异超过阈值就需要检查是提升还是退化。这个阈值在动作空间上是看选择动作的编号变化在连续控制量上是看速度或加速度误差。对这个回归集写一个自动评测脚本每次训练完批量跑一遍并把失败场景截图存下来用图像比对来定位状态空间里的盲区。部署层面的实质问题是安全冗余。决策模型绝不能直接连到执行器。我的方案是加一层规则校验器策略输出的动作先经过安全检查检查内容包括目标车道是否有碰撞风险、车辆是否在限速内、换道动作是否符合当前车道线虚实线规则。校验器不通过就回退到上一时刻的动作或默认跟车策略。这个逻辑说清楚就是“RL 做选择规则做否决”。因为深度强化学习策略天然缺乏对安全边界的显式建模靠奖励函数里的碰撞惩罚是远远不够的一旦出现分布外状态策略可能产生无法理解的输出。校验器的降级策略不要只做一级。我一般设两级第一级是安全校验直接否决危险动作第二级是置信度低于阈值时从 RL 策略切换到模型预测控制或纯跟车模式。置信度可以用策略的概率分布来近似当最高动作概率低于 0.4 时说明策略内部存在犹豫此时切换到保守模式比强行选择一个低置信度动作更可靠。切换时需要注意平滑过渡通过速率限制器约束纵向加速度的变化率防止模式切换瞬间给乘客带来冲击。实车测试时先封闭场地验证降级触发逻辑再上公开道路这个顺序不要省。本文还有配套的精品资源点击获取