基于MNE的EEGNet 神经网络的脑电信号分类实战(附完整源码)

ops/2024/12/22 21:58:42/

利用MNE中的EEG数据,进行EEGNet神经网络的脑电信号分类实现:

代码:

代码主要包括一下几个步骤:
1)从MNE中加载脑电信号,并进行相应的预处理操作,得到训练集、验证集以及测试集,每个集中都包括数据和标签;
2)基于tensorflow构建EEGNet网络模型;
3)编译模型,配置损失函数、优化器和评估指标等,并进行模型训练和预测;
4)绘制训练集和验证集的损失曲线以及训练集和验证集的准确度曲线。
代码如下:

import mne
import os
from pathlib import Path
import numpy as np
from keras.src.utils import np_utilsfrom mne import io
from mne.datasets import sample
import matplotlib.pyplot as plt
import pathlibfrom keras.models import Model
from keras.layers import Dense, Activation, Permute, Dropout
from keras.layers import Conv2D, MaxPooling2D, AveragePooling2D
from keras.layers import SeparableConv2D, DepthwiseConv2D
from keras.layers import BatchNormalization
from keras.layers import SpatialDropout2D
from keras.regularizers import l1_l2
from keras.layers import Input, Flatten
from keras.constraints import max_norm
from keras import backend as K
from keras.src.callbacks import ModelCheckpointfrom sklearn.pipeline import make_pipeline
from sklearn.linear_model import LogisticRegressiondef EEGNet(nb_classes, Chans=64, Samples=128,dropoutRate=0.5, kernelLength=64,F1=8, D=2, F2=16, norm_rate=0.25,dropout_type='Dropout'):"""EEGNet模型的实现。参数:- nb_classes: int, 输出类别的数量。- Chans: int, 通道数,默认为64。- Samples: int, 每个通道的样本数,默认为128。- dropoutRate: float, Dropout率,默认为0.5。- kernelLength: int, 卷积核的长度,默认为64。- F1: int, 第一个卷积层的滤波器数量,默认为8。- D: int, 深度乘法器,默认为2。- F2: int, 第二个卷积层的滤波器数量,默认为16。- norm_rate: float, 权重范数约束,默认为0.25。- dropout_type: str, Dropout类型,默认为'Dropout'。返回:- Model: Keras模型对象。"""# 根据dropout_type参数确定使用哪种Dropout方式if dropout_type == 'SpatialDropout2D':dropoutType = SpatialDropout2Delif dropout_type == 'Dropout':dropoutType = Dropoutelse:raise ValueError('dropout_type must be one of SpatialDropout2D ''or Dropout, passed as a string.')# 定义模型的输入层input1 = Input(shape=(Chans, Samples, 1))# 第一个卷积块block1 = Conv2D(F1, (1, kernelLength), padding='same',input_shape=(Chans, Samples, 1),use_bias=False)(input1)block1 = BatchNormalization()(block1)block1 = DepthwiseConv2D((Chans, 1), use_bias=False,depth_multiplier=D,depthwise_constraint=max_norm(1.))(block1)block1 = BatchNormalization()(block1)block1 = Activation('elu')(block1)block1 = AveragePooling2D((1, 4))(block1)block1 = dropoutType(dropoutRate)(block1)# 第二个卷积块block2 = SeparableConv2D(F2, (1, 16),use_bias=False, padding='same')(block1)block2 = BatchNormalization()(block2)block2 = Activation('elu')(block2)block2 = AveragePooling2D((1, 8))(block2)block2 = dropoutType(dropoutRate)(block2)# 将卷积块的输出展平以便输入到全连接层flatten = Flatten(name='flatten')(block2)# 定义全连接层dense = Dense(nb_classes, name='dense', kernel_constraint=max_norm(norm_rate))(flatten)softmax = Activation('softmax', name='softmax')(dense)# 创建并返回模型return Model(inputs=input1, outputs=softmax)def get_data4EEGNet(kernels, chans, samples):"""为EEGNet模型准备数据。该函数从指定的文件路径中读取原始EEG数据和事件数据,进行预处理,包括滤波、选择通道、分割数据集,并将数据集按给定的通道、核数和样本数进行重塑。参数:kernels - 数据集中的核数量。chans - 数据集中的通道数量。samples - 数据集中的样本数量。返回:X_train, X_validate, X_test, y_train, y_validate, y_test - 分别是训练、验证和测试数据集,以及相应的标签。"""# 设置图像数据格式,确保数据维度顺序正确K.set_image_data_format('channels_last')# 定义数据路径data_path = Path("C:\\Users\\72671\\mne_data\\MNE-sample-data")# 定义原始数据和事件数据的文件路径raw_fname = os.path.join(data_path, "MEG", "sample", "sample_audvis_filt-0-40_raw.fif")event_fname = os.path.join(data_path, "MEG", "sample", "sample_audvis_filt-0-40_raw-eve.fif")# 定义时间范围和事件IDtmin, tmax = -0., 1event_id = dict(aud_l=1, aud_r=2, vis_l=3, vis_r=4)# 读取并预处理原始数据raw = io.Raw(raw_fname, preload=True, verbose=False)raw.filter(2, None, method='iir')events = mne.read_events(event_fname)# 设置无效通道并选择所需通道类型raw.info['bads'] = ['MEG 2443']picks = mne.pick_types(raw.info, meg=False, eeg=True, stim=False, eog=False,exclude='bads')# 创建epochs数据集epochs = mne.Epochs(raw, events, event_id, tmin, tmax, proj=False, picks=picks, baseline=None,preload=True, verbose=False)labels = epochs.events[:, -1]# 获取数据并进行缩放X = epochs.get_data(copy=False) * 1e6y = labels# 分割数据集为训练、验证和测试集X_train = X[0:144, ]y_train = y[0:144]X_validate = X[144:216, ]y_validate = y[144:216]X_test = X[216:, ]y_test = y[216:]# 将训练、验证和测试数据集中的标签转换为one-hot编码# 减1是因为标签通常从1开始计数,而one-hot编码需要从0开始y_train = np_utils.to_categorical(y_train-1)y_validate = np_utils.to_categorical(y_validate-1)y_test = np_utils.to_categorical(y_test-1)# 重塑数据集以匹配EEGNet模型的输入要求X_train = X_train.reshape(X_train.shape[0], chans, samples, kernels)X_validate = X_validate.reshape(X_validate.shape[0], chans, samples, kernels)X_test = X_test.reshape(X_test.shape[0], chans, samples, kernels)# 返回准备好的数据集return X_train, X_validate, X_test, y_train, y_validate, y_test#########################################################################
# 定义模型参数
kernels, chans, samples = 1, 60, 151
# 获取预处理后的EEG数据集
X_train, X_validate, X_test, y_train, y_validate, y_test = get_data4EEGNet(kernels, chans, samples)# 初始化EEGNet模型
model = EEGNet(nb_classes=4, Chans=chans, Samples=samples, dropoutRate=0.5,kernelLength=32, F1=8, D=2, F2=16, dropout_type='Dropout')# 编译模型,配置损失函数、优化器和评估指标
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])# 设置模型检查点以保存最佳模型
checkpointer = ModelCheckpoint(filepath='./models/EEGNet_best_model.h5', verbose=1, save_best_only=True)
# 定义类别权重
class_weights = {0: 1, 1: 1, 2: 1, 3: 1}# 训练模型
fittedModel = model.fit(X_train, y_train, batch_size=32, epochs=500, verbose=2,validation_data=(X_validate, y_validate),callbacks=[checkpointer], class_weight=class_weights)# 加载最佳模型权重
model.load_weights('./models/EEGNet_best_model.h5')# 对测试集进行预测
probs = model.predict(X_test)
# 获取预测标签
preds = probs.argmax(axis=-1)
# 计算分类准确率
acc = np.mean(preds == y_test.argmax(axis=-1))# 输出分类准确率
print("Classification accuracy: %f " % (acc))# 获取训练历史
history = fittedModel.history# 绘制训练集和验证集的损失曲线
plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.plot(history['loss'], label='Training Loss')
plt.plot(history['val_loss'], label='Validation Loss')
plt.title('Loss Curves')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()# 绘制训练集和验证集的准确度曲线
plt.subplot(1, 2, 2)
plt.plot(history['accuracy'], label='Training Accuracy')
plt.plot(history['val_accuracy'], label='Validation Accuracy')
plt.title('Accuracy Curves')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()plt.tight_layout()
plt.show()

效果如下:

在这里插入图片描述

参考资料:

论文链接: EEGNet: a compact convolutional neural network for EEG-based brain–computer interfaces(Journal of Neural Engineering,SCI JCR2,Impact Factor:4.141)
Github链接: the Army Research Laboratory (ARL) EEGModels project


http://www.ppmy.cn/ops/144139.html

相关文章

深入探讨C++标准输入输出流:iostream

C标准库中的输入输出流(iostream)是处理数据输入和输出的核心部分,提供了灵活且高效的方式来读写各种数据类型。通过理解和运用iostream,开发者可以实现丰富的输入输出功能,从而增强程序的交互性和用户体验。本文将深入探讨C的标准输入输出流…

STM32 水质水位检测项目 显示模块

Driver层 FSMC(之前代码) Interface层 LCD(之前代码) App层 Display(显示模块) display.h #ifndef __DISPLAY_H__ #define __DISPLAY_H__#include "lcd.h"//初始化 void Display_Init(voi…

【YOLOv3】 源码(common.py)

概述 该文件中提供了构建yolov3模型的各种基础模块,其中包含了常用的功能模块,如标准卷积层、瓶颈层、空间金字塔池化层、图像预处理和后处理工具等,这些都是构建高效和模块化模型的基本 该文件的作用类似于一栋建筑的建筑材料和工具&#…

超灵敏红外光谱技术:MIP-PS技术如何实现痕量分子检测

大家好!今天来了解一种超灵敏红外光谱技术——《Ultrasensitive infrared spectroscopy via vibrational modulation of plasmonic scattering from a nanocavity》发表于《SCIENCE ADVANCES》,它为化学分析和生物传感领域带来了新的突破。这项技术基于纳…

智能工厂的设计软件 三种处理单元(NPU/GPU/CPU)及其在深度学习框架中的作用 之5(腾讯云AI代码助手 之3)

前情提要 前面讨论了智能工厂的设计软件 中三种处理单元(NPU/GPU/CPU)及其在深度学习框架中的作用是协作完成一个深度学习任务。 最后通过明确深度学习本身的目的是建构一个公理化系统--作为 自然语言形式化 建模约束(为人类编辑 &#xff0…

ICLR 2025 | 时间序列(Time Series)高分论文总结

ICLR2025已经结束了讨论阶段,进入了meta-review阶段,分数应该不会有太大的变化了,本文总结了其中时间序列(Time Series)高分的论文。如有疏漏,欢迎大家补充。 挑选原则:均分要大于等于6(≥6,即…

云计算赋能:TSP 问题求解与创新定价机制的全景剖析

🏡作者主页:点击! 🤖编程探索专栏:点击! ⏰️创作时间:2024年12月18日14点02分 神秘男子影, 秘而不宣藏。 泣意深不见, 男子自持重, 子夜独自沉。 论文源地址: Aspiringco…

FPGA-PS端编程1:

目标 在小梅哥的zynq 7015上,完成以下目标: 读取 S1 按键的电平, 当 S1 按键为按下状态时,驱动 PS LED 以 1S 的频率闪烁(注意理解 1S 的频率闪烁和 1S的时间翻转两种描述之间的差别), 当 S1 释放后,停止…