2. 卷积运算原理:从数学定义到硬件实现

各位同学,今天我们来聊聊卷积运算的核心原理。说实话,这章内容我讲了不下几十遍,但每次备课还是会想起自己刚入行时踩过的坑。嗯,咱们先从最基础的2D卷积说起。

2.1 2D卷积的数学定义

2D卷积,说白了就是用一个小的窗口(我们叫它卷积核)在输入图像上滑动,每次做一次点乘求和。数学上可以写成:

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

这里m和n是卷积核的尺寸索引。举个例子,一个3×3的卷积核,m和n都是从0到2。

我个人习惯把卷积理解为“加权求和”。每个输出像素,都是它周围邻域像素的加权平均——权重就是卷积核里的数值。我在做第一个CNN加速器项目时,就是靠这个直觉来设计数据流架构的。

关键点:卷积核的每个权重,决定了输入像素对输出的贡献程度。比如边缘检测核,中间权重高、周围权重低,就能突出边缘。

2.2 步长与填充:控制输出尺寸的两个旋钮

你想想看,如果卷积核每次只移动1个像素,输出特征图会比输入小一圈。那如果我想让输出和输入一样大呢?或者想快速缩小特征图呢?这时候就需要步长和填充了。

步长(Stride)

步长就是卷积核每次滑动的像素数。步长=1时,输出密集;步长=2时,输出直接减半。我在设计一个实时目标检测加速器时,就用了步长=2的卷积来替代池化层,省掉了一个硬件模块。

输出尺寸计算公式:

输出尺寸 = floor((输入尺寸 - 卷积核尺寸 + 2 × 填充) / 步长) + 1

填充(Padding)

填充就是在输入图像周围补一圈0。最常见的两种:

  • Valid卷积:不填充,输出比输入小
  • Same卷积:填充到输出和输入一样大

避坑指南:我曾经在项目里忘记考虑填充对数据流的影响,结果DMA读地址算错了,整整调了两天。记住:填充的0不需要从DDR读取,但你的地址生成器必须跳过这些位置。

2.3 多通道卷积:从单层到立体

前面讲的都是单通道输入、单卷积核。但实际CNN里,输入通常是RGB三通道,中间层更是成百上千个通道。多通道卷积怎么算?

说白了:每个输出通道对应一组卷积核,这组卷积核的深度等于输入通道数。每个卷积核在对应输入通道上做2D卷积,然后把所有通道的结果加起来。

输出通道k的像素(i,j) = Σ_c Σ_m Σ_n 输入通道c(i+m, j+n) × 卷积核k的通道c(m, n)

这里c是输入通道索引,k是输出通道索引。你看,多了一个维度,计算量直接翻倍。

我记得有一次优化一个16层CNN的加速器,发现多通道卷积的累加树设计特别关键。如果每个通道单独累加再求和,硬件面积会很大。后来我改用逐通道流水线累加,面积省了30%。

硬件视角:多通道卷积的本质是三维卷积——空间维度(H×W)和通道维度(C)。在硬件里,空间维度适合用脉动阵列并行,通道维度适合用累加树串行。

2.4 卷积的计算复杂度分析

做硬件加速,第一件事就是算清楚计算量。不然你设计出来的架构要么跑不满,要么面积爆炸。

对于一个卷积层:

  • 输入尺寸:H × W × C_in
  • 卷积核尺寸:K × K
  • 输出通道数:C_out
  • 输出尺寸:H_out × W_out

总乘法次数 = H_out × W_out × C_out × C_in × K × K

举个例子:一个224×224的输入,3通道,用64个3×3卷积核,步长=1,填充=1。输出也是224×224×64。计算量:

224 × 224 × 64 × 3 × 3 × 3 ≈ 86.7M 次乘法

嗯,8600万次乘法。这还只是一层。VGG16有13个卷积层,总计算量超过150亿次。你想想看,在嵌入式设备上跑这个,没有硬件加速根本不可能。

注意:计算复杂度分析时,千万别忘了考虑数据复用。我在一个项目里只算了乘法次数,没考虑数据搬运的能耗,结果实际功耗比预期高了40%。卷积的能耗大头往往在数据搬运,而不是计算本身。

2.5 硬件设计中的几个关键考量

基于上面的分析,我在设计卷积加速器时,会重点关注以下几点:

  1. 数据复用策略:输入特征图、卷积核、部分和,这三者哪个复用次数多,就优先把它放在片上缓存。
  2. 并行度选择:空间维度并行还是通道维度并行?我一般建议先做通道并行,因为通道间数据独立,控制逻辑简单。
  3. 填充处理:填充的0不需要存储,但地址生成器要能跳过边界。我习惯用状态机来处理边界情况。
  4. 步长实现:步长>1时,数据读取要跳着读。可以用一个计数器来控制读地址的步进。

个人经验:刚开始做卷积加速器时,别想着一次把所有优化都做全。先实现一个基础版本,跑通功能,再逐步加优化。我第一个卷积加速器只支持3×3核、步长1,后来才慢慢扩展到支持任意尺寸。

好了,这一章的内容就到这里。卷积运算原理是硬件加速的基石,把这些搞清楚了,后面讲脉动阵列、数据流优化时你才能跟得上。下一章我们聊聊卷积的硬件加速架构设计。