A3T-GCN架构预测交通流量

我们在 TGNN 中引出了基于时空信息的GNN架构。但没有详述其在交通预测上的应用。近年来,智慧城市的概念越来越受欢迎。这个概念指的是使用数据来管理和改善运营和服务的城市。在这种情况下,其主要吸引力之一是智能交通系统的创建。准确的交通预测可以帮助交通管理者优化交通信号、规划基础设施和减少拥堵。然而,由于复杂的时空依赖关系,交通预测是一个具有挑战性的问题。


前言

在本博文中,我们将把T-GNN应用于交通预测的一个特定案例。首先,我们将探索和处理一个新的数据集,以从原始CSV文件创建一个时间图。然后,我们将应用一种新型的T-GNN来预测未来的交通速度。最后,我们将可视化并将结果与基线解决方案进行比较,以验证我们的体系结构是否相关。


一、初识PeMS-M数据集

在本博文中,我们所使用的数据集是PeMSD7数据集的变体,原始数据集是通过使用Caltrans性能测量系统(PeMS)收集2012年5月和6月工作日内39,000个传感器站的交通速度而获得的。但我们仅仅考虑在加州第7区内的228个传感器站的速度数据。这些站输出30秒的速度测量值,在这个数据集中被聚合成5分钟的间隔。
交通数据

图1 交通数据

二、数据处理

变体数据的形式不符合GNN所需输入变量的形式。因此,我们需要对数据进行初步处理,使其满足要求。同时,对原始数据进行可视化,可以帮助我们更好的了解数据的具体表示。

2.1 数据库引入

import torch
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import networkx as nx

from time import time
from torch_geometric_temporal.signal import StaticGraphTemporalSignal
from torch_geometric_temporal.signal import temporal_signal_split
from torch_geometric_temporal.nn.recurrent import A3TGCN

np.random.seed(42)
torch.manual_seed(42)
torch.cuda.manual_seed(42)
torch.cuda.manual_seed_all(42)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False

2.2 数据导入及可视化

数据链接 可自行下载。

path = 'F:\Python_eBook\Graph Neural Networks\MyCode\PeMSD\STGCN_IJCAI-18-master\dataset\PeMSD7_Full'
# V_228 contains the speed data of 228 sensors
# W_228 contains the distance data of 228 sensors
speeds = pd.read_csv(path + '\PeMSD7_V_228.csv', names=range(228))
distances = pd.read_csv(path + '\PeMSD7_W_228.csv', names=range(0,228))

# visualize the evolution of traffic speed
mean = speeds.mean(axis=1)
std = speeds.std(axis=1)

plt.figure(figsize=(10,5), dpi=100)
plt.plot(mean, 'k-')
plt.grid(linestyle=':')
plt.fill_between(mean.index, mean-std, mean+std, color='r', alpha=0.1)
plt.xlabel('Time (5 min)')
plt.ylabel('Traffic speed')
plt.show()

# We can also visualize the correlation between the timeseries in different routes
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 8))
fig.tight_layout(pad=3.0)
ax1.matshow(distances)
ax1.set_xlabel("Sensor station")
ax1.set_ylabel("Sensor station")
ax1.title.set_text("Distance matrix")
ax2.matshow(-np.corrcoef(speeds.T))
ax2.set_xlabel("Sensor station")
ax2.set_ylabel("Sensor station")
ax2.title.set_text("Correlation matrix")
plt.show()

在上述内容中,PeMSD7_V_228.csv包括了228个传感器站每5分钟采集的交通数据。PeMSD7_W_228.csv表示传感器站点之间的欧几里得距离。为了可视化速度数据,我们将228个传感器站在每次采样后的速度数据求平均,一共有12672个数据点。并且,为了初步求证相邻传感器站的速度数据是否有关联性,我们求解了传感器之间的相关系数,并同距离矩阵相比较。

可视化结果如下。
平均交通速度

图2 平均交通速度

从图2中可以发现,当我们忽略5800附近的数据点时,其他数据点具有周期性。同时,交通流量有很大的可变性和重要的峰值。

距离和相关性矩阵

图3 距离和相关性矩阵,颜色较深的表示距离较短,相关性较高,颜色较亮的表示距离较远,相关性较低

有趣的是,监测站之间的距离远并不意味着它们不高度相关(反之亦然)。如果我们只考虑这个数据集的一个子集,这一点尤其重要:靠近的车站可能有非常不同的输出,这使得交通预测更加困难。在本章中,我们将考虑数据集中的每个传感器站。

2.3 相连节点计算

在对数据具有初步认识后,我们需要对数据进行变化使其符合架构所需形式。

第一步是将表格数据集转换为时间图。因此,首先,我们需要从原始数据创建一个图形。换句话说,我们必须以一种有意义的方式连接不同的传感器站。幸运的是,我们可以访问距离矩阵,这应该是连接车站的好方法。

从距离矩阵计算邻接矩阵有几种方法。例如,当两个站点之间的距离小于平均距离时,我们可以分配一个链接。然而,我们将执行更高级的处理来计算加权邻接矩阵。我们不使用二进制值,而是使用以下公式计算加权邻接矩阵。
i f    exp ⁡ ( − d i s t ( v i , v j ) 2 σ 2 )    ⩽ κ , W i j = 0 , e l s e    W i j = exp ⁡ ( − d i s t ( v i , v j ) 2 σ 2 )    if\,\,\exp \left( -\frac{dist\left( v_i, v_j \right) ^2}{\sigma ^2} \right) \,\,\leqslant \kappa , W_{ij}=0, else\,\,W_{ij}=\exp \left( -\frac{dist\left( v_i, v_j \right) ^2}{\sigma ^2} \right) \,\, ifexp(σ2dist(vi,vj)2)κ,Wij=0,elseWij=exp(σ2dist(vi,vj)2)
上式中, W i j W_{ij} Wij 代表了节点相连边的权重, d i s t dist dist 代表了两个节点之间的距离, κ \kappa κ σ \sigma σ 是控制邻接矩阵分布和稀疏度的两个阈值。

下面是代码实现。

# The nodes that are close to each other are selected
def compute_adj(distances, sigma2=0.1, epsilon=0.5):
    d = distances.to_numpy() / 10000.
    d2 = d * d
    n = distances.shape[0]
    w_mask = np.ones([n, n]) - np.identity(n)
    return np.exp(-d2 / sigma2) * (np.exp(-d2 / sigma2) >= epsilon) * w_mask

adj = compute_adj(distances)
edge_index = (np.array(adj) > 0).nonzero()

compute_adj函数中,我们构建w_mask变量,使其自循环处为0,其他位置为1。判断节点之间距离 exp ⁡ ( − d i s t ( v i , v j ) 2 σ 2 )    \exp \left( -\frac{dist\left( v_i, v_j \right) ^2}{\sigma ^2} \right) \,\, exp(σ2dist(vi,vj)2) 是否大于所设阈值,否则为False,与w_mask变量相乘后为0。最后,找到非0处索引,即为边。

可视化结果如下。

图4 邻接节点权重矩阵

图4同图3左图比较可以发现,邻接权重矩阵将距离相近的点筛选出来并赋予它们一定的权重,将距离较远的点赋值为0。

2.4 时间数据转换

交通数据在时间上具有相关性。因此,我们需要时间序列方面的问题。第一步是将速度值归一化,这样它们就可以被输入到神经网络中。在交通预测文献中,许多作者选择z-score归一化(或标准化),我们将在这里实现:

# Apply z-score
def zscore(x, mean, std):
    return (x - mean) / std

speeds_norm = zscore(speeds, speeds.mean(axis=0), speeds.std(axis=0))
speeds_norm.head()

这些值被正确地标准化了。现在,我们可以使用它们为每个节点创建时间序列。我们需要在每个时间步长 t t t 上输入 n n n 个数据样本,来预测 t + h t + h t+h 时的速度值。一个很大的数字输入数据样本也会增加数据集的内存占用。 h h h 的值,也称为边界,取决于我们想要执行的任务:短期或长期交通预测。

在这个例子中,我们取一个高值48来预测4小时(48*5=240min=4h)后的交通速度:

lags = 24
horizon = 48
xs = []
ys = []
for i in range(lags, speeds_norm.shape[0]-horizon):
    xs.append(speeds_norm.to_numpy()[i-lags:i].T)
    ys.append(speeds_norm.to_numpy()[i+horizon-1])

最后,利用边索引和加权邻接矩阵构建时间图:

dataset = StaticGraphTemporalSignal(edge_index, adj[adj > 0], xs, ys)
dataset[0]

train_dataset, test_dataset = temporal_signal_split(dataset, train_ratio=0.8)

最终的时间图有228个节点,24个特征值和1664个连接。我们将用228个传感器站在24个采样数据预测4个小时后228个传感器站交通速度,并以步长为1的形式改变训练数据。至此,数据的初步处理已经完成。

三、A3T-GCN架构

在本节中,我们将训练一个用于交通预测的注意力时序图卷积网络(A3T-GCN)。这种架构允许我们考虑复杂的空间和时间依赖性:

  • 空间依赖性是指一个地点的交通状况会受到附近地点交通状况的影响。例如,交通堵塞经常蔓延到邻近的道路。
  • 时间依赖性是指一个地点在某一时刻的交通状况会受到同一地点在前一时刻的交通状况的影响。例如,如果一条道路在早高峰期间拥挤不堪,那么它很可能会一直拥挤到晚高峰。

A3T-GCN是对GCN (TGCN)架构的改进。TGCN是GCN和GRU的组合,它从每个输入时间序列中产生隐藏向量。这两层的组合从输入中捕获空间和时间信息。然后使用注意力模型来计算权重并输出上下文向量。最后的预测是基于结果上下文向量的。增加这种注意力模型的动机是为了解全局趋势。
A3T-GCN架构

图5 A3T-GCN架构

3.1 架构建立

class TemporalGNN(torch.nn.Module):
    def __init__(self, dim_in, periods):
        super().__init__()
        self.tgnn = A3TGCN(in_channels=dim_in, out_channels=32, periods=periods)
        self.linear = torch.nn.Linear(32, periods)

    def forward(self, x, edge_index, edge_attr):
        h = self.tgnn(x, edge_index, edge_attr).relu()
        h = self.linear(h)
        return h

model = TemporalGNN(lags, 1).to('cpu')
optimizer = torch.optim.Adam(model.parameters(), lr=0.005)
model.train()
print(model)

整体架构如下。

TemporalGNN(
  (tgnn): A3TGCN(
    (_base_tgcn): TGCN(
      (conv_z): GCNConv(24, 32)
      (linear_z): Linear(in_features=64, out_features=32, bias=True)
      (conv_r): GCNConv(24, 32)
      (linear_r): Linear(in_features=64, out_features=32, bias=True)
      (conv_h): GCNConv(24, 32)
      (linear_h): Linear(in_features=64, out_features=32, bias=True)
    )
  )
  (linear): Linear(in_features=32, out_features=1, bias=True)
)

其中,线性层输入特征之所以是前一层输出特征的两倍是因为需要结合所有节点的隐藏状态向量。

3.2 模型训练

注:模型训练在我电脑上耗时2910s 。

# Training
for epoch in range(31):
    loss = 0
    step = 0
    for i, snapshot in enumerate(train_dataset):
        y_pred = model(snapshot.x.unsqueeze(2), snapshot.edge_index, snapshot.edge_attr)
        loss += torch.mean((y_pred-snapshot.y)**2)
        step += 1
    loss = loss / (step + 1)
    loss.backward()
    optimizer.step()
    optimizer.zero_grad()
    if epoch % 5 == 0:
        print(f"Epoch {epoch:>2} | Train MSE: {loss:.4f}")

训练输出如下。

Epoch  0 | Train MSE: 1.0085
Epoch  5 | Train MSE: 0.9778
Epoch 10 | Train MSE: 0.9515
Epoch 15 | Train MSE: 0.9293
Epoch 20 | Train MSE: 0.9131
Epoch 25 | Train MSE: 0.9026
Epoch 30 | Train MSE: 0.8948

四、模型评估

现在我们的模型已经训练好了,我们必须对它进行评估。除了诸如均方根误差(RMSE)和平均绝对误差(MAE)等经典指标之外,将我们的模型与时间序列数据的基线解决方案进行比较特别有帮助。在下面的列表中,我们将介绍两种方法:

  • 使用随机漫步(RW)作为 n a i v e naive naive 预测器。在这种情况下,RW指的是使用最后一次观测值作为预测值。换句话说, t t t 点的值和 t + h t + h t+h 点的值是一样的。
  • 使用历史平均(HA)作为稍微进化的解决方案。在这种情况下,我们计算前 k k k 个样本的平均交通速度作为 t + h t + h t+h 的值。在这个例子中,我们将使用延迟的数量作为我们的 k k k 值,但我们也可以取整体的历史平均值。

4.1 模型预测性能

A3T-GCN架构性能。

 # naive model
def inverse_zscore(x, mean, std):
    return x * std + mean

y_test = []
for snapshot in test_dataset:
    y_hat = snapshot.y.numpy()
    y_hat = inverse_zscore(y_hat, speeds.mean(axis=0), speeds.std(axis=0))
    y_test = np.append(y_test, y_hat)

gnn_pred = []
model.eval()
for snapshot in test_dataset:
    snapshot = snapshot
    y_hat = model(snapshot.x.unsqueeze(2), snapshot.edge_index, snapshot.edge_weight).squeeze().detach().numpy()
    y_hat = inverse_zscore(y_hat, speeds.mean(axis=0), speeds.std(axis=0))
    gnn_pred = np.append(gnn_pred, y_hat)


def MAE(real, pred):
    return np.mean(np.abs(pred - real))

def RMSE(real, pred):
    return np.sqrt(np.mean((pred - real) ** 2))

def MAPE(real, pred):
    return np.mean(np.abs(pred - real) / (real + 1e-5))

print(f'GNN MAE  = {MAE(gnn_pred, y_test):.4f}')
print(f'GNN RMSE = {RMSE(gnn_pred, y_test):.4f}')
print(f'GNN MAPE = {MAPE(gnn_pred, y_test):.4f}')

构建 n a i v e naive naive模型。

# baseline model
rw_pred = []
for snapshot in test_dataset:
    y_hat = snapshot.x[:,-1].squeeze().detach().numpy()
    y_hat = inverse_zscore(y_hat, speeds.mean(axis=0), speeds.std(axis=0))
    rw_pred = np.append(rw_pred, y_hat)

print(f'RW MAE  = {MAE(rw_pred, y_test):.4f}')
print(f'RW RMSE = {RMSE(rw_pred, y_test):.4f}')
print(f'RW MAPE = {MAPE(rw_pred, y_test):.4f}')

ha_pred = []
for i in range(lags, speeds_norm.shape[0]-horizon):
    y_hat = speeds_norm.to_numpy()[:i].T.mean(axis=1)
    y_hat = inverse_zscore(y_hat, speeds.mean(axis=0), speeds.std(axis=0)) 
    ha_pred.append(y_hat)
ha_pred = np.array(ha_pred).flatten()[-len(y_test):]

print(f'HA MAE  = {MAE(ha_pred, y_test):.4f}')
print(f'HA RMSE = {RMSE(ha_pred, y_test):.4f}')
print(f'HA MAPE = {MAPE(ha_pred, y_test):.4f}')
表1 性能比较表
RMSEMAEMAPE
A3T-GCN11.96%8.31%14.90%
RW17.65%11.04%29.99%
HA13.15%9.33%16.33%

我们看到基线技术在每个指标上都劣于A3T-GCN模型。这是一个重要的结果,因为基线通常很难被超越。将这些指标与LSTM或GRU网络提供的预测进行比较,以衡量拓扑信息的重要性,这将是一件有趣的事情。

4.2 预测结果可视化

最后,我们可以绘制平均预测,得到类似于图2的可视化:

# visualize the prediction
y_preds = [inverse_zscore(model(snapshot.x.unsqueeze(2), snapshot.edge_index, snapshot.edge_weight).squeeze().detach().numpy(), speeds.mean(axis=0), speeds.std(axis=0)).mean() for snapshot in test_dataset]

mean = speeds.mean(axis=1)
std = speeds.std(axis=1)

plt.figure(figsize=(10,5))
plt.plot(np.array(mean), 'k-', label='Mean')
plt.plot(range(len(speeds)-len(y_preds), len(speeds)), y_preds, 'r-', label='Prediction')
plt.grid(linestyle=':')
plt.fill_between(mean.index, mean-std, mean+std, color='r', alpha=0.1)
plt.axvline(x=len(speeds)-len(y_preds), color='b', linestyle='--')
plt.xlabel('Time (5 min)')
plt.ylabel('Traffic speed to predict')
plt.legend(loc='upper right')
plt.show()

在这里插入图片描述

图6 A3T-GCN架构预测结果

T-GNN正确地预测了峰值,并遵循了总体趋势。然而,预测的速度更接近整体平均值,因为由于MSE损失函数的定义,模型犯严重错误的代价更大。尽管如此,GNN是相当准确的,可以微调输出更极端的值。


总结

本博文主要讨论使用T-GNN的交通流量预测任务。首先,我们研究了PeMS-M数据集,并将其从表格数据转换为具有时间信号的静态图形数据集。在实践中,我们基于输入距离矩阵创建了一个加权邻接矩阵,并将交通速度转换为时间序列。最后,我们实现了一个A3T-GCN模型,这是一个为交通预测而设计的T-GNN模型。我们将结果与两条基线进行了比较,并验证了我们的模型所做的预测。

  • 8
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
t-gcn(Temporal Graph Convolutional Networks)交通预测代码是一种时间序列数据的神经网络模型,可以用于交通预测。这个模型可以处理不同的时空交通数据,并能够自适应地学习数据的特征,因此在交通预测的应用中是非常有效的。 t-gcn交通预测代码有以下几个主要的步骤: 1. 数据预处理。首先需要将原始的数据进行解析,并且把数据转换成合适的格式。这个过程应该包括对数据的平滑、划分时间段等操作,并且需要保证输入数据的格式和维度的一致性,以方便后续的处理。 2. 模型定义。在这一步中,需要定义神经网络的架构、各层的参数和超参数等。t-gcn交通预测代码采用了多层的时空卷积神经网络(Spatio-Temporal Convolutional Network,STCN)模型,可以根据数据的特征自适应地学习卷积核的权重,从而能够提升预测的准确性。 3. 模型训练。在模型训练阶段,需要将数据输入模型进行训练,以求得最优的权重参数。t-gcn交通预测代码采用了均方误差(Mean Square Error,MSE)损失函数,通过反向传播来计算和更新网络的参数,以增强模型的预测性能。 4. 模型测试和评估。在这一步中,需要使用训练好的模型输入测试数据,然后通过预测和实际值之间的误差来评估模型的预测精度。t-gcn交通预测代码使用了多种指标来评估模型的性能,例如均方误差、平均绝对误差以及RMSE(均方根误差)等。 总之,t-gcn交通预测代码是一种先进的神经网络模型,可以提高交通预测的准确性和可靠性,并且具有良好的扩展性和适应性,可以广泛应用于交通领域的实践中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值