别再只盯着原始EEG信号了!用Python+PyTorch Geometric实战CR-GCN,搞定脑电情感识别

张开发
2026/4/7 23:15:26 15 分钟阅读

分享文章

别再只盯着原始EEG信号了!用Python+PyTorch Geometric实战CR-GCN,搞定脑电情感识别
用Python实战CR-GCN从EEG信号到情感识别的完整指南在脑机接口和神经科学领域情感识别一直是个令人着迷的挑战。传统方法往往将EEG信号视为独立的时间序列却忽视了大脑各区域之间复杂的交互关系。这正是CR-GCNChannel-Relationships-Based Graph Convolutional Network的创新之处——它将图神经网络引入EEG分析同时考虑通道的物理拓扑结构和功能连接性。1. 环境准备与数据理解开始之前确保你的Python环境已安装以下关键库pip install torch torch-geometric numpy mne scipy scikit-learnEEG数据通常以.edf或.gdf格式存储包含多个电极通道的时间序列。以DEAP数据集为例每个样本包含32个电极的40秒记录采样率128Hz。我们需要理解几个核心概念通道拓扑结构描述电极在头皮上的物理位置关系功能连接反映不同脑区活动的统计相关性PSD特征功率谱密度表征不同频段的能量分布提示处理EEG数据时务必注意采样率和电极名称的标准化不同数据集可能使用不同的命名约定。2. 数据预处理流程2.1 基础预处理完整的EEG预处理通常包括以下步骤降采样至统一频率如128Hz带通滤波0.5-45Hz去除极端频率去除眼电、肌电等伪迹分段提取感兴趣的时间窗口import mne raw mne.io.read_raw_edf(sample.edf, preloadTrue) raw.filter(0.5, 45) # 带通滤波 raw.resample(128) # 降采样2.2 特征提取关键步骤CR-GCN的核心特征是基于频带的PSD计算频带频率范围(Hz)情感关联Theta4-8冥想状态Alpha8-13放松状态Beta13-30活跃思维Gamma30-45认知处理计算PSD的Python实现from scipy import signal def compute_psd(eeg_segment, fs128): freqs, psd signal.welch(eeg_segment, fsfs, nperseg256) bands { theta: (4, 8), alpha: (8, 13), beta: (13, 30), gamma: (30, 45) } band_features [] for band, (low, high) in bands.items(): mask (freqs low) (freqs high) band_features.append(np.mean(psd[:, mask], axis1)) return np.stack(band_features, axis-1)3. 构建图结构表示3.1 通道拓扑矩阵基于电极物理位置的邻接矩阵构建from sklearn.metrics.pairwise import euclidean_distances def build_topology_matrix(channel_positions): dist_matrix euclidean_distances(channel_positions) sigma np.mean(dist_matrix) # 自适应阈值 adj np.exp(-dist_matrix**2 / (2 * sigma**2)) np.fill_diagonal(adj, 0) # 移除自连接 return adj3.2 功能连接矩阵使用PLV相位锁定值衡量通道间功能连接from mne.connectivity import spectral_connectivity def compute_functional_connectivity(eeg_data, methodplv): con, freqs, times, n_epochs, n_tapers spectral_connectivity( [eeg_data], methodmethod, modemultitaper, sfreq128, fmin4, fmax45, faverageTrue) return np.squeeze(con)3.3 矩阵融合策略将两种矩阵加权融合def combine_matrices(topology, functional, alpha0.5): # 归一化处理 topology topology / np.max(topology) functional functional / np.max(functional) return alpha * topology (1 - alpha) * functional4. CR-GCN模型实现4.1 PyTorch Geometric模型架构import torch import torch.nn as nn import torch.nn.functional as F from torch_geometric.nn import GCNConv class CRGCN(nn.Module): def __init__(self, num_features, num_classes): super(CRGCN, self).__init__() self.conv1 GCNConv(num_features, 64) self.conv2 GCNConv(64, 32) self.fc nn.Linear(32, num_classes) def forward(self, x, edge_index, edge_weight): x F.relu(self.conv1(x, edge_index, edge_weight)) x F.dropout(x, trainingself.training) x self.conv2(x, edge_index, edge_weight) return F.log_softmax(self.fc(x), dim1)4.2 数据加载与训练from torch_geometric.data import Data def create_graph_data(features, adj_matrix): edge_index torch.tensor(np.where(adj_matrix 0), dtypetorch.long) edge_weight torch.tensor(adj_matrix[adj_matrix 0], dtypetorch.float) x torch.tensor(features, dtypetorch.float) return Data(xx, edge_indexedge_index, edge_attredge_weight) # 示例训练循环 model CRGCN(num_features4, num_classes2) optimizer torch.optim.Adam(model.parameters(), lr0.01) for epoch in range(100): model.train() optimizer.zero_grad() out model(data.x, data.edge_index, data.edge_attr) loss F.nll_loss(out, data.y) loss.backward() optimizer.step()5. 实战技巧与问题排查5.1 常见问题解决方案维度不匹配确保PSD特征矩阵形状为[通道数×频带数]梯度消失尝试在GCN层间添加残差连接过拟合增加Dropout比例或添加L2正则化5.2 性能优化技巧使用混合精度训练加速计算scaler torch.cuda.amp.GradScaler() with torch.cuda.amp.autocast(): out model(data.x, data.edge_index, data.edge_attr)批处理多个图数据预计算邻接矩阵减少训练时间5.3 评估指标选择指标公式适用场景准确率(TPTN)/(PN)类别平衡时F1分数2*(P*R)/(PR)类别不平衡AUC-ROC曲线下面积概率输出评估在情感识别任务中由于正负样本往往不平衡F1分数通常比准确率更有参考价值。

更多文章