Convolution
卷积会将一个小型权重核滑过输入,生成特征图,这是 CNN 的核心操作。介绍步幅、填充和各种变体。
卷积是指将一个称为核或滤波器的小型权重网格在输入上滑动,并在每个位置计算加权和。在计算机视觉 (CV)中,输入可以是图像或一组特征图,每个卷积核都会生成一张输出图;只要某处出现了对应模式——垂直边缘、纹理块,或是网络深层中的车轮或人脸的一部分——输出图在该处的值就会较高。图像处理长期使用手工设计的卷积核来模糊、锐化和检测边缘。在卷积神经网络 (CNN)中,卷积核的值是训练过程中学到的模型权重,因此网络能够发现自己的特征检测器。
卷积的工作原理#
在每个位置,卷积核都会覆盖输入的一个局部区域;每个卷积核权重与其下方的输入值相乘,再将乘积求和并加上偏置,得到一个输出值。卷积核遍历输入的整个高和宽后,就会生成二维输出图。实际输入有多个通道,例如图像的红、绿、蓝通道,因此每个卷积核都会覆盖所有输入通道:作用于 64 通道输入的 3×3 卷积核包含 3 × 3 × 64 = 576 个权重,但仍只生成一个输出通道。卷积层会应用多个这样的卷积核,卷积核的数量决定输出通道数,因此,将 64 个通道映射到 128 个通道的 3×3 卷积层包含 3 × 3 × 64 × 128 = 73,728 个权重。
同一个卷积核会在每个位置重复使用,因此卷积层所需的参数远少于全连接层,而且在图像某个角落学到的模式也能在其他位置识别出来。输入发生平移时,输出也会平移相同的距离,这一性质称为平移等变性。每个输出值只取决于输入的一个小邻域;堆叠多个层后,深层输出所概括的感受野会逐渐扩大,从几个像素扩展到图像的大部分区域。
深度学习库实际上计算的是互相关:数学上的卷积会在滑动卷积核前将其翻转,而 PyTorch 的 Conv2d不会。由于卷积核是学习得到的,网络只需学习翻转后的权重,因此实际应用中两者可以互换。GPU库(例如 cuDNN)通常会将卷积重新表示为大型矩阵乘法,或使用 Winograd 或基于 FFT 的算法,以比直接滑动卷积核更快的速度计算相同结果。
步幅、填充、膨胀和分组#
有四个超参数会影响卷积输出的形状和计算成本:
- 步幅:卷积核每次移动的距离。步幅为 2 时会跳过每隔一个的位置,使输出的高和宽减半;许多现代 CNN 都通过这种方式进行下采样。
- 填充:在输入边缘周围添加的额外值,通常为零。步幅为 1 时,填充 1 可使 3×3 卷积的输出大小与输入相同。
- 膨胀:拉开卷积核采样点之间的间隔,因此膨胀率为 2 的 3×3 卷积核可以覆盖 5×5 的区域,同时仍只使用九个权重,以零额外成本扩大感受野。
- 分组:将通道拆分为互相独立的组。每个通道单独成组时,深度卷积会分别对每个通道进行滤波,后续的 1×1 逐点卷积再混合这些通道;这对操作称为深度可分离卷积,MobileNets让它在移动硬件上广泛流行。
对于大小为 n 的输入、大小为 k 的卷积核、填充 p、步幅 s 和膨胀率 d,输出大小为 ⌊(n + 2p − d(k − 1) − 1) / s⌋ + 1。下面的代码片段应用四个卷积层,每层都将 64 通道、80×80 的特征图映射为 128 个通道:
import torch
from torch import nn
x = torch.randn(1, 64, 80, 80) # a 64-channel, 80x80 feature map
# Four ways to map 64 input channels to 128 output channels
layers = {
"standard 3x3": nn.Conv2d(64, 128, kernel_size=3, padding=1, bias=False),
"stride 2": nn.Conv2d(64, 128, kernel_size=3, stride=2, padding=1, bias=False),
"dilation 2": nn.Conv2d(64, 128, kernel_size=3, padding=2, dilation=2, bias=False),
"depthwise separable": nn.Sequential(
nn.Conv2d(64, 64, kernel_size=3, padding=1, groups=64, bias=False), # one 3x3 filter per channel
nn.Conv2d(64, 128, kernel_size=1, bias=False), # 1x1 convolution mixes channels
),
}
for name, layer in layers.items():
params = sum(p.numel() for p in layer.parameters())
print(f"{name}: output {tuple(layer(x).shape)}, {params:,} weights")标准层输出 (1, 128, 80, 80),包含 73,728 个权重。步幅为 2 时,输出缩小为 (1, 128, 40, 40),权重数量不变;膨胀率为 2 时,输出仍为 80×80,且包含 73,728 个权重,但每个输出值对应 5×5 的区域。深度可分离卷积对只用 8,768 个权重,就能产生相同的 (1, 128, 80, 80) 输出,权重数量约减少 8.4 倍。YOLO26采用了这两种思路:五个步幅为 2 的 3×3 卷积会将 640×640 图像缩小为 20×20 网格,对应最深层的骨干网络特征图;其检测头的分类分支则将深度 3×3 卷积与逐点 1×1 卷积配对,以减少计算量。
其他维度中的卷积#
- 一维卷积:沿单个轴滑动,适用于音频波形、传感器信号和时间序列。
- 三维卷积:增加深度或时间轴,适用于视频片段以及医学图像分析中的 CT 和 MRI 等体积扫描。
- 转置卷积:将每个输入值扩展到更大的输出中,为 U-Net 等分割模型中的特征图上采样。它使用自己学习到的权重,恢复被步幅卷积缩小的空间尺寸。










