3 · 卷积计算原理
卷积操作,说白了就是让一个“小窗口”在输入数据上滑动,每次做一次点乘求和。你想想看,这跟图像处理里的滤波其实是一个道理。我刚开始接触卷积时,总觉得它跟全连接层比有点“绕”,但后来在NPU上做加速才发现——卷积天生就是为并行而生的。
3.1 卷积操作的本质
卷积核(也叫滤波器)是一组可学习的权重。它每次覆盖输入的一个局部区域,然后计算加权和,再加上偏置。这个操作能提取局部特征,比如边缘、纹理、角点。
举个例子,一个 3×3 的卷积核在 32×32 的图上滑动,步长为1,无填充,输出就是 30×30。我习惯把卷积核想象成一个“特征探测器”——每个核只关注一个小邻域。
在NPU里,卷积会被拆成矩阵乘或者直接走脉动阵列。我记得第一次在RTL里看卷积的数据流,发现数据复用是性能的关键。你想想看,如果每次滑动都重新从DRAM读数据,那带宽根本扛不住。
3.2 步长与填充
步长(stride) 控制卷积核每次移动的像素数。步长越大,输出尺寸越小,计算量也越低。但步长太大会丢失空间信息,这个要权衡。
填充(padding) 是在输入周围补零,目的是控制输出尺寸,或者保留边缘信息。常用的有“valid”(不填充)和“same”(填充后输出尺寸与输入相同)。
| 参数 | 作用 | 典型值 |
|---|---|---|
| 步长 (stride) | 每次滑动的像素数 | 1, 2 |
| 填充 (padding) | 输入边缘补零的圈数 | 0, 1, 'same' |
| 输出尺寸公式 | (W - K + 2P)/S + 1 | W:输入宽, K:核大小, P:填充, S:步长 |
3.3 池化层的作用
池化层本质上是一个下采样操作。它没有可学习参数,只是取一个窗口内的最大值(最大池化)或平均值(平均池化)。
- 最大池化: 保留最显著的特征,对纹理、边缘更敏感。我一般在分类网络里用它。
- 平均池化: 保留整体分布,适合平滑特征。在最后的全局平均池化里很常见。
池化层能减少特征图尺寸,降低计算量,还能提供一定的平移不变性。但注意,现在很多网络用步长卷积代替池化,因为可学习的下采样往往效果更好。我个人习惯在轻量级模型里保留池化,毕竟NPU对池化有专门的硬件加速,延迟很低。
3.4 经典卷积网络结构
聊几个我实际部署过的经典结构,它们都深刻影响了NPU的算子设计。
- LeNet-5:卷积+池化+全连接的开山之作。手写数字识别的鼻祖,结构简单,适合验证NPU的卷积流水线。
- AlexNet:引入了ReLU和Dropout,用了更大的卷积核(11×11)。我记得第一次在NPU上跑AlexNet,发现大卷积核的访存局部性很差,后来做了权重重排才把吞吐提上去。
- VGGNet:全部用3×3小卷积核堆叠。小核在NPU上特别友好,因为可以高效利用脉动阵列,数据复用率高。
- ResNet:残差连接(跳跃连接)解决了深层网络退化问题。在NPU上实现时,需要额外处理特征图相加的路径,不过现代NPU基本都原生支持残差融合。
嗯,到这里你应该对卷积的底层逻辑有个清晰的画面了。从本质到参数,再到经典网络,其实都围绕一个核心——如何高效地提取空间特征。在NPU上,这些操作会被映射成并行的数据流,我们后面几章会深入硬件视角。