EEGNet: 神经网络应用于脑电信号

  • 2021-12-12
  • Admin

bd9f4098ed9bb565a21b2cc181a6f8e6.png

脑机接口(BCI)使用神经活动作为控制信号,实现与计算机的直接通信。这种神经信号通常是从各种研究透彻的脑电图(EEG)信号中挑选出来的。卷积神经网络(CNN)主要用来自动特征提取和分类,其在计算机视觉和语音识别领域中的使用已经很广泛。CNN已成功应用于基于EEG的BCI;但是,CNN主要应用于单个BCI范式,在其他范式中的使用比较少,论文作者提出是否可以设计一个CNN架构来准确分类来自不同BCI范式的EEG信号,同时尽可能地紧凑(定义为模型中的参数数量)。

该论文介绍了EEGNet,这是一种用于基于EEG的BCI的紧凑型卷积神经网络。论文介绍了使用深度和可分离卷积来构建特定于EEG的模型,该模型封装了脑机接口中常见的EEG特征提取概念。论文通过四种BCI范式(P300视觉诱发电位、错误相关负性反应(ERN)、运动相关皮层电位(MRCP)和感觉运动节律(SMR)),将EEGNet在主体内和跨主体分类方面与目前最先进的方法进行了比较。结果显示,在训练数据有限的情况下,EEGNet比参考算法具有更强的泛化能力和更高的性能。同时论文也证明了EEGNet可以有效地推广到ERP和基于振荡的BCI。

实验结果如下图,P300数据集的所有CNN模型之间的差异非常小,但是MRCP数据集却存在显著的差异,两个EEGNet模型的性能都优于所有其他模型。对于ERN数据集来说,两个EEGNet模型的性能都优于其他所有模型(p < 0.05)。

5f34e988f3d8254212d60812b730d868.png

EEGNet网络原理

EEGNet网络结构图:

73ac5ac127ddb5014af12a3fc67b7be7.png

EEGNet原理架构如下:

8aa50510a83d3ddb071f522b1098b125.png

EEGNet网络实现

  1. import numpy as np
  2. from sklearn.metrics import roc_auc_score, precision_score, recall_score, accuracy_score
  3. import torch
  4. import torch.nn as nn
  5. import torch.optim as optim
  6. from torch.autograd import Variable
  7. import torch.nn.functional as F
  8. import torch.optim as optim

定义网络模型:

  1. class EEGNet(nn.Module):
  2. def __init__(self):
  3. super(EEGNet, self).__init__()
  4. self.T = 120
  5. # Layer 1
  6. self.conv1 = nn.Conv2d(1, 16, (1, 64), padding = 0)
  7. self.batchnorm1 = nn.BatchNorm2d(16, False)
  8. # Layer 2
  9. self.padding1 = nn.ZeroPad2d((16, 17, 0, 1))
  10. self.conv2 = nn.Conv2d(1, 4, (2, 32))
  11. self.batchnorm2 = nn.BatchNorm2d(4, False)
  12. self.pooling2 = nn.MaxPool2d(2, 4)
  13. # Layer 3
  14. self.padding2 = nn.ZeroPad2d((2, 1, 4, 3))
  15. self.conv3 = nn.Conv2d(4, 4, (8, 4))
  16. self.batchnorm3 = nn.BatchNorm2d(4, False)
  17. self.pooling3 = nn.MaxPool2d((2, 4))
  18. # 全连接层
  19. # 此维度将取决于数据中每个样本的时间戳数。
  20. # I have 120 timepoints.
  21. self.fc1 = nn.Linear(4*2*7, 1)
  22. def forward(self, x):
  23. # Layer 1
  24. x = F.elu(self.conv1(x))
  25. x = self.batchnorm1(x)
  26. x = F.dropout(x, 0.25)
  27. x = x.permute(0, 3, 1, 2)
  28. # Layer 2
  29. x = self.padding1(x)
  30. x = F.elu(self.conv2(x))
  31. x = self.batchnorm2(x)
  32. x = F.dropout(x, 0.25)
  33. x = self.pooling2(x)
  34. # Layer 3
  35. x = self.padding2(x)
  36. x = F.elu(self.conv3(x))
  37. x = self.batchnorm3(x)
  38. x = F.dropout(x, 0.25)
  39. x = self.pooling3(x)
  40. # 全连接层
  41. x = x.view(-1, 4*2*7)
  42. x = F.sigmoid(self.fc1(x))
  43.         return x

定义评估指标:

    acc:准确率

    auc:AUC 即 ROC 曲线对应的面积

    recall:召回率

    precision:精确率

    fmeasure:F值

  1. def evaluate(model, X, Y, params = ["acc"]):
  2. results = []
  3. batch_size = 100
  4. predicted = []
  5. for i in range(len(X)//batch_size):
  6. s = i*batch_size
  7. e = i*batch_size+batch_size
  8. inputs = Variable(torch.from_numpy(X[s:e]))
  9. pred = model(inputs)
  10. predicted.append(pred.data.cpu().numpy())
  11. inputs = Variable(torch.from_numpy(X))
  12. predicted = model(inputs)
  13. predicted = predicted.data.cpu().numpy()
  14. """
  15. 设置评估指标:
  16. acc:准确率
  17. auc:AUC 即 ROC 曲线对应的面积
  18. recall:召回率
  19. precision:精确率
  20. fmeasure:F值
  21. """
  22. for param in params:
  23. if param == 'acc':
  24. results.append(accuracy_score(Y, np.round(predicted)))
  25. if param == "auc":
  26. results.append(roc_auc_score(Y, predicted))
  27. if param == "recall":
  28. results.append(recall_score(Y, np.round(predicted)))
  29. if param == "precision":
  30. results.append(precision_score(Y, np.round(predicted)))
  31. if param == "fmeasure":
  32. precision = precision_score(Y, np.round(predicted))
  33. recall = recall_score(Y, np.round(predicted))
  34. results.append(2*precision*recall/ (precision+recall))
  35. return results

构建网络EEGNet,并设置二分类交叉熵和Adam优化器

  1. # 定义网络
  2. net = EEGNet()
  3. # 定义二分类交叉熵 (Binary Cross Entropy)
  4. criterion = nn.BCELoss()
  5. # 定义Adam优化器
  6. optimizer = optim.Adam(net.parameters())

创建数据集

  1. """
  2. 生成训练数据集,数据集有100个样本
  3. 训练数据X_train:为[0,1)之间的随机数;
  4. 标签数据y_train:为0或1
  5. """
  6. X_train = np.random.rand(100, 1, 120, 64).astype('float32')
  7. y_train = np.round(np.random.rand(100).astype('float32'))
  8. """
  9. 生成验证数据集,数据集有100个样本
  10. 验证数据X_val:为[0,1)之间的随机数;
  11. 标签数据y_val:为0或1
  12. """
  13. X_val = np.random.rand(100, 1, 120, 64).astype('float32')
  14. y_val = np.round(np.random.rand(100).astype('float32'))
  15. """
  16. 生成测试数据集,数据集有100个样本
  17. 测试数据X_test:为[0,1)之间的随机数;
  18. 标签数据y_test:为0或1
  19. """
  20. X_test = np.random.rand(100, 1, 120, 64).astype('float32')
  21. y_test = np.round(np.random.rand(100).astype('float32'))

训练并验证

  1. batch_size = 32
  2. # 训练 循环
  3. for epoch in range(10):
  4. print("\nEpoch ", epoch)
  5. running_loss = 0.0
  6. for i in range(len(X_train)//batch_size-1):
  7. s = i*batch_size
  8. e = i*batch_size+batch_size
  9. inputs = torch.from_numpy(X_train[s:e])
  10. labels = torch.FloatTensor(np.array([y_train[s:e]]).T*1.0)
  11. # wrap them in Variable
  12. inputs, labels = Variable(inputs), Variable(labels)
  13. # zero the parameter gradients
  14. optimizer.zero_grad()
  15. # forward + backward + optimize
  16. outputs = net(inputs)
  17. loss = criterion(outputs, labels)
  18. loss.backward()
  19. optimizer.step()
  20. running_loss += loss.item()
  21. # 验证
  22. params = ["acc", "auc", "fmeasure"]
  23. print(params)
  24. print("Training Loss ", running_loss)
  25. print("Train - ", evaluate(net, X_train, y_train, params))
  26. print("Validation - ", evaluate(net, X_val, y_val, params))
  27. print("Test - ", evaluate(net, X_test, y_test, params))
  1. Epoch 0
  2. ['acc', 'auc', 'fmeasure']
  3. Training Loss 1.6107637286186218
  4. Train - [0.52, 0.5280448717948718, 0.6470588235294118]
  5. Validation - [0.55, 0.450328407224959, 0.693877551020408]
  6. Test - [0.54, 0.578926282051282, 0.6617647058823529]
  7. Epoch 1
  8. ['acc', 'auc', 'fmeasure']
  9. Training Loss 1.5536684393882751
  10. Train - [0.45, 0.41145833333333337, 0.5454545454545454]
  11. Validation - [0.55, 0.4823481116584565, 0.6564885496183207]
  12. Test - [0.65, 0.6530448717948717, 0.7107438016528926]
  13. Epoch 2
  14. ['acc', 'auc', 'fmeasure']
  15. Training Loss 1.5197088718414307
  16. Train - [0.49, 0.5524839743589743, 0.5565217391304348]
  17. Validation - [0.53, 0.5870279146141215, 0.5436893203883495]
  18. Test - [0.57, 0.5428685897435898, 0.5567010309278351]
  19. Epoch 3
  20. ['acc', 'auc', 'fmeasure']
  21. Training Loss 1.4534167051315308
  22. Train - [0.53, 0.5228365384615385, 0.4597701149425287]
  23. Validation - [0.5, 0.48152709359605916, 0.46808510638297873]
  24. Test - [0.61, 0.6502403846153847, 0.5517241379310345]
  25. Epoch 4
  26. ['acc', 'auc', 'fmeasure']
  27. Training Loss 1.3821702003479004
  28. Train - [0.46, 0.4651442307692308, 0.3076923076923077]
  29. Validation - [0.47, 0.5977011494252874, 0.29333333333333333]
  30. Test - [0.52, 0.5268429487179488, 0.35135135135135137]
  31. Epoch 5
  32. ['acc', 'auc', 'fmeasure']
  33. Training Loss 1.440490186214447
  34. Train - [0.56, 0.516025641025641, 0.35294117647058826]
  35. Validation - [0.36, 0.3801313628899836, 0.2]
  36. Test - [0.53, 0.6113782051282052, 0.27692307692307694]
  37. Epoch 6
  38. ['acc', 'auc', 'fmeasure']
  39. Training Loss 1.4722238183021545
  40. Train - [0.47, 0.4194711538461539, 0.13114754098360656]
  41. Validation - [0.46, 0.5648604269293925, 0.2285714285714286]
  42. Test - [0.5, 0.5348557692307693, 0.10714285714285714]
  43. Epoch 7
  44. ['acc', 'auc', 'fmeasure']
  45. Training Loss 1.3460421562194824
  46. Train - [0.51, 0.44871794871794873, 0.1694915254237288]
  47. 原文:https://blog.csdn.net/zyb228107/article/details/121882410

联系站长

QQ:769220720

Copyright © SibooSoft All right reserved 津ICP备19011444号