🧱 新所得库 - 深度卷积网络中的 Padding 与 Stride 精讲实战

📘 本文对应李沐《动手学深度学习》7.3 节内容,讲解 CNN 中控制特征图尺寸变化的两个关键技术:Padding(填充)与 Stride(步幅)。


7.3 Padding 和 Stride

在图像卷积过程中,如果每次卷积核都从左上角出发逐像素滑动,那么输出的尺寸会逐层缩小。当堆叠多个卷积层后,图像的边缘信息可能彻底丢失。因此,我们需要引入两种控制输出尺寸的机制:

  • Padding(填充):扩展输入边界,防止尺寸过早缩小;

  • Stride(步幅):跳跃滑动窗口,控制压缩率,降低计算成本。


7.3.1 填充(Padding)

在标准卷积中,输入图像的边缘像素因无法被完全覆盖,往往被忽略,导致“像素利用率”变差,如图所示:

🖼️ 图 7.3.1:不同卷积核大小对像素利用率的影响。可以看到角落几乎完全无参与。

🔧 解决办法:填充

我们通常通过在图像四周添加 0 像素的边框来扩展尺寸。这一操作被称为 填充(padding)。如下图所示:

🖼️ 图 7.3.2:带填充的二维互相关,填充后输出矩阵尺寸不再缩小。

📐 输出尺寸计算公式:

假设填充高度为 php_h,填充宽度为 pwp_w,卷积核尺寸为 kh×kwk_h \times k_w,输入尺寸为 nh×nwn_h \times n_w,则输出尺寸为:

✅ 常用实践:

  • 使用奇数大小卷积核(如 3×3、5×5)+ 对称填充,可以保持输出尺寸不变;

  • 保持输入输出尺寸一致是图像任务中常见的需求(如语义分割、自动编码器等);

  • PyTorch 中 padding=1 搭配 kernel_size=3 可实现等尺寸输出。

conv2d = nn.LazyConv2d(1, kernel_size=3, padding=1)
X = torch.rand(size=(8, 8))
comp_conv2d(conv2d, X).shape  # 输出为 torch.Size([8, 8])

🎯 更复杂的填充设置:

可为高和宽分别设置不同的填充量:

conv2d = nn.LazyConv2d(1, kernel_size=(5, 3), padding=(2, 1))
comp_conv2d(conv2d, X).shape  # 仍保持为 (8, 8)

🎓 理论理解:

在卷积层中,如果不使用填充,输入图像会在每一层“缩水”。比如一个 5x5 图像经过一次 3x3 卷积后,输出就变为 3x3。

为了防止这种快速压缩,我们会在输入图像的边缘填充像素(通常为 0),扩大输入的“有效区域”。

输出尺寸公式为:

其中 ph,pwp_h, p_wph​,pw​ 是填充高度和宽度。

🏭 企业实战理解:

  • 字节跳动/抖音短视频推荐模型中,使用 padding=1, kernel=3 保证每一层输出尺寸不变,使得模型可以做深度堆叠,尤其用于高分辨率图像内容理解。

  • Google 在 DeepLab V3 语义分割中广泛使用 same padding,保证像素级对齐,提升 mask 的边界精度;

  • NVIDIA 推理优化工具 TensorRT 会根据 padding 自动融合卷积操作,减少内存拷贝,提高推理效率。


7.3.2 步幅(Stride)

默认情况下,卷积窗口每次移动一个像素(stride = 1)。但如果我们每次跨多个像素滑动窗口,会带来两个优势:

  1. 减少计算量;

  2. 缩小特征图尺寸(即下采样效果)。

🖼️ 图 7.3.3:高和宽分别为 3 和 2 的步幅下,卷积窗口跳跃滑动。

📐 输出尺寸计算公式:

当 stride 为 sh×sws_h \times s_w 时,输出尺寸为:

若 stride 恰好整除输入尺寸,则可简化为:

✅ 典型用法:

将特征图尺寸缩小一半:

conv2d = nn.LazyConv2d(1, kernel_size=3, padding=1, stride=2)
comp_conv2d(conv2d, X).shape  # 输出为 torch.Size([4, 4])

设置不对称 stride:

conv2d = nn.LazyConv2d(1, kernel_size=(3, 5), padding=(0, 1), stride=(3, 4))
comp_conv2d(conv2d, X).shape  # 输出为 torch.Size([2, 2])

🎓 理论理解:

Stride 决定卷积窗口每次滑动的距离:

  • 默认 stride=1stride=1stride=1:逐像素滑动;

  • 设置 stride>1stride > 1stride>1:跳着滑动,常用于下采样。

输出尺寸计算公式:

可以看出,stride 越大,输出越小。

🏭 企业实战理解:

  • 百度搜索引擎中使用 stride=2 卷积替代 pooling,进行语义压缩同时保留上下文感知能力;

  • OpenAI 在 GPT-Vision 类 Transformer 模型中 使用嵌入模块基于 stride-4 卷积进行 Patch 提取,减少计算量;

  • NVIDIA 在实时目标检测 YOLOX 中使用 stride=2 提取多尺度特征图,提升小目标检测性能;

  • 字节跳动推荐系统中,对用户点击轨迹做序列卷积时使用 stride=2 加速推理、提取局部行为模式。


7.3.3 小结与讨论

  • Padding 是为保持输出尺寸或防止边界信息丢失而在输入边界添加像素;

  • Stride 控制卷积窗口每次移动的跨度,常用于下采样;

  • 组合使用 padding 和 stride 能实现灵活的特征图尺寸控制;

  • 实际中多使用零填充(zero-padding),因其计算效率高、实现简单;

  • PyTorch、TensorFlow 等框架均支持 kernel、padding、stride 的独立设置。

属性 作用 应用场景
Padding 防止尺寸过早变小,保留边缘 图像语义对齐、语义分割、风格迁移
Stride 控制输出尺寸压缩率 特征下采样、加快计算、减少显存

默认:

  • padding = 0 → 不填充;

  • stride = 1 → 步幅为1。

🚧 关于零填充的讨论:

  • 零填充有明显计算优势,GPU 加速库可以融合 padding + conv;

  • 但某些任务(如图像修复、风格迁移)需要非零填充,如 reflection、replicate;

  • Alsallakh 等人在 2020 年提出更鲁棒的 padding 替代方案,但仍需根据任务性质权衡使用。


7.3.4 练习建议

  1. 理解 kernel=3, padding=1, stride=2 的输出尺寸计算方式;

  2. 推导图中示例代码的输出尺寸是否正确;

  3. 思考音频信号中 stride=2 表示什么(→ 下采样);

  4. 尝试实现镜像填充(reflection padding);

  5. 步幅大于 1 在计算与统计上的潜在优势。


Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐