一文讲懂填充与步幅
目录
什么是填充?什么是步幅?
1. 填充(Padding)
数学公式(输出尺寸)
常见填充方式
2. 步幅(Stride)
数学公式(输出尺寸)
3. 填充与步幅的协同作用
构图真实案例详解?
一、案例 1:无填充(p=0)+ 步幅 = 1(s=1)
二、案例 2:填充 = 1(p=1)+ 步幅 = 1(s=1)
三、案例 3:无填充(p=0)+ 步幅 = 2(s=2)
四、案例 4:填充 = 1(p=1)+ 步幅 = 2(s=2)
五、公式总结与对比表
完整代码
什么是填充?什么是步幅?
- 填充(Padding):控制输出尺寸,补充边缘信息,避免丢失,可以增加输出的高度和宽度。
- 步幅(Stride):控制卷积核滑动步长,影响输出尺寸和计算效率,可以减小输出的高和宽。
1. 填充(Padding)
作用:在输入特征图的边缘补充额外元素(通常是 0),控制输出特征图的尺寸,避免边缘信息丢失,也可让输出尺寸与输入一致。
数学公式(输出尺寸)
常见填充方式
- Valid:不填充
,输出尺寸最小,边缘信息易丢失。
- Same:填充使输出尺寸与输入一致(需满足
,即
,要求卷积核尺寸为奇数)。
2. 步幅(Stride)
作用:控制卷积核在输入特征图上 “滑动” 的步长,影响输出尺寸和计算效率,步幅越大,输出尺寸越小。
数学公式(输出尺寸)
3. 填充与步幅的协同作用
通过调整填充和步幅,可灵活控制输出特征图的尺寸:
- 若需 输出尺寸与输入相同:设
(卷积核尺寸 K 为奇数)且步幅 s=1。
- 若需 大幅压缩输出尺寸:增大步幅 s,或减少填充 p。
构图真实案例详解?
一、案例 1:无填充(p=0)+ 步幅 = 1(s=1)
输入X(3×3): ┌───┬───┬───┐ │ 0 │ 1 │ 2 │ ├───┼───┼───┤ │ 3 │ 4 │ 5 │ ├───┼───┼───┤ │ 6 │ 7 │ 8 │ └───┴───┴───┘卷积核K(2×2): ┌───┬───┐ │ 0 │ 1 │ ├───┼───┤ │ 2 │ 3 │ └───┴───┘滑动计算(步幅=1,无填充): 1. 位置(0,0)窗口: 2. 位置(0,1)窗口: 3. 位置(1,0)窗口: 4. 位置(1,1)窗口: ┌───┬───┐ ┌───┬───┐ ┌───┬───┐ ┌───┬───┐ │ 0 │ 1 │ │ 1 │ 2 │ │ 3 │ 4 │ │ 4 │ 5 │ ├───┼───┤ ├───┼───┤ ├───┼───┤ ├───┼───┤ │ 3 │ 4 │ │ 4 │ 5 │ │ 6 │ 7 │ │ 7 │ 8 │ └───┴───┘ └───┴───┘ └───┴───┘ └───┴───┘计算:0×0+1×1+3×2+4×3=19 计算:1×0+2×1+4×2+5×3=25 计算:3×0+4×1+6×2+7×3=37 计算:4×0+5×1+7×2+8×3=43输出Y(2×2): ┌────┬────┐ │ 19 │ 25 │ ├────┼────┤ │ 37 │ 43 │ └────┴────┘
无填充 + 步幅 = 1 时,输出尺寸小于输入,边缘像素仅参与一次计算,易丢失信息。
二、案例 2:填充 = 1(p=1)+ 步幅 = 1(s=1)
填充后输入X'(5×5,边缘补0): ┌───┬───┬───┬───┬───┐ │ 0 │ 0 │ 0 │ 0 │ 0 │ ← 顶部填充1行 ├───┼───┼───┼───┼───┤ │ 0 │ 0 │ 1 │ 2 │ 0 │ ← 原始第1行(左右补0) ├───┼───┼───┼───┼───┤ │ 0 │ 3 │ 4 │ 5 │ 0 │ ← 原始第2行(左右补0) ├───┼───┼───┼───┼───┤ │ 0 │ 6 │ 7 │ 8 │ 0 │ ← 原始第3行(左右补0) ├───┼───┼───┼───┼───┤ │ 0 │ 0 │ 0 │ 0 │ 0 │ ← 底部填充1行 └───┴───┴───┴───┴───┘滑动计算(步幅=1,填充=1):1. 位置(0,0)窗口: 2. 位置(0,1)窗口: 3. 位置(1,0)窗口: 4. 位置(2,2)窗口: ┌───┬───┐ ┌───┬───┐ ┌───┬───┐ ┌───┬───┐ │ 0 │ 0 │ │ 0 │ 0 │ │ 0 │ 0 │ │ 4 │ 5 │ ├───┼───┤ ├───┼───┤ ├───┼───┤ ├───┼───┤ │ 0 │ 0 │ │ 0 │ 1 │ │ 0 │ 3 │ │ 7 │ 8 │ └───┴───┘ └───┴───┘ └───┴───┘ └───┴───┘计算:0×0+0×1+0×2+0×3=0 计算:0×0+0×1+0×2+1×3=3 计算:0×0+0×1+0×2+3×3=9 计算:4×0+5×1+7×2+8×3=43输出Y(4×4): ┌────┬────┬────┬────┐ │ 0 │ 3 │ 8 │ 4 │ ← 顶部填充区域结果 ├────┼────┼────┼────┤ │ 9 │ 19 │ 25 │ 10 │ ← 原始第1行结果 ├────┼────┼────┼────┤ │ 21 │ 37 │ 43 │ 16 │ ← 原始第2行结果 ├────┼────┼────┼────┤ │ 6 │ 7 │ 8 │ 0 │ ← 底部填充区域结果 └────┴────┴────┴────┘
填充的作用是 “扩展输入边缘”,使输出尺寸增大(本例输入 3×3→输出 4×4),边缘像素参与多次计算,减少信息丢失。
三、案例 3:无填充(p=0)+ 步幅 = 2(s=2)
输入X(4×4): ┌───┬───┬───┬───┐ │ 0 │ 1 │ 2 │ 3 │ ├───┼───┼───┼───┤ │ 4 │ 5 │ 6 │ 7 │ ├───┼───┼───┼───┤ │ 8 │ 9 │10 │11 │ ├───┼───┼───┼───┤ │12 │13 │14 │15 │ └───┴───┴───┴───┘滑动计算(步幅=2,无填充): 1. 位置(0,0)窗口: 2. 位置(0,2)窗口: 3. 位置(2,0)窗口: 4. 位置(2,2)窗口: ┌───┬───┐ ┌───┬───┐ ┌───┬───┐ ┌───┬───┐ │ 0 │ 1 │ │ 2 │ 3 │ │ 8 │ 9 │ │10 │11 │ ├───┼───┤ ├───┼───┤ ├───┼───┤ ├───┼───┤ │ 4 │ 5 │ │ 6 │ 7 │ │12 │13 │ │14 │15 │ └───┴───┘ └───┴───┘ └───┴───┘ └───┴───┘计算:0×0+1×1+4×2+5×3=24 计算:2×0+3×1+6×2+7×3=36 计算:8×0+9×1+12×2+13×3=72 计算:10×0+11×1+14×2+15×3=84输出Y(2×2): ┌────┬────┐ │ 24 │ 36 │ ├────┼────┤ │ 72 │ 84 │ └────┴────┘
步幅 > 1 时,卷积核跳过部分区域,输出尺寸大幅缩小(本例输入 4×4→输出 2×2),可快速减少计算量。
四、案例 4:填充 = 1(p=1)+ 步幅 = 2(s=2)
略
填充 + 步幅组合可灵活控制输出尺寸,既保留边缘信息,又压缩特征图,是深度学习中平衡性能与效率的常用策略。
五、公式总结与对比表
案例 输入尺寸 卷积核尺寸 填充p 步幅s 输出尺寸公式 输出尺寸 无填充 + 步幅 = 1 3×3 2×2 0 1 2×2 填充 = 1 + 步幅 = 1 3×3 2×2 1 1 4×4 无填充 + 步幅 = 2 4×4 2×2 0 2 2×2 填充 = 1 + 步幅 = 2 5×5 3×3 1 2 3×3
完整代码
"""
文件名: 6.3 填充和步幅
作者: 墨尘
日期: 2025/7/13
项目名: dl_env
备注:
"""
import torch
import torch.nn as nndef comp_conv2d(conv2d, X):X = X.reshape((1, 1) + X.shape) # 转换为 (1, 1, H, W)Y = conv2d(X)return Y.reshape(Y.shape[2:]) # 移除批量和通道维度if __name__ == '__main__':# 填充1:3×3卷积核 + 每边填充1# 参数:输入通道=1,输出通道=1,卷积核3×3,上下左右各填充1行/列,步幅默认=1conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1)X = torch.rand(size=(8, 8)) # 输入尺寸:8×8print(f"填充1:输入尺寸 {X.shape} → 输出尺寸 {comp_conv2d(conv2d, X).shape}")# 输出尺寸计算:# H_out = (H_in + 2*p_h - K_h)/s_h + 1 = (8 + 2*1 - 3)/1 + 1 = 8# W_out = (W_in + 2*p_w - K_w)/s_w + 1 = (8 + 2*1 - 3)/1 + 1 = 8# 结果:输出尺寸保持为8×8# 填充2:5×3卷积核 + 高度方向填充2、宽度方向填充1# 参数:输入通道=1,输出通道=1,卷积核5×3,高度方向上下各填充2行,宽度方向左右各填充1列conv2d = nn.Conv2d(1, 1, kernel_size=(5, 3), padding=(2, 1))print(f"填充2:输入尺寸 {X.shape} → 输出尺寸 {comp_conv2d(conv2d, X).shape}")# 输出尺寸计算:# H_out = (8 + 2*2 - 5)/1 + 1 = 8# W_out = (8 + 2*1 - 3)/1 + 1 = 8# 结果:输出尺寸保持为8×8(非对称卷积核通过非对称填充实现尺寸不变)# 步幅示例1:3×3卷积核 + 每边填充1 + 步幅2# 参数:输入通道=1,输出通道=1,卷积核3×3,填充1,步幅2(垂直和水平方向均为2)conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride=2)print(f"步幅1:输入尺寸 {X.shape} → 输出尺寸 {comp_conv2d(conv2d, X).shape}")# 输出尺寸计算:# H_out = (8 + 2*1 - 3)/2 + 1 = 4# W_out = (8 + 2*1 - 3)/2 + 1 = 4# 结果:输出尺寸减半为4×4(步幅2的作用)# 步幅示例2:3×5卷积核 + 高度方向填充0、宽度方向填充1 + 非对称步幅(3,4)# 参数:输入通道=1,输出通道=1,卷积核3×5,高度方向不填充,宽度方向左右各填充1列,垂直步幅3,水平步幅4conv2d = nn.Conv2d(1, 1, kernel_size=(3, 5), padding=(0, 1), stride=(3, 4))print(f"步幅2:输入尺寸 {X.shape} → 输出尺寸 {comp_conv2d(conv2d, X).shape}")# 输出尺寸计算:# H_out = (8 + 2*0 - 3)/3 + 1 = 2# W_out = (8 + 2*1 - 5)/4 + 1 = 2# 结果:输出尺寸压缩为2×2(非对称步幅和卷积核的组合效果)
实验结果