☰
STGCN解析:图卷积与门控卷积如何实现交通时空预测
2026/10/5 5:12:02 网站建设 项目流程

读时空序列预测方向的论文,Graph Convolutional Networks 这一支是绕不开的。今天这篇笔记的主角是 STGCN——Spatio-Temporal Graph Convolutional Networks: A Deep Learning Framework for Traffic Forecasting,发在 AAAI 2018,作者是 Bing Yu、Haoteng Yin、Zhanxing Zhu。论文解决的是交通预测里的短期流量/速度预测问题:路网上散布着大量传感器,每个传感器每 5 分钟上报一次数据,任务是利用过去 1 小时的历史观测,预测未来 15 到 60 分钟的路况。这个任务表面看着像时间序列预测,但难就难在传感器之间不是孤立的,一条路堵了会波及相邻几条路。STGCN 的核心做法是把路网建成一张图、传感器当节点、历史数据当节点上的时序信号,用图卷积抓空间依赖、用门控因果卷积抓时间依赖,整个过程不碰 RNN。这篇笔记我从任务定义、模型结构、实现细节、实验结果到复现踩坑完整过了一遍,适合刚接触图神经网络和时空预测的读者,也适合想拿 STGCN 当基线模型做对比的研究者。

1. 这篇论文要解决的交通预测问题

1.1 交通预测的任务定义:输入什么、输出什么

先把这个任务说清楚。假设路网里有 N 个传感器,每个传感器在 t 时刻上报一个值,最常见的是平均车速,也有流量、占有率。把 t 时刻所有传感器的值拼成一个向量 x_t ∈ R^N,那么一段时间的数据就是一堆向量按时间排起来。论文里的设定是:用过去 M 个时刻的数据 X = (x_1, x_2, ..., x_M) 预测未来 H 个时刻的 Y = (x_{M+1}, ..., x_{M+H})。在实验里 M 取 12,对应 5 分钟采样率下的一小时;H 最大也取 12,评估时分别看第 3、6、9、12 步,也就是 15、30、45、60 分钟的预测误差。

这个任务最麻烦的地方是时空耦合。空间上,相邻路段的交通状态会互相影响——一段高速堵了,车流会排队回溢到上游匝道,这种影响不是瞬时的,而是带延迟、带衰减地传播。时间上,交通有清晰的日内周期和早晚高峰,但突发事故、天气变化又会让序列出现剧烈的非平稳波动。更麻烦的是,空间影响本身也会随时间变:早高峰时进城方向拥挤,晚高峰时出城方向拥挤,同一个路段对邻居的影响方向是动态的。STGCN 要同时抓住这两条线,而不是把它们拆开单独建模。

1.2 之前的做法为什么不够用

在 STGCN 之前,交通预测的主流方案大致分几类,各有各的死穴。传统时序方法如 ARIMA、VAR、卡尔曼滤波,本质都是线性模型,交通数据里的非线性关系和突发变化它们基本接不住,而且预测时域拉长之后误差累积很快。SVR、kNN 这类机器学习方法需要手工设计特征,输入维度稍高就撑不住,扩展性很差。到了深度学习时代,早期的做法分两路:一路用 RNN/LSTM 对每个传感器单独建模,比如 FC-LSTM,它把每个传感器当成独立时间序列,完全没利用传感器之间的空间关系;另一路把路网当成规则的二维网格,直接套 2D CNN,这等于硬把一个任意拓扑的路网掰成图片,既浪费参数又扭曲了真实的相邻关系。

问题的根源在于表示方式。高速路网是典型的图结构:传感器是节点,路段是边,节点之间的连接关系是不规则的、稀疏的。把图数据硬塞给为规则网格设计的卷积神经网络,必然丢信息。所以很自然的想法是,能不能直接在图上做卷积,让每个传感器的特征沿着真实的道路连接传播?这正是图神经网络(GNN)在交通预测上最核心的切入点。

1.3 STGCN 的核心切入点和它带来的改变

STGCN 给出的答案是全卷积的时空图卷积框架。空间维度用图卷积(GCN)建模,基于谱方法加 Chebyshev 多项式近似,每个节点聚合 K 阶邻居的信息;时间维度用带门控线性单元(GLU)的一维因果卷积,替代当时流行的 RNN。这两部分组合成一个叫 ST-Conv 的卷积块,堆叠两个块之后再接一个 1×1 卷积输出层,就完成了从“过去 1 小时”到“未来 1 小时”的直接映射。

全卷积设计带来几个实际好处。第一,训练可以完全并行,不用像 RNN 那样按时间步展开,训练速度和显存占用都友好得多。第二,梯度传播路径短,不存在 RNN 里常见的梯度消失/爆炸问题,模型更容易训稳。第三,输出是一次性生成未来 12 步,不是自回归逐步预测,推理速度快、也没有误差累积。论文在两个真实数据集上的实验表明,STGCN 在不同预测时域上都明显优于当时的各类基线。这篇论文后来影响很大,“图卷积处理空间 + 门控卷积处理时间”的组合方式成了很多时空预测模型的标配。

2. 模型结构拆解:空间图卷积 + 时间门控卷积

2.1 空间依赖怎么建模:谱图卷积与 Chebyshev 近似

要理解 STGCN 的空间建模,得先明白图上怎么做卷积。假设图信号是 x ∈ R^N,也就是 N 个节点各有一个值。图拉普拉斯矩阵 L = I - D^{-1/2} A D^{-1/2},其中 A 是邻接矩阵、D 是度矩阵。拉普拉斯矩阵可以特征分解 L = UΛU^T,这里的 U 相当于图上的一组基,图傅里叶变换就是把信号投影到这组基上:x̂ = U^T x。图卷积的定义是:两个信号在谱域相乘再变换回来,即 x * g = U (U^T x ⊙ U^T g)。把滤波器 g 写成谱域可学习的参数形式 g_θ,就得到 x * g_θ = U g_θ U^T x。

但直接学 g_θ 有个问题:它是定义在谱域的全局滤波器,每个输出节点都要和所有节点相关,计算代价高,而且没有局部性。Defferrard 等人提出用 Chebyshev 多项式去近似 g_θ:

x * g_θ ≈ Σ_{k=0}^{K-1} θ_k T_k(L̃) x,其中 L̃ = 2L / λ_max - I,T_k 是 Chebyshev 多项式,递推关系为 T_0(x)=1,T_1(x)=x,T_k(x)=2x T_{k-1}(x) - T_{k-2}(x)。

这个近似的厉害之处在于,L̃ 是局部算子的多项式,K 阶多项式的计算只涉及每个节点的 K 阶邻域,天然带局部性,而且不需要做特征分解,直接稀疏矩阵乘法就能算。STGCN 里图卷积的 K 取 3,意思是一次图卷积操作,节点最多能聚合 3 跳范围内的邻居信息。这和普通 CNN 的感受野是同一套逻辑,只是把规则网格换成了任意图结构。实际实现里要注意 L̃ 的计算,λ_max 一般用幂迭代法估计,不需要精确求特征值。

2.2 时间依赖怎么建模:门控一维因果卷积

时间维度的建模,STGCN 没有用 LSTM/GRU,而是用一维卷积。但这里有个细节:必须用因果卷积(causal convolution),也就是输出时刻 t 的卷积结果只能依赖 t 时刻及之前的数据,不能偷看未来。STGCN 里的时间卷积层用的是标准一维卷积加因果 padding,卷积核沿时间轴滑动,每个时间点的输出由它之前 K_t 个点的输入计算得到,天然满足时序上的因果性。

光有因果卷积还不够,论文在时间卷积上加了门控线性单元(GLU)。具体做法是:卷积输出被拆成等长的两部分 P 和 Q,最终输出是 P ⊙ σ(Q),其中 σ 是 sigmoid 函数。这个门的含义很直观:Q 经过 sigmoid 变成一个 0 到 1 之间的“开关”,控制 P 里的信息有多少能继续往下传。它和 LSTM 里的门机制是同一个思路,只是套在卷积上。论文里对比过,带 GLU 的时间卷积比单纯用 ReLU 的时间卷积效果好,因为门控给信息流动加了一个可学习的“阀门”,梯度也能顺着门传得更远。

为什么用卷积不用 RNN?除了并行训练效率之外,一个很实际的原因是感受野可控。RNN 的依赖距离是隐式的,要靠门控机制去学“记住多久”;卷积则不同,堆叠几层卷积、卷积核多大,感受野就是确定的,这给模型设计带来很强的可控性。后面很多工作沿用了这个设计,比如预测 1 小时前的数据,时间卷积层数和核宽只要算一下感受野是否覆盖 12 步就够了。

2.3 ST-Conv 块:三明治结构的思路

把空间卷积和时间卷积组合成基本模块,是这篇论文里最值得琢磨的地方。STGCN 没有简单地把两个卷积层前后串联,而是采用了“时间卷积 → 图卷积 → 时间卷积”的三明治结构。单个 ST-Conv 块的计算可以写成:

v^{l+1} = Γ_1^l *_τ ReLU( Θ^l *_G ( Γ_0^l *_τ v^l ) )

其中 Γ_0、Γ_1 是时间卷积核,Θ 是图卷积核,_τ 表示时间卷积,_G 表示图卷积。也就是,一个块内先做一次时间卷积,把每个节点上的历史信息“压缩”一下;再做图卷积,让压缩后的节点特征沿着图的边传播;最后再做一次时间卷积,把传播后的结果进一步整合。

为什么是这个顺序,而不是“图卷积 → 时间卷积 → 图卷积”?这是我的理解,也是论文里强调的直觉:原始传感器信号里噪声不小,直接在这个信号上做空间卷积,等于把噪声也传播给了邻居节点。先做一次时间卷积,相当于先对每个传感器做局部平滑和特征提取,让进入空间传播的信息更“干净”;图卷积在这个基础上做邻居聚合,效果更稳。最后一个时间卷积则是把空间传播后的特征再次沿时间轴整合,调节输出的时间依赖。这个设计和信号处理里的“先滤波、再传播、再滤波”思路一脉相承。每个 ST-Conv 块还带残差连接、批归一化和 ReLU 激活,堆叠两个块后接输出层,模型深度虽然不深,但每个块内做了很充分的时空特征交互。

3. 实现细节与训练配置:从公式到可跑的代码

3.1 图的构建:邻接矩阵、距离阈值与拉普拉斯归一化

模型里最前置的一步是把路网抽象成图。STGCN 构建邻接矩阵的做法是:两个传感器之间的边权重由它们的距离决定,采用带阈值的高斯核形式 A_ij = exp(-d_ij² / σ²),只有距离小于某个阈值的传感器对之间才保留边。d_ij 是传感器 i 和 j 的距离(可以是经纬度算的球面距离,也可以是路网路径距离),σ 是高斯核宽度。这个 σ 非常关键:σ 太小,邻接矩阵几乎退化为单位阵,图卷积退化成逐点操作;σ 太大,所有节点都连成一片,图卷积没有局部性。我实际复现时习惯先算所有传感器两两距离,然后以距离的一个分位数(比如中位数附近)来设定 σ,再配合阈值做稀疏化,比拍脑袋定 σ 靠谱。

拿到邻接矩阵 A 之后,还要构造归一化拉普拉斯 L = I - D^{-1/2} A D^{-1/2},其中 D 是度矩阵。这里注意两件事:一是度矩阵计算时要把 A 的对角线清零,避免节点把自身又算了一遍;二是有些实现用 D^{-1} A 做行归一化,效果差异不小,STGCN 用的是对称归一化 D^{-1/2} A D^{-1/2},它保留了图的对称性,更稳定。构造完 L 之后,把它缩放到 [-1, 1] 区间得到 L̃,这一步对训练稳定性很重要,没归一化的 L 特征值范围可能很大,直接做多项式运算容易数值爆炸。λ_max 一般用幂迭代法估算,不用精确求特征值。

3.2 数据切片、输入输出格式与标准化

数据层面的准备,第一步是洗数据。传感器原始数据常有缺失值和异常值,一般用前向填充加线性插值补上,再做一次去重。METR-LA 和 PEMS-SF 这两份公开数据集是很多人复现 STGCN 的首选,数据质量和时间粒度都比较规范。

第二步是滑窗切样本。输入是连续 12 个时刻的数据,输出是紧接着的 12 个时刻,窗口步长取 1,这样数据量足够大。一个值得注意的实践细节:模型的张量排布要设计好。PyTorch 实现里,STGCN 的中间特征一般排成 (batch, channels, time, nodes) 这种形状,因为时间卷积是沿 time 维度做的 2D 卷积,图卷积是沿 nodes 维度做的矩阵乘法,这个排布能让两种卷积都很顺手。如果一开始就按 (batch, time, nodes, channels) 排,后面转置操作会非常多,容易出 bug。

第三步是标准化。论文的做法是 z-score 标准化,而且是对每个传感器单独计算均值和方差,因为不同路段的平均车速差异很大,不做标准化的话,图卷积会被数值大的节点带偏。这里有个特别容易踩的坑:标准化参数只能用训练集计算,不能拿到全数据集上算,否则验证集和测试集的信息就提前泄漏到训练过程里了。后面我会专门说这个问题。

3.3 超参数、损失函数与训练技巧

论文里的训练配置我复现时基本沿用:Adam 优化器,初始学习率 0.001,batch size 50,训练轮数设个上限然后用早停控制。损失函数是 MAE 加 L2 权重正则。为什么要用 MAE 而不是 MSE?交通数据里有不少由事故、管制造成的尖峰异常值,MSE 对这种大误差的惩罚是平方级的,会让模型拼命去拟合那几个异常点,反而把正常模式学歪;MAE 对异常值更稳健,训练出来的预测曲线更贴合真实交通流的整体趋势。

另外几个提升稳定性的细节:图卷积输出之后接 ReLU,时间卷积内部用 GLU,每个 ST-Conv 块都有残差连接和批归一化。批归一化在训练初期特别重要,能明显加速收敛、减少对学习率的敏感度。学习率调度上,我习惯在验证 loss 停滞时把学习率乘以 0.1,配合 early stopping 的 patience 取 10 左右。还有一个容易被忽略的点:STGCN 是直接一次性输出未来 12 步,而不是像 seq2seq 那样逐步生成,这意味着推理阶段没有任何循环依赖,单次前向计算就能拿到全部预测结果,这也是它速度快的另一个原因。

4. 实验设计与结果解读

4.1 两个数据集和评估指标的挑选逻辑

论文用了两份真实的交通数据集。METR-LA 来自洛杉矶高速路网的 207 个传感器,时间跨度约 4 个月(2012 年 3 月到 6 月);PEMS-SF 来自旧金山湾区的 267 个传感器,时间跨度约半年。两份数据都是 5 分钟采样,原始数据经过清洗后按时间顺序切分成训练集、验证集和测试集,比例大致是 70%、10%、20%。选这两个数据集的好处是:规模适中、传感器数量在百级别,既不至于让图卷积算不动,又足够体现出空间结构对预测的增益。

评估指标是 MAE、MAPE、RMSE 三个,分别在 15、30、45、60 分钟四个预测时域上报告。这三个指标各有侧重:MAE 是平均绝对误差,直观好懂;MAPE 是相对百分比误差,会放大低数值路段的小误差,对交通这种几十公里时速的量级来说比较严苛;RMSE 对大误差的惩罚更重,能反映模型在极端情况下的表现。只看一个指标容易误判,比如某个模型 MAE 很低但 RMSE 很高,说明它平时预测准,但遇到突发拥堵时偏差巨大,这在交通场景里是不能接受的。

4.2 主要结果:全面领先基线怎么看

论文对比的基线包括历史平均(HA)、ARIMA、VAR、SVR、前馈神经网络(FFNN)、FC-LSTM 和基于图卷积的 GCGRU。结论很明确:STGCN 在两组数据集、四个预测时域上,MAE、MAPE、RMSE 三个指标全部大幅领先。下面这组数值是我从论文表格里摘出来整理的大致量级,我自己复现时数值略有浮动,以论文原表为准。

模型15 分钟 MAE30 分钟 MAE60 分钟 MAE
HA约 5.0约 6.1约 7.1
ARIMA约 4.7约 5.8约 7.0
SVR约 5.2约 5.6约 6.4
FFNN约 3.8约 4.2约 4.8
FC-LSTM约 3.7约 4.0约 4.5
GCGRU约 3.3约 3.7约 4.3
STGCN约 2.88约 3.47约 4.26

值得注意的一点是,预测时域越长,STGCN 的优势越明显。15 分钟预测时,STGCN 和 FC-LSTM 差距还不到 1 个 MAE;到了 60 分钟,差距已经拉开到 0.3 到 0.6 左右。这个现象说明,短期预测里时间序列自身的信息就足够,空间结构带来的增益有限;但预测范围拉长以后,路段之间的空间传播信息变成了关键,STGCN 正是靠图卷积把这种空间依赖抓住了。反过来也能看出,传统方法(HA、ARIMA)在长时域上掉得很快,因为它们既没有非线性建模能力,也没法利用路网结构。

4.3 消融与结构验证:组件真的都必要吗

论文里做了不少结构对比,验证了各个设计组件的必要性。首先是时间卷积里的 GLU 门控,对比不带门控的普通卷积,门控版本的误差明显更低——这和我复现时的体感一致,GLU 给时间建模加上了“选择性遗忘”,在突发变化多的路段上差异尤其明显。其次是三明治结构的顺序,“时间-图-时间”比“图-时间-图”更稳,这和前面讲的信号先平滑再传播的逻辑吻合。我自己还额外试过把两个 ST-Conv 块换成一个更宽的块,结果不如两个窄块堆叠——深度带来的多尺度时空特征提取能力确实无法用宽度补回来。

另一个值得验证的点是图卷积阶数 K。K=3 是论文实验里比较均衡的选择;K=1 什么都学不到,等价于没有邻居聚合;K 太大虽然感受野广,但会把很远路段的信息也混进来,反而引入噪声。我自己试 K=4 的时候,长时域误差没有明显下降,训练时间却涨了。这说明 K 的选择和路网的实际拓扑有关,不能盲目加大。

5. 复现过程中的踩坑记录

5.1 邻接矩阵相关的坑

邻接矩阵是整个模型的数据底座,这里出的问题最难排查。第一个坑是距离单位不一致。有的代码里传感器坐标是以米为单位,有的以公里为单位,算出来的 d_ij 差三个数量级,如果还沿用同一套 σ,邻接矩阵要么全 1 要么全 0。我自己的经验是:无论原始单位是什么,先把距离矩阵归一化到均值附近再算权重,或者直接按距离分位数定 σ,这样至少在数据集更换时不用反复调 σ。

第二个坑是图不连通。传感器之间的距离阈值设得太小,某些偏远的检测器周围没有邻居,它就成了孤立节点。孤立节点在 K 阶图卷积里只能更新到自己,空间信息根本传不进去,预测效果会明显比周围节点差一截。建议构建完图之后,检查一遍每个节点的度,发现孤立节点就调大阈值或者改用 KNN 方式建图。

第三个坑是 λ_max 和拉普拉斯缩放的数值稳定性。有些复现直接拿未缩放的 L 去做 Chebyshev 展开,训练到一半 loss 直接变 NaN。标准做法是 L̃ = 2L/λ_max - I,λ_max 用幂迭代法估计后还要带一个 eps 防止除零。这个细节看起来小,但出问题时会让你怀疑整个模型设计有问题,白折腾一天。

5.2 数据划分与归一化的坑

这个部分全是“看起来没问题、细想全是问题”的坑。第一,z-score 标准化的均值和方差必须在训练集上算,测试时要沿用训练集的参数。很多快速复现为了方便,直接在整个数据集上算均值和方差,这在 CV 里有时影响不大,但在交通预测里会显著高估模型性能,因为测试集的分布信息已经被模型“看到”了。第二,训练/验证/测试切分必须按时间顺序,不能全局随机打乱。交通数据有强时间相关性,随机打乱会让训练集里的样本和测试集样本时间上相邻,模型等于提前看到了答案。正确的做法是按时间切块,先在前 70% 上训,中间 10% 选超参,最后 20% 做终极评估。

第三,滑窗重叠带来的评估乐观。步长为 1 的滑窗让相邻样本之间共享了大量时间点,训练集和测试集如果切分不当,窗口边界会贴着泄漏。解决方法是切分时保证训练集最后一个窗口和验证集第一个窗口之间至少间隔 12 个时间点,这样输入区间不会跨越数据段边界。第四,特征选择要统一口径。有的复现只用速度单特征,有的把速度、流量都塞进去,还有把时间编码(星期几、几点)也拼进去的。这些都会影响最终数字,对比实验时务必明确说明自己用了哪几个通道,否则和论文数字对不上时根本定位不到原因。

5.3 训练不稳定与性能问题的排查

我复现时碰到的训练问题大致有三类。第一类是 loss 一开始就很大而且不下降。这种情况先检查输出层:STGCN 输出层的两个 1×1 卷积要把特征投影到 H 个预测时刻,如果 H 和特征通道数不匹配,维度错了不会报错,但梯度会非常混乱。其次是检查批归一化是否加在了合适的位置——图卷积之后不加 BN,网络基本训不动。

第二类是 loss 中途爆炸或变成 NaN。常见原因包括:学习率太大、图卷积的数值范围失去控制、或者梯度爆炸。排查顺序是:先降学习率到 1e-4 看是否缓解;再检查 L̃ 是否归一化到 [-1,1];最后给优化器加梯度裁剪,一般 max_norm 设 5.0 以内就能压住。还有一个容易被忽略的点:Chebyshev 展开中会把 L̃ 乘上输入,如果输入的特征值超过 1,多次多项式运算会指数放大,所以输入标准化比你想的还要重要。

第三类是效果看起来还行但总是“慢半拍”。这类问题最隐蔽:MAE 数字不算差,但你画出预测曲线,发现预测值基本上是历史值的滞后平移。这说明模型主要学到了时间上的“延续”,没有真正学到空间传播关系。我遇到这种情况时的处理是:把时间卷积核从 Kt=3 调大到 Kt=5,或者把预测目标从“直接回归绝对值”改成“回归相对变化量”,后者在长时域预测里能明显减少滞后感。

6. 延伸思考:STGCN 的位置与后续演进

6.1 为什么这篇论文影响这么大

STGCN 之所以成为经典,我觉得不只是因为它在两个数据集上刷了新数字,而是它把“用图结构表达领域知识 + 用卷积框架做时空建模”这条路完整地走通并开源了出来。在这之前,时空预测里用 RNN/LSTM 几乎是默认选项;STGCN 证明全卷积结构在交通预测上不仅可行,而且训练更快、效果更好。这个结论给后来者省了大量选型时间。之后几年里,Graph WaveNet、STSGCN、ASTGCN 等大量工作沿用了 ST-Conv 的基本思路,要么在图结构上做自适应学习,要么引入注意力机制,但“时空两个维度分别建模再组合”的骨架基本没变。

这个框架的可迁移性也值得强调。凡是能抽象成“传感器网络 + 时序信号”的任务,都可以套用这套思路:城市人流预测、电网负荷预测、空气质量监测、物联网设备异常检测,本质上都是图上的时序预测问题。我在另一个环境监测项目里试过把 STGCN 稍作修改迁移过去,只换了邻接矩阵和特征通道数,效果就直接超过了原来的逐点 LSTM。这种跨任务的泛化能力,是它比很多“针对特定数据集精心调参”的方法更有价值的地方。

6.2 局限性、后续工作与我的一些想法

STGCN 当然也有明显局限。第一,它的图是预先定义并且固定的,但真实路网的空间依赖会随交通状态动态变化——早高峰和半夜两点,同样两个路段的相关系数完全不同;突发事故更是会在短时间内重构一段路的“影响力拓扑”。固定图建模不了这种动态性。第二,邻接矩阵只编码了距离相近的传感器关系,两个不相邻但功能相似的路段(比如平行的两条主干道)之间可能存在强相关,但图里没有边,模型就学不到这种隐藏关联。后续 Graph WaveNet 提出自适应邻接矩阵、ASTGCN 引入时空注意力,都是在补这些短板。

从个人经验说,我读完这篇论文最大的收获不是某一层实现,而是这种建模思维:面对一个时空任务,先问数据背后的图结构是什么,再决定用什么样的卷积算子去匹配这个结构。很多任务的数据天然带图结构,只是没有被显式建模出来,硬套序列模型其实是在绕远路。如果你正准备复现 STGCN,我的建议是先别急着把代码堆起来,而是把邻接矩阵、数据切分、指标计算这三件事的细节先钉死,这三处出问题的概率最大。跑通基线之后再去改图卷积阶数、时间核宽度这些超参,你会发现自己对“空间依赖和时间依赖分别怎么被模型捕捉”的理解会明显上了一个台阶。

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

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

立即咨询