57、通过EEG数据的SHAPE变化,揭开EEG-TCNet的黑匣子[看好了小子,我只教这一次]

之前在第18篇博客中对于EEG-TCNet这个处理EEG信号的sota模型进行了介绍,也给出了模型,目前也是全网对于EEG-TCNet浏览度最高的文章了,我觉得讲的已经很细致了,没想到还是有不少同学疑问,这也是全网缺少该模型pytorch代码的原因,因为pytorch中没有封装TCN模块,无法直接调用,而在Tensorflow中可直接调用,废话不多少,上菜:

EEG-TCNet模型图:

原论文EEG-TCNet结构图

模型结构分析:

1、BCI IV2a数据以4维数据输入,shape=(288,1,22,1000)

2、数据先经过一个完整的EEGNet结构(时间卷积+深度卷积+深度可分离),来处理这个4维数组

3、数据从EEGNet出来,进入到TCN块之前进行降维处理(TCN只能处理1维数组)

下面我们来看2a数据以(batch_size,1,22,1000)输入到EEG-TCNet中是如何改变shape的

我自己写的EEG-TCNet代码模型-结构图:(我自己画的,别盗图)

TCN块(膨胀因果卷积)分析:

代码编写:

Chomp1d(nn.Module):裁剪类

TemporalBlock(nn.Module):TCN主体类,调用Chomp1d(),在这个类使用的卷积是Conv1d

TemporalConvNet(nn.Module):调用TemporalBlock()TCN完全体类

TCNNet(nn.Module):调用TemporalConvNet(),降维,使得TCN完全体跑的通


讲上面这4个类,我要倒着讲,费点劲要:(为啥倒着讲?同学想想 0。0 )

input_data = batch_size,1,22,1000经过一个前3个block后,此时控制台输出shape = 32,8,1,31断点如下:

数据此时还是4维的,所以我们在这使用if来判断维度,给他降维度

1、Data = torch.rand(x.shape):生成一个空的和x的维度一致的张量数据,用来存储for循环TCN块裁剪的数据

2、空的张量数据也要送到GPU中,否则报错,因为此时X的数据都在GPU上

3、在x的第二维度channel = 1,进行for循环,通过self来调用类内的tcn_block对应的TCN方法,对x数据进行裁剪并提取数据,把这些数据(此时还是4维)送给张量data

4、x = data(乾坤大魔移!


tcn_block对应着咱们定义的TemporalConvNet() 完全体这个类,如下:

类里面调用了上面定义好的Chomp1d()这个裁剪的类

此时代码跑到了Chomp1d()里面,如下所示:

TCN之前的数据= 32,8,1,31

此时数据维度 = 32,8,40,这里代码自动的去掉了通道=1的维度,并+res这个对x下采样的数据

因为这里是for i in range(x.shape[2])的循环,此时i=0,x.shape[3] = 40,我们再进入下一个循环i=1看看

此时x.shape[3] = 49,所以就这样,在送到Chomp1d()进行裁剪时,x加上了res这个下采样特征数据,导致了x的数据量增加,我们规定了Chomp1d()中的chomp_size这个数值,只保留与原始数据总量相同的前chomp_size的这个数目,来最后送给Fc层做最后结果的输出

此时我们送给Fc的shape :

又变回原来的31个数据了,这事裁剪类的功劳!但此时前后的这个31数据是不同的,多了下采样的特征,所以TCNNet这个类实现了先降维再生维的神奇操作,使得代码流通,完事。

全部代码如下:

class Chomp1d(nn.Module):def __init__(self, chomp_size):super(Chomp1d, self).__init__()self.chomp_size = chomp_sizedef forward(self, x):return x[:, :, :-self.chomp_size].contiguous()class TemporalBlock(nn.Module):def __init__(self, n_inputs, n_outputs, kernel_size, stride, dilation, padding, dropout=0.2):super(TemporalBlock, self).__init__()self.conv1 = weight_norm(nn.Conv1d(n_inputs, n_outputs, kernel_size,stride=stride, padding=padding, dilation=dilation))self.chomp1 = Chomp1d(padding)self.relu1 = nn.ReLU()self.dropout1 = nn.Dropout(dropout)self.conv2 = weight_norm(nn.Conv1d(n_outputs, n_outputs, kernel_size,stride=stride, padding=padding, dilation=dilation))self.chomp2 = Chomp1d(padding)self.relu2 = nn.ReLU()self.dropout2 = nn.Dropout(dropout)self.net = nn.Sequential(self.conv1, self.chomp1,self.relu1, self.dropout1,self.conv2, self.chomp2,self.relu2, self.dropout2)self.downsample = nn.Conv1d(n_inputs, n_outputs, 1) if n_inputs != n_outputs else Noneself.relu = nn.ReLU()#   self.init_weights()# def init_weights(self):#     self.conv1.weight.data.normal_(0, 0.01)#     self.conv2.weight.data.normal_(0, 0.01)#     if self.downsample is not None:#         self.downsample.weight.data.normal_(0, 0.01)def forward(self, x):out = self.net(x)res = x if self.downsample is None else self.downsample(x)return self.relu(out + res)class TemporalConvNet(nn.Module):def __init__(self, num_inputs, num_channels, kernel_size=2, dropout=0.2):super(TemporalConvNet, self).__init__()layers = []num_levels = len(num_channels)for i in range(num_levels):dilation_size = 2 ** iin_channels = num_inputs if i == 0 else num_channels[i-1]out_channels = num_channels[i]layers += [TemporalBlock(in_channels, out_channels, kernel_size, stride=1, dilation=dilation_size, padding=(kernel_size-1) * dilation_size, dropout=dropout)]self.network = nn.Sequential(*layers)def forward(self, x):return self.network(x)import numpy as npclass TCNNet(nn.Module):def __init__ (self,*args) -> None:super(TCNNet,self).__init__()if len(args) < 2:print('error')exit()else:num_inputs = args[0]num_channels = args[1]kernel_size = int(args[2][0])self.tcn_block =  TemporalConvNet(num_inputs,num_channels,kernel_size) #self.tcn_block =  TemporalConvNet(num_inputs=self.F2,num_channels=[tcn_filters,tcn_filters],kernel_size=tcn_kernelSize) def forward(self,x) :if len(x.shape) == 4:data = torch.rand(x.shape)device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') data = data.to(device)for i in range(x.shape[2]):data[:,:,i,:] = self.tcn_block(x[:,:,i,:])x = dataelse:x = torch.squeeze(x,dim=2) x = self.tcn_block(x)return x 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3D Gaussian Splatting技术原理

3D Gaussian Splatting 是一种用于体积渲染的技术,特别适用于科学和医学可视化。这种技术使得用户能够以一种直观的方式查看和分析三维数据集,如医学成像数据(MRI、CT扫描)或科学模拟数据。 技术原理 3D Gaussian Splatting基本上是一种将3D空间中的点数据转换成一个连续…

前端基础(之三)

Q1&#xff1a;介绍一下盒模型 A1&#xff1a;盒模型是用于描述Html在页面总所占空间的方式&#xff0c;盒模型将每个html元素视为一个矩形框&#xff0c;该框主要由四个主要部分组成&#xff1a;内容区域、内边距、边框和外边距。 内容区域是Html元素实际包含内容的部分&…

Redis中的Sentinel(五)

Sentinel 检测主观下线状态 在默认情况下&#xff0c;Sentinel会以每秒一次的频率向所有与它创建了命令连接的实例(包括主服务器、从服务器、其他Sentinel在内) 发送PING命令&#xff0c;并通过实例返回的PING命令回复来判断实例是否在线。如图所示&#xff0c;带箭头的连线显…

Word学习笔记之奇偶页的页眉与页码设置

1. 常用格式 在毕业论文中&#xff0c;往往有一下要求&#xff1a; 奇数页右下角显示、偶数页左下角显示奇数页眉为每章标题、偶数页眉为论文标题 2. 问题解决 2.1 前期准备 首先&#xff0c;不论时要求 1、还是要求 2&#xff0c;这里我们都要做一下设置&#xff1a; 鼠…

如何封装Vue组件并上传到npm

前言 环境准备 1.注册npm账号&#xff1a;npm | Home (npmjs.com) 2.保证当前环境安装了vue、webpack、node&#xff0c;以下工作将在该环境下进行&#xff08;没有的小伙伴自行百度安装哈~&#xff09; 3.一下用到的环境版本 webpack&#xff1a;v5.1.4node&#xff1a;v…

如何在Java中实现线程同步

在Java中实现线程同步是多线程编程中的一个重要概念&#xff0c;目的是控制对共享资源的访问&#xff0c;以防止多个线程同时修改某一资源&#xff0c;从而避免数据的不一致性和发生冲突。以下是几种在Java中实现线程同步的方法&#xff1a; ### 使用synchronized关键字 sync…

使用 MyBatis 的 mapper 接口调用时的要求

1&#xff1a; Mapper 接口方法名和 mapper.xml 中定义的每个 sql 的 id 相同&#xff1b; 2&#xff1a; Mapper 接口方法的输入参数类型和 mapper.xml 中定义的每个 sql 的parameterType 的类型相同&#xff1b; 3&#xff1a; Mapper 接口方法的输出参数类型和 mapper.xml 中…

SAM5716B 法国追梦DREAM 音频DSP芯片

法国追梦/DERAM SAM5504/5704/5716/5808音频DSP芯片,开发板&#xff0c;方案 可用于电子鼓、电子琴、电吉他、效果器、均衡器、啸叫抑制器等电声产品领域 全系列芯片&#xff1a; SAM2634 SAM2695 SAM5504B SAM5704B SAM5708B SAM5808B SAM5716B SAM5916B... 原厂开发…

根据状态转移图实现时序电路

描述 某同步时序电路的状态转换图如下&#xff0c;→上表示“C/Y”&#xff0c;圆圈内为现态&#xff0c;→指向次态。 请使用D触发器和必要的逻辑门实现此同步时序电路&#xff0c;用Verilog语言描述。 如图所示&#xff1a; 电路的接口如下图所示&#xff0c;C是单bit数据…

密码学 | 承诺:常见的承诺方案

&#x1f951;原文&#xff1a;密码学原语如何应用&#xff1f;解析密码学承诺的妙用 - 知乎 1 简介 密码学承诺 涉及 承诺方、验证方 两个参与方&#xff0c;以及以下两个阶段&#xff1a; 承诺阶段&#xff1a;承诺方选择一个敏感数据 v v v&#xff0c;为它计算出相应…

国家信息安全漏洞库(CNNVD)技术支撑单位等级证书

国家信息安全漏洞库&#xff08;CNNVD&#xff09;技术支撑单位等级证书是CNNVD对参与信息安全漏洞研究、事件解读、漏洞信息共享等工作的单位进行认证和评级的机制。该证书有助于提升单位在信息安全领域的影响力和公信力&#xff0c;同时也是对单位技术实力和贡献的一种认可。…

AUTOSAR ARXML处理 - C#的解析代码(四)

4.3 配置参数关键类 4.3.1 配置数据&#xff1a;模块 MODULE &#xff08;ECUCMODULECONFIGURATIONVALUES&#xff0c;<ECUC-MODULE-CONFIGURATION-VALUES>&#xff09; 与ECUCMODULEDEF&#xff0c;<ECUC-MODULE-DEF> 关联 /// <remarks/>[System.CodeDom…

标题:探索算法世界的奇妙与力量

标题&#xff1a;探索算法世界的奇妙与力量 在当今信息时代&#xff0c;算法已经成为了我们生活中不可或缺的一部分。从搜索引擎、社交媒体&#xff0c;到无人驾驶、机器人&#xff0c;算法都在其中发挥着重要的作用。本文将为您详细介绍算法的概念、类型、应用场景以及算法的…

美国家安全局等发布安全部署人工智能系统指南

该指南旨在为部署和运行由其他实体设计和开发的人工智能系统的组织提供最佳实践。 2024年4月15日&#xff0c;美国国家安全局发布了名为《安全部署人工智能系统&#xff1a;部署安全、弹性人工智能系统的最佳实践》&#xff0c;该指南旨在为部署和运行由其他实体设计和开发的人…

【Jupyter Notebook】快捷键

在命令模式下&#xff0c;单元格边框是灰色&#xff08;缺省&#xff09;的。这些快捷键主要用于操作单元格。 Enter&#xff1a;进入编辑模式Shift Enter&#xff1a;运行当前单元格并选中下一个单元格Ctrl Enter&#xff1a;运行当前单元格Alt Enter&#xff1a;运行当前单…

类声明是public类型的变量如何赋值

在面向对象编程(如Java、C#、PHP等语言)中,类声明为public类型的变量是类的成员变量,也称为属性或字段。这些变量可以在类内部、构造函数中、或者从类外部通过实例化对象来赋值。以下是一些基本的赋值方式: 在类内部赋值: // Java 示例 public class MyClass {public S…

途游游戏,科锐国际(计算机类),得物,蓝禾,奇安信,顺丰,康冠科技,金证科技24春招内推

途游游戏&#xff0c;科锐国际&#xff08;计算机类&#xff09;&#xff0c;得物&#xff0c;蓝禾&#xff0c;奇安信&#xff0c;顺丰&#xff0c;康冠科技&#xff0c;金证科技24春招内推 ①得物 【岗位】技术&#xff0c;设计&#xff0c;供应链&#xff0c;风控&#xff0…

Mac多媒体播放器 Movist Pro v2.11.4中文激活版下载

Movist Pro for Mac是一款专业的媒体播放器&#xff0c;特别为Mac用户设计。它不仅界面简洁美观&#xff0c;而且功能强大&#xff0c;能满足用户各种播放需求。 Movist Pro v2.11.4中文激活版下载 首先&#xff0c;Movist Pro for Mac支持多种媒体文件的播放&#xff0c;包括视…

关于Qt主窗口的菜单部件

前言 在介绍主窗口的两大部件之前&#xff0c;我们要先知道关于主窗口的一些知识。 主窗口 一个主窗口可以没有菜单条、工具条、状态条&#xff0c;但必须设置中心部件。在 Q 生成的 C头文件 ui_mainwindow.h 代码中,我们可以看到以下代码: centralWidget new Qwidget(MainWi…

CSS基础常用属性之颜色(如果想知道CSS的颜色知识点,那么只看这一篇就足够了!)

前言&#xff1a;在我们学习CSS的时候&#xff0c;主要学习选择器和常用的属性&#xff0c;而这篇文章讲解的就是最基础的属性——颜色。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客 目录 1.颜色属性 【1】使用颜色关键词表…