Conv2d输出尺寸由padding和stride的物理意义决定:padding是每边补零数,stride是卷积核移动步长;公式为⌊(H_in+2p−k)/s⌋+1,需实测验证。

Conv2d 输出尺寸怎么算?别背公式,看懂 padding 和 stride 的物理意义
输出尺寸不是靠死记公式推出来的,而是由卷积核“怎么滑”决定的。关键就两点:stride 控制每次滑多远,padding 决定输入边缘要不要补零。补得少、滑得快,输出就小;补得多、滑得慢,输出就大。
常见错误是把 padding 当成“加几行几列”,其实它是**每边补多少**(比如 padding=1 是上下左右各补 1 行/列);stride 也不是“跳几个像素”,而是**步长单位是 kernel 移动的格子数**,默认为 1 就是挨个移。
- 输入尺寸
H_in × W_in,卷积核大小k,则不考虑 padding 和 stride 时,最大能放下的位置数是H_in - k + 1 -
padding=p后,输入等效变成(H_in + 2p) × (W_in + 2p),再套上滑动逻辑 -
stride=s时,实际可停的位置数是floor((H_in + 2p - k) / s) + 1(向下取整)
padding='same' 在 PyTorch 里不存在?用对称 padding 模拟它
TensorFlow/Keras 里的 padding='same' 意思是让输出尺寸和输入一致(假设 stride=1)。PyTorch 没这个字符串选项,但可以手动算出需要的 padding 值来达到同样效果。
注意:PyTorch 的 Conv2d 只接受整数或 4 元组((top, bottom, left, right)),不支持自动对齐。如果你硬设 padding='same',会直接报错 TypeError: expected int, tuple or list。
- 当
stride=1且 kernel 大小为奇数(如 3、5)时,用padding=(k-1)//2即可实现 same 效果 - 若 kernel 是偶数(如 4),无法做到完全对称,必须选
padding=1或2,输出尺寸会有 1 像素偏差 - 想偷懒?写个辅助函数:
def same_padding(kernel_size): return (kernel_size - 1) // 2,但只适用于奇数 kernel
stride > 1 时,padding 不只是“保尺寸”,还影响感受野连续性
很多人以为 stride=2 就是下采样,加不加 padding 无所谓。其实不然:不加 padding 会导致卷积核从图像左上角开始跳着覆盖,边缘信息容易丢失;加了之后,虽然输出尺寸变化不大,但第一行/列的响应更“居中”,特征对齐更好。
典型场景是 Encoder-Decoder 结构(如 U-Net),编码器用 stride=2 下采样,解码器用转置卷积上采样。如果编码器没加 padding,解码后会出现 1 像素偏移,拼接时 feature map 对不齐。
-
stride=2时,推荐至少设padding=1(尤其 kernel=3),否则输出尺寸骤减,且边界响应变弱 - 验证方法:用全 1 输入过一层
Conv2d,打印输出,看是否四周有明显衰减——有,说明 padding 不足 - 极端情况:
stride=3, kernel=3, padding=0→ 输入 7×7,输出只有 3×3,中间区域被反复扫到,边缘只扫一次
nn.Conv2d 初始化时漏掉 bias=False,可能引发 shape 不匹配错误
这不是 padding 或 stride 的问题,但常和它们一起出现:当你手动计算输出尺寸并做后续操作(如 reshape 或拼接)时,如果忘了 bias=False,而模型里又用了 BatchNorm,就会触发 RuntimeError: Given groups=1, weight of size [o,i,k,k], expected input[1,i,h,w] to have i channels, but got X channels instead 这类迷惑错误。
原因往往是:你改了 in_channels 却没同步更新 weight 维度,而 bias 默认存在会让参数量多一维,间接干扰 shape 推导。
- 显式写
bias=False更安全,尤其在自定义模块或复现论文结构时 - 检查方式:打印
layer.weight.shape和layer.bias.shape(如果存在),确认是否符合预期 - 搭配
BatchNorm2d时,bias 几乎总是冗余的,关掉还能省点显存
事情说清了就结束。最常被忽略的是:padding 和 stride 的组合效果必须在真实输入上跑一遍 print(out.shape) 来验证,光靠公式算容易在奇偶、边界、batch 维度上栽跟头。


















