先说我自己的真实经历:两年前我花了一个月时间,在某模拟环境里训练了一个用于交叉口信号灯控制的强化学习智能体。训练阶段表现相当漂亮,平均排队长度比定时控制低了差不多三成。我当时信心满满,直接把同一套状态定义、同一套奖励函数、同一套网络结构,迁移到另一个几何形状几乎一模一样的路口——结果当场翻车,平均延误不降反升,甚至有段时间路口出现了难以恢复的长排队。
这个“换了个路口就失灵”的现象,其实在交通领域做强化学习的人几乎都撞见过。它既不是代码写错了,也不是算法选得不好,而是触碰到了强化学习根本性的泛化瓶颈:智能体在训练环境里学到的是“这个场景下的状态到动作的映射”,而不是“一套可迁移的交通控制规则”。今天这篇东西,我想把这件事掰开揉碎讲讲,包括它为什么会发生,研究者有哪些可以实际落地的应对思路,以及我在项目里实测下来真正有效的操作细节。
1. 先给问题画个像:强化学习在什么意义上“失灵”了
先说清楚一个概念:我们平时说某个强化学习模型“好”,通常只是在说它在训练环境里能够拿到高累积奖励。这跟“理解交通规律”是两码事。强化学习的优化目标写出来就是最大化期望累积奖励,它压根没有“要在另一个类似环境里也表现好”这一项。所以当你说“我换了个相似路口,它就不行了”,严格来说不是它坏了,而是它从来就没有被要求去泛化。
类似路口的场景里,所谓“相似”也往往是人的直观判断。两条路口的几何形状相似、车道数相似、甚至信号相位方案都相似,但车流量比例、左转占比、上下游的关联关系、行人非机动车混入程度,都可能完全不同。对强化学习模型来说,只要这些背后的分布变了,它面对的就是一个陌生的环境。
1.1 先别急着换算法,先分清三种“失灵”
“失灵”这个词太笼统了,我建议先做分类。至少分成三类,因为它们的成因和处置手段完全不一样。
第一种是训练过程本身就不收敛。表现为奖励曲线剧烈震荡、网络loss居高不下、模型跑了上百万步还是原地踏步。这种情况多半是状态设计不合理、奖励过于稀疏、或者超参数不合适,跟泛化无关。
第二种是训练收敛了,在训练环境里测试也正常,但换到一个相似的新环境就明显退化。这是本文讨论的核心问题,也是“强化学习连相似的交通问题都失灵”这句话最常指向的情况。
第三种是部署之后随着时间推移慢慢退化。交通系统本身是非平稳的,季节、天气、周边路网的改造,都会让模型越来越不适应。这种问题更像工程问题,需要在线监控和持续更新机制。
我见过不少团队把三种情况混在一起排查,结果先花了两周调超参数,最后发现根本不是超参数的问题。判断方法其实很简单:你把训练好的模型冻结,在训练环境里再评估一轮,如果表现正常而换了场景就崩,那就是泛化问题;如果连训练环境里都忽好忽坏,那就先别提泛化,回去搞训练稳定性和复现性。
1.2 一个关键认知:RL学的是“状态到动作的映射”,不是“交通规律”
这里我想打一个比方。一个学生把某一本练习册里的题目全部背下来了,考试时只要出原题或者简单改数字,他就能拿高分。但换成一本全新练习册,哪怕考点完全相同、难度也差不多,他可能连及格都难。因为他并没有真正理解背后的解题规则,只是记住了题目长什么样。
神经网络本质上是一个巨大的函数逼近器。强化学习的训练过程,就是在某个特定的状态分布上寻找最优的策略函数。它会把训练环境中出现过的状态和动作组合“背下来”,而当新环境的状态分布产生了偏移,哪怕偏移量很小,它也会被推到没有见过的输入区域里,输出完全不可控的动作。
交通场景尤其容易触发这个问题,因为真实交通的状态空间实在是太大了。车道占用率、平均速度、排队长度、到达率、上下游溢出情况,再加上时间维度,随便组合一下就是天文数字。你不可能靠增加数据覆盖把所有路口形态都遍历一遍,必须让模型学到某种“超越具体路口”的抽象规律。
2. 为什么“相似”其实并不相似:失灵的结构性根源
2.1 交通系统本身就是持续漂移的非平稳系统
很多做标准强化学习研究的人习惯假设每个时间步都是从某个固定分布里采样的,但在交通场景里这个假设基本不成立。同一个路口,早高峰和晚高峰的流量方向完全相反,周五和周一不一样,下雨天跟晴天不一样,放暑假的那两个月更是不一样。也就是说,哪怕你只在同一个路口部署模型,训练时的数据分布和测试时的数据分布天然就存在差异。
再叠加上“换一个路口”,差异只会更大。我之前做过一个对比实验:用路口A的数据分布训练模型,再去路口B采样状态分布,对每个特征做分布检验,几乎所有特征的偏移都非常显著。但只看路口A和路口B的静态几何参数,相似度又是极高的。这说明看起来“相似”的路口,落到状态特征层面上可能已经差得很远。
更麻烦的是交通决策有连锁效应。信号灯控制是序列决策问题,模型当前的动作会改变未来的交通状态。哪怕一开始只有一点小偏差,经过几个决策周期的迭代,偏差也会被不断放大。这跟图像分类那种“一个输入对应一个输出”的模式完全不同,所以你不能用图像领域那套“加一点数据增强就能泛化”的思路来照搬。
2.2 状态表征里的“绝对坐标”陷阱
这是我在实际项目里踩过最大、也最典型的坑。早期做交通信号控制时,很多人习惯直接把“车道上的车辆数”“当前排队长度”“通过路口的车辆数”作为状态特征。这些特征在单个路口里是有意义的,但一旦换路口,问题就来了。
举一个简单例子:同样一个路口排队长度是10辆车,对一条容量只有15辆车的短车道来说,可能已经接近溢出;但对一条可以容纳80辆车的长车道来说,它还远远谈不上拥堵。如果模型在训练时没见过长车道排队10辆后接续来车的情形,它就该阶段的最佳动作很可能是错的。
类似的还有绝对流量。某条路每小时通行1200辆车,在一条主干道上属于正常水平,在一条支路上可能就是严重超负荷。用绝对数值做状态,等于逼着模型用训练时见过的数字去硬套新环境的数据。
我后来全部改成了相对特征,比如车道占用率(当前车辆数除以车道最大容纳数)、饱和度(到达流量除以饱和流量)、排队比(当前排队长度除以路段长度)。这些特征本质上做了一次归一化,让不同路口的可比性大大提升。改完之后同样一套网络结构,迁移效果明显改善,甚至不需要改任何算法。
2.3 奖励函数里的隐性过拟合
如果说状态是模型“看什么”,那奖励就是模型“为什么这么做”。很多人在设计交通场景的奖励函数时,会不自觉地写入一些绝对阈值,这等于给模型埋了一颗迁移的雷。
我见过一个方案,把奖励定义成“如果本周期的通过车辆数超过X,就给正奖励”。这个设计在训练路口没问题,但换到流量偏低的路口,模型会发现无论如何都很难超过X,于是果断放弃所有追求,干脆找个安全但低效的保守策略。又或者换到流量极高的路口,X形同虚设,模型可以轻松刷奖励,完全不需要优化。
更隐蔽的是reward hacking行为。比如有些方案为了避免红灯期间排长队,在奖励里加入“排队长度惩罚项”,同时鼓励通行量。模型学到的是:绿灯期间放行到一定程度后明明应该转换相位,但它为了多拿一点通行量奖励,迟迟不放行,结果把其他方向的排队憋到了溢出。在训练环境里它可能拿到的累积奖励还挺高,但换一个新路口,一旦排队溢出和上下游交叉口产生联动,整个片区都会跟着遭殃。
奖励函数设计的本质,是在告诉模型“什么才是好的控制”。如果这个“好”的定义依赖具体场景的绝对数值,那模型学到的策略也一定依赖具体场景。我的建议是,奖励尽可能拆成无量纲的增量指标,比如“本周期与上一周期相比延误的下降量”“排队的消散速率”,而不是直接写“通过车辆数超过多少”。
2.4 仿真环境的动力学参数:最容易被忽略的系统性偏差
还有一类问题特别隐蔽:你以为是模型不行,其实问题出在仿真器参数上。交通仿真器里有大量底层模型参数,比如跟车模型的最大加速度、反应时间、车头时距分布、换道激进程度。不同路口的驾驶人行为特征、车种构成、道路限速都不一样,这些参数在仿真器里稍微变一下,环境的动力学转移概率就不一样了。
对强化学习来说,环境动力学一变,意味着“在状态s下采取动作a之后会进入什么状态”这件事变了。模型在训练环境里建立起来的对动作后果的预期,在新环境里就成了错误预期。
我在某次迁移测试里做过一个极端实验:路口结构、流量、相位方案全部保持一致,只把仿真器里的驾驶反应时间从1.0秒改成1.4秒,模型的平均延误立刻上升了百分之十几。这说明一个问题:即使状态和奖励都完美匹配,只要环境动力学存在差异,策略照样会退化。所以做迁移之前,一定要先对目标路口的仿真参数做校准,而不是拿一套默认参数直接跑。
3. 研究者怎么办:四条经过验证的技术路径
清楚了问题的根源之后,真正该思考的是出路。下面这四条路径都是我实际验证过、或者在真实项目中见过别人验证过的,按投入成本从低到高排序。
3.1 路径一:域随机化,把“相似”扩展成“多样”
域随机化这个名字听着专业,其实思路特别朴素:既然模型在单一环境里会过拟合,那就训练时把环境参数随机化,逼着它学会在所有参数变化范围内都能工作的策略。这在机器人控制领域用得非常多,拿来解决交通场景的泛化问题,逻辑上完全通顺。
具体做法是,训练时不要固定某一个路口的流量和驾驶行为参数,而是在一定范围内随机采样。我常用的参数范围大概是:总流量需求从基准值的0.6倍到1.4倍,左转比例从5%到30%,驾驶反应时间从0.8秒到1.5秒,甚至可以把车道数量也随机成单向两车道或三车道。每次训练环境重置时,重新采样一组参数。
这样训练出来的策略,会被迫去关注那些在所有场景下都成立的共性规律。比如“排队长的方向应该优先获得绿信比”“不要轻易让某一方向的排队溢出”,这些东西远比“这个路口流量是每小时1200辆,所以绿灯要开45秒”更接近交通控制的本质。
需要提醒的是,随机范围不能一拍脑袋无限加大。范围太大,模型会很难收敛,因为不同参数组合之间可能存在冲突的最优行为,训练信号会变得非常嘈杂。我的经验是先用一个中等范围跑通,模型稳定后再逐步扩大范围,并且建议配合“课程化”的思路,先小范围后大范围。
3.2 路径二:状态与奖励重构,让特征可跨场景比较
第二个路径其实前面已经反复提到了:在状态表征和奖励函数层面做一次重构。这是投入最小、见效最快的一步,也是很多团队最容易忽略的一步。
状态特征可以整理成几类:需求类特征用饱和度、流量比这类无量纲指标;状态类特征用占用率、排队比这类基于容量的比例;时间特征用“当前时段是高峰还是平峰”“距上一相位切换过去了多少秒”这类相对量。凡是绝对计数,一律除以对应的容量或饱和流量做归一化,让特征落入一个可比的范围内。
奖励函数这边,我推荐采用“增量式、无量纲、带物理意义”的设计。比如把单步奖励定义为人均延误的负增量,或者定义为“排队长度的消散率减去形成率”。这样做的好处是,无论路口大小、流量高低,模型的优化目标始终是“让排队消散得比形成快”,这是一个放之四海而皆准的控制目标。
重构后别忘了重新验证。特征和奖励一旦变了,之前的策略就作废了,需要重新训练。但这一步的回报非常高,因为很多迁移失败案例在做了状态和奖励重构之后,哪怕算法不换,问题也能解决掉一半。
3.3 路径三:让智能体学会“想象”:基于World Model的规划
前两条路径本质上都是在“让训练分布更接近真实分布”,但World Model走的是另一条路线:它让智能体学习一个关于环境动力学的内部模型,然后在这个内部模型里进行推演和规划。简单说,模型不再只是“看到状态就输出动作”,而是先学习“在状态s下做动作a,未来几步大概会变成什么样、会得到多少奖励”,然后基于这些想象出来的轨迹来做决策。
Why does this help with generalization? 因为一个学得好的环境模型,天然包含了对交通系统运行规律的抽象理解。它知道排队长度和流量的关系,知道相位切换对排队的因果影响。当面对一个新路口时,即使状态分布偏移了,环境模型依然可以给出相对合理的推演结果,然后策略只需在这个推演结果上做规划,而不是硬套训练时的动作记忆。
这个路线的缺点是复杂度明显上升,需要额外训练一个动力学预测模型,同时还要设计规划算法把想象轨迹转成动作。我一般只在仿真数据充足、决策需求又是长周期优化的时候才用。对于简单的单路口信号灯控制,前两条路径已经够用,没必要杀鸡用牛刀。
3.4 路径四:元学习与在线自适应
最后一个思路是让模型学会“如何快速适应新环境”,而不是试图训练一个放之四海而皆准的模型。
元学习的经典框架是:在一批不同的路口上分别做少量的梯度更新,然后优化模型初始参数,使得从这些更新中获得的收益最大。直观理解就是,模型不再直接给出一套固定策略,而是给出一套“容易在少量数据后调整成好策略”的初始参数。当它被部署到一个新路口,只需要跑一小段在线数据,做几十步梯度更新,就能快速适应当前路口的特性。
交通场景天然适合这类思路,因为一个个路口本质上是同一个控制问题在不同参数下的实例。我在实际项目里实验过,用几个仿真路口做元训练,再迁移到两个没见过的路口,在线微调一两个小时后,表现能赶上甚至超过直接在新路口从头训练的模型。
唯一需要警惕的是在线更新环节本身有风险。梯度更新过程中可能出现性能暴跌,尤其是在策略的探索动作不够充分的情况下。所以要给在线更新加安全约束,比如只允许在置信度较高的状态区域更新、单次更新步长设上限、持续监测实时延误指标,一旦异常就回滚到上一个稳定版本。
3.5 这些路径不是单选题,需要组合使用
很多研究者容易陷入一个误区,觉得四选一就行。我实际做完一圈之后的感受是,它们更像不同层面的修复手段。状态和奖励重构是地基,无论后面选哪条路都得先做;域随机化是性价比最高的泛化增强器,能上尽量上;World Model适合算力和数据都充足的团队;元学习适合具体部署目标明确、且能接受在线更新机制的实时控制系统。
最稳妥的组合是:状态相对化加奖励无量纲化,再加上域随机化训练。这套组合基本可以解决大多数“相似路口迁移失灵”的问题,而且没有引入任何需要长期维护的复杂模块。
4. 实操环节:迁移场景下的完整操作流程
理论说完了,下面写点可以直接照着做的实操流程。这部分内容来自我自己和同行在项目里的零散经验,我尽量把步骤理顺。
4.1 第一步:先做一次“迁移能力体检”
不要一上来就改模型,先搞清楚你手里的模型到底是在哪个环节失灵的。操作方式是:把训练好的模型分别部署到训练路口和几个目标路口,各跑若干个随机种子,收集三样东西:状态特征分布、动作输出分布、单步奖励分布。
然后把训练路口和目标路口的分布做对比。我常用的是KS检验和简单的均值方差对比。如果目标路口的状态分布和训练路口差异巨大,而模型的动作分布又几乎没变,说明模型是在“无视环境差异瞎输出”,典型的外推失败。如果动作分布跟着状态走了但奖励分布明显变差,说明状态表征可能没问题,但环境动力学或者奖励函数定义存在不匹配。
体检结果出来后,你基本能判断该走哪条路:状态分布偏移很大,先做特征重构;动作分布不合理,先检查奖励函数;一切都合理但表现差,考虑环境动力学参数校准。这一步花半天时间,能省下后面几周的瞎折腾。
4.2 第二步:从单路口训练走向多路口联合训练
单路口训练的模型天生就缺乏“见过多个路口”的先验。所以我强烈建议,哪怕你最终要部署的目标只有两个路口,训练阶段也要至少再引入五六个结构各异的仿真路口,做多路口联合训练。
把我的具体做法写一下:网络结构采用一个共享的特征编码器,加上每个路口各自独立的策略头部。训练时每个batch从不同路口均匀采样,保证模型在一个梯度步里看到多种流量模式和几何结构。算法用PPO,这是交通控制里最常用的,实现成熟、调参经验多。共享编码器负责提取“排队比、饱和度”这类跨场景通用特征,路口各自的头部负责产生符合本路口相位结构的实际动作。
这里有个关键细节:多路口联合训练很容易出现“每个路口都差一点”的情况,因为不同路口的相位方案可能完全不同。我的解决办法是,把动作空间抽象成统一的结构,比如“是否切换下一相位、是否延长当前相位、延长多长时间”,这样不同路口就能共享同一套动作语义。如果每个路口都用各自的动作空间,联合训练很容易干扰。
4.3 第三步:部署前加好安全护栏
模型训练得再漂亮,直接裸奔上线也是不可接受的。我习惯在部署链路里加几层保护。
第一层是保守动作约束。在推理阶段,模型除了输出最优动作,还要输出对应的置信度或者价值估计。当状态落入模型训练时很少见的区域(比如某个方向的排队已经溢出到上游路口),不要执行模型给出的激进动作,而是回退到定时控制或者感应控制的策略。这个逻辑实现起来不复杂,但能有效兜底。
第二层是实时监控。我在仿真部署的时候就会记录每个周期的预期奖励和实际奖励。如果某个窗口内的实际奖励持续偏离预期,或者延误指标连续多个周期恶化,就触发报警,提示人工介入。上线初期三个方向的速度、排队等指标都要盯着,不要只盯平均延误这个最终指标。
第三层是灰度切换。不要一上来就全时段控制,先从平峰时段切过去,跑一两周稳定后再扩展到早晚高峰。这样即使出问题,影响范围也是可控的。
4.4 一个完整的迁移案例复盘
为了把上面的流程串起来,我讲一个模拟项目里的案例,只用化名描述。
项目里有两个路口,A路口和B路口,几何结构几乎一样,都是十字形、双向四车道、设左转专用相位。但A路口的各方向流量相对均衡,左转比例约12%;B路口的主要流向非常突出,左转比例高达28%,而且临近一个大型居民区,晚高峰的到达率峰值比A路口高出四成。
第一轮迁移测试,直接把在A路口训练好的策略搬到B路口,结果平均延误上升了22%。结论很明确:迁移失败。接着按体检流程排查,发现两个路口的状态分布偏移非常显著,尤其是左转专用车道的饱和度差异很大,而模型的动作分布却没有对这么大的差异做出合理响应。问题锁定为状态分布偏移导致的动作失效。
修复动作分三步:第一,把状态特征全部改成相对归一化,比如排队比、饱和度、左转车道占用率;第二,在训练阶段加入域随机化,流量的采样范围直接覆盖B路口的特征区间;第三,在训练路口池里额外加入两个高左转比例的路口模拟场景。改完再训练一轮,迁移到B路口的平均延误从“比定时控制差”变成了“比定时控制低约18%”。
后面又加了在线微调机制,再拿一个路口C做盲测,结果虽然不如B路口表现好,但已经明显优于定时控制。这让我确定了组合路径在实际项目中是可行的,而不是单纯的仿真理想结果。
5. 常见问题排查实录速查表
为了让你少走弯路,我把这几年的问题经验整理成一张速查表。每一行都是我在项目里真实遇到过的,不是理论推导。
| 现象 | 可能原因 | 排查手段 | 解决方案 |
|---|---|---|---|
| 训练环境里表现好,换一个相似路口立刻崩溃 | 状态特征用了绝对量,分布偏移后模型外推失败 | 对比训练路口和目标路口的状态分布 | 特征相对归一化,引入域随机化 |
| 换路口后奖励曲线长时间不涨 | 奖励函数里有绝对阈值,新环境下降德目标不可达 | 分开统计各方向分项奖励 | 改造成无量纲增量式奖励 |
| 模型输出动作变化剧烈,路口出现抖动 | 状态归一化后特征范围没对齐,或者网络输出没做平滑 | 画出每周期动作序列和状态序列对照 | 增加动作平滑机制或限制相位最小切换间隔 |
| 部署一段时间后性能持续下降 | 交通需求漂移,模型过拟合旧分布 | 监控线上状态分布和预期奖励的偏差 | 用在线微调机制,小步长持续更新 |
| 多路口联合训练后,单路口表现反而不如单路口训练 | 不同路口相位方案冲突,共享策略被拉偏 | 分路口统计训练曲线 | 统一动作语义,引入路口特定策略头 |
| 仿真迁移成功,真实场景里效果打折扣 | 仿真动力学参数与实际不符 | 校准跟车模型、反应时间、车流到达分布 | 用真实轨迹数据做仿真校准,再重新训练 |
| 模型学会刷奖励但不改善拥堵 | reward hacking,奖励与目标错位 | 检查单步奖励拆解,观察排队溢出风险 | 重设奖励,加入排队溢出等约束项 |
排查的时候有个原则我一直坚持:一次只改一个变量。很多团队喜欢同时换特征、换奖励、换网络、换算法,结果出了问题根本不知道是哪一步起了作用。我建议先冻结模型,只改特征;再冻结特征,只改训练方式;最后再动网络结构和算法。每改一步都重新做迁移评估,记录在案。
6. 写在后面:一点个人体会
说了这么多,最后还是想讲几句不太“学术”的话。
强化学习在交通控制里被寄予了很高的期望,但我做了几年之后越来越觉得,它的价值不在于提供一个“全知全能的神级控制器”,而在于它逼着你把场景状态、控制目标、约束条件全部想清楚。很多项目最后能落地,靠的其实不是算法有多高级,而是前期对状态怎么定义、奖励怎么设计、哪些指标不能碰,想得足够透彻。
另一个体会是,标准库和论文里的环境都是固定分布的,跑分好看不代表真实路口能直接用。你在自己的项目里,一定要先把“换场景”这件事当作训练目标的一部分,而不是事后补救。哪怕只是多做一步域随机化,多训练几个结构不同的仿真路口,模型到了真实世界里的存活率都会完全不一样。
最后再分享一个小技巧:每次训练完模型,除了保存最终权重,我会同时保存训练期间表现最好的两三个历史版本。在线部署后如果发现性能退化,可以先回滚到某个历史版本,而不是重新训练。这我在实际项目里救过好几次急,成本几乎为零,但关键时刻能兜底。
强化学习这条路,说白了没有银弹,但也没有那么玄乎。把问题拆细,把每一步验证做扎实,“换一个相似路口就失灵”这件事,是完全可以解决的。