第四章:模型架构设计——EEGNet、DeepConvNet、ShallowConvNet、Transformer for EEG
好,咱们进入正题。模型架构设计这块,说实话,是深度学习做EEG信号处理最核心的一环。你想想看,EEG信号本身信噪比低、样本量小、个体差异大,选不对模型,后面再怎么调参都是白搭。
我个人习惯把EEG模型分成两类:一类是轻量级、适合实时部署的,比如EEGNet;另一类是深度堆叠、追求极致精度的,比如DeepConvNet。当然,还有Transformer这种“外来物种”,这两年也开始在EEG领域大放异彩。咱们一个一个聊。
4.1 EEGNet——小而美的典范
EEGNet是我在项目里用得最多的模型。为什么?因为它真的轻。我记得第一次在嵌入式设备上跑EEGNet,模型大小才几十KB,推理延迟不到5ms。嗯,这种体验,谁用谁知道。
它的核心思路其实很简单:先用一个时间卷积提取每个通道的时序特征,再用一个深度可分离卷积做空间滤波。说白了,就是把时间和空间两个维度分开处理,参数少,效果好。
核心结构:
- 输入层:C × T(通道数 × 时间点)
- Conv2D:2D卷积,kernel=(1, 64),学习时间滤波器
- DepthwiseConv2D:每个通道独立卷积,kernel=(C, 1),学习空间滤波器
- SeparableConv2D:可分离卷积,进一步提取高层特征
- 分类层:全连接 + Softmax
# EEGNet 核心代码(PyTorch风格)
class EEGNet(nn.Module):
def __init__(self, chans=64, samples=128, classes=4):
super().__init__()
# 时间卷积:学习时间滤波器
self.conv1 = nn.Conv2d(1, 8, kernel_size=(1, 64), padding=(0, 32))
# 深度可分离:空间滤波
self.depthwise = nn.Conv2d(8, 16, kernel_size=(chans, 1), groups=8)
# 可分离卷积:特征组合
self.separable = nn.Conv2d(16, 16, kernel_size=(1, 16), padding=(0, 8))
# 分类头
self.classifier = nn.Linear(16 * (samples // 4), classes)
def forward(self, x):
x = self.conv1(x)
x = self.depthwise(x)
x = self.separable(x)
x = x.view(x.size(0), -1)
return self.classifier(x)
避坑指南:我曾经在EEGNet里把时间卷积的kernel size设得太大(比如128),结果模型过拟合得一塌糊涂。后来我总结了一个经验:对于128Hz的采样率,kernel size取64就够,相当于0.5秒的窗口。太小了抓不到特征,太大了容易过拟合。
4.2 DeepConvNet——深度堆叠的力量
如果你追求的是分类精度,DeepConvNet是个不错的选择。它借鉴了VGGNet的设计思路,用多个卷积块堆叠,逐层提取更抽象的特征。
但说实话,DeepConvNet在EEG上有个致命问题:参数量太大。我试过在只有几百个样本的数据集上训练DeepConvNet,结果验证集准确率还不如EEGNet。为什么会这样?因为EEG数据量太小,深度模型很容易过拟合。
| 模型 | 参数量 | 推理时间(CPU) | 推荐场景 |
|---|---|---|---|
| EEGNet | ~3K | <5ms | 实时系统、嵌入式设备 |
| DeepConvNet | ~200K | ~20ms | 离线分析、高精度需求 |
| ShallowConvNet | ~50K | ~10ms | 平衡方案 |
注意:DeepConvNet需要配合大量数据增强才能发挥效果。我建议至少准备5000个以上的样本,否则别碰它。
4.3 ShallowConvNet——折中之道
ShallowConvNet是DeepConvNet的“瘦身版”。它只有两个卷积块,但保留了空间滤波和时间滤波的核心设计。我个人觉得,ShallowConvNet是“性价比”最高的模型——参数不多,精度不差。
它的结构是这样的:
- 第一层:时间卷积(kernel=25),提取低频特征
- 第二层:空间卷积(kernel=C×1),做通道融合
- 平均池化 + 全连接分类
你想想看,ShallowConvNet为什么适合EEG?因为EEG信号的主要能量集中在低频段(0.5-40Hz),浅层网络就能捕捉到这些特征。太深的网络反而会学到噪声。
4.4 Transformer for EEG——新思路
Transformer这两年火得不行,从NLP杀到了CV,现在又杀到了EEG。它的核心优势是长距离依赖建模——EEG信号的时间序列很长,Transformer的Self-Attention机制能捕捉到相隔很远的两个时间点之间的关系。
但我要泼一盆冷水:Transformer在EEG上并不总是好用。我踩过一个坑:直接把ViT(Vision Transformer)搬到EEG上,结果训练了三天都不收敛。后来才发现,EEG的时序结构跟图像完全不同,需要做专门的适配。
EEG Transformer 的关键改进:
- 位置编码:用相对位置编码替代绝对位置编码,因为EEG的时序关系是相对的
- 通道注意力:在Self-Attention中加入通道维度,让模型学会关注哪些通道更重要
- 局部窗口:用滑动窗口限制Attention范围,避免计算量爆炸
# EEG Transformer 核心模块(简化版)
class EEGTransformerBlock(nn.Module):
def __init__(self, d_model=64, nhead=4):
super().__init__()
self.attention = nn.MultiheadAttention(d_model, nhead)
self.norm1 = nn.LayerNorm(d_model)
self.ffn = nn.Sequential(
nn.Linear(d_model, d_model * 4),
nn.GELU(),
nn.Linear(d_model * 4, d_model)
)
self.norm2 = nn.LayerNorm(d_model)
def forward(self, x):
# x: (seq_len, batch, d_model)
attn_out, _ = self.attention(x, x, x)
x = self.norm1(x + attn_out)
ffn_out = self.ffn(x)
x = self.norm2(x + ffn_out)
return x
我的建议:如果你的数据量超过1万条,可以试试Transformer。否则,老老实实用EEGNet或ShallowConvNet。别问我怎么知道的——都是泪的教训。
4.5 模型选择决策流程
说了这么多,到底该选哪个?我画了一张流程图,帮你快速决策:
这张图是我在实际项目中总结出来的经验。说白了,没有最好的模型,只有最合适的模型。你想想看,如果数据量只有几百条,硬上Transformer,那不是自找麻烦吗?
4.6 实战建议
最后,我给出几条实战建议:
- 从EEGNet开始:不管什么任务,先用EEGNet跑个baseline。它训练快、调参简单,能帮你快速验证数据质量。
- 数据增强是王道:EEG数据太少了。我常用的增强方法有:加噪声、时间偏移、通道随机丢弃。效果立竿见影。
- 迁移学习:如果你有公开数据集(比如BCI Competition IV),可以先在上面预训练,再微调到你的数据上。我试过,准确率能提升5-10%。
- 别迷信Transformer:它确实强,但前提是你有足够的数据和算力。否则,CNN依然是EEG领域最可靠的选择。
总结一句话:EEGNet保底,ShallowConvNet进阶,DeepConvNet冲高,Transformer尝鲜。按这个顺序来,准没错。