☰
SUMO与DQN实战:用强化学习优化交通信号灯配时
2026/10/13 19:51:33 网站建设 项目流程

简介:面向交通仿真与强化学习研究者,提供一套基于开源微观交通仿真平台、利用深度强化学习网络改进路口信号灯相位时长的完整工程包。内容覆盖从仿真路网搭建、车流定义到状态特征提取、相位动作设计、奖励设置与策略训练的全流程,核心脚本包含多个用于训练与辅助的Python脚本文件,可通过经验回放和迭代更新逼近最优控制策略,适合智能交通课程设计、算法验证与实际路口信号优化研究。压缩包共32个文件,以路网配置、地图数据、算法脚本、表格数据及说明文档为主,其中XML文件用于定义路网与仿真参数,OSM文件提供真实地图底图,Python脚本实现Q学习及优先级优化,Excel表格记录车道与配时信息,整体大小仅532KB,结构清晰便于快速加载和二次开发。已有497人学习下载,对理解交通仿真与强化学习结合的接口设计、建模方法及性能评估具有直接参考价值。

1. 利用SUMO和DQN优化交通信号灯:一个值得下手的强化学习仿真项目

交通信号灯配时优化是个典型的时序决策问题,传统固定配时方案在高峰期经常出现单方向排队溢出、绿灯空放。用强化学习中的DQN做自适应信号控制,核心思路是把路口状态当成观测值,让智能体通过学习选择最优的相位持续时间。这个基于SUMO的仿真项目正好把整条技术链路打通了:SUMO负责搭建路网和车辆流,DQN算法负责决策相位时间,两边通过TraCI接口实时交互。对于想入门强化学习落地、又不想纠结真实路测成本的从业者,这个资源相当于给了你一套可复现的实验平台,既能看算法效果,又能对比训练曲线和通行效率指标。


2. 为什么是SUMO和DQN:选型逻辑与适用边界

2.1 SUMO的仿真能力与TraCI接口价值

SUMO(Simulation of Urban MObility)是个开源微观交通仿真平台,能在没有真实道路数据的情况生成路网、车流和信号控制逻辑。选它做强化学习环境,核心原因是TraCI(Traffic Control Interface)提供了实时读取和操控仿真状态的通道。你可以在训练循环里获取每个路口的车辆数、等待时间、排队长度,也可以动态修改信号灯相位。这种双向控制能力,让外部Python代码能像操作真实基础设施一样驱动仿真。

推荐流量下SUMO的单步仿真速度很快,但这并不能说明它适合所有场景。SUMO的路网建模需要手动配置交叉口、车道、连接关系和信号灯组,前期环境搭建工作量比使用虚拟仿真环境大得多,这也是项目中值得认真拆解的部分。不过好处是建模粒度可控:从单路口到多路口网络,从固定车流到随机到达,都能在SUMO里精确描述。

2.2 DQN在信号控制问题中的适配性

DQN(Deep Q-Network)擅长处理高维状态空间和离散动作空间的问题。交通信号控制正好满足这两个条件:状态来自路口的连续数值(排队长度、车辆数、当前相位),动作则是可选相位方案或相位持续时间调整。传统Q表格在这个规模下会因状态组合爆炸而失效,深度网络正好替代Q表格做值函数逼近。

项目用DQN而不选策略梯度方法,主要理由在于信号控制问题天然是离散决策:要么延长当前相位,要么切换下一个相位,不存在连续动作的需求。虽然DDPG、PPO这类算法也能处理离散动作,但DQN网络结构简单,训练稳定,调参成本低,对刚接入SUMO的团队来说是最快能跑通整个闭环的算法。项目里使用经验回放和目标网络两个组件,是为了打破样本相关性并稳定目标值计算,这两个在后续代码解析里会看到具体落点。


3. 环境搭建与项目文件结构:从零跑通训练闭环

3.1 安装配置三件套:SUMO、Python环境和依赖库

跑通这个项目的第一步是装好SUMO本体。常见做法是下载Windows安装包或Linux源码编译,装完确认环境变量里能调用sumo-gui和sumo命令。Python版本建议3.8或3.9,配合traci库做通信。依赖库主要集中在PyTorch(DQN网络用)、NumPy(数据处理)和Matplotlib(画训练曲线)这几个。

bash

创建虚拟环境并激活

python -m venv sumo-rl-env source sumo-rl-env/bin/activate # Windows下为 sumo-rl-env\Scripts\activate

安装依赖

pip install traci numpy matplotlib torch

验证SUMO安装

sumo --version python -c "import traci; print(traci.version)"

这里sumo --version用于确认命令行工具可用,import traci验证Python能连接SUMO。如果traci版本与SUMO主程序版本不一致,极容易在仿真中途报连接断开,下面会专门说这个坑。

3.2 项目文件的模块拆解

项目压缩包内部大致包含三类内容:路网文件、训练脚本、工具脚本。路网文件通常是.net.xml和.rou.xml后缀,分别描述交叉口几何形态和车辆出行需求;训练脚本是核心逻辑,从环境封装到DQN智能体都在里面;工具脚本负责画图、统计结果、生成对比报告。

文件类型典型后缀作用关键参数
路网描述文件.net.xml定义车道、节点、连接交叉口类型、车道数、限速
车辆流文件.rou.xml定义车辆出发时间、路径流量密度、车辆类型比例
仿真配置.sumocfg整合路网与车流仿真时长、步长、输出文件
训练主脚本.pyDQN训练与评估循环学习率、batch size、epsilon

训练脚本内部包含四个模块:SUMO环境封装类负责启动仿真并返回状态;DQN网络结构定义采用三层全连接网络;经验回放缓冲区存储最近N条转移样本;训练循环则控制探索率衰减和目标网络同步频率。初次看代码时建议按这个顺序读,因为后面的网络更新逻辑依赖前面的接口定义。

3.3 启动训练:命令行参数与首次运行观察

bash

python train_dqn.py
--config config/single_intersection.sumocfg
--episodes 500
--max-steps 3600
--learning-rate 0.001
--batch-size 64
--epsilon-start 1.0
--epsilon-end 0.05
--epsilon-decay 0.995
--save-dir ./models

这段命令的含义:--config指向SUMO仿真的总配置文件;--episodes 500表示训练500个回合,每个回合对应一次完整的仿真运行;--max-steps 3600限制单回合最大仿真步数,防止个别回合因车辆堵死导致超时;探索率从1.0线性衰减到0.05,让智能体前期充分探索相位策略,后期逐渐倾向利用已学策略。如果训练过程打开SUMO-GUI动态观察车辆运行状态,建议将仿真步长调慢,否则图像刷新跟不上训练速度。

首次跑通训练后,观察两个关键指标:Loss曲线是否震荡下降,平均回报是否逐步上升。如果训练过程显示Loss极低但路口的平均等待时间没有改善,优先怀疑奖励函数设计出了问题,而不是网络参数问题。这个判定逻辑在后面避坑章节会展开。


4. DQN核心实现拆解:网络结构、奖励设计与训练参数

4.1 DQN网络结构与状态定义

项目里的网络结构没什么花哨设计,就是一个输入层、两个隐藏层、一个输出层的全连接网络。输入维度取决于状态特征数量,这里的状态向量由当前相位索引、当前相位已持续时长、各车道排队车辆数、等待时间共四个部分组成,经过标准化后送入网络。输出维度等于可选相位持续动作的数量,动作空间上采用离散方式。

python

import torch import torch.nn as nn

class DQN(nn.Module): definit(self, state_dim, action_dim, hidden_dim=128): super(DQN, self).init() self.fc1 = nn.Linear(state_dim, hidden_dim) self.fc2 = nn.Linear(hidden_dim, hidden_dim) self.fc3 = nn.Linear(hidden_dim, action_dim)

def forward(self, x): x = torch.relu(self.fc1(x)) x = torch.relu(self.fc2(x)) return self.fc3(x)

这里把两层隐藏层设为128维,属于经验值。状态维度过小时网络容量过剩,容易过拟合到早期训练数据;发现训练后期回报上不去时,可以先把隐藏层降到64维试试。动作维度与相位方案一一对应,比如方案0表示维持当前相位不变,方案1表示切换相位,具体数量要和路网信号灯组配置匹配。

4.2 奖励函数设计:等待时间与排队长度的权衡

奖励函数是这个项目里最值得研究的部分,直接决定智能体学出来的是“真会”还是“假会”。如果只按路口总等待时间给负奖励,智能体会倾向于让某一方向的车一直等,因为整体等待时间可能并不会明显增加。实际项目采用的是加权组合奖励,把等待时间变化量和排队长度同时纳入:

python

def compute_reward(previous_wait, current_wait, queue_length): wait_delta = current_wait - previous_wait reward = -abs(wait_delta) - 0.5 * queue_length return reward

previous_wait和current_wait分别表示上一仿真步和当前仿真步的路口总等待时间,wait_delta取绝对值后惩罚等待时间剧烈波动,目的是避免相位频繁切换带来的大量加减速损失;queue_length乘以0.5的权重,让智能体顾及到排队的公平性。参数权重需要根据路口规模调整,单路口项目里0.5足够,多路口网络建议把排队项权重下调到0.3左右,防止个别路口被过度邯郸。

等待时间统计在SUMO里通过traci.vehicle.getAccumulatedWaitingTime()获取,这个API返回的是车辆累计等待时间的均值,适合做单路口实验。多路口场景建议改用traci.lane.getWaitingTime()做分车道统计,粒度更细,也能更容易定位到异常相位。

4.3 训练参数的经验取值与调试方向

训练收敛速度和稳定性受多个参数影响。学习率设0.001是PyTorch默认配置下的稳妥选择,太高容易让Loss震荡,太低则收敛慢。批大小64、目标网络更新频率通常设为每200步同步一次,这些参数在项目的默认配置里已经做了平衡。

参数名称默认值调试方向失败表现
learning-rate0.001调低范围Loss不降、回报不稳定
batch-size64调高范围内存占用偏大、单步耗时增加
gamma0.99调低范围短期决策过于激进,频繁切换相位
target-update-freq200调低目标值不稳定,训练震荡

gamma参数尤其值得注意,它在DQN里决定智能体对远期回报的重视程度。调太低会让智能体只关注眼前几秒的等待时间变化,训练结果就是信号灯疯狂切换、车辆不停启停;调太高又会忽略近期拥堵。单路口场景设置在0.99附近比较合理,如果是多路口联动场景,建议下调到0.95,因为交通流在路网上的传播延时远大于单路口。


5. 避坑与常见问题:跑SUMO+DQN最容易翻车的五个点

5.1 仿真连接中断:报“TraCI connection closed”或仿真卡住不动

  • 现象一:训练跑了几百步后突然报连接关闭错误,或者仿真窗口无响应。
  • 原因一:SUMO版本与traci库版本不匹配,常见于用pip安装的traci是最新版本,而SUMO本体停在旧版。另外,当仿真步长设得过小时,网络通信频率太高,Python主进程处理不过来也会触发连接断开。
  • 解决一:先用pip show traci查库版本,再去SUMO的安装目录下sumo --version查主程序版本。若不一致,用pip install traci==对应版本号锁定版本更稳妥。跑长训练时把仿真步长从0.1s改到0.5s或1s,降低通信频率,训练速度也会提上来。

5.2 Loss掉得快但通行效率没改善:奖励设计缺陷

  • 现象二:训练Loss一路走低,但路口的平均等待时间不降反升,甚至出现某方向车辆白白等了一整个训练回合。
  • 原因二:奖励函数只惩罚了等待时间而没有惩罚排队长度,或者权重失衡。DQN优化的是奖励信号,不是路口通行本身,一个设计不当的奖励信号会让智能体学习到“钻空子”的行为。
  • 解决二:把排队长度纳入负奖励,并检查reward计算里用的是绝对值变化量还是差值本身。差值符号混乱会让智能体无法分辨动作好坏,解决方法是统一奖励朝向:通行效率越好,奖励越大。

5.3 训练后期探索不足:陷入局部最优

  • 现象三:训练到300回合以后,回报曲线不再上升,固定在一个较差水平震荡。
  • 原因三:epsilon衰减过快,智能体过早进入利用阶段,没有机会再尝试更优的相位组合策略。这与epsilon-decay参数直接相关。
  • 解决三:把epsilon衰减速度调慢,或者改成阶段性重置探索率。常见做法是每隔100回合把epsilon回调到0.3再继续衰减,相当于让智能体在学到的策略基础上重新审视一下有没有更好的可选动作。项目里如果不方便改这段逻辑,也可以手动降低--epsilon-decay的数值,让探索周期拉长。

5.4 单回合训练时间异常长:仿真步长和车流量设置不合理

  • 现象四:一个回合训练跑了5分钟还没结束,对比其他回合明显偏慢。
  • 原因四:--max-steps设置过大,或者车辆流文件里的车辆数太多,导致单回合需要仿真很久。另一种情况是路网里存在死锁,车辆全部堵在一个路口,仿真卡住在循环里。
  • 解决四:检查车辆流文件的begin和end标签确认总车辆数,按经验把单回合仿真时长控制在60~90秒之间;死锁问题要回netedit检查交叉口连接关系,特别是T型路口和右转专用道的车道连接,这一项纸面调试无法解决,必须在GUI里可视化看。

5.5 目标网络不更新导致训练崩溃:忘记同步权重

  • 现象五:训练Loss波动幅度越拉越大,最后直接变成inf。
  • 原因五:目标网络用于计算TD目标值,其权重是定期从评估网络复制过来的。如果训练代码里漏掉了同步操作,目标值会一直使用初始随机权重,训练目标本身就是漂移的,网络没法收敛这是强化学习里的经典问题。
  • 解决五:检查训练循环里是否调用了target_net.load_state_dict(policy_net.state_dict()),并确认调用时机是按步数而不是按回合。按回合同步会让目标Q值更新过于缓慢,在SUMO这类环境变化较大的仿真里容易造成偏差累积。

6. 进阶调优:从单路口扩展到多路口与真实路网验证

单路口跑通之后,真正有价值的是把模型迁移到多路口场景。这里会遇到两个新问题:状态维度和动作维度都变大,以及路网耦合带来的信用分配难题。项目里单路口模型泛化到多路口时,推荐直接改用参数共享的DQN变体:所有路口共用一套网络权重,但每个路口的观测独立编码。这样既避免了状态维度过高的计算开销,又能让所有路口的学习经验互相补充。

评估阶段建议做一次呼应性对比实验:固定配时方案、固定相位切换方案、训练完成的DQN方案,三种方案在同一组车流数据下对比平均等待时间、平均车速和排队长度三项指标。为了避免偶然性,每种方案至少跑10个回合取平均值。绘制等待时间分布曲线时,注意只看稳态区间的数据,跳过仿真刚开始车辆逐渐进入路网的头几百步,否则容易把启动阶段的空载数据混进来拉低平均值。

多路口模型的难点在于,一个路口的相位决策会通过上游来车直接影响到下游路口的状态分布,此时单路口训练经验里学到的“当前路口状态足以决定最优动作”这个假设不再成立。如果迁移后出现上游绿灯放行、下游反而严重拥堵的现象,可以在状态向量里额外增加上一路口的信号灯状态和排队信息,也就是把状态从独立观测改成受邻接路口影响的联合观测。这是很多仿真项目实战中最后能真正提高路网吞吐量的关键一步。

最后提醒一句有价值的经验:调SUMO+DQN项目时,每次训练前强制走一遍“清缓存、查版本、跑短回合验证环境连接”三连操作,能省掉很多四分之一的调试时间。血泪教训是,有次改了路网文件忘记重新生成net文件,结果训练了三百回合才发现车流全部跑在旧路网上,相当于白学了三个小时。从那以后每次环境变更都强制走一遍版本核对和短回合冒烟测试。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询