# 动态图神经网络

## 如何对GAT的权重（$W$）和注意力参数（$a$）进行增量更新（邻居偶尔变化）

#### 1. 核心思想

- **局部更新**：邻居变化的节点及其直接邻域的权重和注意力参数需要调整，其他部分冻结。  
- **梯度隔离**：反向传播时，仅计算受影响节点的梯度，避免全局参数震荡。  

---

#### 2. 数学实现步骤

#### **(1) 识别受影响的节点**

设邻居变化后的新邻接矩阵为 $\tilde{A}$，原邻接矩阵为 $A$，受影响节点集合 $\mathcal{V}_{\text{affected}}$ 包括：  

- 新增或删除边的两端节点（直接受影响）。  
- 这些节点的1-hop邻居（间接受影响，根据GAT层数决定）。  

#### **(2) 损失函数局部化**

仅对 $\mathcal{V}_{\text{affected}}$ 中的节点计算损失：  
$$
\mathcal{L}_{\text{incremental}} = \sum_{i \in \mathcal{V}_{\text{affected}}} \ell(y_i, \hat{y}_i)
$$
其中 $\ell$ 为交叉熵损失，$y_i$ 为标签，$\hat{y}_i$ 为模型输出。  

#### **(3) 梯度计算与参数更新**

- **梯度掩码**：  
  反向传播时，非受影响节点的梯度强制置零：  
  $$
  \nabla_{W,a} \mathcal{L}_{\text{incremental}} = \left\{ 
  \begin{array}{ll}
  \nabla_{W,a} \ell(y_i, \hat{y}_i) & \text{if } i \in \mathcal{V}_{\text{affected}} \\
  0 & \text{otherwise}
  \end{array} \right.
  $$

- **参数更新**：  
  使用优化器（如Adam）仅更新有梯度的参数：  
  $$
  W \leftarrow W - \eta \nabla_W \mathcal{L}_{\text{incremental}}, \quad a \leftarrow a - \eta \nabla_a \mathcal{L}_{\text{incremental}}
  $$
  其中 $\eta$ 为较小的学习率（防止过拟合）。  

#### **(4) 注意力权重的动态适应**

GAT的注意力机制会自动适应新邻居：  
$$
\alpha_{ij} = \text{softmax}\left(\text{LeakyReLU}\left(a^T [W h_i \| W h_j]\right)\right)
$$
由于 $W$ 和 $a$ 已局部更新，新邻居 $j \in \tilde{\mathcal{N}}(i)$ 的权重 $\alpha_{ij}$ 会重新计算。  

#### 3. 适用场景

- **低频变化**：如社交网络每天新增少量边、论文引用网络月度更新。  
- **局部变化**：每次变化仅影响图中少量节点（<10%）。  

若邻居**高频变化**（如秒级更新），需改用动态GNN（如TGAT）或时间序列建模。  



## EvolveGCN

### EvolveGCN-H

#### **1. EvolveGCN-H核心思想**

EvolveGCN-H 通过 **GRU（门控循环单元）** 动态更新 GCN 每一层的权重矩阵 $W_t^{(l)}$，将权重矩阵视为 GRU 的 **隐藏状态**，并利用当前时间步的 **节点嵌入（特征）** 作为输入来驱动演化。  
**关键特点**：  

- **输入依赖**：利用节点嵌入 $H_t^{(l)}$ 指导权重更新。  
- **时序建模**：通过 GRU 隐式捕捉参数演化的长期依赖。

---

#### **2. 动态更新流程（以第 $l$ 层为例）**

**输入**：

1. 当前节点嵌入矩阵 $H_t^{(l)} \in \mathbb{R}^{n \times d}$：  
2. 上一时间步的权重矩阵 $W_{t-1}^{(l)} \in \mathbb{R}^{d \times d'}$：  
3. 邻接矩阵 $A_t \in \mathbb{R}^{n \times n}$：  

**输出**：

1. 更新后的权重矩阵 $W_t^{(l)} \in \mathbb{R}^{d \times d'}$。  
2. 下一层节点嵌入 $H_t^{(l+1)} \in \mathbb{R}^{n \times d'}$。

---

#### **3. 动态更新示意图**

```plaintext
Time Step t-1                          Time Step t
+-------------------+                 +-------------------+
|  Weight Matrix    |                 |  Weight Matrix    |
|    W_{t-1}^{(l)}  |  --(GRU更新)--> |    W_t^{(l)}      |
+-------------------+                 +-------------------+
         ^                                      ^
         |                                      |
+-------------------+                 +-------------------+
|  Node Embeddings  |                 |  Node Embeddings |
|    H_t^{(l)}      |  --(GCN计算)--> |    H_t^{(l+1)}    |
+-------------------+                 +-------------------+
         ^                                      ^
         |                                      |
+-------------------+                 +-------------------+
|  邻接矩阵 A_t     |                 |  邻接矩阵 A_{t+1} |
| (显式输入)        |                 | (下一时间步输入)  |
+-------------------+                 +-------------------+
```

$$
\begin{align*}
W_t^{(l)} &<= H_t^{(l)} + W_{t-1}^{(l)} \\
H_t^{(l+1)} &<= A_t + H_t^{(l)} + W_t^{(l)}
\end{align*}
$$

#### **4. 具体步骤分解**

##### **步骤 1：节点嵌入聚合（Summarize）**

由于 GRU 的输入需与隐藏状态 $W_{t-1}^{(l)}$ 的列维度匹配（即 $d'$），需将 $H_t^{(l)}$ 从 $n \times d$ 压缩为 $d' \times d$ ：
$$
Z_t = \text{Summarize}(H_t^{(l)}, d')
$$

将会舍弃部分节点

**实现方式**（论文方案）：  

1. 计算得分：  
   $$
   y_t = H_t^{(l)} p / \|p\| \quad (p \in \mathbb{R}^d \text{为可学习参数})
   $$
   学一个“打分器”参数 $p$，$H_t^{(l)} p$相当于对每个节点的嵌入向量和 $p$做点积，得到一个分数。比如在社交网络中，$p$ 可能代表“活跃度”，得分高的用户更活跃。

2. 选取 Top-$d'$ 个节点（按 $y_t$ 排序），加权求和：  
   $$
   Z_t = [H_t^{(l)} \circ \tanh(y_t)]_{\text{top-}d'} \quad (\circ \text{为逐元素乘})
   $$

   - 输出 $Z_t \in \mathbb{R}^{d' \times d}$。

**举个例子**

假设：  
- 有3个节点（$n=3$），嵌入维度 $d=2$，选Top-2个节点（$d'=2$）。  
- 节点嵌入：  
  $$
  H_t^{(l)} = \begin{bmatrix} 1 & 0.5 \\ 0.3 & 2 \\ -1 & 1 \end{bmatrix}, \quad p = [1, 0]
  $$
  
  （$p$ 只关注嵌入的第一维，比如“用户发帖数量”）

1. **计算分数**：  
   $$
    y_t = H_t^{(l)} p = [1 \cdot 1 + 0.5 \cdot 0, \ 0.3 \cdot 1 + 2 \cdot 0, \ -1 \cdot 1 + 1 \cdot 0] = [1, 0.3, -1] 
   $$
   
   Top-2节点是第1、第2个节点（分数1和0.3）。
   
2. **加权聚合**：   
   $$
    Z_t = \begin{bmatrix} [1, 0.5] \circ \tanh(1) \\ [0.3, 2] \circ \tanh(0.3) \end{bmatrix} = \begin{bmatrix} 0.76 & 0.38 \\ 0.09 & 0.58 \end{bmatrix} 
   $$
   （假设 $\tanh(1) \approx 0.76$, $\tanh(0.3) \approx 0.29$）
   
3. **输出**：$Z_t$ 是 $2 \times 2$ 矩阵，可以直接喂给GRU。



##### **步骤 2：GRU 更新权重矩阵**

$$
W_t^{(l)} = \text{GRU}(Z_t^T, W_{t-1}^{(l)})
$$

标准GRU的输入、隐藏、输出都是向量，但这里都是矩阵！

当前时间步的输入：$Z_t^T$

上一时间步的隐藏状态：$W_{t-1}^{(l)}$

更新隐藏状态： $W_t^{(l)}$

| **标准GRU**              | **论文中的矩阵GRU** | **作用**                                                     |
| ------------------------ | ------------------- | ------------------------------------------------------------ |
| $W_{xz}$ (输入→更新门)   | $W_Z$               | 将当前输入 $Z_t^T$ 映射到更新门。                            |
| $W_{hz}$ (隐藏→更新门)   | $U_Z$               | 将上一隐藏状态 $W_{t-1}^{(l)}$ 映射到更新门。                |
| $b_z$ (更新门偏置)       | $B_Z$               | 更新门的偏置项。                                             |
| $W_{xh}$ (输入→候选状态) | $W_H$               | 将当前输入 $Z_t^T$ 映射到候选状态。                          |
| $W_{hh}$ (隐藏→候选状态) | $U_H$               | 将调制后的隐藏状态 $(R_t \circ W_{t-1}^{(l)})$ 映射到候选状态。 |
| $b_h$ (候选状态偏置)     | $B_H$               | 候选状态的偏置项。                                           |

**GRU 的矩阵形式计算**：  

1. **重置门** $R_t$：控制历史信息的遗忘程度  
   $$
   R_t = \sigma(Z_t^T W_Z + W_{t-1}^{(l)} U_Z + B_Z)
   $$

2. **更新门** $Z_t$：控制新旧状态混合比例  
   $$
   U_t = \sigma(Z_t^T W_U + W_{t-1}^{(l)} U_U + B_U)
   $$

3. **候选状态** $\widetilde{W}_t$：  
   $$
   \widetilde{W}_t = \tanh(Z_t^T W_H + (R_t \circ W_{t-1}^{(l)}) U_H + B_H)
   $$

4. **最终权重更新**：  
   $$
   W_t^{(l)} = (1 - U_t) \circ W_{t-1}^{(l)} + U_t \circ \widetilde{W}_t
   $$

   - 输出 $W_t^{(l)} \in \mathbb{R}^{d \times d'}$。



##### **步骤 3：GCN 生成下一层嵌入**

使用更新的 $W_t^{(l)}$ 执行标准 GCN 操作：  
$$
H_t^{(l+1)} = \sigma\left(\widehat{A}_t H_t^{(l)} W_t^{(l)}\right)
$$

- $\widehat{A}_t$ 为归一化邻接矩阵（含自环）。

---

#### **5. 关键设计细节**

1. **权重共享**：  
   - 所有时间步共享同一 GRU 的参数（$W_*, U_*, B_*$），确保模型尺寸不随时间增长。  
2. **层独立性**：  
   - 每一层 GCN 的权重矩阵独立演化（不同层有各自的 GRU）。
3. **特征与结构的协同**：  
   - 节点嵌入 $H_t^{(l)}$ 既包含特征信息，也隐含历史结构信息（通过多层 GCN 传播），因此 GRU 能间接感知结构变化。

#### 6. 所需提前训练的权重

| **参数类型**     | **符号**        | **维度**                    | **作用**                        |
| ---------------- | --------------- | --------------------------- | ------------------------------- |
| GCN 初始权重     | $W_0^{(l)}$     | $\mathbb{R}^{d \times d'}$  | 初始时刻各层 GCN 的初始参数     |
| GRU 输入变换矩阵 | $W_Z, W_R, W_H$ | $\mathbb{R}^{d \times d'}$  | 将输入 $Z_t^T$ 映射到门控       |
| GRU 隐藏变换矩阵 | $U_Z, U_R, U_H$ | $\mathbb{R}^{d' \times d'}$ | 将 $W_{t-1}^{(l)}$ 映射到门控   |
| GRU 偏置项       | $B_Z, B_R, B_H$ | $\mathbb{R}^{d'}$           | 门控和候选状态的偏置            |
| Summarize 参数   | $p$             | $\mathbb{R}^d$              | 对特征进行打分，不同层$p$不一样 |
| 任务相关参数     | 例如 MLP 权重   | 任务相关                    | 链接预测、节点分类等输出层      |



### **EvolveGCN-O**

#### **1. 核心思想**

EvolveGCN-O 通过 **LSTM** 直接演化 GCN 的权重矩阵 $W_t^{(l)}$，将权重矩阵视为 **LSTM的输出**（下一时间步的输入），**不依赖节点嵌入**。  
**关键特点**：  

- **结构驱动**：仅通过历史权重 $W_{t-1}^{(l)}$ 预测当前权重，完全基于图结构的动态变化。  
- **轻量化**：无需处理节点嵌入，计算效率更高。  

---

#### **2. 动态更新流程（第$l$层）**

**输入**：  

1. 上一时间步权重 $W_{t-1}^{(l)} \in \mathbb{R}^{d \times d'}$  
2. 邻接矩阵 $A_t \in \mathbb{R}^{n \times n}$（仅用于GCN计算）  

**输出**：  

1. 更新后权重 $W_t^{(l)} \in \mathbb{R}^{d \times d'}$  
2. 下一层节点嵌入 $H_t^{(l+1)} \in \mathbb{R}^{n \times d'}$  

#### 3.具体步骤分解

##### **步骤1：LSTM更新权重矩阵**

**矩阵版LSTM计算**：  

1. 遗忘门：  
   $F_t = \sigma(W_F W_{t-1}^{(l)} + U_F C_{t-1} + B_F)$  
2. 输入门：  
   $I_t = \sigma(W_I W_{t-1}^{(l)} + U_I C_{t-1} + B_I)$  
3. 候选状态：  
   $\widetilde{C}_t = \tanh(W_C W_{t-1}^{(l)} + U_C C_{t-1} + B_C)$  
4. 细胞状态更新：  
   $C_t = F_t \circ C_{t-1} + I_t \circ \widetilde{C}_t$  
5. 输出门：  
   $O_t = \sigma(W_O W_{t-1}^{(l)} + U_O C_{t-1} + B_O)$  
6. 最终权重输出：  
   $W_t^{(l)} = O_t \circ \tanh(C_t)$  

##### **步骤2：GCN生成下一层嵌入**  

$H_t^{(l+1)} = \sigma(\widehat{A}_t H_t^{(l)} W_t^{(l)})$  

#### **4. 与EvolveGCN-H对比**

| **特性**       | **EvolveGCN-H**            | **EvolveGCN-O**              |
| -------------- | -------------------------- | ---------------------------- |
| **RNN类型**    | GRU                        | LSTM                         |
| **演化依据**   | 节点嵌入+历史权重          | 仅历史权重                   |
| **计算复杂度** | 高（需Summarize）          | 低                           |
| **适用场景**   | 特征动态性强（如社交网络） | 结构变化主导（如路由器拓扑） |



## TGAT

### Bochner定理

Bochner定理为TGAT的**连续时间编码**提供了理论基础，使其能够将任意时间差映射为可学习的向量表示，从而在动态图中有效捕捉时序依赖。这一方法超越了传统离散编码的局限性，是TGAT的核心创新之一。  

#### 时间编码的构造  

**（1）Bochner 定理的数学形式**

根据Bochner定理，任意正定时间核函数 $ f(\Delta t) $ 可表示为：  
$$
f(\Delta t) = \mathbb{E}_{\omega \sim \mu} \left[ e^{i \omega \Delta t} \right],
$$
其中 $e^{i \omega \Delta t} = \cos(\omega \Delta t) + i \sin(\omega \Delta t)$ 是复指数函数。 

**（2）蒙特卡洛近似 & 实值化**

由于直接计算期望复杂，TGAT 用蒙特卡洛采样近似：  

1. 从分布 $\mu$ 中采样 $d$ 个频率 $\omega_1, \omega_2, \ldots, \omega_k$。  

2. 用这些频率构造实值编码（取复指数的实部和虚部，即 $\cos$ 和 $\sin$）：  
   $$
   \Phi_d(\Delta t) = \frac{1}{\sqrt d}\bigl[\cos(\omega_1 \Delta t),\sin(\omega_1 \Delta t),\dots,\cos(\omega_d \Delta t),\sin(\omega_d \Delta t)\bigr]
   $$
   这样就把时间差转成了一个长度为 $2d$ 的实值向量。 



#### 例子

取 $d=1$（此时时间编码向量就是二维的），有  
$$
\Phi_1(\Delta t)\;=\;\frac{1}{\sqrt1}\bigl[\cos(\omega_1\Delta t),\;\sin(\omega_1\Delta t)\bigr]
=\bigl[\cos(\omega_1\Delta t),\;\sin(\omega_1\Delta t)\bigr].
$$

例如，若我们令 $\omega_1=1$ 且 $\Delta t = \pi/3$，那么  
$$
\Phi_1\bigl(\pi/3\bigr)
=\bigl[\cos(\pi/3),\;\sin(\pi/3)\bigr]
=\bigl[0.5,\;0.866\!\dots\bigr].
$$

所以在这个例子里，二维时间编码就是 $\bigl[0.5,\;0.866]$。



#### **为什么这样设计？**

- 普通的图神经网络即使有时间戳，也只能把它当作一个离散特征，很难推广到模型没见过的时刻。TGAT通过把相对时间差 $\Delta t$ 映射成一组连续、周期性的函数值 $(\cos(\omega_1 \Delta t),\sin(\omega_1 \Delta t))$,让模型天然具备处理任意实数时间差的能力。
- 用一堆正余弦函数来编码时间，使得时间特征是平滑连续的
- 节点对邻居信息的关注度不仅由节点特征决定，也由时间编码决定。模型可以自动学出“距离现在越近的交互越重要”“一周前的活动强度要比一个月前的活动强度高”之类的规律。
- **可学习性**：频率参数`{ωᵢ}`可以通过训练优化（例如让模型自动学习“短期交互”和“长期交互”的不同时间尺度）。



### 需要维护的数据：

1. **全量事件日志（事件流）**  
   整个动态图被表示成一条“事件流”──每一条事件是一个三元组  
   $$
   (u, v, t)
   $$
   表示节点 $u$ 和节点 $v$ 在时刻 $t$ 上发生了一次交互。训练／推断时，TGAT 会遍历这条有时间戳的边列表，按时间顺序对每个目标节点做消息聚合。

2. **每个节点的历史邻居列表**  
   为了快速地找到“截止当前时刻 $t$，某节点 $v$ 最近接触过哪些节点”，TGAT 通常会为每个节点维护一个按时间排序的邻居列表：  
   $$
     \mathit{Nbrs}(v) \;=\; [(u_1,t_1),\,(u_2,t_2),\,\dots]
   $$
   其中每个 $(u_i, t_i)$ 表示节点 $u_i$ 在时间 $t_i$ 与 $v$ 交互过。这样，给定当前时间 $t$，就可以高效地检索出所有满足 $t_i < t$ 的历史交互。

3. **每层的节点隐藏状态**  
   TGAT 是一个多层（multi-layer）注意力网络，在第 $l$ 层它会产生每个节点在各个时间点的隐藏表示  
   $$
     \tilde h_v^{(l)}(t)\,.
   $$
   为了在更高层次继续聚合，这些中间表示需要被缓存下来，至少要保存上一次（前一层）计算出的向量，才能和后续的时间编码一起拼接、送入下一层注意力。

4. **时间编码的频率参数**  
   TGAT 中的 $\{\omega_k\}_{k=1}^d$（映射 $\Delta t\mapsto [\cos(\omega_k\Delta t),\sin(\omega_k\Delta t)]$ 用的频率向量）是模型的可学习参数，也需要存储。



### 工作原理

#### 1.检索时间邻居

从事件流中取出所有在 $t$ 之前与 $v_0$ 有过交互的节点集合以及交互的时间 $t_i$。
$$
\mathcal{N}(v_0; t) = \{ v_i \mid \exists (v_0, v_i, t_i) \in \mathcal{E}, t_i < t \}
$$
实际实现中，TGAT通过以下两种策略避免邻居集合无限膨胀：

（1）**时间窗口截断**

- 仅保留目标时间 $t$ 的最近 $\Delta T$ 时间内的交互节点（例如过去7天的邻居）。

- **数学表达**：  
  $$
  \mathcal{N}(v_0; t) = \{ v_i \mid (v_0, v_i, t_i) \in \mathcal{E}, t - \Delta T \leq t_i < t \}
  $$

（2）**邻居采样（Neighborhood Sampling）**

- 即使在一个时间窗口内，如果邻居数量过多（例如社交网络中的活跃用户），TGAT会随机采样固定数量的邻居（如最多20个）。



#### 2.准备输入特征＋时间编码

在 TGAT 模型中，每一层都需要计算隐藏表示：

在第 $l$ 层里，既要计算目标节点 $v_0$ 在当前时刻 $t$ 的隐藏表示 $\tilde{h}_0^{(l-1)}(t)$，也要计算它的每个邻居 $v_i$ 在各自交互时刻 $t_i$ 的隐藏表示 $\tilde{h}_i^{(l-1)}(t_i)$。

- 若 $l=1$，则将原始静态特征 $x_i$ 作为第 0 层隐藏表示 $\tilde h_i^{(0)}(t_i)$；  
- 若 $l>1$，则使用第 $(l-1)$ 层计算出的隐藏表示 $\tilde h_i^{(l-1)}(t_i)$。  
  对每个邻居 $v_i$ 计算相对时间差 $\Delta t_i = t - t_i$，再通过  

$$
  \Phi_d(\Delta t_i) = \tfrac1{\sqrt d}\bigl[\cos(\omega_1\Delta t_i),\sin(\omega_1\Delta t_i),\dots\bigr]
$$

得到长度为 $2d$ 的时间编码向量。对目标节点自身，使用 $\Delta t=0$ 的时间编码。



#### 3.拼接构建"实体—时间"矩阵

$$
Z(t) =
  \begin{bmatrix}
    \tilde h_0^{(l-1)}(t)\,\|\,\Phi_d(0)\\
    \tilde h_1^{(l-1)}(t_1)\,\|\,\Phi_d(\Delta t_1)\\
    \;\;\vdots\\
    \tilde h_N^{(l-1)}(t_N)\,\|\,\Phi_d(\Delta t_N)
  \end{bmatrix}
$$

其中 $\Delta t_i=t-t_i$ ，这里 $v_0$ 一共有 $N$ 个节点。可能存在同一时间有多个交互的节点。



#### 4. 线性映射到 Query/Key/Value

分别用三组可学习的线性变换把 $Z(t)$ 投影出  
$$
  Q = Z(t)W^Q,\quad
  K = Z(t)W^K,\quad
  V = Z(t)W^V
$$
其中 $Q$ 取第一行（目标节点），$K,V$ 取其余行。



#### 5.计算注意力权重

对每个邻居 $i$ 计算  
$$
  \alpha_i \;=\;\frac{\exp\bigl(Q^\top K_i\bigr)}{\sum_j\exp\bigl(Q^\top K_j\bigr)}\,,
$$
这样就能在同一时刻、同一节点间对「谁更重要」自动打分。



#### 6.加权求和生成聚合向量

$$
h^{(l)}(t)\;=\;\sum_{i\in N(v_0;t)}\alpha_i\,V_i\quad\in\mathbb{R}^{d_h}.
$$



#### 7.与目标节点静态特征融合并通过 FFN

把聚合向量 $h^{(l)}(t)$ 和目标节点的原始特征 $x_0$ 拼接，送入两层前馈网络：  
$$
\tilde h_0^{(l)}(t)
  = \mathrm{FFN}\bigl(h^{(l)}(t)\,\|\,x_0\bigr)
  = \mathrm{ReLU}\Bigl(\bigl[h^{(l)}(t)\parallel x_0\bigr] W_0^{(l)} + b_0^{(l)}\Bigr) W_1^{(l)} + b_1^{(l)}
$$
这样就得到了第 $l$ 层节点 $v_0$ 在时刻 $t$ 的最终输出表示。

FFN 并不是只在最后一层使用，而是在**每一层**注意力聚合后都要执行，以产生该层的节点时刻表示。



#### 8.**多头与多层堆叠**  

- 如果使用多头注意力，则在步骤 4–6 中并行做 $k$ 组不同投影，得出 $\{h^{(l,i)}(t)\}_{i=1}^k$，再将它们拼接后送入 FFN；  
- 堆叠 $L$ 层上述流程，就能把多跳（$L$ 跳）邻居信息聚合进来。



总结：每个节点，动态融合节点自身及其邻居在不同时间点的嵌入，其中这些嵌入都显式编码了时间信息。

不同层之间的嵌入维度可以不同，但同一层内所有时间步的嵌入维度必须保持一致。



#### **举例**

假设目标节点 $v_0$ 在时间 $t=10$ 需要聚合历史邻居，其中：

 $t=10$时$v_0$的特征：$\tilde{h}_0(t=10)=[0.1, 0.2, 0.3, 0.4, 0.5]$

- 在时间 $t_1=8$，$v_0$ 与邻居 $\{v_{1}, v_{2}\}$ 交互。

  - $v_1$ 的特征：$\tilde{h}_1(t=8) = [0.6, 0.7, 0.8, 0.9, 1.0]$

  - $v_2$ 的特征：$\tilde{h}_2(t=8) = [0.2, 0.3, 0.4, 0.5, 0.6]$

- 在时间 $t_2=5$，$v_0$ 与邻居 $\{v_{3}\}$ 交互。

  - $v_3$ 的特征：$\tilde{h}_3(t=5) = [1.1, 1.2, 1.3, 1.4, 1.5]$

**时间编码**（$d_T=2$, $\omega_1=1$）：

- $\Phi_{d_T}(10-8=2) = [\cos(2), \sin(2)] \approx [-0.42, 0.91]$
- $\Phi_{d_T}(10-5=5) = [\cos(5), \sin(5)] \approx [0.28, -0.96]$
- $\Phi_{d_T}(0) = [1, 0]$

**将每个邻居的特征与对应时间编码拼接：**
$$
Z(10) = \begin{bmatrix}
\tilde{h}_0(10) \| \Phi_{d_T}(0) \\
\tilde{h}_1(8) \| \Phi_{d_T}(2) \\
\tilde{h}_2(8) \| \Phi_{d_T}(2) \\
\tilde{h}_3(5) \| \Phi_{d_T}(5)
\end{bmatrix} = \begin{bmatrix}
0.1, 0.2, 0.3, 0.4, 0.5, 1, 0 \\
0.6, 0.7, 0.8, 0.9, 1.0, -0.42, 0.91 \\
0.2, 0.3, 0.4, 0.5, 0.6, -0.42, 0.91 \\
1.1, 1.2, 1.3, 1.4, 1.5, 0.28, -0.96
\end{bmatrix}_{4 \times 7}
$$

**注意力权重计算:**

**1.投影矩阵参数**（简化示例，设 $d_h = 3$,真实情况由训-练得来）：
$$
W_Q = W_K = \begin{bmatrix}
0.1 & 0.2 & 0.3 \\
0.4 & 0.5 & 0.6 \\
0.7 & 0.8 & 0.9 \\
1.0 & 1.1 & 1.2 \\
1.3 & 1.4 & 1.5 \\
0.2 & 0.3 & 0.4 \\
0.5 & 0.6 & 0.7
\end{bmatrix}_{7 \times 3}, \quad
W_V = \begin{bmatrix}
0.3 & 0.4 & 0.5 \\
0.6 & 0.7 & 0.8 \\
0.9 & 1.0 & 1.1 \\
1.2 & 1.3 & 1.4 \\
1.5 & 1.6 & 1.7 \\
0.1 & 0.2 & 0.3 \\
0.4 & 0.5 & 0.6
\end{bmatrix}_{7 \times 3}
$$
**2.计算 Query/Key/Value**：

- **Query**（目标节点 $v_0$）：

$$
q(10) = [Z(10)]_0 W_Q = [0.1, 0.2, 0.3, 0.4, 0.5, 1, 0] \cdot W_Q = [2.38, 2.76, 3.14]
$$

- **Keys**（邻居节点）：
  $$
  K(10) = [Z(10)]_{1:3} W_K = \begin{bmatrix}
  0.6 & 0.7 & 0.8 & 0.9 & 1.0 & -0.42 & 0.91 \\
  0.2 & 0.3 & 0.4 & 0.5 & 0.6 & -0.42 & 0.91 \\
  1.1 & 1.2 & 1.3 & 1.4 & 1.5 & 0.28 & -0.96
  \end{bmatrix} \cdot W_K = \begin{bmatrix}
  3.22 & 3.68 & 4.14 \\
  1.82 & 2.18 & 2.54 \\
  4.18 & 4.64 & 5.10
  \end{bmatrix}
  $$

- **Values**（邻居节点）：
  $$
  V(10) = [Z(10)]_{1:3} W_V = \begin{bmatrix}
  3.52 & 3.92 & 4.32 \\
  2.12 & 2.42 & 2.72 \\
  4.48 & 4.88 & 5.28
  \end{bmatrix}
  $$

**3.计算注意力权重**

- 计算未归一化分数（缩放因子 $\sqrt{d_h} = \sqrt{3} \approx 1.732$）：

$$
\text{scores} = \frac{q(10) K(10)^\top}{\sqrt{3}} = \frac{[2.38, 2.76, 3.14] \cdot \begin{bmatrix}3.22 & 1.82 & 4.18 \\ 3.68 & 2.18 & 4.64 \\ 4.14 & 2.54 & 5.10\end{bmatrix}}{1.732}\approx [18.46, 10.56, 21.40]
$$

- Softmax 归一化：
  $$
  \alpha = \text{softmax}([18.46, 10.56, 21.40]) = [2.4 \times 10^{-2}, 1.6 \times 10^{-5}, 0.976]
  $$



**4.加权求和生成聚合向量**
$$
h(10) = \sum_{i=1}^3 \alpha_i V_i = 0.024 \cdot \begin{bmatrix}3.52 \\ 3.92 \\ 4.32\end{bmatrix} + 1.6 \times 10^{-5} \cdot \begin{bmatrix}2.12 \\ 2.42 \\ 2.72\end{bmatrix} + 0.976 \cdot \begin{bmatrix}4.48 \\ 4.88 \\ 5.28\end{bmatrix}\approx [4.48, 4.88, 5.28]
$$
**5.节点嵌入更新**

**1.拼接操作**
$$
z=[h(10) \| x_0] = [4.48, 4.88, 5.28, 0.1, 0.2, 0.3, 0.4, 0.5]
$$
**2. FFN参数设置**

FFN 包含两层：
$$
\tilde{h}_0^{(l)}(10)=\text{FFN}(z) = \text{ReLU}(z W_0 + b_0) W_1 + b_1
$$



### 需提前训练的参数

| 参数名称         | 符号                          | 维度                    | 来源层        | 作用                                                      |
| ---------------- | ----------------------------- | ----------------------- | ------------- | --------------------------------------------------------- |
| 时间编码频率参数 | $\omega_1,\dots,\omega_{d_T}$ | $d_T\times1$            | 全模型        | 控制功能性时间编码基频率，用于生成 $\Phi_{d_T}(\Delta t)$ |
| Query 投影矩阵   | $W_Q^{(l)}$                   | $(d_h + d_T)\times d_h$ | 第 $l$ 层     | 将拼接后的"隐藏表示＋时间编码"映射为 Query 向量           |
| Key 投影矩阵     | $W_K^{(l)}$                   | $(d_h + d_T)\times d_h$ | 第 $l$ 层     | 将拼接后的"隐藏表示＋时间编码"映射为 Key 向量             |
| Value 投影矩阵   | $W_V^{(l)}$                   | $(d_h + d_T)\times d_h$ | 第 $l$ 层     | 将拼接后的"隐藏表示＋时间编码"映射为 Value 向量           |
| FFN 第一层权重   | $W_0^{(l)}$                   | $(d_h + d_0)\times d_f$ | 第 $l$ 层 FFN | 拼接向量 $[\,h^{(l)}(t)\,\|\,x_0\,]$ 的第一层线性变换     |
| FFN 第一层偏置   | $b_0^{(l)}$                   | $d_f$                   | 第 $l$ 层 FFN | 第一层线性偏置                                            |
| FFN 第二层权重   | $W_1^{(l)}$                   | $d_f\times d$           | 第 $l$ 层 FFN | 第二层线性变换，生成本层最终节点表示                      |
| FFN 第二层偏置   | $b_1^{(l)}$                   | $d$                     | 第 $l$ 层 FFN | 第二层线性偏置                                            |





每个节点运行的模型是一样的QKV这些参数都是一样的。

运行过程中这些训练好的参数不会变化，模型的动态性体现在：

- 维护**全局事件流**；当新的边 $(u, v, t)$ 加入或旧的边变得不再被采样时，下一次你对某个节点做推理时，检索到的邻居集合就不一样；
- 时间编码会根据新的 $\Delta t$ 动态计算；
- 注意力权重 $\alpha_i$ 会重新分配，FFN 也会基于新的聚合结果给出新的输出。



节点是否需要交互（是否需要全局信息） 

- 如果节点仅关注自己的特征更新以及任务，仅需维护：

  从事件流中取出所有在 $t$ 之前与 $v_0$ 有过交互的节点集合以及交互的时间 $t_i$。
  $$
  \mathcal{N}(v_0; t) = \{ v_i \mid \exists (v_0, v_i, t_i) \in \mathcal{E}, t_i < t \}
  $$

- 如果节点还关注其他节点的特征更新及任务，需要知道**全局事件流** (若干时刻邻接矩阵转化而来)

  