地铁客流预测这个方向这几年我陆陆续续做了好几个版本。从一开始的单模型硬啃到后来转向多任务联合建模最直观的感受是客流预测本质上不是一个“单输出”问题而是一组相互关联的需求估计问题。日常调度关注的进站量、出站量、断面拥挤度、换乘客流背后共享同一套出行需求来源只是从不同角度投影出来。如果把它们割裂成若干个独立模型等于主动扔掉了大量可用信息。TITS这个深度多任务学习模型就是针对地铁客流需求预测场景设计的。它的核心思路是把进站量、出站量这类强相关任务放进同一个骨架里训练通过共享时空编码器提取通用的出行规律再用分叉的任务头输出各自的预测结果。这套思路不仅比多个单任务模型省资源更重要的是在高峰期、节假日这些样本少但波动大的时段预测稳定性明显更好。如果你正在做短时客流预测、车站级客流估计或者正准备把多任务学习引入交通领域这篇文章应该能给你一个完整的参考。1. 为什么地铁客流需求预测要走向“多任务”——单输出模型解决不了的两个问题做地铁客流预测的同行应该都有体会业务方一开始提的需求往往很简单“你帮我把明天的客流算出来”。但真正拆解下来这个需求落地的时候会变成一整串问题早高峰哪些站进站量大、哪些站出站量大、哪个换乘通道会挤爆、下一趟车要不要加开。这些问题的预测对象不同、时间尺度不同但底层共享同一个东西——人的出行意愿。1.1 进站量与出站量看起来是“两个数字”底层是同一套出行需求举一个实际场景。A市地铁某条线路早高峰的P站进站量很大因为周边是住宅区大家从这里上车去上班同一时间段Q站的出站量也很大因为那是商务区。如果你只建一个“进站量预测模型”它会学到P站的早高峰规律但对Q站出站量几乎无感。反过来也一样。这里最容易被忽略的点是这两个任务并不是独立的。P站早高峰进站的人大概率会在若干个车站之后形成出站客流。也就是说进站量和出站量之间存在时空上的强耦合关系。单任务模型完全没有建模这种耦合的通道每个模型各学各的等于把一张完整出行网络拆成了多个互不相关的投影。TITS这类多任务模型的做法是让两个或更多任务共享同一个底层特征抽取器这个特征抽取器会同时看到进站序列和出站序列从而学到“哪些特征对两个任务都有解释力”。1.2 单任务模型为什么在高峰期掉链子我用单任务模型做预测的时候一个很头疼的问题是早晚高峰时段的误差会被放大。原因不复杂单任务模型在训练时只对当前任务负责它倾向于把所有可用的模型容量都用来拟合当前任务的均值规律。遇到节假日、恶劣天气、临时管控这类低频但高影响事件历史样本很少单任务模型就很容易退化成“对历史同期做平均”。而多任务模型在处理这类情况时有一个隐性优势进站量和出站量对这些异常事件的响应方向通常不同。比如一场临时大型活动散场附近车站进站量激增但网络的出站量可能是平缓的再比如早高峰突降暴雨进站量可能略微下降但出站量因为很多人提前出门反而可能上升。这种“差异化的响应模式”本身就是一种很强的学习信号多任务模型可以通过任务间的对比来缩小异常事件的假设空间。简单说两个任务互相提供了对方缺失的监督信息。1.3 TITS的目标设定让预测任务之间互相“补信息”TITS在设计目标上刻意把问题定义为给定过去若干时间步的客流状态包括历史进站、出站、线路荷载等信息同时预测未来多个时间步的进站量和出站量。这两个任务共享一个编码器但各自拥有独立的预测头。这里有个容易搞混的地方——多任务学习不是简单地把两个任务的loss加起来。如果只是末尾加两个输出层然后各自算损失训练时大概率会出现任务间“抢梯度”的问题某个任务loss大、梯度方向强就会把共享层的参数往自己那边拉另一个任务的效果反而变差。TITS在这方面的处理方式我后面会单独展开。为了先建立整体画面你可以把多任务结构理解成“一个大脑两只手”大脑负责理解客流的整体规律两只手分别负责进站和出站的具体输出但两只手之间不允许互相打架。2. TITS模型的整体设计共享时空编码器与任务专属头TITS的完整结构可以拆成三个层次底层是时空特征编码中间是任务交互与融合顶层是任务预测输出。下面按这个顺序把每一层的设计思路说清楚。2.1 模型骨架时空特征怎么被编码地铁客流数据本质上是一个时空序列。空间上车站之间有物理拓扑结构还有OD起讫点关联关系时间上客流有明显的日周期性、周周期性以及节假日等长周期模式。TITS的编码器部分我采用的方式是“图结构时序结构”双通道处理。空间维度用一个图注意力层来建模车站之间的相互影响节点是车站边的权重由线路距离、换乘关系和历史OD相关性共同决定。时间维度用Transformer或者堆叠的时序卷积来捕捉客流随时间的演化规律。在实际编码的时候输入特征并不仅仅是单一的历史进站量序列。我把输入组织成一个特征矩阵每一行是一个车站每一列是一个时间步每个元素是一个特征向量里面包含该车站在这个时间步的进站量、出站量、列车满载率估计、是否节假日、天气编码等。这里有一个容易被忽略的工程点特征对齐。不同车站的进出站量绝对值差别很大——枢纽站一天几十万小站可能只有几千直接喂进模型会让注意力机制偏向大客流车站。我通常会对每个车站的客流序列做独立标准化每个车站算自己的均值和方差而不是全局统一标准化。2.2 任务专属预测头进站量和出站量各自要什么共享编码器输出的是一个高维的时空特征表示理论上包含了对当前客流状态的整体理解。但进站量和出站量在业务语义上还是有区别的——进站量更依赖车站周边的居住人口、发车频率、安检口排队情况出站量更依赖目的地周边的岗位密度、商圈活动、换乘便捷度。这些差异决定了任务头不能只是简单的全连接层。TITS在每个任务头上会先对共享特征做一个针对性的注意力池化然后接两个分支一个输出未来多步的点预测值另一个输出预测的不确定性方差估计。这里引入不确定性估计不只是为了好看它在实际调度中很有用比如预测某站未来15分钟进站量均值是3000人方差很大说明这个预测不可靠调度员需要准备备选方案。另一个细节是任务头输入的构造。共享编码器的输出是一个时空张量直接展平喂到任务头会丢掉很多结构信息。我通常会把时间维度和空间维度的信息分别做聚合时间维度用全局平均池化取整体趋势空间维度用注意力加权去突出那些和当前任务最相关的车站。这样每个任务头都能从同一个共享表示中抽取自己关心的那一部分。2.3 为什么不用简单的“先共享后分支”最早做多任务模型最常见的结构就是“backbone共享 末端多分支”backbone用同一个编码器最后每个任务接自己的几层全连接。这种结构实现简单但有两个问题。第一任务差异对共享层的反馈是隐式的共享层并不知道自己哪些特征该偏向哪个任务完全靠梯度自己摸索收敛很慢。第二当任务数量增多时不同任务的梯度方向冲突会变得非常明显模型参数更新会震荡。TITS在“先共享后分支”的基础上做了两个关键改动。第一在共享编码器和任务头之间插入一个任务交互层让两个任务在最终输出之前先交换一次信息。具体做法是把进站任务头的中间表示和出站任务头的中间表示做一次拼接和交叉注意力再回到各自的任务头。这样进站预测就“知道”了当前出站预测的意图反之亦然。第二在损失函数层面引入不确定性加权机制动态调整两个任务的权重而不是手动固定成1比1。这个机制我下一节详细讲。从实际效果看这两个改动的组合解决了一个很实际的问题任务间耦合是存在的但耦合程度是动态变化的——平峰期进出站相关性高高峰期由于通勤方向性太强相关性反而下降。任务交互层能根据当前输入状态自适应地决定信息交换的多少而不是所有时刻都用同一个强度。3. 训练策略与损失设计让两个任务不打架把多个任务放进一个模型最难的不是结构设计而是训练时怎么让它们“和谐共处”。任务之间梯度方向冲突、loss量纲不一致、收敛速度不一样这三个问题任何一个处理不好多任务模型效果都可能比单任务还差。3.1 多任务损失平衡的基础逻辑最简单的多任务损失是所有任务loss直接相加。这个方案在任务量纲接近、难度相近的场合勉强能用但客流预测里进站量和出站量的量纲虽然一样不同时段的波动幅度却差很多。高峰期进站量可能到一两万平峰期只有两三千。如果我们把各时段样本混在一起算MSE大数值时段会主导梯度模型会优先优化高峰期的表现平峰期就容易被“忽视”。一种常见的改进是给每个任务乘一个固定权重比如进站量loss乘0.5出站量loss乘0.5。但固定权重的毛病在于不同训练阶段、不同数据分布下任务间的相对难度是变化的。固定权重本质上是“静态假设”遇到数据分布漂移就失效了。3.2 动态门控与不确定性加权TITS实际采用的方案是不确定性加权。核心思想是让模型自己学习每个任务输出的置信度用置信度来调整loss的权重。公式上可以理解为总损失等于每个任务自身损失除以该任务的预测方差再加上方差的对数项作为正则。这样做的好处是方差小的任务模型对其有把握自动获得更大权重方差大的任务权重自动降低而且方差也是由模型自己预测出来的不需要人工调。为了进一步增加灵活性我还在任务交互层里加了一个轻量级的门控模块。这个门控读取当前输入的时间特征比如是不是早高峰、是不是节假日输出一个介于0和1之间的融通系数控制进出站信息交换的程度。高峰期间通勤方向性强进出站关联度弱门控会自动降低交互强度平峰期和节假日人们出行目的更多样进出站时空关联更强门控放开交互。这个设计没有增加多少参数量但对预测精度的提升非常明显尤其是在节假日样本上。这里有一个实操细节值得注意不确定性加权里初始方差不要设得太小。我一开始把初始预测方差设成很小的值结果loss前期被方差项主导模型迟迟不收敛。后来把预测层的初始偏置设置成对应训练集label方差的对数模型很快就稳定下来了。3.3 数据组织与训练细节TITS训练时样本按“天”组织会比按“时间片”组织效果好得多。原因在于客流有极强的日周期性如果随机打乱所有时间片模型会看到大量“割裂”的序列很难学到完整的一天节奏。我更倾向于按日期划分训练集、验证集、测试集保证同一个日期的数据不会同时出现在训练和验证里避免信息泄漏。训练过程中我习惯额外采样加权方案对节假日和周末样本提高采样权重。这个技巧来自一个很直接的观察——平常日样本量太大模型很容易就把“平时规律”学得很好但节假日的样本占比太小很容易被淹没。把节假日样本的采样权重提到2到3倍能让模型在训练时多“看”几遍这些特殊情况预测效果会有肉眼可见的提升。优化器选AdamW学习率用3e-4batch size设64大约100轮左右收敛。如果有条件CosineAnnealing的lr schedule比StepLR更稳因为多任务训练后期最怕的就是lr突变导致某个任务头的参数被“踢”出收敛区。4. 实验设计与结果解读对比单任务模型的收益到底在哪这节讲实验设计。做多任务学习最容易被质疑的问题就是“你说的多任务效果好是不是只是因为模型变大了”所以实验设计必须回答清楚收益到底来自多任务机制本身还是来自额外的参数和计算量。4.1 实验数据与评估指标我用的数据集来自某市轨道交通的刷卡流水模拟数据仅用于方法验证覆盖大约200个车站、8个月的时间跨度时间粒度为15分钟。这样每个车站每天有96个时间点总共的样本量在百万级足够支撑深度模型的训练。评估指标我没有只盯MAE和RMSE。RMSE对大误差敏感适合衡量极端情况下的表现MAE反映平均偏差更接近业务感知。但在客流预测任务里还有一个指标非常重要——高峰时段最大误差Peak-hour Max Error。哪怕平均误差很低只要某一天早高峰某一站预测偏差超过30%调度那边就会打电话来问。所以我会单独统计工作日早高峰7点到9点时段、晚高峰17点到19点时段的误差。4.2 实验对比结果与分析对比实验里我会放这么几组第一组是“单任务进站模型”和“单任务出站模型”各自独立训练结构上和TITS的任务头部分保持一致。第二组是“共享backbone 两个独立分支”的朴素多任务模型用来验证任务交互层到底有没有用。第三组是TITS完整版本。结果通常呈现这么几个规律首先TITS的进站量和出站量预测误差都低于对应的单任务模型但差异的幅度因车站类型而异。在换乘站、枢纽站这类进出站都很大的车站上提升最明显单任务模型的MAE大约能下降8%到12%。在纯粹的小型住宅站进站量单任务模型的提升相对有限因为这些站客流规律简单单任务本来就已经能学得不错。这个现象其实很好理解车站越复杂任务间的互信息越丰富多任务学习越能发挥优势。其次对比“朴素多任务”和“TITS完整版”差距主要集中在节假日和极端天气时段。朴素多任务在常规日的预测精度和TITS差别不大但一到节假日朴素多任务的误差明显上升说明它没有利用好任务间的动态关联。而TITS带着任务交互层和不确定性加权对这类“非常规日”的泛化能力明显更强。最后高峰时段的单项指标上TITS的最大误差比单任务模型低了15%到20%上下。这个收益来源我认为有两个一是任务交互层让进站预测能参考出站预测的上下文二是不确定性加权让模型能自动降低那些“没把握样本”的权重不会因为个别异常样本把整个模型参数带偏。4.3 案例分析节假日与天气影响挑一个具体的案例某年中秋假期前一天傍晚开始全城地铁客流猛增。单任务进站模型在这个时段的预测偏差超过了20%因为它把这一天当成了普通工作日而历史同期又没有足够多的“假期前一天周末”样本来参考。TITS在这天的表现就稳定很多——模型虽然没见过完全相同的场景但它从进站序列里看到趋势异常同时从出站序列里也看到了同样的异常两个任务互相印证让共享编码器更快地意识到“今天的情况不一般”从而调整预测。这个案例挺能说明多任务学习的本质它不是凭空增加信息而是让模型更有能力利用已有信息之间的冗余性和差异性。5. 工程落地时的注意点与常见坑模型效果好只是第一步。从离线实验到线上预测中间有一堆和模型结构无关、但决定成败的工程细节。这里挑几个我踩过、也花了不少时间填平的坑。5.1 缺失刷卡数据与标签噪声客流数据来自刷卡流水天然存在延迟和丢包现象。某一个15分钟窗口的进站量统计可能不完整因为部分乘客的出站刷卡记录还没回传如果直接拿这部分数据当训练标签模型会被脏标签带偏。我的处理方案是训练时过滤掉明显低于正常水平的样本。具体方法是先计算每个车站每个时段的历史客流区间比如用分位数取正常范围如果某条样本的标签落在正常范围之外且没有对应事件标注例如临时封站直接丢弃或做回填。线上推理时也一样输入序列里的异常点不能直接喂给模型需要先做简单的异常检测和填充。5.2 多任务模型上线的监控多任务模型上线和单任务模型上线有个很大的区别你需要分别监控每个任务的预测质量以及任务间的平衡状态。如果某一个任务的loss突然升高而另一个任务正常不一定说明模型整体退化了也可能是输入数据分布出了变化导致任务间耦合度改变。只看一个总指标很容易漏掉问题。我的监控做法里会加入一个“任务间一致性指标”实时计算进站预测和出站预测的correlation如果这个值在一段时间内异常升高或降低说明共享编码器可能学到了偏移的模式值得深入排查。另外每个任务的预测方差输出也要监控——如果模型对大多数样本都预测高方差说明模型已经“没有信心”了这时候哪怕点预测值还没明显偏离也要警惕。5.3 模型更新的节奏客流预测模型不能像某些NLP模型那样训一次用半年。地铁网络本身会变新开一条线路、某个站附近开了大型商场、附近学校放暑假都会改变客流的时空规律。我一般会设置一个rolling retrain策略每周自动用近3个月的数据重新训练一次基线模型只有当验证集指标比线上模型有明显提升时才切换。这个策略看起来很保守但实际运行中最稳。另外如果条件允许加入一些实时反馈信号会更好。比如把当前时刻的进站闸机通过数、列车定位数据作为额外特征输入模型。这些数据虽然“脏”但能让模型更快响应当天的突发情况。最后总结一下实操中的个人体验。TITS这个模型真正让我认可多任务学习的地方不是它比单任务模型高出来的那几个百分点而是在节假日、恶劣天气这些“关键但样本少”的场景里它表现出的稳定性。预测这个领域稳定比平均精度更值钱。如果你正准备在客流预测里尝试多任务学习我可以给出的最精简建议是第一不要急着堆模型结构先想清楚哪两个任务真的共享底层规律第二动态损失加权和任务交互层的收益往往比想象中大第三把工夫花在数据清洗和异常处理上模型结构的差异在脏数据面前会被迅速抹平。
阅读完成 · 觉得有帮助?