Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

3.2 卷积运算:从单通道到多通道

3.1 节给出了结论:卷积用「核在图上滑动」处理图像。但这句话里的每个词都还没定义:「滑动」的步长是多少?边界怎么办?一张 RGB 图有三个通道,核该长什么样?输出有几个通道?

这一节把这些问号逐个变成公式,目标是让你具备一项不依赖任何代码的能力:给定输入形状与层配置,写出输出形状、参数量与计算量。这项能力在工程上的价值很难被高估——卷积网络里绝大多数维度报错、显存溢出、速度不达标,都可以先在一张纸上算出来。

这节解决的六个问题
  1. 「卷积」在深度学习里到底算什么运算?(3.2.1)
  2. 边界与步长怎么改(填充、步幅、空洞)?输出尺寸公式是什么?(3.2.2)
  3. 多通道卷积与 1×11\times1 卷积在哪里?(3.2.3)
  4. 一层卷积有多少参数、要多少次乘加?(3.2.4)
  5. 堆到第 LL 层时,一个神经元到底看多大范围?(3.2.5)
  6. 分组 / 深度可分离卷积省了多少?怎么把特征图放大回去?框架内部在算什么?(3.2.6、3.2.7、3.2.8)

3.2.1 卷积与互相关:框架算的其实是「互相关」

先澄清一个符号上的历史包袱。数学里的卷积要求把核翻转 180°,而深度学习框架里的 Conv2d 不翻转。

定义 3.2.1 · 二维互相关(2-D cross-correlation)

给定单通道输入 x∈RH×Wx\in\mathbb R^{H\times W}、核(卷积核 / 滤波器,filter / kernel)w∈Rk×kw\in\mathbb R^{k\times k}、偏置 bb、步幅 ss、填充 pp,输出 y∈RHout×Wouty\in\mathbb R^{H_{out}\times W_{out}} 的第 (i,j)(i,j) 个元素为

yi,j=b+∑u=0k−1∑v=0k−1wu,v x i⋅s+u−p,  j⋅s+v−p,i=0,…,Hout−1, j=0,…,Wout−1.(3.1)y_{i,j}=b+\sum_{u=0}^{k-1}\sum_{v=0}^{k-1}w_{u,v}\,x_{\,i\cdot s+u-p,\;j\cdot s+v-p},\qquad i=0,\dots,H_{out}-1,\ j=0,\dots,W_{out}-1 . \tag{3.1}

越界的下标(i⋅s+u−p<0i\cdot s+u-p\lt0 或 ≥H\ge H)在填零(zero padding)约定下取 00。深度学习文献与所有主流框架把这个运算直接称为「卷积」,本章沿用这一习惯,但读者应知道公式 (3.1) 算的是互相关。

一次滑动窗口 = 一个内积

把公式 (3.1) 读成一句话:每个输出位置,取输入上的一个 k×kk\times k 窗口,与核逐元素相乘再求和,加上偏置。这个「逐元素相乘再求和」正是两个 k2k^2 维向量的内积——所以卷积核本质上是一组用来和图像局部做相似度比较的模板。

由此立刻得到两个直觉:① 核与窗口越相似(同号且数值大),输出越大——核是「模式探测器」;② 神经网络「学习」卷积层,学的就是这些模板的数值。第 1 层学到的往往是对比度、方向边缘这类低级模板,越深越抽象(3.4 节会把这个层次讲成一个演进故事)。

既然只差翻转,为什么还要专门澄清?三个原因:① 梯度回传公式在两种约定下不同,手推反向传播时忘记约定就会写错符号;② 卷积结合律在互相关约定下不成立(一般 w1,w2w_1,w_2 下无法合并成单核),凡「把多层合并成一层」的等价变换都必须用数学卷积的约定;③ 与信号处理、控制理论的卷积公式对接时(本教程姊妹书大量使用),翻转必须显式写出。

命题 3.2.1 · 「卷积」与「互相关」只差一次翻转

定义翻转核 w~u,v=wk−1−u, k−1−v\tilde w_{u,v}=w_{k-1-u,\,k-1-v},则对任意 x,wx,w 有 conv(x,w)=crosscorr(x,w~)\mathrm{conv}(x,w)=\mathrm{crosscorr}(x,\tilde w)。即互相关是核翻转后的数学卷积,两者在表达能力上完全等价。

推导(可跳)

数学卷积(离散、二维)定义为 (x∗w)i,j=∑u∑vxu,vw i−u, j−v(x*w)_{i,j}=\sum_{u}\sum_{v}x_{u,v}w_{\,i-u,\,j-v}。令 u′=i−u, v′=j−vu&#x27;=i-u,\ v&#x27;=j-v,求和指标遍历同一范围:

(x∗w)i,j=∑u′∑v′x i−u′, j−v′ wu′,v′.(x*w)_{i,j}=\sum_{u&#x27;}\sum_{v&#x27;}x_{\,i-u&#x27;,\,j-v&#x27;}\,w_{u&#x27;,v&#x27;}.

设窗口左上角为 (i−k+1,j−k+1)(i-k+1,j-k+1),把输入下标写成「左上角 + 偏移 (a,b)(a,b)」的形式,与互相关 yi,j=∑a,bw~a,bx i+a−p, j+b−py_{i,j}=\sum_{a,b}\tilde w_{a,b}x_{\,i+a-p,\,j+b-p} 对照,只需核的取值满足 w~a,b=w k−1−a,  k−1−b\tilde w_{a,b}=w_{\,k-1-a,\;k-1-b},即「翻转 180° 后的核」。以 k=3k=3 为例:ww 的左上角元素在数学卷积里乘的是窗口右下角的输入,在互相关里乘的是左上角——这正是翻转的效果。■\blacksquare

∎
定理 3.2.1 · 无激活的多个线性卷积可等价为一个核

设 y=x∗w1y=x\ast w_1、z=y∗w2z=y\ast w_2(数学卷积,单通道、无偏置、步幅 1、填充足够使尺寸不变),则 z=x∗(w2∗w1)z=x\ast(w_2\ast w_1)。

推导(可跳)

zi,j=∑a,bw2 a,b y i−a, j−b=∑a,bw2 a,b∑c,dw1 c,d x i−a−c,  j−b−d=∑e,f(∑a,bw2 a,bw1 e−a, f−b)⏟= (w2∗w1)e,fx i−e, j−f,\begin{aligned} z_{i,j}&amp;=\sum_{a,b}w_{2\,a,b}\,y_{\,i-a,\,j-b}=\sum_{a,b}w_{2\,a,b}\sum_{c,d}w_{1\,c,d}\,x_{\,i-a-c,\;j-b-d}=\sum_{e,f}\underbrace{\Bigl(\sum_{a,b}w_{2\,a,b}w_{1\,e-a,\,f-b}\Bigr)}_{=\,(w_2\ast w_1)_{e,f}}x_{\,i-e,\,j-f}, \end{aligned} 第二步用了换元 e=a+c, f=b+de=a+c,\ f=b+d。这就是卷积的结合律。在框架的互相关约定下,合并时应把其中一个核翻转,否则得到的是翻转核的结果。■\blacksquare

∎
为什么「合并核」只在推理时有用,训练时禁用

若两层之间没有非线性,它们在数学上就是两次线性运算,合并后完全等价:参数与计算量都下降。但训练时绝不能这么干——去掉一层等于去掉那一层的非线性与额外容量,表达能力直接下降。

正确的用法是训练之后:模型收敛、权重冻结,再把「卷积 → BatchNorm」或相邻的线性卷积融合成单个核,用更少的算子跑同样的函数。这是推理优化(TensorRT、torch.fx 的 conv-bn folding 等)里最常见的一类图优化,其合法性完全依赖这条定理。

3.2.2 步幅与填充:输出尺寸公式

定义 3.2.2 · 填充、步幅与空洞(padding / stride / dilation)
  • 填充(padding)pp:在输入四周补 pp 圈元素(通常补 00),用于控制输出尺寸、保住边缘信息。
  • 步幅(stride)ss:核每次移动的距离。s=1s=1 逐个位置滑;s>1s\gt1 相当于边卷积边下采样。
  • 空洞 / 膨胀率(dilation)dd:核元素之间插入 d−1d-1 个空隙,等价于把 k×kk\times k 核撑成有效核 keff=k+(k−1)(d−1)k_{\text{eff}}=k+(k-1)(d-1) 而不增加参数。
三个旋钮各管一件事

kk 管「看多大」:核越大,单层覆盖范围越大,但参数按 k2k^2 涨、层内非线性变少。pp 管「边界与尺寸」:不填充时边缘像素被窗口覆盖的次数远少于中心像素,填充让边缘与中心视野次数趋于一致,同时让尺寸可控。ss 管「降不降分辨率」:s>1s\gt1 使输出变小、跳距被放大(3.2.5),感受野开始滚雪球,代价是空间精度损失。dd 是 kk 的廉价替身:9 个参数得到 5×55\times5 视野,代价是采样稀疏(会漏掉细结构,出现网格效应)。

命题 3.2.2 · 输出尺寸公式

一维情形(二维逐轴独立应用)为

Wout=⌊Win+2p−keffs⌋+1=⌊Win+2p−k−(k−1)(d−1)s⌋+1.(3.2)W_{out}=\left\lfloor\frac{W_{in}+2p-k_{\text{eff}}}{s}\right\rfloor+1=\left\lfloor\frac{W_{in}+2p-k-(k-1)(d-1)}{s}\right\rfloor+1 . \tag{3.2}

两种常用命名:valid 指不填充(p=0p=0,输出变小);same 指输出与输入同尺寸(s=1s=1 且 kk 为奇数时取 p=(k−1)/2p=(k-1)/2)。

推导

滑动窗口的左边界只能取整数位置。设最后一个合法窗口的左边界为 jj,其右边界 j+k−1j+k-1 必须落在填充后的输入范围内(长度 Win+2pW_{in}+2p),故 j≤Win+2p−kj\le W_{in}+2p-k。jj 从 00 出发、每次加 ss,可取的个数为 ⌊(Win+2p−k)/s⌋+1\lfloor(W_{in}+2p-k)/s\rfloor+1。边界处剩余像素不足 ss 个、放不下完整窗口时该位置被丢弃——这就是向下取整的来源。窗口必须完整落在填充后的范围内,框架(如 PyTorch 的 Conv2d)不会补齐最后一个不完整位置;若 Win+2p−k<0W_{in}+2p-k\lt0 则直接报错。有空洞时把 kk 换成 keffk_{\text{eff}} 即可,因为「核元素之间的空隙」等效于把核撑大。■\blacksquare

∎
不必背公式,背三句话

① 填充把可用范围从 WinW_{in} 撑到 Win+2pW_{in}+2p;② 一个窗口占 kk 格,所以 s=1s=1 时有 Win+2p−k+1W_{in}+2p-k+1 个起始位置;③ 步幅 s>1s\gt1 时起始点每 ss 个取一个,于是 ⌊(Win+2p−k)/s⌋+1\lfloor(W_{in}+2p-k)/s\rfloor+1。两个常用特例随手可得:k=3,s=1,p=1k=3,s=1,p=1 → 尺寸不变;k=4,s=2,p=1k=4,s=2,p=1 → 精确减半(224 到 112 就靠这类配置)。

例 3.2.1 · 输出尺寸的四则手算 + ResNet 首层

输入 Win=32W_{in}=32,求下列配置的输出尺寸:(a) k=3,s=1,p=0,d=1k=3,s=1,p=0,d=1;(b) k=3,s=1,p=1k=3,s=1,p=1;(c) k=3,s=2,p=1k=3,s=2,p=1;(d) k=3,s=1,p=2,d=2k=3,s=1,p=2,d=2。再求 Win=224,k=7,s=2,p=3W_{in}=224,k=7,s=2,p=3。

解

(a) ⌊(32+0−3)/1⌋+1=30\lfloor(32+0-3)/1\rfloor+1=30:valid 约定,边界处丢两圈信息。 (b) ⌊(32+2−3)/1⌋+1=32\lfloor(32+2-3)/1\rfloor+1=32:same 约定,尺寸不变。 (c) ⌊(32+2−3)/2⌋+1=⌊31/2⌋+1=16\lfloor(32+2-3)/2\rfloor+1=\lfloor31/2\rfloor+1=16:尺寸精确减半——骨干网络的降采样常用这组配置。 (d) keff=3+(3−1)(2−1)=5k_{\text{eff}}=3+(3-1)(2-1)=5,⌊(32+4−5)/1⌋+1=32\lfloor(32+4-5)/1\rfloor+1=32:空洞卷积保尺寸、扩视野,参数仍是 9 个而视野变成 5×55\times5。 ResNet 首层:⌊(224+6−7)/2⌋+1=112\lfloor(224+6-7)/2\rfloor+1=112;再接 3×3,s=2,p=13\times3,s=2,p=1 的最大池化得 ⌊(112+2−3)/2⌋+1=56\lfloor(112+2-3)/2\rfloor+1=56。这就是 ResNet 各阶段入口为 56×5656\times56 的来源。

规律小结(背下来比推导快):s=1s=1 且 p=(k−1)/2p=(k-1)/2(kk 奇)→ 尺寸不变;s=2s=2 → 大致减半;d>1d\gt1 → 核撑大而参数不变,用于不降分辨率地扩视野(分割网络常用,见 3.7 节)。

∎

3.2.3 多通道卷积与 1×1 卷积

定义 3.2.3 · 多通道卷积

输入 x∈RCin×H×Wx\in\mathbb R^{C_{in}\times H\times W},输出通道数 CoutC_{out}。第 oo 个输出通道由一个三维核 w(o)∈RCin×k×kw^{(o)}\in\mathbb R^{C_{in}\times k\times k} 与偏置 b(o)b^{(o)} 给出:

yi,j(o)=b(o)+∑c=1Cin∑u=0k−1∑v=0k−1wu,v(o,c) x i⋅s+u−p,  j⋅s+v−p(c),o=1,…,Cout.(3.3)y^{(o)}_{i,j}=b^{(o)}+\sum_{c=1}^{C_{in}}\sum_{u=0}^{k-1}\sum_{v=0}^{k-1}w^{(o,c)}_{u,v}\,x^{(c)}_{\,i\cdot s+u-p,\;j\cdot s+v-p},\qquad o=1,\dots,C_{out}. \tag{3.3}

两条要点:每个输出通道有自己的一整套核;每个核的深度必须等于输入通道数——它在 CinC_{in} 个输入通道上各取 k×kk\times k 权重,把结果求和成 1 个通道。

多通道卷积 = 全通道求和 + 输出通道个「探测器」

拆成两步看最清楚:一个核是一个 (Cin,k,k)(C_{in},k,k) 张量,同时看所有输入通道的同一空间邻域,做一次 Cink2C_{in}k^2 维内积得到 1 个数——它回答「这一小块位置-通道组合里,有没有我关心的模式」;一套核(CoutC_{out} 个) 各自给出一张特征图,于是输出张量是 CoutC_{out} 张特征图,通道维就是「模式维」。

一个有用的类比:CinC_{in} 是「输入证据通道」,CoutC_{out} 是「输出假设通道」,卷积核是它们之间的权重矩阵——固定空间位置后,公式 (3.3) 与一次 (Cout×Cink2)(C_{out}\times C_{in}k^2) 的矩阵乘完全同构,这正是 3.2.8 中 im2col 实现的依据。1×11\times1 卷积是这个视角的极端情形:空间上什么都不做,纯粹在每个像素位置把 CinC_{in} 个通道线性组合成 CoutC_{out} 个通道,即「逐像素的全连接层」,用来升降维、跨通道融合,并在不改空间尺寸的前提下加一层非线性。

命题 3.2.3 · 参数量与计算量公式

一层卷积(含偏置)的参数与乘加次数(MACs,1 MAC = 1 次乘 + 1 次加)为

Params=Cout⋅Cin⋅k2+Cout,(3.4)\text{Params}=C_{out}\cdot C_{in}\cdot k^2+C_{out}, \tag{3.4}

MACs=Hout⋅Wout⋅Cout⋅Cin⋅k2.(3.5)\text{MACs}=H_{out}\cdot W_{out}\cdot C_{out}\cdot C_{in}\cdot k^2 . \tag{3.5}

若按 FLOPs 计(一次乘加算 2 次浮点运算),FLOPs≈2×MACs\text{FLOPs}\approx2\times\text{MACs}。偏置项 CoutC_{out} 在通道数很大时可以忽略(6464 对 36,86436{,}864,约 0.17%0.17\%),工程口算时常直接写 Params≈CoutCink2\text{Params}\approx C_{out}C_{in}k^2;但核对模型总参数量时必须把偏置与归一化层的参数加回来。

推导

参数:由 定义 3.2.3,每个输出通道有 Cink2C_{in}k^2 个权重与 1 个偏置,共 CoutC_{out} 个通道,得 (3.4)。计算量:每个输出位置、每个输出通道都要做 Cink2C_{in}k^2 次「乘 + 加」,输出共有 CoutC_{out} 个通道、HoutWoutH_{out}W_{out} 个位置,得 (3.5)。

三个直接推论(工程上极实用):① 参数量与 H×WH\times W 无关——图像放大一倍,参数不变、计算量涨 4 倍,这是卷积「省参数不省算力」的根源;② 参数量按 k2k^2 涨——kk 从 3 到 7 参数涨 5.4 倍,这是「小核堆叠」优于「大核」的算术理由(3.2.5);③ 计算量按 CinCoutC_{in}C_{out} 涨——把 64→6464\to64 换成 256→256256\to256,计算量涨 16 倍。■\blacksquare

∎
例 3.2.2 · ResNet 瓶颈块与「1×11\times1 降维」的收益

ResNet-50 的瓶颈块(bottleneck)在 56×56×25656\times56\times256 上做三次卷积:1×11\times1(256→64256\to64)、3×33\times3(64→6464\to64,p=1p=1)、1×11\times1(64→25664\to256),全部 s=1s=1。求各自与整块的参数量、MACs,并与「单层 3×33\times3、256→256256\to256」比较。

解

① 1×11\times1,256→64256\to64:Params =64⋅256+64=16,448=64\cdot256+64=16{,}448;MACs =56⋅56⋅64⋅256=5.14×107=56\cdot56\cdot64\cdot256=5.14\times10^{7}。 ② 3×33\times3,64→6464\to64:Params =64⋅64⋅9+64=36,928=64\cdot64\cdot9+64=36{,}928;MACs =56⋅56⋅64⋅64⋅9=1.156×108=56\cdot56\cdot64\cdot64\cdot9=1.156\times10^{8}。 ③ 1×11\times1,64→25664\to256:Params =256⋅64+256=16,640=256\cdot64+256=16{,}640;MACs =56⋅56⋅256⋅64=5.14×107=56\cdot56\cdot256\cdot64=5.14\times10^{7}。

瓶颈块合计:Params =69,016≈6.9×104=69{,}016\approx6.9\times10^{4},MACs ≈2.18×108\approx2.18\times10^{8}。 单层 3×33\times3、256→256256\to256:Params =256⋅256⋅9+256=590,080=256\cdot256\cdot9+256=590{,}080,MACs =56⋅56⋅256⋅256⋅9=1.85×109=56\cdot56\cdot256\cdot256\cdot9=1.85\times10^{9}。

结论:瓶颈设计把参数降到约 1/8.61/8.6、计算量降到约 1/8.51/8.5,而表达方式更丰富(多两层非线性、通道可升可降)。把中间宽度 mm 当参数扫一遍,可见这是计算预算的再分配:

结构中间通道 mm参数量MACs(H=W=56H=W=56,C=256C=256)相对单层 3×33\times3
直接 3×33\times3256590,0801.85×10⁹1.000
瓶颈(m=C/4m=C/4)6469,0162.18×10⁸0.118
瓶颈(m=C/2m=C/2)128147,7123.97×10⁸0.215
瓶颈(m=Cm=C)256295,1687.55×10⁸0.409

注意最后一行:即使把中间宽度设回 256256,参数量仍只有单层 3×33\times3 的一半——因为两个 1×11\times1 卷积一共是 2C22C^2 个参数,比一个 3×33\times3 的 9C29C^2 小。ResNet-50/101/152 采用 m=C/4m=C/4,用省下的算力把深度做上去(3.4 节)。

∎

3.2.4 参数量与计算量的速查表

模型 / 层输入参数量MACs(一次前向)备注
全连接 150528→10001×1505281.51×10⁸1.51×10⁸3.1 节的对照基准
卷积 3×3,64→6456×56×6436,9281.16×10⁸参数省 4 个数量级、算力同量级
深度可分离 3×3,64→6456×56×644,8001.45×10⁷约为标准卷积的 1/8
分组卷积 3×3,64→64(g=4g=4)56×56×649,2802.89×10⁷约为 1/4
ResNet 瓶颈块56×56×25669,0162.18×10⁸1×1→3×3→1×11{\times}1 \to 3{\times}3 \to 1{\times}1
AlexNet(227²)3×227×2276.16×10⁷—其中 5.86×10⁷ 在全连接层
VGG16(224²)3×224×2241.384×10⁸—其中 1.236×10⁸ 在全连接层
ResNet-18(224²)3×224×2241.17×10⁷约 1.8×10⁹无大全连接层
ResNet-50(224²)3×224×2242.55×10⁷约 4.1×10⁹与论文报告 25.6M 一致
ViT-B/16(224²)3×224×2248.65×10⁷约 1.76×10¹⁰无卷积,见 3.5.2

AlexNet / VGG16 的参数几乎全在全连接层——这正是它们在新的骨干出现后迅速退出主舞台的直接工程原因;ResNet / ViT 的参数分布在卷积 / 注意力层里,因此能在同量级参数下取得高得多的精度。表中 MACs 只统计主要乘加项(卷积、矩阵乘),忽略激活函数、归一化、偏置加法与显存搬运;真实耗时还要看算子效率与访存(3.3 节与本教程第 9 讲)。

3.2.5 感受野:堆叠为什么让视野变大

定义 3.2.4 · 感受野与跳距(receptive field / jump)

第 ll 层某个输出神经元能追溯到原始输入的区域的大小,称为它的感受野 rlr_l。第 ll 层相邻两个神经元在原始输入上的中心间距,称为跳距(jump,也叫等效步幅)jlj_l。

为什么要单独记「跳距」

感受野回答「看多大」,跳距回答「隔多远一个采样点」。两者共同决定一件事:第 ll 层的一张特征图相当于原图的什么分辨率。jL=4j_L=4 意味着特征图上一个像素对应原图 4×44\times4 块——做像素级分割时,这个 jLj_L 就是定位精度的上限(这也是分割网络要保住高分辨率特征的原因)。更实用的一条:把原图上某层的核换算到第 ll 层时尺寸要乘 jlj_l,所以设计网络时「这一层相当于原图上看多大」必须用 k⋅jlk\cdot j_l 而不是 kk。

命题 3.2.4 · 感受野递推公式

在第 ll 层之上再堆一层 k×kk\times k、步幅 ss 的卷积(或池化),则

rl+1=rl+(k−1) jl,jl+1=jl⋅s.(3.6)r_{l+1}=r_l+(k-1)\,j_l,\qquad j_{l+1}=j_l\cdot s . \tag{3.6}

初始条件:第一层直接作用于输入时 r1=kr_1=k、j1=sj_1=s。

推导

感受野:第 l+1l+1 层的输出是 k×kk\times k 个第 ll 层神经元的加权和,这些神经元在原始输入上的中心依次相差 jlj_l,最外侧两个中心的跨度为 (k−1)jl(k-1)j_l;再把两端各自的半个视野(合起来正好是完整的一个 rlr_l)算进来,得 rl+1=(k−1)jl+rlr_{l+1}=(k-1)j_l+r_l。自检:k=1k=1 时 rl+1=rlr_{l+1}=r_l,符合直觉。跳距:第 l+1l+1 层相邻两个输出位置对应第 ll 层上相差 ss 个位置的窗口,这 ss 个位置在原始输入上相隔 s⋅jls\cdot j_l,故 jl+1=s jlj_{l+1}=s\,j_l。初始条件:第一层直接看输入时窗口覆盖 k×kk\times k 个原始像素(r1=kr_1=k),相邻窗口中心相差 ss 个像素(j1=sj_1=s)。■\blacksquare

∎
例 3.2.3 · 感受野的三种堆叠方式

(a) LL 层 3×33\times3、s=1s=1 的卷积;(b) 每两层 3×33\times3 后接一次 2×22\times2 最大池化;(c) ResNet 风格浅层骨架:7×7,s=27\times7,s=2 → 3×33\times3 最大池化 s=2s=2 → 12 层 3×33\times3。分别求最终感受野。

解

(a) jl≡1j_l\equiv1,每层增量 22:rL=3+2(L−1)=2L+1r_L=3+2(L-1)=2L+1。2 层看 5×55\times5、3 层看 7×77\times7。线性增长,很慢。

(b) 从 r=3, j=1r=3,\ j=1 出发,每阶段 = 两次 3×33\times3(各 +2j+2j)再一次池化(+j+j 后 jj 翻倍):

阶段 1 2 3 4 5
rr 8 18 38 78 158
jj 2 4 8 16 32

感受野从 8 到 18、38、78、158——近似每阶段翻倍,与 (a) 的线性增长形成鲜明对比。

(c) 逐步套用 (3.6):

步骤 操作 rr jj
1 7×77\times7,s=2s=2 7 2
2 3×33\times3 最大池化,s=2s=2 7+2×2=117+2\times2=11 4
3 12 层 3×33\times3,s=1s=1 11+12×(2×4)=10711+12\times(2\times4)=107 4

到 stage1 结束,感受野已达 107×107107\times107(接近输入 224 的一半),跳距仍为 4——特征图分辨率 56×5656\times56,每个点对应原图约 107107 见方的区域。

三个工程结论:① 想要大感受野,下采样比堆层划算得多——纯堆 3×33\times3 要达到 101×101101\times101 需要 50 层,而按 (b) 的方式 10 层就到 158158;② 感受野不是越大越好——分类偏好大感受野,分割 / 检测的定位分支需要小跳距,所以它们用空洞卷积或特征金字塔(3.7 节);③ 理论感受野 ≠ 有效感受野——理论值是能追溯的最大范围,而实际梯度与响应集中在中心的一小块区域,有效感受野通常只是理论值的一小部分,别把它当作「网络真正用了多大上下文」的证据(见本节延伸阅读)。

∎

3.2.6 分组卷积与深度可分离卷积

定义 3.2.5 · 分组卷积与深度可分离卷积
  • 分组卷积(grouped convolution):把 CinC_{in} 个输入通道与 CoutC_{out} 个输出通道各分成 gg 组,第 tt 组只做组内卷积,组间不通信。
  • 深度可分离卷积(depthwise separable convolution):两步——① 逐通道卷积(depthwise)每个输入通道用一个独立 k×kk\times k 核卷积;② 逐点卷积(pointwise)用 1×11\times1 卷积做通道混合。它是分组卷积取 g=Cin=Coutg=C_{in}=C_{out} 的特例再加一个混合层。
分组 = 「同组通道负责一类模式」,分离 = 「空间与通道解耦」

分组:让不同组各管一类特征,组内自足、组间互不干扰。历史上 AlexNet 在两块 GPU 上并行训练时被迫把网络分成两半,那个工程妥协后来被发现也是一种有效的正则与压缩(组数越多,跨通道容量越小)。分离:标准卷积让每个核元素同时承担「空间滤波」与「通道混合」两件事,拆开后空间部分(k2k^2 个小核)与通道部分(1×11\times1)各司其职;代价是跨通道的空间联合模式需要两层才能表达,省下算力的同时把一部分容量交给了深度来补。

命题 3.2.6 · 可分离卷积的省算比

设 Cin=Cout=CC_{in}=C_{out}=C,忽略偏置,标准卷积与深度可分离卷积的参数量之比为

ρ=Ck2+C2C2k2=1C+1k2(k=3, C=64⇒ρ=164+19≈0.127),\rho=\frac{Ck^2+C^2}{C^2k^2}=\frac{1}{C}+\frac{1}{k^2}\qquad\Bigl(k=3,\ C=64\Rightarrow\rho=\frac{1}{64}+\frac{1}{9}\approx0.127\Bigr),

即参数量与 MACs 都降到约 1/81/8。(含偏置时实测比值略大于该式。)

推导

标准卷积参数 C2k2C^2k^2;可分离为逐通道 Ck2Ck^2 加逐点 C2C^2,合计 Ck2+C2Ck^2+C^2,相除即得。计算量同理:逐通道的 MACs 为 HoutWoutCk2H_{out}W_{out}Ck^2、逐点为 HoutWoutC2H_{out}W_{out}C^2,相加后除以标准的 HoutWoutC2k2H_{out}W_{out}C^2k^2 得到完全相同的比值——因为输出面积在分子分母中约掉了。■\blacksquare

∎
例 3.2.4 · 把 ResNet 的 3×33\times3 换成深度可分离会怎样

把例 3.2.2 中瓶颈块的 3×33\times3、64→6464\to64、56×5656\times56 换为深度可分离卷积,求新参数量与 MACs,并给出该块总量相对对照组的变化。

解

逐通道(C=64C=64,k=3k=3;PyTorch 的 groups=C 默认带偏置,故为 C(k2+1)C(k^2+1)):Params =640=640,MACs =56⋅56⋅64⋅9=1.81×106=56\cdot56\cdot64\cdot9=1.81\times10^{6}。 逐点(1×11\times1,64→6464\to64):Params =64⋅64+64=4,160=64\cdot64+64=4{,}160,MACs =56⋅56⋅64⋅64=1.28×107=56\cdot56\cdot64\cdot64=1.28\times10^{7}。

可分离合计:Params =4,800=4{,}800(原 36,92836{,}928 的 13.0%13.0\%);MACs =1.45×107=1.45\times10^{7}(原 1.156×1081.156\times10^{8} 的 12.6%12.6\%)。 该块总量(降维 16,44816{,}448 + 可分离 4,8004{,}800 + 升维 16,64016{,}640):Params =37,888=37{,}888,MACs ≈1.34×108\approx1.34\times10^{8},相对原瓶颈块分别降到 55%55\% 与 61%61\%,相对单层 3×33\times3 的参数量降到 6.4%6.4\%。

权衡提醒:这只是「更省」的一半故事。省下的容量需要用更多通道或更多层补回来,否则精度下降。MobileNet 系列(面向移动端与嵌入式)正基于这一组取舍设计,在同等精度下计算量比同期 ResNet 低一个数量级左右——具体基准数字随实现与训练配方变化,引用时需核实版本与训练配置。

∎

3.2.7 转置卷积与上采样

定义 3.2.6 · 转置卷积(transposed convolution)

设卷积可写成矩阵形式 y=Axy=Ax(AA 由核、步幅、填充唯一确定,是稀疏的带状矩阵)。转置卷积(又称反卷积 deconvolution、分数步幅卷积)定义为以 ATA^{\mathrm T} 为权重矩阵的线性映射 y′=ATx′y&#x27;=A^{\mathrm T}x&#x27;。它交换了「卷积输入空间」与「输出空间」的角色,故输出尺寸满足

Wout=(Win−1) s−2p+k(3.7)W_{out}=(W_{in}-1)\,s-2p+k \tag{3.7}

(s=1s=1 时退化为对称式;s>1s\gt1 时具体输出尺寸还依赖 output padding,可落在长度为 ss 的一个区间内)。

转置卷积不是「逆运算」,而是「与卷积的梯度同形」

不要把它理解成「把卷积撤销」。两个正确的理解方式:① 形状一致的梯度算子——对 y=Axy=Ax,反向传播要算 ∂L/∂x=AT(∂L/∂y)\partial\mathcal L/\partial x=A^{\mathrm T}(\partial\mathcal L/\partial y),这个 ATA^{\mathrm T} 是必然出现的运算;转置卷积就是把这个「卷积反向传播中对输入求导」的线性层单独拿出来当上采样层用,这也解释了它为什么天然带可学习参数(就是那个核)。② 等效的「零插值 + 普通卷积」——把输入元素之间插入 s−1s-1 个零、再补零填充,然后用翻转的核做一次普通卷积,结果与转置卷积完全一致;因此它不需要新算子。

代价:零插值 + 大步幅会在输出上留下棋盘格伪影(checkerboard artifact)——不同位置参与的乘加次数不一致导致幅度周期性起伏。常见缓解:用「上采样 + 普通卷积」替代(最近邻 / 双线性放大后接 3×33\times3 卷积),或让核大小能被步幅整除。

上采样方式可学习参数量典型用途与注意点
最近邻插值否0快、无伪影;块状感明显,常后接卷积平滑
双线性插值否0平滑,分割网络常用;不引入可学习容量
转置卷积是k2CinCoutk^2C_{in}C_{out}表达力强;s>1s\gt1 易出棋盘格,需谨慎设核与步幅
像素重排 PixelShuffle否(前置卷积可学)0(本身)把通道维重排成空间维,与 ss 倍放大等价,超分常用
反池化 / 最大位置索引否0U-Net 早期版本用过;现代多用插值 + 卷积

(上采样方式的取舍见下表;本教程在第 3.7 节还会回到「解码器如何恢复分辨率」的完整讨论。)

3.2.8 实现视角:im2col 与卷积的效率

「滑窗 + 内积」是一句双重循环,但 GPU 跑不出速度。工业界把卷积变成矩阵乘(GEMM),因为矩阵乘有几十年优化积累(cuBLAS / MKL)。

算法 3.2.1 · im2col + GEMM 的卷积实现
# 输入 x: (C_in, H, W),核 w: (C_out, C_in, k, k),步幅 s,填充 p
1. im2col:把每个输出位置的 k×k×C_in 窗口拉成一列
   → X_col: (C_in·k·k, H_out·W_out)     # 内存放大 k² 倍,是其主要代价
2. reshape 核 → W_mat: (C_out, C_in·k·k)
3. GEMM:Y = W_mat @ X_col → (C_out, H_out·W_out)
4. col2im:按列还原为 (C_out, H_out, W_out),加偏置

为什么有效:把「带边界的滑窗」这道麻烦交给第 1 步的访存变换,剩下的交给高度优化的矩阵乘。k=3k=3 时内存放大 9 倍、k=7k=7 时 49 倍。

三种主流实现路线的取舍
  • im2col + GEMM:通用、易写、能吃 BLAS 优化;代价是内存放大与额外访存,小核(3×33\times3)最常用。
  • Winograd:用多项式变换减少乘法次数(F(2×2,3×3)F(2\times2,3\times3) 把每 4 个输出的乘法从 36 次降到 16 次),代价是数值误差略升、变换本身有开销,对深度可分离卷积收益有限。
  • 隐式 GEMM / 直接卷积:不物化 X_col,在片上缓存里分块累加,避免 k2k^2 倍内存放大——现代算子库的默认路线。

学习建议:用 torch.unfold 亲手写一遍 im2col,确认自己算的 MACs 与工具(如 thop、fvcore)报的一致;然后记住「真实速度还取决于访存与算子库,不能只看 MACs」——这条在本教程第 9 讲会再次出现。

import torch
import torch.nn as nn
import torch.nn.functional as F

x = torch.randn(2, 3, 224, 224)          # (B, C_in, H, W):批优先,通道在维度 1

# 1) 基本卷积:核 3x3、64 个输出通道、步幅 2、填充 1 → 尺寸减半
conv = nn.Conv2d(3, 64, kernel_size=3, stride=2, padding=1)
y = conv(x)
assert y.shape == (2, 64, 112, 112)                        # floor((224+2-3)/2)+1 = 112
assert sum(p.numel() for p in conv.parameters()) == 1792    # 64*3*9 + 64

# 2) 手写 im2col 卷积,与 Conv2d 数值比对
def conv2d_via_unfold(x, weight, bias=None, stride=1, padding=1):
    B, C, H, W = x.shape
    C_out, _, k, _ = weight.shape
    if padding:
        x = F.pad(x, (padding,) * 4)                      # 上下左右各补 padding
    cols = F.unfold(x, kernel_size=k, stride=stride)      # (B, C*k*k, L)
    out = weight.view(C_out, -1) @ cols                   # 批矩阵乘 → (B, C_out, L)
    if bias is not None:
        out = out + bias.view(1, -1, 1)                   # 偏置按通道广播
    Ho = (H + 2 * padding - k) // stride + 1              # 与公式 (3.2) 一致
    return out.view(B, C_out, Ho, (W + 2 * padding - k) // stride + 1), cols

y2, cols = conv2d_via_unfold(x, conv.weight, conv.bias, stride=2, padding=1)
print("与 Conv2d 最大误差 =", (y - y2).abs().max().item())  # 期望 ~1e-6 量级
print("col 形状 =", tuple(cols.shape), "内存放大 = C_in*k^2 =", 3 * 9, "倍")

# 3) 分组与深度可分离:groups 就是全部代码
dw = nn.Conv2d(64, 64, 3, padding=1, groups=64)   # 逐通道:groups = C_in = C_out
pw = nn.Conv2d(64, 64, 1)                          # 逐点:通道混合
sep = sum(p.numel() for p in dw.parameters()) + sum(p.numel() for p in pw.parameters())
print(f"标准 {64*64*9+64} vs 深度可分离 {sep},比值 {sep/(64*64*9+64):.3f}")   # ≈0.13

# 4) 转置卷积:k=4, s=2, p=1 时输出精确翻倍
up = nn.ConvTranspose2d(64, 32, kernel_size=4, stride=2, padding=1)
assert up(torch.randn(1, 64, 56, 56)).shape == (1, 32, 112, 112)
本节常见误解
  1. 「卷积」到底翻不翻核:深度学习实现的是互相关,不翻转核;但手推反向传播、做核合并、对接信号处理公式时必须显式处理翻转(命题 3.2.1、定理 3.2.1)。
  2. 核形状写反:核是 (Cout,Cin,k,k)(C_{out},C_{in},k,k)。nn.Conv2d(64, 32, 3) 表示输入 64 通道、输出 32 通道,不是反过来——写错就是形状报错十有八九的来源。
  3. 以为输出通道由输入通道决定:输出通道数由核的个数决定,是完全自由的超参数;唯一硬约束是核的深度 =Cin=C_{in}。
  4. 忘了 1×11\times1 卷积也有偏置:瓶颈块参数量核对时的 +64+64 就是它,漏掉会以为「公式算错了」。
  5. 把转置卷积当卷积的逆:它不是逆运算,只是「与卷积梯度同形」的上采样;用零插值 + 大步幅时还会带来棋盘格伪影。
  6. 低估大核卷积的参数开销:kk 从 3 到 7,参数涨 49/9≈5.449/9\approx5.4 倍、内存放大也涨到 49 倍;「用大核扩视野」通常不如「下采样 + 小核」或空洞卷积划算。
  7. 把理论感受野当作实际上下文:有效感受野远小于理论值,且呈中心加权分布(延伸阅读 Luo et al. 2016)。
即时自测 · 3.2

Q1 输入 64×64×3264\times64\times32,用 5×55\times5 核、6464 个输出通道、s=2s=2、p=2p=2,求输出形状、参数量与 MACs。

Q2 LL 层 5×55\times5、s=1s=1 卷积的感受野是多少?要得到 101×101101\times101 的感受野,纯堆 5×55\times5 需要多少层?改用「每两层后接一次 2×22\times2 池化」,10 层能到多大?

Q3 深度可分离卷积在 k=5k=5、C=128C=128 时参数量是标准卷积的几分之几?为什么这个比值随 CC 增大趋近 1/k21/k^2?

Q4 为什么说「转置卷积不是卷积的逆」?从信息量角度给一句话理由,并解释它为什么必然带可学习参数。

参考要点

Q1 Hout=⌊(64+4−5)/2⌋+1=32H_{out}=\lfloor(64+4-5)/2\rfloor+1=32,输出 32×32×6432\times32\times64。参数量 =64×32×25+64=51,264=64\times32\times25+64=51{,}264。MACs =32⋅32⋅64⋅32⋅25=5.24×108=32\cdot32\cdot64\cdot32\cdot25=5.24\times10^{8}。

Q2 rL=5+4(L−1)=4L+1r_L=5+4(L-1)=4L+1;要 4L+1≥1014L+1\ge101 得 L≥25L\ge25。改用每两层后接一次 2×22\times2 池化:每阶段增量 =2×4j+j=9j=2\times4j+j=9j,且 jj 每阶段翻倍,从 r=5,j=1r=5,j=1 出发五阶段得 r=5+9+18+36+72+144=284r=5+9+18+36+72+144=284——10 层就到 284,远超 101。(这正是「下采样让感受野滚雪球」的量级感。)

Q3 ρ=1/128+1/25≈0.048\rho=1/128+1/25\approx0.048,约 4.8%4.8\%。C≫k2C\gg k^2 时第一项可忽略,比值趋近 1/k21/k^2:参数量大头是逐点卷积的 C2C^2,它与标准卷积的 C2k2C^2k^2 只差一个 k2k^2。

Q4 正向卷积把多个不同输入映射到同一输出(多对一),信息在此时不可逆地丢失;转置卷积只把维度放大回来,既不能恢复被平均掉的信息,也无法保证 ATAx=xA^{\mathrm T}Ax=x(卷积矩阵几乎总是奇异的)。它必然带参数,因为 ATA^{\mathrm T} 的元素就是原卷积核(翻转后)的元素——上采样层里的「核」与卷积同构;实践中这些权重是另学的一组,所以它同时是可训练的。

延伸阅读
  • LeCun, Bottou, Bengio & Haffner, Gradient-Based Learning Applied to Document Recognition(1998,Proc. IEEE)——LeNet-5,卷积用于图像识别的奠基文献。
  • Simonyan & Zisserman, Very Deep Convolutional Networks for Large-Scale Image Recognition(2014,arXiv:1409.1556)——「小核堆叠」的系统论证。
  • He, Zhang, Ren & Sun, Deep Residual Learning for Image Recognition(2015,arXiv:1512.03385)——瓶颈设计与残差块。
  • Luo, Li, Urtasun & Zemel, Understanding the Effective Receptive Field in Deep Convolutional Neural Networks(2016,arXiv:1701.04128)——理论感受野与有效感受野的区别。
  • Yu & Koltun, Multi-Scale Context Aggregation by Dilated Convolutions(2015,arXiv:1511.07122)——空洞卷积用于分割的原始动机。
  • Howard et al., MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications(2017,arXiv:1704.04861)——深度可分离卷积的工程化。
  • Lavin & Gray, Fast Algorithms for Convolutional Neural Networks(2015,arXiv:1509.09308)——Winograd 卷积的系统论述。
  • PyTorch 文档 torch.nn.Conv2d、torch.nn.functional.unfold、torch.nn.ConvTranspose2d——形状语义以官方文档为准(API 有版本差异,引用时注明版本)。

本节小结:网络里的卷积实际是互相关(命题 3.2.1),与数学卷积只差一次核翻转;输出尺寸、参数量、计算量三条公式 (3.2)、(3.4)、(3.5) 必须能随手手算;感受野按 (3.6) 递推,下采样让感受野近似几何增长而纯堆小核只是线性增长;分组 / 深度可分离卷积用「解耦空间与通道」换来约 1/81/8 的算力;转置卷积是「与卷积梯度同形」的上采样,能放大形状但不能恢复信息。下一节处理卷积之外剩下的零件:池化如何把等变升级为不变,归一化层为什么在训练与推理时行为不同,以及 Dropout 在卷积里为什么必须换一种做法。