AGCRN论文解读
一、创新点
传统GCN只能基于静态预定义图建模全局共享模式,而AGCRN通过两种GCN的增强模块(NAPL、DAGG)实现了更精细的节点特性学习和图结构生成。

1 节点自适应参数学习模块(NAPL)
传统GCN通过共享参数(权重和偏置)在所有节点上执行图卷积操作,这样只能考虑到邻近节点间的空间相关性。然而在交通序列中,还因时间序列的动态特性和节点的多种影响因素(例如兴趣点、天气)而表现出多样性模式。
因此,传统的图卷积公式必须作出如下变换。将权重 Θ 分解为两个更小的权重矩阵。其中EG代表节点嵌入矩阵,它为每个节点提供了一个区分性的表示,使得模型能够识别节点间的差异。WG是一个共享的权重池,包含了所有节点共享的候选特征模板,由节点嵌入EG确定哪些模板最适合每个节点。

这么讲非常抽象晦涩!!!作者据说受到了矩阵分解的启发,也许可以从这方面入手理解。Θ 是三维矩阵(节点N,输入特征C,输出特征F),这时一个节点对应死了一个权重值。如果把第0维和第1维中间拦腰斩断,插入一个索引维度d,那么就分解出了EG(节点N,索引d)和WG(索引d,输入特征C,输出特征F)。因此,每个节点 Ni 就能通过索引 di 在权重池子里找到适合自己的那个权重。这种生成方式允许节点共享一个全局权重池,同时保留节点特定性。代码如下:
self.node_embeddings = nn.Parameter(torch.randn(self.num_node, args.embed_dim), requires_grad=True)self.weights_pool = nn.Parameter(torch.FloatTensor(embed_dim, cheb_k, dim_in, dim_out))
self.bias_pool = nn.Parameter(torch.FloatTensor(embed_dim, dim_out))weights = torch.einsum('nd,dkio->nkio', node_embeddings, self.weights_pool) #N, cheb_k, dim_in, dim_out
bias = torch.matmul(node_embeddings, self.bias_pool)
那么到底改进了什么?
- 在GCN中,一个权重矩阵 Θ 就能处理所有节点的特征,不管每个节点今天刮风下雨还是有车祸。而在NAPL中,每个节点都有选择自己权重矩阵的权力。这样模型针对不同的节点才会预测得更加精准。
- 如果每个节点都有多个不同的权重矩阵,而不是共享一个权重池。那样会导致模型过于复杂,徒增计算资源。
因此NAPL是一个很折中的办法!
2 数据自适应图生成(DAGG)
在传统的基于GCN的交通预测模型中需要预定义的邻接矩阵 A 以进行图卷积操作。而预定义的图无法包含完整的空间依赖信息,也无法直接与预测任务相关联。
有两点原因:首先,两条物理上相邻的道路可能由于单行道或隔离带而没有直接的交通交互。某条道路因为施工或重大活动会突然变得与其他道路关联更强。其次,构建预定义图通常需要依赖领域专家的知识,而且需要大量人力来设计和验证图的质量。
因此,作者提出了数据自适应图生成(DAGG)模块。这个模块首先基于输入数据(如交通流量或速度)为所有节点随机初始化一个可学习的节点嵌入字典 EA ,是一个二维矩阵(节点数量N,嵌入维度d)。通过 EA 和其转置矩阵相乘即可得到节点之间的内积相似度矩阵,即新的邻接矩阵。这是为什么?

首先,内积的本质就是用来衡量两个向量的相似性。两个向量方向相同,且相似性越大,内积就会越大。当两个向量垂直时,内积为0;方向相反,内积为负。而EA 的第 i 行和其转置矩阵的第 i 列是同一向量,那么 EA 的 i 行与其转置矩阵的 i+1 列相乘得到的结果就代表,第 i 个节点和 第 i+1 个节点的相似度。因此,逐行逐列相乘后就可以得到一个 N 行 N 列的邻接矩阵。
下面是作者的实现代码,node_embeddings 就是上图的 EA 矩阵。
# AGCRN.py 中的代码
self.node_embeddings = nn.Parameter(torch.randn(self.num_node, args.embed_dim), requires_grad=True)# AGCN.py 中的代码
supports = F.softmax(F.relu(torch.mm(node_embeddings, node_embeddings.transpose(0, 1))), dim=1)
不过,自适应图生成的生成并不是作者的首创,早在2019年的 Graph WaveNet 论文(Graph WaveNet for Deep Spatial-Temporal Graph Modeling)中就提出过类似的方法,叫做自适应邻接矩阵。本篇论文是 2020 年的,不管是查看论文还是代码,可以发现就是说的一个东西。。。
二、自适应图卷积递归网络(AGCRN)
作者讲上述两个模块与 GRU 结合起来可以得到:

在前文中,可以得到图卷积 Z,再将 Z 提取为更新门 z 和重置门 r,那么我们就可以计算出候选状态以及最终输出 h。代码如下:
state = state.to(x.device) # 确保 state 与输入 x 在相同设备(如 GPU)上
input_and_state = torch.cat((x, state), dim=-1) # 将当前输入 x 和隐藏状态 state 沿特征维度拼接
z_r = torch.sigmoid(self.gate(input_and_state, node_embeddings))
z, r = torch.split(z_r, self.hidden_dim, dim=-1)
candidate = torch.cat((x, z*state), dim=-1)
hc = torch.tanh(self.update(candidate, node_embeddings))
h = r*state + (1-r)*hc
return h
三、实验
作者使用了 PeMSD4 和 PeMSD8 数据集,其中训练集、验证集和测试集的划分比例为 6:2:2。将 12 步的历史数据作为输入,接下来的 12 步数据作为输出。
3.1 消融实验
同时,作者为了更好地评估 NAPL 和 DAGG 的性能,还进行了全面的消融实验。分别对比了如下几组实验:
- GCGRU:传统的 GCN ;
- NAPL-GCGRU:将传统的 GCN 替换为我们提出的 NAPL-GCN;
- DAGG-GCGRU:将预定义图替换为 DAGG 模块;
- AGCRN-I:不统一节点嵌入,而是在不同的 NAPL-GCN 层和 DAGG 中使用独立的节点嵌入矩阵。
- AGCRN:作者的模型。
其中作者提到了节点嵌入,是指在模型中使用统一的节点嵌入向量来表示不同模块或层之间的节点特性。这意味着,在 AGCRN 中,节点的嵌入向量在整个模型中是共享的,而不是为每个模块分别学习不同的嵌入。 查看代码,也可以发现整个项目只有一个 node_embeddings。
下图为作者的测试结果。可以发现NAPL在短期预测时表现不佳。这是因为短期预测(例如 5 分钟或 15 分钟的预测)通常能从已有的历史数据中获得足够的信息,所以不太依赖于节点特定的嵌入(即 NAPL 学到的每个节点的特性)。换句话说,短期预测可以依赖于前几个时间步的交通数据,而不需要太多的额外个性化特征。然而长期预测(例如 30 分钟或 60 分钟的预测)则面临更大的不确定性,因为历史数据可能无法充分预测未来的变化。这时,NAPL 所学习的节点特定嵌入变得尤为重要,因为它能帮助模型更好地捕捉每个节点的独特模式(例如道路的特殊流量模式、影响因素等),从而提高对长期预测的准确性。

3.2 图生成过程分析
在上述的图卷积的公式中,还有一个单位矩阵 I。它的作用是保持每个节点的自信息,即让节点的当前特征在计算中不被忽视。这就类似于一个节点在做预测时不考虑自己的历史数据,只依赖邻居节点的状态,可能导致信息丢失或不准确。因此,作者对自适应图生成(DAGG)做了两个变种,即不使用单位矩阵的 DAGG-r 和 不使用生成的图拉普拉斯矩阵的 DAGG-2。
由下表可以看出,如果不使用单位矩阵,那么效果会大打折扣。但是不使用图生成的拉普拉斯矩阵(预定义图),效果并没有很大差距。

最后,作者还考虑了嵌入维度对实验的影响。发现嵌入维度为10时效果最好。


本论文的PeMSD4数据集运行结果如下:
2024-12-07 06:19: Total training time: 25.8792min, best loss: 19.460032
2024-12-07 06:19: Horizon 01, MAE: 18.68, RMSE: 30.26, MAPE: 12.5175%
2024-12-07 06:19: Horizon 02, MAE: 18.78, RMSE: 30.61, MAPE: 12.5259%
2024-12-07 06:19: Horizon 03, MAE: 18.98, RMSE: 31.03, MAPE: 12.6548%
2024-12-07 06:19: Horizon 04, MAE: 19.22, RMSE: 31.49, MAPE: 12.8187%
2024-12-07 06:19: Horizon 05, MAE: 19.50, RMSE: 31.96, MAPE: 13.0233%
2024-12-07 06:19: Horizon 06, MAE: 19.77, RMSE: 32.41, MAPE: 13.2145%
2024-12-07 06:19: Horizon 07, MAE: 20.01, RMSE: 32.82, MAPE: 13.3573%
2024-12-07 06:19: Horizon 08, MAE: 20.20, RMSE: 33.19, MAPE: 13.4612%
2024-12-07 06:19: Horizon 09, MAE: 20.38, RMSE: 33.54, MAPE: 13.5726%
2024-12-07 06:19: Horizon 10, MAE: 20.59, RMSE: 33.93, MAPE: 13.7235%
2024-12-07 06:19: Horizon 11, MAE: 20.93, RMSE: 34.43, MAPE: 13.9569%
2024-12-07 06:19: Horizon 12, MAE: 21.45, RMSE: 35.11, MAPE: 14.3262%
2024-12-07 06:19: Average Horizon, MAE: 19.87, RMSE: 32.60, MAPE: 13.2627%

相关文章:
AGCRN论文解读
一、创新点 传统GCN只能基于静态预定义图建模全局共享模式,而AGCRN通过两种GCN的增强模块(NAPL、DAGG)实现了更精细的节点特性学习和图结构生成。 1 节点自适应参数学习模块(NAPL) 传统GCN通过共享参数(权重…...
Python机器学习笔记(五、决策树集成)
集成(ensemble)是合并多个机器学习模型来构建更强大模型的方法。这里主要学习两种集成模型:一是随机森林(random forest);二是梯度提升决策树(gradient boosted decision tree)。 1…...
Kafka单机及集群部署及基础命令
目录 一、 Kafka介绍1、kafka定义2、传统消息队列应用场景3、kafka特点和优势4、kafka角色介绍5、分区和副本的优势6、kafka 写入消息的流程 二、Kafka单机部署1、基础环境2、iptables -L -n配置3、下载并解压kafka部署包至/usr/local/目录4、修改server.properties5、修改/etc…...
如何使用 Python 实现链表的反转?
在Python中实现链表的反转可以通过几种不同的方法。这里,我将向你展示如何使用迭代和递归两种方式来反转链表。 1. 迭代方法 迭代方法是通过遍历链表,逐个节点地改变其指向来实现反转的。 class ListNode: def __init__(self, val0, nextNone): …...
react跳转传参的方法
传参 首先下载命令行 npm react-router-dom 然后引入此代码 前面跳转的是页面 后面传的是你需要传的参数接参 引入此方法 useLocation():这是 react-router-dom 提供的一个钩子,用于获取当前路由的位置对象location.state:这是从其他页面传…...
Scala:正则表达式
object test03 {//正则表达式def main(args: Array[String]): Unit {//定义一个正则表达式//1.[ab]:表示匹配一个字符,或者是a,或者是b//2.[a-z]:表示从a到z的26个字母中的任意一个//3.[A-Z]:表示从A到Z的26个字母中的任意一个//4.[0-9]:表示从0到9的10…...
【数电】常见时序逻辑电路设计和分析
本文目的:一是对真题常考题型总结,二是对常见时序电路设计方法进行归纳,给后面看这个文档的人留有一点有价值的东西。 1.不同模计数器设计 2.序列信号产生和检测电路 2.1序列信号产生电路 2.1.1设计思路 主要设计思路有三种 1)…...
Spring IOCAOP
Spring介绍 个人博客原地址 Spring是一个IOC(DI)和AOP框架 Sprng的优良特性 非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的API 依赖注入:DI是控制反转(IOC)最经典的实现 面向切面编程&am…...
Scala中的隐式转换
package qiqiobject qqqqq {//给参数设置一个默认值:如果用户不传入,就使用这个值def sayName(implicit name:String"小花"):Unit{println(s"我叫:$name")}//需求:能够自己设置函数的参数默认值,而不是在代码…...
GESP 2024年12月认证 真题 及答案
CCF GESP第八次认证将于2024年12月7日上午9:30正式开考,1-4级认证时间为上午9:30-11:30,5-8级认证时间为下午13:30-16:30。认证语言包括:C、 Python和图形化编程三种语言,其中C和Python编程为1-8级,图形化编程为1-4级。…...
C++多态性
概念 C中的多态性是面向对象编程的一个重要特征,它允许我们通过一个基类的指针或引用来操作不同派生类的对象。多态性增强了代码的灵活性和可扩展性。主要分为两种类型:编译时多态(静态多态)和运行时多态(动态多态&am…...
PyODBC: Python 与数据库连接的桥梁
PyODBC: Python 与数据库连接的桥梁 介绍 在现代的开发环境中,数据是核心要素之一。几乎所有的应用程序都需要与数据库进行交互。在 Python 中,pyodbc 是一个非常常用的库,它提供了一种简便的方法,通过 ODBC(开放数据…...
专题二十五_动态规划_两个数组的 dp (含字符串数组)_算法专题详细总结
目录 动态规划_两个数组的 dp (含字符串数组) 1. 最⻓公共⼦序列(medium) 解析: 1. 状态表⽰: 2. 状态转移⽅程: 3. 初始化:编辑 4. 填表顺序:编辑 5. 返回值…...
PHP语法学习(第七天)-循环语句,魔术常量
老套路了,朋友们,先回忆昨天讲的内容PHP语法学习(第六天)主要讲了PHP中的if…else语句、关联数组以及数组排序。 想要学习更多PHP语法相关内容点击“PHP专栏!” 下列代码都是在PHP在线测试运行环境中得到的!! 还记得电…...
数据库授权讲解一下
这条 SQL 命令是 MySQL 数据库中用于权限管理的 GRANT 语句。它用于授予用户特定的权限。下面是命令的详细解释: GRANT ALL PRIVILEGES ON *.* TO root% IDENTIFIED BY Zz!12345678 WITH GRANT OPTION;GRANT: 这是一个关键字,用于…...
组件开发的环境准备: nodejs安装,npm镜像源的修改,pnpm包管理器的安装(全局安装),基于pnpm创建脚手架项目
Node.js 是一个开源的、跨平台的 JavaScript 运行环境(本质是Chrome引擎的封装),允许开发者使用 JavaScript 来编写服务器端代码 npm(Node Package Manager)是 Node.js 包管理器, 用来安装各种库、框架和工具 【Node.js官网】 https://nodejs.org 【n…...
学生成绩统计系统
实验内容 问题描述: 输入n个学生的考试成绩,每个学生信息由姓名与分数组成;试设计一种算法: (1)按分数高低次序,打印出每个学生的名次,分数相同的为同一名次; (2)按名次输出每个学生的姓名与分数。 基本要求: (1)学生的考试成绩必须通过…...
【Spring项目】图书管理系统
阿华代码,不是逆风,就是我疯 你们的点赞收藏是我前进最大的动力!! 希望本文内容能够帮助到你!! 目录 一:项目实现准备 1:需求 (1)登录 2:准备…...
Vivado ILA数据导出MATLAB分析
目录 ILA数据导出 分析方式一 分析方式二 有时候在系统调试时,数据在VIVADO窗口获取的信息有限,可结合MATLAB对已捕获的数据进行分析处理 ILA数据导出 选择信号,单击右键后,会有export ILA DATA选项,将其保存成CS…...
【开源免费】基于SpringBoot+Vue.JS高校学科竞赛平台(JAVA毕业设计)
博主说明:本文项目编号 T 075 ,文末自助获取源码 \color{red}{T075,文末自助获取源码} T075,文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
