卷积层输出尺寸是怎么来的?从公式到直觉理解(含 224×224 示例)
在卷积神经网络(CNN)里,一个最容易让人“卡住”的点就是:卷积之后,特征图到底变多大?
尤其是你第一次看到这个公式时:
Hout=⌊Hin+2P−KS⌋+1 H_{out} = \left\lfloor \frac{H_{in} + 2P - K}{S} \right\rfloor + 1Hout=⌊SHin+2P−K⌋+1
其中,HinH_{\text{in}}Hin是输入尺寸(高或宽) ,KKK是卷积核大小,SSS是步长(stride) ,PPP是padding。
看起来像公式,但本质其实只有一句话:卷积输出 = 卷积核在输入上“能滑动的次数”
一、先用一个最直觉的例子理解
例如对于输入数据索引为[0,1,2,3,4,5,6],一共7个元素。若stride=1,padding=0, kernel_size=3,卷积核会在序列上以步长 1 进行滑动。每一个合法的滑动位置都会产生一个输出,因此输出个数等于“窗口可以放置的起始位置数量”,最终得到 5 个输出。
1.1 关键问题:卷积核能放多少次?
卷积核每次覆盖 3 个元素,对于上述示例,可以放5个位置,因此输出长度为5。
二、公式理解
我们可以将公式拆分为三部分来理解:
Hout=⌊Hin+2P−KS⌋+1 H_{out} = \left\lfloor \frac{H_{in} + 2P - K}{S} \right\rfloor + 1Hout=⌊SHin+2P−K⌋+1
2.1 有效滑动范围
Hin+2P−K H_{\text{in}} + 2P - KHin+2P−K
这一部分表示卷积核在“展开后的输入”上,最后一个合法起点能走到的最远距离。
直觉上可以理解为:输入长度扩展为Hin+2PH_{in} + 2PHin+2P, 每次窗口占用KKK个位置, 所以真正能滑动的是“剩余可移动空间”。
2.2 除以 stride
SSS表示表示“每次跳多少步”,即卷积核每次“跳跃”的间隔大小。
- S=1S = 1S=1→ 每个位置都看
- S=2S = 2S=2→ 隔一个看一个
- S=kS = kS=k→ 稀疏采样
本质是控制“采样密度”,而不是影响窗口大小
2.3 最后+1:从“步数”变成“位置数”
因为卷积输出统计的是所有“合法起点”的数量,而不是移动了多少次。
把“滑动距离对应的步数”转换为“窗口起点的数量”,因为卷积的输出本质是在统计所有合法的起始位置(包括 0)。
三、推广到二维图像(CNN真正用的情况)
当输入是高为HHH,宽为WWW的图像时,卷积是一样的逻辑,只是变成“2D滑动窗口”。
以224×224224 \times 224224×224图像为例,假设参数为:kernel_size = 3 , stride = 1 , padding = 0
3.1 计算输出尺寸
带入公式可以得到输出高度:
Hout=⌊224+2⋅0−31⌋+1=222 H_{out} = \lfloor \frac{224 + 2\cdot0 - 3}{1}\rfloor + 1 = 222Hout=⌊1224+2⋅0−3⌋+1=222
同理输出宽度通过计算得到的也是222222222,因此输出特征图尺寸为222×222222 \times 222222×222。
3.2 直觉理解
可以看到输入特征尺寸从224224224变成222222222,本质是在问:3×33 \times 33×3的卷积核在长度为224224224的序列上,有多少个合法的放置位置?
卷积核的起始位置可以从:第 0 个位置(覆盖 0~2) ,一直移动到第 221 个位置(覆盖 221~223)
因此合法起点范围为:0, 1, 2, ..., 221,总共有222个位置,所以输出长度为222。
输出变小的原因在于:卷积计算可以理解为以某个“中心位置”为基准,在其左右各取一个元素(kernel_size=3)形成一个长度为 3 的局部窗口。因此,一个位置要成为合法的计算点,必须满足其左右两侧都存在足够的邻域元素。在无 padding 的情况下,输入序列最左侧和最右侧各有 1 个位置由于缺少邻域信息,无法作为有效的中心点参与计算,相当于两侧各“损失”了 1 个位置。由此,输入到输出的尺寸变化从224变为222。
四、padding 的作用:为什么可以“保持尺寸不变”
如果我们希望卷积前后尺寸不变,比如输入224×224224 \times 224224×224,输出仍然是224×224224 \times 224224×224。
常见设置如下:
- kernel_size = 3
- stride = 1
- padding = 1
4.1 公式计算
Hout=⌊224+2⋅1−31⌋+1=224 H_{out} = \lfloor \frac{224 + 2\cdot1 - 3}{1} \rfloor + 1 = 224Hout=⌊1224+2⋅1−3⌋+1=224
4.2 直觉理解
没有 padding 时, 卷积核只能在“完全落在图像内部”的区域滑动,边缘会被“裁掉”。
有 padding 时,在四周补 0 ,卷积核可以“跨到原图外侧” ,这样边界位置也能被计算。
padding 的本质,是通过在边界补零,扩展了卷积核的“合法滑动区域”,从而控制输出尺寸。
五、stride 的作用:控制“跳着看”的密度
stride(步幅)决定了卷积核在特征图上每次移动的步长。
当stride = 2时,卷积核每次在输入上向前移动 2 个位置(而不是逐格滑动)。这意味着我们不再对每一个可能的位置都进行计算,而是隔一个位置采样一次,从而减少了参与计算的“中心点”数量。因此,输出特征图的尺寸相较于stride = 1会明显减小,通常接近原来的一半(具体大小仍取决于输入尺寸和kernel size)。
5.1 直觉理解:从“逐像素扫描”到“间隔采样”
可以把卷积看成在图像上做扫描:
stride = 1:像逐像素走路,每一格都看得很仔细stride = 2:像隔一格走一步,只看“关键位置”
结果就是stride 越大,看到的信息越“稀疏”,但计算量也越小
5.2 对输出尺寸的影响
stride 本质上是在控制输出网格的“采样频率”。在不改变 padding 和 kernel 的情况下:
stride = 1 → 输出密集(信息保留更多)
stride = 2 → 输出变稀疏(尺寸缩小)
stride > 1 → 相当于对特征图做下采样(downsampling)
因此,stride 控制的不是“看哪里”,而是“每隔多远看一次”。
六、总结
可以这样理解三者分工:kernel_size控制每次“看多大范围” ,padding控制边界“能不能看见” ,stride控制看得有多密。
卷积输出尺寸本质就是:卷积核在输入上,按 stride 规则可以滑动多少次。公式只是这个过程的数学表达。
工程里最常见的几个组合:
| 设置 | 作用 | 输出变化 |
|---|---|---|
| kernel=3, stride=1, padding=1 | 保持尺寸 | 不变 |
| kernel=3, stride=2 | 下采样 | 减半 |
| kernel=1 | 通道混合 | 不变 |
