28、清华大学SSVEP数据集实战:从EEG信号到深度学习模型的完整处理流程

张开发
2026/4/5 14:43:52 15 分钟阅读

分享文章

28、清华大学SSVEP数据集实战:从EEG信号到深度学习模型的完整处理流程
1. 清华大学SSVEP数据集初探第一次接触清华大学SSVEP数据集时我被它的完整性和规范性惊艳到了。这个数据集可以说是脑机接口(BCI)研究领域的标准答案特别适合用来学习EEG信号处理和深度学习建模。数据集包含了35名受试者在不同频率视觉刺激下的脑电信号记录采样率250Hz数据维度为[64,1500,40,6]分别对应电极数、时间点、目标刺激和试验次数。我下载数据时发现清华大学脑机接口研究组的网站设计得非常友好。数据以.mat格式存储每个受试者一个文件命名规则也很清晰S01.mat到S35.mat。配套的还有电极位置文件64通道.loc和频率相位信息文件Freq_phase.mat这些都为后续分析提供了完整支持。数据集的一个亮点是它区分了有经验组S01-S08和初学者组S09-S35的受试者。这在实际建模时特别有用你可以分别测试模型在不同经验水平受试者上的表现或者专门针对某一组进行优化。我在实际使用时发现有经验组的数据质量明显更好信号特征也更明显。2. 数据下载与环境准备要开始这个项目首先需要准备好Python环境。我推荐使用Anaconda创建一个专门的环境conda create -n bci python3.8 conda activate bci pip install numpy scipy matplotlib pandas scikit-learn tensorflow数据下载地址在清华大学脑机接口研究组官网。下载后你会得到几个关键文件S01.mat到S35.mat每个受试者的EEG数据64通道.loc电极位置信息Freq_phase.mat刺激频率和相位信息Sub_info.txt受试者基本信息我建议新建一个项目目录结构如下/bci_project /data /raw (存放原始.mat文件) /processed (存放处理后的数据) /notebooks (存放Jupyter笔记本) /src (存放Python脚本)加载数据时我习惯先用scipy.io加载.mat文件检查结构import scipy.io data scipy.io.loadmat(data/raw/S01.mat) print(data.keys()) # 查看数据结构3. 数据理解与预处理原始数据的维度是[64,1500,40,6]这个结构需要好好理解。64个电极通道1500个时间点6秒×250Hz40个不同频率的视觉刺激每个刺激重复6次。我常用的预处理流程包括数据检查查看是否有异常通道或时间段滤波通常用4-40Hz带通滤波去除噪声降采样如果原始采样率过高可以考虑降采样分段根据实验设计切分epoch这里有个实用技巧使用mne库可以方便地可视化EEG数据import mne info mne.create_info(ch_namesch_names, sfreq250, ch_typeseeg) raw mne.io.RawArray(data, info) raw.plot()对于SSVEP数据我特别关注8-15.8Hz这个频段因为这是刺激频率的范围。可以通过频谱分析来验证数据质量psd raw.compute_psd(fmin8, fmax16) psd.plot()4. 数据重塑与特征工程原始数据的[64,1500,40,6]维度需要转换为适合深度学习模型的格式。我的经验是分几步走合并最后两个维度40×6240个样本转置维度顺序(样本,通道,时间点)添加通道维度(样本,1,通道,时间点)对应的Python代码import numpy as np # 原始数据维度 (64,1500,40,6) data np.load(original_data.npy) # 重塑为 (64,1500,240) data data.reshape(64,1500,240) # 转置为 (240,64,1500) data np.transpose(data, (2,0,1)) # 添加通道维度 (240,1,64,1500) data np.expand_dims(data, axis1)标签处理也很关键。原始标签是1×40的数组每个值对应一个刺激频率。我们需要将其扩展为240个样本的标签并进行独热编码from sklearn.preprocessing import OneHotEncoder # 原始标签 (1,40) labels np.array([[...]]) # 扩展为240个样本 labels np.repeat(labels, 6, axis1).reshape(-1,1) # 独热编码 encoder OneHotEncoder() labels_onehot encoder.fit_transform(labels).toarray()5. 构建深度学习模型经过多次尝试我发现一个简单的CNN模型就能在SSVEP分类上取得不错的效果。模型结构可以这样设计from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense model Sequential([ Conv2D(32, (3,3), activationrelu, input_shape(1,64,1500)), MaxPooling2D((2,2)), Conv2D(64, (3,3), activationrelu), MaxPooling2D((2,2)), Flatten(), Dense(128, activationrelu), Dense(40, activationsoftmax) ]) model.compile(optimizeradam, losscategorical_crossentropy, metrics[accuracy])训练时我习惯使用早停和模型检查点from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint callbacks [ EarlyStopping(patience10), ModelCheckpoint(best_model.h5, save_best_onlyTrue) ] history model.fit(X_train, y_train, validation_data(X_val, y_val), epochs100, batch_size32, callbackscallbacks)6. 模型评估与优化评估SSVEP分类模型时我通常会看几个指标总体准确率每个频率的分类准确率混淆矩阵不同受试者间的表现差异绘制混淆矩阵的代码from sklearn.metrics import confusion_matrix import seaborn as sns y_pred model.predict(X_test) y_pred_classes np.argmax(y_pred, axis1) y_true np.argmax(y_test, axis1) cm confusion_matrix(y_true, y_pred_classes) sns.heatmap(cm, annotTrue, fmtd)模型优化方面我尝试过以下几种方法增加数据增强添加轻微的时间扭曲或噪声尝试不同网络结构EEGNet、DeepConvNet等专用架构调整超参数学习率、批大小、网络深度等使用迁移学习用预训练模型的特征提取部分7. 实际应用中的注意事项在实际项目中应用这个流程时我踩过几个坑值得分享数据标准化很重要不同受试者、不同session间的信号强度可能有差异建议对每个样本单独做z-score标准化。类别不平衡问题某些频率可能比其他频率更容易识别可以考虑类别权重或过采样。计算资源管理EEG数据维度大训练CNN可能很耗资源。我建议使用GPU加速尝试降低时间分辨率使用更小的批大小模型解释性可以可视化卷积核或使用Grad-CAM等方法理解模型关注哪些EEG特征。实时应用考虑如果要部署到实时BCI系统需要考虑模型的计算延迟和内存占用。

更多文章