第二节 卷积运算的数学原理

各位同学,今天我们来聊聊卷积运算最核心的数学原理。说实话,很多做硬件加速的同学,一上来就撸代码、搭电路,结果连输入输出尺寸怎么算都搞不清楚。我当年刚入行时也犯过这个错——有一次设计一个加速器,算错了输出特征图的尺寸,导致整个数据流都乱了,改了两版才搞定。

所以这节课,咱们把基础打扎实。你想想看,卷积运算说白了就是四个要素:输入特征图、卷积核、步长、填充。搞懂它们之间的关系,后面的硬件设计才能顺风顺水。

2.1 输入特征图

输入特征图,就是我们要处理的数据。在卷积神经网络里,它通常是一个三维的张量。

举个例子,一张彩色图片输入到网络中,它的维度是:

  • 高度 H:图片的行数
  • 宽度 W:图片的列数
  • 通道数 C:RGB 三个通道,所以 C=3

我习惯用 (H, W, C) 来表示。比如一个 224×224 的彩色图,就是 (224, 224, 3)。

个人经验:在硬件设计时,我建议把输入特征图的尺寸固定成 2 的幂次,比如 224 虽然不规整,但实际加速器里往往会做 padding 对齐。这样做地址计算会简单很多。

2.2 卷积核

卷积核,也叫滤波器。它就是一个小的权重矩阵,在输入图上滑动做点积运算。

卷积核也有三个维度:

  • 核高度 K_h:比如 3、5、7
  • 核宽度 K_w:通常和高度相等,比如 3×3
  • 输入通道数 C_in:必须和输入特征图的通道数一致

另外,每个卷积层会有多个卷积核,数量就是输出通道数 C_out。

举个例子,一个 3×3 的卷积层,输入 64 通道,输出 128 通道。那么卷积核的维度就是 (3, 3, 64, 128)。嗯,这里要注意,最后一个维度是输出通道数。

核心公式:每个输出通道对应一组卷积核,这组卷积核的个数等于输入通道数。

2.3 步长

步长,就是卷积核每次滑动的步数。用 S 表示。

步长 = 1 时,卷积核一个像素一个像素地挪。步长 = 2 时,每次跳两个像素。说白了,步长越大,输出特征图越小。

我在项目中遇到过一个问题:步长设得太大,导致输出尺寸太小,丢失了很多空间信息。后来我们一般用步长 1 或 2,很少用更大的。

2.4 填充

填充,就是在输入特征图的边缘补一圈数据。用 P 表示填充的层数。

为什么要填充?两个原因:

  1. 保持尺寸:如果不填充,卷积后输出会变小。比如 5×5 的图,用 3×3 的核,步长 1,输出只有 3×3。
  2. 利用边缘信息:边缘的像素被卷积的次数少,填充后边缘信息也能被充分提取。

常见的填充方式有两种:

  • Valid 卷积:不填充,P=0
  • Same 卷积:填充后输出尺寸和输入相同,P = (K-1)/2
避坑指南:我曾经在设计一个加速器时,忽略了填充对数据流的影响。结果发现,填充后的边界像素需要特殊处理,否则地址会越界。所以硬件设计时,一定要把填充逻辑单独拎出来考虑。

2.5 输出特征图的计算

好了,前面四个要素都讲完了。现在来看最关键的——输出特征图怎么算?

公式其实很简单:

输出高度 H_out = floor((H_in + 2P - K_h) / S) + 1
输出宽度 W_out = floor((W_in + 2P - K_w) / S) + 1
输出通道数 C_out = 卷积核的个数

举个例子:

  • 输入:32×32×3
  • 卷积核:5×5,6 个
  • 步长:1
  • 填充:2

计算一下:

H_out = floor((32 + 2×2 - 5) / 1) + 1 = floor(31) + 1 = 32
W_out = floor((32 + 2×2 - 5) / 1) + 1 = 32
C_out = 6

输出就是 32×32×6。你看,用了 Same 卷积,尺寸没变。

再举一个步长为 2 的例子:

  • 输入:64×64×3
  • 卷积核:3×3,16 个
  • 步长:2
  • 填充:0(Valid 卷积)
H_out = floor((64 + 0 - 3) / 2) + 1 = floor(61/2) + 1 = 30 + 1 = 31
W_out = 31
C_out = 16

输出就是 31×31×16。尺寸缩小了一半左右。

硬件设计小技巧:我建议在 RTL 设计时,把输出尺寸的计算做成参数化的。这样换网络结构时,只需要改几个参数,不用重新写地址生成逻辑。

2.6 知识体系总览

下面我用一张图来总结卷积运算的核心逻辑。这张图是我自己画的,把输入、卷积核、步长、填充、输出之间的关系都串起来了。

输入特征图 (H, W, C) 卷积核 (K_h, K_w, C) 步长 S 填充 P 输出特征图 (H_out, W_out, C_out) 卷积运算 点积 + 累加 输出尺寸公式 H_out = floor((H + 2P - K_h) / S) + 1 W_out = floor((W + 2P - K_w) / S) + 1 C_out = 卷积核个数

这张图把整个流程串起来了。你想想看,输入特征图经过填充后,和卷积核做点积运算,步长控制着滑动间隔,最终得到输出特征图。说白了,就是一套数学公式在驱动。

2.7 实际项目中的注意事项

最后,我分享几个在实际项目中踩过的坑:

  • 边界条件:当输入尺寸不是步长的整数倍时,floor 操作会导致最后一行/列被丢弃。硬件设计时一定要考虑这种情况。
  • 填充的硬件开销:填充意味着要多存几行数据。如果填充很大,片上缓存会吃紧。我一般建议用 Same 卷积,P 不超过 2。
  • 多通道的累加:每个输出像素是多个输入通道的累加结果。在硬件里,这个累加器要设计得足够宽,防止溢出。
总结一下:卷积运算的数学原理并不复杂,但它是硬件设计的基石。搞懂了输入、卷积核、步长、填充、输出之间的关系,你就能设计出正确的数据通路和地址生成逻辑。

好了,这节课就到这里。记住,公式要烂熟于心,硬件设计才能游刃有余。