FA_CNN卷积神经网络二十七---填充与步幅PyTorch

FA :Formula and Algorithm,CNN:Convolution Netural Network

1. 引言

在卷积神经网络中,卷积核大小(kernel size)决定了感受野,而**填充(padding)与步幅(stride)**则决定了卷积输出特征图的空间尺寸。合理设置这两个超参数,既能控制输出分辨率,也能影响计算量与信息保留程度。

本文先讲清填充与步幅的原理,再给出基于 PyTorch 的完整代码示例,帮助读者快速验证输出形状。

2. 填充(Padding)

2.1 为什么需要填充

如果不做填充,每次卷积都会让特征图变小。以输入尺寸 nh×nwn_h \times n_wnh×nw、卷积核 kh×kwk_h \times k_wkh×kw 为例,输出尺寸为:

(nh−kh+1)×(nw−kw+1) (n_h - k_h + 1) \times (n_w - k_w + 1) (nh−kh+1)×(nw−kw+1)

为了让卷积后的图像大小与原图保持一致,通常会在输入四周补零,这就是填充。

2.2 输出尺寸公式

设高度方向填充 php_hph 行、宽度方向填充 pwp_wpw 列,则输出形状为:

(nh−kh+ph+1)×(nw−kw+pw+1) (n_h - k_h + p_h + 1) \times (n_w - k_w + p_w + 1) (nh−kh+ph+1)×(nw−kw+pw+1)

当 ph=kh−1p_h = k_h - 1ph=kh−1、pw=kw−1p_w = k_w - 1pw=kw−1 时,输出尺寸与输入完全相同。

2.3 为什么卷积核多为奇数

实践中卷积核大小几乎都取奇数(3×3、5×5),原因有两点:

  • 便于对称填充 :假设卷积核大小为 k×kk \times kk×k,为了让输出与原图同尺寸,需要 p=(k−1)/2p = (k-1)/2p=(k−1)/2。只有当 kkk 为奇数时,ppp 才是整数,可以在上下(左右)对称地填充。
  • 有明确的中心像素:奇数卷积核存在唯一的中心位置,便于描述以该像素为中心的邻域。

当 kkk 为偶数时,p=(k−1)/2p = (k-1)/2p=(k−1)/2 为浮点数,只能一侧向上取整、另一侧向下取整,即上下(左右)填充数量不对称,实现上不够优雅。

3. 步幅(Stride)

步幅指卷积核在输入上滑动的步长。设高度步幅为 shs_hsh、宽度步幅为 sws_wsw,则输出形状为:

⌊nh−kh+ph+shsh⌋×⌊nw−kw+pw+swsw⌋ \left\lfloor \frac{n_h - k_h + p_h + s_h}{s_h} \right\rfloor \times \left\lfloor \frac{n_w - k_w + p_w + s_w}{s_w} \right\rfloor ⌊shnh−kh+ph+sh⌋×⌊swnw−kw+pw+sw⌋

直观理解:

  • 步幅为 1:卷积核逐像素滑动,输出分辨率较高,计算量较大。
  • 步幅大于 1:卷积核跳跃式滑动,输出尺寸成比例缩小,相当于在卷积中同时完成下采样,可替代部分池化操作。

4. 代码实践:使用 PyTorch 框架

下面通过一个辅助函数 comp_conv2d 统一验证不同参数下的输出形状。该函数在输入前补上批量大小与通道数两个维度,卷积后再去掉,便于直接观察二维结果。

python 复制代码
import torch
from torch import nn


def comp_conv2d(conv2d, X):
    # conv2d 作为传参传进去,在内部使用
    X = X.reshape((1, 1) + X.shape)  # 在维度前面加入通道数和批量大小
    Y = conv2d(X)                    # 卷积处理是一个四维的矩阵
    return Y.reshape(Y.shape[2:])    # 将前面两个维度拿掉


X = torch.rand(size=(8, 8))

# 1) 在所有侧边填充 1 个像素,输出尺寸不变
conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1)
print(comp_conv2d(conv2d, X).shape)

# 2) 高度填充 2 行、宽度填充 1 列,卷积核 5×3,输出尺寸不变
conv2d = nn.Conv2d(1, 1, kernel_size=(5, 3), padding=(2, 1))
print(comp_conv2d(conv2d, X).shape)

# 3) 将高度和宽度的步幅都设置为 2
conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride=2)
print(comp_conv2d(conv2d, X).shape)

# 4) 一个稍微复杂的例子:卷积核 3×5,填充 (0,1),步幅 (3,4)
conv2d = nn.Conv2d(1, 1, kernel_size=(3, 5), padding=(0, 1), stride=(3, 4))
print(comp_conv2d(conv2d, X).shape)

运行结果:

text 复制代码
torch.Size([8, 8])
torch.Size([8, 8])
torch.Size([4, 4])
torch.Size([2, 2])

4.1 结果解读

场景 卷积核 填充 步幅 输出形状
同尺寸卷积 3×3 (1,1) (1,1) 8×8
非方形核同尺寸 5×3 (2,1) (1,1) 8×8
步幅下采样 3×3 (1,1) (2,2) 4×4
复杂组合 3×5 (0,1) (3,4) 2×2

以第 4 个例子验证公式:高度方向 ⌊(8−3+0+3)/3⌋=2\lfloor (8 - 3 + 0 + 3) / 3 \rfloor = 2⌊(8−3+0+3)/3⌋=2,宽度方向 ⌊(8−5+1+4)/4⌋=2\lfloor (8 - 5 + 1 + 4) / 4 \rfloor = 2⌊(8−5+1+4)/4⌋=2,与输出 2×2 一致。

5. 总结

  • 填充 用于控制输出尺寸,p=(k−1)/2p = (k-1)/2p=(k−1)/2 时输出与输入同尺寸;这也是卷积核普遍取奇数的原因。
  • 步幅用于成倍缩小输出尺寸,可替代池化完成下采样。
  • 二者可以分别对高度和宽度独立设置,PyTorch 中通过 padding=(p_h, p_w)、stride=(s_h, s_w) 传入元组即可。
  • 记住输出尺寸公式,就能在搭建网络时快速推算每一层的特征图大小,避免维度不匹配的问题。






相关推荐
CyrusYiVPP13 分钟前
哪个用户会再来买?RFM模型+plotly画出用户分层,数据分析实战第2期
人工智能·python
AI源码21 分钟前
基于深度学习的热带水果检测系统设计与实现
人工智能·深度学习
AGI_Eval23 分钟前
AI 3D生成技术:从“可用”走向“可靠”还有多远?
人工智能·3d
程序员cxuan24 分钟前
LobeHub 是真的夯,简直 Super-Agent 最佳实现。
人工智能·后端·程序员
QXWZ_IA30 分钟前
高楼遮挡RTK失锁:三层安全网怎么搭
人工智能·安全
sun8612207742 分钟前
Hy4 Preview 高效预览与协作应用指南
人工智能
码云之上1 小时前
10 颗一模一样的「Edit」:中后台 Web Agent 怎么找到对的那一行
前端·人工智能·浏览器
阿里云大数据AI技术1 小时前
EMR Serverless Ray:让 AI 推理融入数据处理
人工智能·spark
TDengine (老段)1 小时前
TDengine IDMP 十大实用功能(9)
大数据·数据库·人工智能·物联网·时序数据库·tdengine·idmp