TSception:从EEG中捕获时间动态和空间不对称性用于情绪识别

TSception:从EEG中捕获时间动态和空间不对称性用于情绪识别(论文复现)

  • 摘要
  • 模型结构
  • 代码实现
  • 写在最后

**这是一篇代码复现,原文通过Pytorch实现,本文中使用Keras对该结构进行复现。**该论文发表在IEEE Transactions on Affective Computing,第一作者Yi Ding

摘要

高时间分辨率和不对称的空间激活是脑内情绪过程的基本特征。为了学习EEG的时间动态性和空间不对称性,以实现准确和广义的情感识别,Yi Ding等人提出了一种多尺度卷积神经网络TSception,可以从EEG中对情感进行分类。Tsception由动态时间、非对称空间和高级融合层组成,同时学习时间和信道维度的区分表示。动态时域层由多尺度1D卷积核组成,其长度与EEG的采样率相关,其学习EEG的动态时间和频率表示。非对称空间层利用情绪的非对称EEG模式,学习有区别的全局和半球表示。原文代码可在以下网址获得:https://github.com/yi-ding-cs/TSception,本文复现完整代码可在下面获得:https://github.com/ruix6/tsception

模型结构

关于模型结构的相关公式推理可以参考原文,本文不详细展开,下图是模型的具体结构:
在这里插入图片描述
熟悉经典深度学习模型的同学应该能一眼看出来TSception的设计灵感来自Inception模型。结合脑电信号的特点,TSception分四步实现对脑电信号的计算。

  1. 多尺度时域卷积:第一步通过多个尺度的时域卷积核实现对EEG信号的分解与特征提取。多尺度的优势在于可以给模型提供多个不同的感受野,这对于脑电信号这种多源的复杂信号来说是十分合理的。作为对比,我们可以看一下EEGNet的结构,如下图,EEGNet的第一个部分也是一个一维时域卷积结构,但是由于单一的感受野,在很多任务中它很容易被低频部分的噪声所干扰,所以EEGNet在ERP或者SMR这种有效信息分布在低频段的任务比较友好,但是像情绪识别的话,该网络的原始结构似乎不能发挥其全部能量(改变其时域卷积核大小似乎能有效提升其能力)。在这里插入图片描述
  2. 不对称空间卷积层:模型的第二部分由两个尺度的卷积实现。大尺度的卷积层覆盖所有通道,小尺度的卷积层分可以分别卷积大脑左半球的通道和右半球的通道。前面提到过,不对称的空间激活(即受试者在不同的情绪状态下,大脑的左右半球的激活状态是不一样的,原文中分析了受试者的大脑激活状态,想进一步了解可以看看原文)是情绪的重要特征,所以通过小尺度的空间卷积可以进一步的抓住这些特征。
    在这里插入图片描述
  3. 高级融合层:该层为了进一步的融合输入的时空特征而设计,这个和EEGNet的可分离卷积层的效果是一样的,我更愿意称之为为了减小参数量而设计的🙂,这个卷积层的出现,其实使得模型的可解释性进一步降低。
  4. 分类:把高级融合层的输出做个全局平均池化然后全连接,最后输出。

代码实现

代码如下:

from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Conv2D, AveragePooling2D, Flatten, Dense, Dropout, BatchNormalization, concatenate, LeakyReLU


# 定义时域卷积块
def conv_block(input, out_chan, kernel, step, pool):
    x = Conv2D(out_chan, kernel, strides=step)(input)# padding='same', use_bias=False
    x = LeakyReLU()(x)
    x = AveragePooling2D(pool_size=(1, pool), strides=(1, pool))(x)

    return x


def Tsception(num_classes, Chans, Samples, sampling_rate, num_T, num_S, hidden, dropout_rate, pool=8):

    '''
    input_size: 输入数据的维度,(chans, samples, 1)
    '''
    inception_window = [0.5, 0.25, 0.125]
    # 定义输入层
    input = Input(shape=(Chans, Samples, 1))
    # 定义时域卷积层
    x1 = conv_block(input, num_T, (1, int(sampling_rate * inception_window[0])), 1, pool)
    x2 = conv_block(input, num_T, (1, int(sampling_rate * inception_window[1])), 1, pool)
    x3 = conv_block(input, num_T, (1, int(sampling_rate * inception_window[2])), 1, pool)
    # 在height维度上进行拼接
    x = concatenate([x1, x2, x3], axis=2)
    x = BatchNormalization()(x)
    # 定义空域卷积层
    y1 = conv_block(x, num_S, (Chans, 1), (Chans, 1), int(pool*0.25))
    y2 = conv_block(x, num_S, (int(Chans*0.5), 1), (int(Chans*0.5), 1), int(pool*0.25))
    # 在width维度上进行拼接
    y = concatenate([y1, y2], axis=1)
    y = BatchNormalization()(y)
    # 定义fusion_layer
    z = conv_block(y, num_S, (3, 1), (3, 1), 4)
    z = BatchNormalization()(z)
    # 定义全局平均池化层
    z = AveragePooling2D(pool_size=(1, z.shape[2]))(z)
    z = Flatten()(z)
    # 全连接层
    z = Dense(hidden, activation='relu')(z)# , use_bias=False
    z = Dropout(dropout_rate)(z)
    z = Dense(num_classes, activation='softmax')(z)# , use_bias=False

    return Model(inputs=input, outputs=z)

参照原文的各个超参数,引用方式为:

if __name__ == '__main__': 
    model = Tsception(num_classes=2, Chans=28, Samples=512, sampling_rate=128, num_T=15, num_S=15, hidden=32, dropout_rate=0.5)
    model.summary()

最后的输出为:

__________________________________________________________________________________________________
 Layer (type)                   Output Shape         Param #     Connected to
==================================================================================================
 input_1 (InputLayer)           [(None, 28, 512, 1)  0           []
                                ]

 conv2d (Conv2D)                (None, 28, 449, 15)  975         ['input_1[0][0]']

 conv2d_1 (Conv2D)              (None, 28, 481, 15)  495         ['input_1[0][0]']

 conv2d_2 (Conv2D)              (None, 28, 497, 15)  255         ['input_1[0][0]']

 leaky_re_lu (LeakyReLU)        (None, 28, 449, 15)  0           ['conv2d[0][0]']

 leaky_re_lu_1 (LeakyReLU)      (None, 28, 481, 15)  0           ['conv2d_1[0][0]']

 leaky_re_lu_2 (LeakyReLU)      (None, 28, 497, 15)  0           ['conv2d_2[0][0]']

 average_pooling2d (AveragePool  (None, 28, 56, 15)  0           ['leaky_re_lu[0][0]']
 ing2D)

 average_pooling2d_1 (AveragePo  (None, 28, 60, 15)  0           ['leaky_re_lu_1[0][0]']
 oling2D)

 average_pooling2d_2 (AveragePo  (None, 28, 62, 15)  0           ['leaky_re_lu_2[0][0]']
 oling2D)

 concatenate (Concatenate)      (None, 28, 178, 15)  0           ['average_pooling2d[0][0]',
                                                                  'average_pooling2d_1[0][0]',
                                                                  'average_pooling2d_2[0][0]']

 batch_normalization (BatchNorm  (None, 28, 178, 15)  60         ['concatenate[0][0]']
 alization)

 conv2d_3 (Conv2D)              (None, 1, 178, 15)   6315        ['batch_normalization[0][0]']

 conv2d_4 (Conv2D)              (None, 2, 178, 15)   3165        ['batch_normalization[0][0]']

 leaky_re_lu_3 (LeakyReLU)      (None, 1, 178, 15)   0           ['conv2d_3[0][0]']

 leaky_re_lu_4 (LeakyReLU)      (None, 2, 178, 15)   0           ['conv2d_4[0][0]']

 average_pooling2d_3 (AveragePo  (None, 1, 89, 15)   0           ['leaky_re_lu_3[0][0]']
 oling2D)

 average_pooling2d_4 (AveragePo  (None, 2, 89, 15)   0           ['leaky_re_lu_4[0][0]']
 oling2D)

 concatenate_1 (Concatenate)    (None, 3, 89, 15)    0           ['average_pooling2d_3[0][0]',
                                                                  'average_pooling2d_4[0][0]']

 batch_normalization_1 (BatchNo  (None, 3, 89, 15)   60          ['concatenate_1[0][0]']
 rmalization)

 conv2d_5 (Conv2D)              (None, 1, 89, 15)    690         ['batch_normalization_1[0][0]']

 leaky_re_lu_5 (LeakyReLU)      (None, 1, 89, 15)    0           ['conv2d_5[0][0]']

 average_pooling2d_5 (AveragePo  (None, 1, 22, 15)   0           ['leaky_re_lu_5[0][0]']
 oling2D)

 batch_normalization_2 (BatchNo  (None, 1, 22, 15)   60          ['average_pooling2d_5[0][0]']
 rmalization)

 average_pooling2d_6 (AveragePo  (None, 1, 1, 15)    0           ['batch_normalization_2[0][0]']
 oling2D)

 flatten (Flatten)              (None, 15)           0           ['average_pooling2d_6[0][0]']

 dense (Dense)                  (None, 32)           512         ['flatten[0][0]']

 dropout (Dropout)              (None, 32)           0           ['dense[0][0]']

 dense_1 (Dense)                (None, 2)            66          ['dropout[0][0]']

==================================================================================================
Total params: 12,653
Trainable params: 12,563
Non-trainable params: 90
__________________________________________________________________________________________________

原文结果,测试数据集是DEAP情绪数据集:
在这里插入图片描述

写在最后

原文的作者并没有对模型进行更加具体的调参,事实上,输出的全连接层的神经元设置为32应该是意义不大的,效果可能不如直接链接到输出层,并且如果要考虑进一步缩小参数量的话,各个卷积层的偏置权重其实可以去除。在原文中,模型的效果表现与其它的卷积神经网络并没有统计学意义上的差别,但是,如果能够进一步调参的话,效果实际上要好很多。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/32040.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spark10-11

10. 广播变量 10.1 广播变量的使用场景 在很多计算场景,经常会遇到两个RDD进行JOIN,如果一个RDD对应的数据比较大,一个RDD对应的数据比较小,如果使用JOIN,那么会shuffle,导致效率变低。广播变量就是将相对…

Spring Boot 如何使用 @ExceptionHandler 注解处理异常消息

Spring Boot 如何使用 ExceptionHandler 注解处理异常消息 在 Spring Boot 应用程序中,异常处理是非常重要的一部分。当应用程序出现异常时,我们需要能够捕获和处理这些异常,并向用户提供有用的错误消息。在 Spring Boot 中,可以…

二叉平衡树之红黑树

目录 1.概念 2.性质 3.节点的定义 4.插入 1.按照二叉搜索树规则插入结点 2.调整颜色 1.uncle存在且为红色 2.uncle不存在或者为黑 cur为 3.根节点改为黑色 5.验证 6.比较 7.应用 1.概念 红黑树,是一种二叉搜索树,但在每个结点上增加一个存…

2023年5月青少年机器人技术等级考试理论综合试卷(五级)

青少年机器人技术等级考试理论综合试卷(五级) 分数: 100 题数: 30 一、 单选题(共 20 题, 每题 4 分, 共 80 分) 1.ESP32 for Arduino, 下列程序的运行结果是? ( &#x…

浅谈无线测温系统在高压开关柜中的应用

关注acrelzxz,了解更多详情 摘要:高压开关柜是配电系统中重要的组成部分,其主要作用是控制电荷、分配电能和开断电流等,对维持系统的稳定性有一定的保障作用。将无线测温技术应用于高压开关柜,可以实现对其进行实时的…

校园外卖行业内卷之下,高校外卖创业者如何成为卷王?

伴随着外卖行业的不断发展,校园市场前景广阔。校园外卖市场因各大平台的竞争而变得越来越复杂。各种技术支持和经验参考让大学生创业校园外卖越来越困难,市场竞争也越来越激烈。 校园外卖市场究竟有多内卷? 外卖龙头企业。 校园市场广阔的发…

【高危】crypto-js<3.2.1 存在不安全的随机性漏洞

漏洞描述 crypto-js 是一个 JavaScript 加密库,用于在浏览器和 Node.js 环境中执行加密和解密操作。 crypto-js 3.2.1 之前版本中的 secureRandom 函数通过将字符串 0. 和三位随机整数拼接的格式生成加密字符串,攻击者可通过爆破破解加密字符。 漏洞…

Oracle 查询优化改写(第五章)

第五章 使用字符串 1.遍历字符串 SELECT 天天向上 内容&#xff0c;level&#xff0c;substr(天天向上, LEVEL, 1) 汉字拆分FROM Dual CONNECT BY LEVEL < Length(天天向上);2.计算字符在字符串中出现的次数 3.从字符中删除不需要的字符 若员工姓名有元音字母AEIOU&#x…

RPC远程调用

简介 PRC是一种调用方式而不是一种协议 在本地调用方式时由于方法在同一个内存空间&#xff0c;所以程序中可以直接调用该方法&#xff0c;但是浏览器端和服务端程序是不在一个内存空间的&#xff0c;需要使用网络来访问&#xff0c;就需要使用TCP或者UDP协议&#xff0c;由于…

STM32实现延时

在STM32单片机中&#xff0c;实现延时一般都是使用定时器&#xff0c;既可以使用Systick定时器&#xff0c;也可以使用常规的定时器。 定时器在设置了定时并开启之后&#xff0c;就会进入自主运行模式&#xff0c;其中&#xff0c;初始化设置这一阶段是由CPU执行相应指令完成的…

ubuntu双系统安装

1. 下载系统 国内镜像 http://mirrors.ustc.edu.cn/ubuntu-releases/2. U盘启动盘 Rufus 软件 制作U盘启动盘 Rufus 链接 https://rufus.en.softonic.com/3. 磁盘中准备一定未分配磁盘 我准备了100G 4. BIOS启动项选择为usb启动&#xff08;每个品牌进BIOS不同&#xff0…

Docker 进入容器和交换文件

1、进入容器 有些时候需要进入容器进行操作&#xff0c;使用 docker exec 命令&#xff0c;这个命令后面可以添加很多参数&#xff0c;我们这里只讲添加 -i 和 -it 参数。 只添加 -i 参数时&#xff0c;由于没有分配伪终端&#xff0c;界面没有我们熟悉的 Linux 命令提示…

Kubernetes 和 Prometheus

资源监控系统是容器编排系统必不可少的组件&#xff0c;也是服务治理的核心之一。而 Prometheus 本质上是一个开源的服务监控系统和时序数据库&#xff0c;是 CNCF 起家的第二个项目&#xff0c;目前已经成为 Kubernetes 生态圈中的监控系统的核心。 Prometheus 的核心组件 Pro…

java学习记录之MySql二

1 mysql回顾 1.1 DDL 数据定义语言&#xff1a;结构  数据库database create database 数据库名称 character set 字符集 [collate 比较]; drop database 数据库名称; alter database 数据库名称 character set 字符集 …;  表 create table 表名(字段描述 , … ); 字段描述…

GD32 SPI 查询方式和DMA方式在全双模式下效率区别

最近在使用SPI的时候&#xff0c;遇到了一些数据传输效率问题&#xff0c;在此记录自己学习过程。SPI的基础知识这里就不在讲述了&#xff0c;直接分析SPI查询方式和DMA方式的效率问题。这里使用的芯片是GD32F303CC。 SPI以查询方式进行全双工通信 1.查询手册&#xff0c;SPI…

Spring Cloud Alibaba-全链路灰度设计

文章目录 灰度发布概念灰度发布架构Spring Cloud Alibaba技术架构下的灰度发布实现基础设计HttpHeader设计 Spring Cloud Gateway改造Spring Cloud Gateway实现灰度发布过滤器 后端服务自定义Spring MVC请求拦截器OpenFeign改造自定义Loadbalancer 测试微服务注册元信息修改自定…

在windows11环境下安装CUDA11.6+Anaconda3+pyToach1.13搭建炼丹炉

0.电脑环境 系统&#xff1a;win11 显卡&#xff1a;NVIDIA GTX1650 还有一个pyCharm&#xff0c;其他也用不到了&#xff0c;需要的文章中会进行说明 1.安装CUDA11.6 目前2023.03出来的pyToach2.0是用不到了&#xff0c;因为最低版本支持CUDA11.7。我的显卡是1650&#xff0c…

阿里巴巴高管换血,吴永明接替张勇

文章目录 经济学人 &#x1f4b0; 第 26 周&#x1fa78; 阿里巴巴高管换血&#xff0c;吴永明接替张勇&#x1f304; 孙正义再出山&#x1f43f;️ 英特尔加码德国&#xff01;投资330亿美元建两座芯片工厂&#xff01;&#x1f30a; 亚马逊被指控强加 Prime 服务✈️ 印度航空…

Jmeter多接口测试之参数传递

目录 前言&#xff1a; 接口示例 正则表达式提取器 正则表达式提取实例 Json提取器 Json提取器实例 前言&#xff1a; 在进行多接口测试时&#xff0c;有些情况下需要将前一个接口返回数据作为后一个接口的参数&#xff0c;以模拟实际场景。JMeter作为一款常用的性能测试…

【EXCEL】如何查找特殊字符 问号‘?’星号 ‘*’

目录 0.环境 1.适用场景 1&#xff09;直接搜索问号的结果&#xff1a; 2&#xff09;修改【查找内容】后&#xff0c;搜索结果变为精准定位&#xff1a; 2.具体做法 0.环境 windows wps&#xff08;或excel&#xff0c;这里试了&#xff0c;此问题wps和excel表格是通用…
最新文章