讲解基于图神经网络的情绪识别深度学习模型DGCNN(附基础原理讲解和代码讲解)

T. Song, W. Zheng, P. Song and Z. Cui, “EEG Emotion Recognition Using Dynamical Graph Convolutional Neural Networks,” in IEEE Transactions on Affective Computing, vol. 11, no. 3, pp. 532-541, 1 July-Sept. 2020, doi: 10.1109/TAFFC.2018.2817622.

Dynamical graph convolutional neural networks (DGCNN) 是一种基于图神经网络的EEG情绪识别模型,引用量截至2024年7月达到了1000+,模型较为简单,所以适合以此了解图神经网络。

DGCNN的模型结构

DGCNN的代码参考以下链接:

什么是Chebynet?

频谱图理论 (Spectral Graph Theory) 是用线性代数概念(如特征向量和特征值理论)研究图的性质。
(想要简单了解频谱图理论可以参考这个视频。)

DGCNN的基础是Chebynet。Chebynet是一种频谱图神经网络(Spectral GNNs) 在频谱域中操作,具体指的是在图的拉普拉斯矩阵上应用卷积算子。

图的拉普拉斯矩阵

A A A 是邻接矩阵, D D D 是度矩阵。 L L L 是拉普拉斯矩阵,假定它是对称的:
L = D − A L=D-A L=DA
L L L 通过 SVD(奇异值分解)获得 U U U 中的特征向量和特征值。
L = U Λ U T L=UΛU^T L=UΛUT
传统频谱滤波器:图上的频谱卷积可以定义为节点信号 x ∈ R N x ∈ R^N xRN 与在傅里叶域中的卷积滤波器 g θ = diag ⁡ ( θ ) g_θ = \operatorname{diag}(θ) gθ=diag(θ) 的乘积,其中 θ \theta θ 是滤波器的编号。
g θ ⋆ x = U g θ U T x g_\theta \star \mathbf{x}=U g_\theta U^T \mathbf{x} gθx=UgθUTx
U T x U^T\mathbf{x} UTx 是输入信号 x x x 的图傅里叶变换。

图拉普拉斯矩阵的多项式滤波器

图拉普拉斯矩阵的多项式滤波器是一种用于在图结构数据上执行卷积操作的技术。
g θ ​ ( L ) = ∑ k = 0 K k θ ​ L k g_θ​(L)=\sum_{k=0}^K k_\theta​L^k gθ(L)=k=0KkθLk
其中, g θ ( L ) g_\theta(L) gθ(L) 是多项式滤波器, θ k \theta_k θk 是需要学习的参数, L k L^k Lk 是图拉普拉斯矩阵 L L L k k k 次幂。

  • 高阶的 L k L^k Lk 表示节点 k k k 步邻域的信息,因此多项式滤波器可以捕捉节点的局部结构。
  • 多项式滤波器可以通过调节多项式的阶数 K K K 来控制滤波器的复杂度和表达能力。

Chebyshev 多项式滤波器

g θ ⋆ x = U g θ U T x g_\theta \star \mathbf{x}=U g_\theta U^T \mathbf{x} gθx=UgθUTx
然而如上式所示,直接在频域进行图卷积需要计算图拉普拉斯矩阵的特征分解,SVD分解的计算量较大。

所以为了提高计算效率,Chebyshev 多项式滤波被引入来近似图拉普拉斯矩阵的多项式滤波器 使用 Chebyshev 多项式。我们将滤波器定义为 Chebyshev 多项式的线性组合:
g θ ​ ( L ) ≈ ∑ k = 0 K ​ k ​ θ T k ​ ( L ~ ) g_θ​(L)≈\sum_{k=0}^K​k​_\theta T_k​(\tilde L) gθ(L)k=0KkθTk(L~)
其中, L ~ \tilde{L} L~ 是归一化后的图拉普拉斯矩阵, θ k \theta_k θk 是需要学习的参数, T k ( L ~ ) T_k(\tilde{L}) Tk(L~) 是 Chebyshev 多项式。
最终卷积操作为:
g θ ( L ~ ) ⋆ x ≈ ∑ k = 0 K θ k T k ( L ~ ) x g_θ(\tilde L) \star \mathbf{x} \approx \sum_{k=0}^K \theta_k T_k(\tilde L) \mathbf{x} gθ(L~)xk=0KθkTk(L~)x

代码:Chebyshev多项式邻接矩阵
def generate_cheby_adj(A: torch.Tensor, num_layers: int) -> torch.Tensor:  
    support = []  
    for i in range(num_layers):  
        if i == 0:  
		  support.append(torch.eye(A.shape[1]).to(A.device))  
        elif i == 1:  
            support.append(A)  
        else:  
            temp = torch.matmul(support[-1], A)  
            support.append(temp)  
    return support

generate_cheby_adj() 是一个生成 Chebyshev 多项式邻接矩阵的方法

  • i == 0 时,添加单位矩阵 I I I
  • i == 1 时,添加邻接矩阵 A A A
  • 对于 i > 1 的情况,利用前一个支持矩阵与邻接矩阵 A A A 的矩阵乘法生成新的 Chebyshev 多项式邻接矩阵。

Chebyshev 多项式滤波器 T k ( A ) T_k(A) Tk(A) 是通过递归方式生成的,其中 T 0 ( A ) = I T_0(A) = I T0(A)=I(单位矩阵), T 1 ( A ) = A T_1(A) = A T1(A)=A,接下来的多项式可以通过以下递归公式生成:
T k ( A ) = 2 A T k − 1 ( A ) − T k − 2 ( A ) Tk(A)=2AT_{k−1}(A)−T_{k−2}(A) Tk(A)=2ATk1(A)Tk2(A)
注:代码的切比雪夫多项式的计算公式代码和原文不一致,参考 https://github.com/xueyunlong12589/DGCNN/issues/4

“动态”图卷积

D代表的是Dynamic,指图的邻接矩阵本身是模型的参数 A A A. 这样可以动态学习不同脑电图(EEG)通道之间的内在关系

相当于在邻接矩阵上计算更高纬度的。数学上通常假设邻接矩阵是对称的,虽然代码里并不假设邻接矩阵是对称的。

使用每个 n n n阶以内的Cheby邻接矩阵可以得到聚合特征,Chebynet把这些聚合特征加在一起最后通过RELU函数

Chebynet的输出变形为1维特征以后再过由两个MLP组成的解码器进行预测。

模型的调用以及输入

在 DGCNN 模型中,EEG 通道在五个频带中表示为一个节点。

  • 使用 torcheeg.transforms.BandDifferentialEntropy 进行频带微分熵计算。
  • 返回类型:np.ndarray,形状为 [电极数量, 子频带数量] 假设有一个包含 32 个电极的 EEG 数据集,并将其划分为 5 个频带。微分熵计算的返回数组将是一个 32 x 5 的矩阵,其中每一行代表一个电极,每一列代表一个频带上的微分熵值。
from torcheeg.models import DGCNN
from torcheeg.datasets import SEEDDataset
from torcheeg import transforms

dataset = SEEDDataset(root_path='./Preprocessed_EEG',
                      offline_transform=transforms.BandDifferentialEntropy(band_dict={
                          "delta": [1, 4],
                          "theta": [4, 8],
                          "alpha": [8, 14],
                          "beta": [14, 31],
                          "gamma": [31, 49]
                      }),
                      online_transform=transforms.Compose([
                          transforms.ToTensor()
                      ]),
                      label_transform=transforms.Compose([
                          transforms.Select('emotion'),
                          transforms.Lambda(lambda x: x + 1)
                      ]))

model = DGCNN(in_channels=5, num_electrodes=62, hid_channels=32, num_layers=2, num_classes=2)

x, y = next(iter(DataLoader(dataset, batch_size=64)))
model(x)

模型结构的细节

1x1卷积层

代码里似乎对切比雪夫多项式的每一个部分都新建了一个1*1卷积。这有助于突出重要特征,并抑制不太有用的特征。

# 图卷积操作的前向步骤
def forward(self, x: torch.Tensor, adj: torch.Tensor) -> torch.Tensor:  
    out = torch.matmul(adj, x)  
    out = torch.matmul(out, self.weight)  
    if self.bias is not None:  
        return out + self.bias  
    else:  
        return out

正则化

首先,特征经过BatchNormalization,当张量有三个维度时,维度代表 ( N , C , L ) (N, C, L) (N,C,L)
self.BN1(x.transpose(1, 2)).transpose(1, 2)

BatchNorm1d和BatchNorm2d的区别

  • BatchNorm1d 设计用于处理 2D 或 3D 输入张量。对于给定的 3D 张量,BatchNorm1d 将在维度 (batch_size, time_length) 上计算均值和方差,对每个通道单独进行归一化。换句话说,它将最后一个维度视为时间维度(如时间序列中的时间),并沿着这个维度计算统计量。
  • 另一方面,BatchNorm2d 设计用于处理 4D 输入张量,通常形状为 (batch_size, channel_num, height, width)。它将在维度 (batch_size, height, width) 上计算均值和方差,对每个通道单独进行归一化。

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-18 01:38:04       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-18 01:38:04       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-18 01:38:04       58 阅读
  4. Python语言-面向对象

    2024-07-18 01:38:04       69 阅读

热门阅读

  1. C语言经典例题-19

    2024-07-18 01:38:04       19 阅读
  2. nvm的安装教程

    2024-07-18 01:38:04       20 阅读
  3. 人工智能前沿讲座——融合知识的自然语言处理

    2024-07-18 01:38:04       20 阅读
  4. centos7单机安装docker和k8s

    2024-07-18 01:38:04       22 阅读
  5. 浔川AI五子棋v5.0预告——浔川总社部

    2024-07-18 01:38:04       19 阅读