第4章:卷积神经网络(CNN)——从原理到经典架构

各位同学,今天我们来聊聊卷积神经网络。说实话,CNN 这个概念在我刚入行那会儿还是个新鲜玩意儿。记得 2012 年 AlexNet 在 ImageNet 上大杀四方的时候,我还在用传统方法做脑电信号分类,准确率死活上不去。后来一咬牙把 CNN 搬过来,效果直接翻倍。嗯,从那以后我就再也没放下过它。

4.1 卷积层原理——到底在卷什么?

卷积层,说白了就是用一个「小窗口」在输入数据上滑动,提取局部特征。你想想看,我们看一张图片,是不是先看局部细节,再看整体?卷积层做的就是这件事。

数学上,卷积操作就是:

输出特征图(i, j) = Σ_m Σ_n 输入(i+m, j+n) × 卷积核(m, n) + 偏置

但别被公式吓到。我习惯这么理解:卷积核就像是一个「特征探测器」。比如一个 3×3 的核,专门检测边缘。如果输入图像某个区域有垂直边缘,卷积结果就会很大。反之,没有边缘的地方,结果接近零。

关键参数:

  • 卷积核大小(Kernel Size):常用 3×3、5×5。我个人偏好 3×3,因为堆叠两个 3×3 的感受野等于一个 5×5,但参数量更少。
  • 步长(Stride):每次滑动的像素数。步长越大,输出越小。
  • 填充(Padding):在输入边缘补零,保持输出尺寸。我常用「same padding」让输入输出尺寸一致。

我在处理神经信号时遇到过一个问题:EEG 信号是 1D 时间序列,但 CNN 通常处理 2D 图像。怎么办?我当时的做法是把多通道 EEG 排成 2D 矩阵,时间轴作为宽度,通道数作为高度。效果出奇的好。说白了,卷积核不在乎你输入是图像还是信号,它只关心局部模式。

4.2 池化层——降维的艺术

池化层,我更喜欢叫它「下采样层」。它的作用很简单:缩小特征图尺寸,保留最重要的信息。

最常见的两种池化:

  • 最大池化(Max Pooling):取窗口内的最大值。我一般用 2×2 窗口,步长 2,输出尺寸直接减半。
  • 平均池化(Average Pooling):取窗口内的平均值。现在用得少了,但早期 LeNet 里用过。

我的经验:在神经信号分析中,最大池化往往比平均池化效果好。因为脑电信号的尖峰(spike)往往包含关键信息,最大池化能保留这些峰值。平均池化反而会把尖峰抹平。

为什么会需要池化?你想想看,卷积层输出的特征图可能很大,直接连全连接层,参数量会爆炸。池化层就像是一个「信息过滤器」,只保留最显著的特征。我曾经在项目中试过不用池化,结果模型参数量翻了 10 倍,训练时间长了 3 倍,准确率反而没提升。嗯,从那以后我再也不省池化层了。

4.3 感受野——神经元在看多大范围?

感受野这个概念,我刚开始学的时候觉得挺玄乎。说白了,就是输出特征图上的一个点,对应输入图像上的多大区域。

计算公式很简单:

RF_out = RF_in + (Kernel_size - 1) × Stride

举个例子:一个 3×3 卷积,步长 1,第一层感受野就是 3×3。再叠一层 3×3 卷积,感受野变成 5×5。再叠一层,变成 7×7。

避坑指南:我曾经犯过一个错误——以为堆叠更多卷积层就能无限扩大感受野。实际上,感受野增长是线性的,而参数量增长是平方的。所以别盲目堆层,要考虑计算成本。

在神经信号分析中,感受野对应的是时间窗口。比如你的 CNN 第一层感受野是 100ms,那它只能看到 100ms 内的信号模式。如果你想检测更长的节律(比如 alpha 波 8-12Hz,周期约 100ms),感受野至少要覆盖一个完整周期。我一般会先算好目标信号的周期,再设计网络深度。

4.4 经典架构——从 LeNet 到 VGG

这部分我直接画了一张图,帮你理清脉络:

LeNet-5 (1998) 输入: 32×32 灰度图 C1: 6@28×28 (5×5) S2: 6@14×14 (2×2 avg) C3: 16@10×10 (5×5) S4: 16@5×5 (2×2 avg) C5: 120@1×1 (5×5) F6: 84 → 输出: 10 特点: 手写数字识别 AlexNet (2012) 输入: 227×227 RGB Conv1: 96@55×55 (11×11, s4) MaxPool1: 96@27×27 (3×3, s2) Conv2: 256@13×13 (5×5) Conv3-5: 384→384→256 FC: 4096→4096→1000 特点: ReLU + Dropout + GPU VGG16 (2014) 输入: 224×224 RGB Block1: 64@224×224 (3×3×2) Block2: 128@112×112 (3×3×2) Block3: 256@56×56 (3×3×3) Block4: 512@28×28 (3×3×3) Block5: 512@14×14 (3×3×3) FC: 4096→4096→1000 特点: 全部3×3卷积, 深度16层

4.4.1 LeNet-5——祖师爷级别的架构

LeNet-5 是 Yann LeCun 在 1998 年提出的,用于手写数字识别。说实话,现在看来它很简单,但当年可是革命性的。

它的结构很清晰:卷积→池化→卷积→池化→全连接。我刚开始学 CNN 时,就是拿 LeNet 练手的。用 MNIST 数据集,从零实现,跑通的那一刻,那种成就感,嗯,至今难忘。

LeNet-5 的关键设计:

  • 输入 32×32 灰度图,比 MNIST 的 28×28 大一圈,为了容纳边缘特征
  • 使用平均池化(现在很少用了)
  • 最后用 RBF 层(径向基函数)做分类,现在基本被 Softmax 取代

4.4.2 AlexNet——深度学习爆发的导火索

2012 年,Alex Krizhevsky 带着 AlexNet 在 ImageNet 上夺冠,错误率直接比第二名低了 10 个百分点。我当时看到这个结果,第一反应是「不可能吧?」。后来自己复现了一遍,才服气。

AlexNet 相比 LeNet 的改进:

  • ReLU 激活函数:解决了梯度消失问题。我之前用 sigmoid 训练深层网络,梯度传到前面几层基本为零。换成 ReLU 后,训练速度快了 6 倍。
  • Dropout:随机丢弃神经元,防止过拟合。我习惯设 0.5,效果不错。
  • 数据增强:随机裁剪、翻转、颜色变换。在神经信号领域,我常用加噪声、时间偏移来做增强。
  • GPU 并行:用两块 GTX 580 训练了 6 天。现在想想,那时候的算力真是可怜。

我的经验:AlexNet 的 11×11 大卷积核在神经信号分析中不太适用。因为 EEG 信号的时间分辨率高,大卷积核会丢失精细的时间结构。我一般用 3×3 或 5×5 的核,堆叠多层来扩大感受野。

4.4.3 VGG——深度才是王道

VGG 是牛津大学 Visual Geometry Group 在 2014 年提出的。它的核心理念很简单:全部用 3×3 卷积,堆得越深越好。

VGG16 有 16 层可学习参数(13 层卷积 + 3 层全连接),VGG19 有 19 层。为什么全部用 3×3?

  • 两个 3×3 堆叠,感受野等于 5×5,但参数量更少(2×3×3=18 vs 5×5=25)
  • 三个 3×3 堆叠,感受野等于 7×7,参数量更少(3×3×3=27 vs 7×7=49)
  • 更多的非线性层,表达能力更强

避坑指南:我曾经在项目中直接套用 VGG16 处理 1D 神经信号,结果模型太大,训练时间太长,还过拟合。后来我把全连接层换成全局平均池化,参数量从 1.2 亿降到 1500 万,效果反而更好。所以,别盲目搬架构,要根据数据特点调整。

VGG 的另一个特点是结构规整。每个 block 的卷积核数量都是 2 的幂次:64→128→256→512。这种设计方便 GPU 并行计算。我在设计自己的网络时,也沿用了这个习惯。

4.5 在神经信号分析中的应用

说了这么多,CNN 在神经信号分析中到底怎么用?我分享几个实际案例:

任务 输入形式 网络设计 我的经验
EEG 情绪识别 62通道×1000时间点 3层Conv1D + 2层FC 卷积核大小设为 50ms 对应的时间点
运动想象分类 22通道×500时间点 2层Conv2D + 全局平均池化 把通道和时间作为 2D 输入
睡眠分期 单通道×3000时间点 5层ResNet 风格 用残差连接防止梯度消失

嗯,CNN 这部分内容确实不少。从卷积层原理到池化层,从感受野到经典架构,每一步都有它的设计哲学。我个人觉得,理解这些原理比背代码重要得多。你想想看,如果你知道为什么 VGG 要用 3×3 卷积,为什么 LeNet 用平均池化而 AlexNet 用最大池化,那你设计自己的网络时就能游刃有余。

最后说一句:别怕动手。我当年学 CNN 时,把 LeNet、AlexNet、VGG 都手写了一遍,虽然代码写得丑,但每个细节都刻在脑子里了。你也试试看?


专注资料整理