资讯动态

转置卷积原理详解:stride、padding与output_padding参数计算指南

发布时间:2026/10/14 12:46:31 来源:尧图企业网站定制
1. 转置卷积到底在做什么从一个反直觉的现象说起很多人第一次接触转置卷积脑子里都会冒出一个巨大的问号明明叫“卷积”为什么它的输出比输入还大普通卷积是做特征压缩把一张大图变小提取出更抽象的特征转置卷积却反着来把一张小图放大。这个方向上的差异是理解转置卷积的第一道门槛也是很多人卡住的地方。我在带新人的时候发现一个特别普遍的现象大家会用nn.ConvTranspose2d也能把代码跑通但一旦被问到“stride 和 padding 到底怎么影响输出尺寸”“为什么它又叫反卷积”“它和插值上采样有什么本质区别”就答不上来了。这说明大家只是记住了 API没有真正理解这个操作在数学上发生了什么。这篇内容就是冲着这个问题来的。我会把转置卷积拆到最底层从“它其实是一种特殊的普通卷积”这个角度切入把 stride、padding、output_padding 三个参数对输出尺寸的影响讲透再顺带把“转置卷积”和“反卷积”这两个名字的来龙去脉说清楚。适合已经学过基础卷积、想彻底搞懂上采样原理的读者也适合在图像分割、超分辨率、生成模型里用到转置卷积、但一直没弄明白参数怎么调的人。核心关键词我先摆在这里转置卷积、反卷积、stride、padding、output_padding、上采样、卷积矩阵。后面所有内容都围绕它们展开。2. 为什么需要转置卷积上采样任务的真实需求2.1 从普通卷积的“降维”说起普通卷积大家都很熟。一张 5×5 的输入配一个 3×3 的卷积核stride 取 1、padding 取 0输出就是 3×3。空间尺寸从 5 缩到 3信息被压缩了。如果 stride 取 2压缩得更狠5×5 直接变成 2×2。这就是卷积的“降采样”特性也是它在分类网络里好用的原因——越往深层走特征图越小感受野越大语义越抽象。但问题来了。图像分割要求输出和输入一样大每个像素都要有类别超分辨率要求输出比输入更大生成模型要从一个低维噪声向量逐步“长出”一张完整图像。这些任务都需要一个和卷积方向相反的操作把小特征图放大回大尺寸。这就是转置卷积要解决的问题。2.2 朴素上采样的局限最朴素的上采样是最近邻插值每个像素复制几份尺寸就放大了。简单、快但有个致命问题——它没有任何可学习的参数。放大过程是固定的网络没法根据数据去学习“怎么放大才合理”。双线性插值稍微好一点会做加权平均但权重也是固定的同样不可学习。转置卷积的价值就在于它把上采样变成了一个带可学习参数的卷积操作。放大多少、怎么填充、每个输出像素由哪些输入像素加权得到全部由卷积核的权重决定而这些权重是训练出来的。这就让网络能够针对具体任务学出一套最适合的上采样方式。这是它和插值上采样最本质的区别也是它在分割、生成任务里长期占据主流的原因。2.3 一个容易混淆的点它不是卷积的逆运算这里必须提前澄清一个误区。转置卷积名字里有“转置”但它不是普通卷积的逆运算。普通卷积会丢失信息5×5 压成 3×3边缘信息被丢掉了一个丢失信息的操作在数学上是不可逆的。转置卷积只是在形状上把尺寸还原回去它还原不出原来每个像素的精确值。你可以把它理解成“形状上的逆”而不是“数值上的逆”。想清楚这一点后面理解它的计算过程会顺畅很多。3. 转置卷积的数学本质它其实还是一次普通卷积3.1 用矩阵乘法重新理解卷积要真正搞懂转置卷积最有效的方法是把卷积写成矩阵乘法。假设输入是一个 4×4 的图我们把它拉平成一个 16×1 的列向量。一个 3×3 的卷积核stride1、padding0输出是 2×2也就是 4 个值。这 4 个值每一个都是输入 16 个元素的加权和所以可以写成一个 4×16 的矩阵去乘那个 16×1 的向量。这个 4×16 的矩阵就是卷积操作的矩阵表示。它的每一行对应一个输出位置行里的非零元素就是卷积核在该位置覆盖到的输入元素对应的权重。这个矩阵有个特点它是稀疏的而且每一行的非零元素是卷积核权重的一种“滑动排列”。3.2 “转置”这个名字的由来现在关键来了。普通卷积的矩阵是 4×16输入 16 维输出 4 维。如果我们想要反过来输入 4 维、输出 16 维最自然的做法是什么把这个矩阵转置一下变成 16×4然后去乘一个 4×1 的向量就得到 16×1 的输出。这就是“转置卷积”这个名字的数学来源——它用的是普通卷积矩阵的转置。所以严格来说转置卷积并不是先定义了一个新操作再起名而是先有了“卷积矩阵的转置”这个数学对象然后大家发现它恰好能实现上采样的效果才把它用起来。理解了这个来源你就明白为什么它的参数配置和普通卷积那么像又为什么它的输出尺寸计算方式和普通卷积是“反着来”的。3.3 转置卷积和普通卷积的等价关系这里有一个非常漂亮、但很多人不知道的结论转置卷积等价于对输入做某种填充后再进行一次普通卷积。具体来说转置卷积可以看成先在输入元素之间插入空洞空洞大小由 stride 决定然后在周围补零补多少由 padding 和 kernel 决定最后用一个翻转过的卷积核做普通卷积。这个等价关系是理解所有参数行为的钥匙。stride 越大插入的空洞越多输出自然越大padding 越大补的零越多输出反而越小因为补零相当于把有效区域往外扩抵消了一部分放大效果。后面讲尺寸公式的时候我会反复回到这个等价关系上你会发现所有公式都能从这里推出来。4. stride 与 padding 对输出尺寸的影响把公式彻底讲透4.1 普通卷积的输出尺寸公式回顾先把普通卷积的公式摆出来方便对照。输入尺寸为 $H_{in}$卷积核大小为 $K$stride 为 $S$padding 为 $P$那么输出尺寸是$$H_{out} \lfloor \frac{H_{in} 2P - K}{S} \rfloor 1$$这个公式大家应该都背过。它的直觉是先加上两边补的 padding减去卷积核覆盖的长度剩下的可滑动范围除以步长再加 1。4.2 转置卷积的输出尺寸公式转置卷积的公式是$$H_{out} (H_{in} - 1) \times S - 2P K \text{output_padding}$$这个公式乍一看很怪但用 3.3 节的等价关系一推就通了。转置卷积先在输入元素之间插入 $S-1$ 个空洞输入从 $H_{in}$ 变成 $H_{in} (H_{in}-1)(S-1)$也就是 $(H_{in}-1)S 1$。然后做一次普通卷积padding 是 $P$核是 $K$套普通卷积公式$$H_{out} \frac{[(H_{in}-1)S 1] 2P - K}{1} 1$$这里 stride 取 1因为空洞已经插好了。化简一下就是 $(H_{in}-1)S 2P - K 2$。等等这和我上面给的公式差了个符号。别急转置卷积里的 padding 是“反向”的——普通卷积是往外补零转置卷积是往里裁掉。所以公式里是减 $2P$ 而不是加。最终得到$$H_{out} (H_{in} - 1) \times S - 2P K$$再加上 output_padding 就是完整公式。这个推导过程我建议你自己在纸上写一遍写完之后你对这个公式的记忆会比死记硬背牢十倍。4.3 参数组合的实战对照表光看公式还是抽象直接上表。假设卷积核 $K3$输入 $H_{in}4$我们看不同 stride 和 padding 组合下的输出stridepaddingoutput_padding输出尺寸说明1006最基础放大4→61104padding 抵消放大尺寸不变2009stride 翻倍放大明显2107padding 裁掉两边2118output_padding 补一个31010大 stride 大放大从表里能看出几个规律。第一stride 是放大倍率的主要控制者stride 越大输出越大。第二padding 起的是“收缩”作用每增加 1输出减 2。第三output_padding 只能微调而且它不参与卷积计算只是在输出的一侧多补一行/一列用来解决尺寸对不齐的问题。4.4 output_padding 到底解决什么问题output_padding 是很多人最迷惑的参数。它的作用只有一个当 $(H_{in}-1)S - 2P K$ 算出来的尺寸和你想要的尺寸差一点点时用它来补齐。举个典型场景。你想做一个 stride2 的上采样输入 4×4希望输出 8×8。用 $K3, S2, P1$ 代入$(4-1)\times2 - 2 3 7$。差 1。这时候 output_padding 设成 1输出就变成 8。如果不设输出是 7和下一层要求的 8 对不上网络就崩了。注意output_padding 必须小于 stride。这是硬性约束因为它的本质是在输出的一侧补额外的行/列补多了会和下一次卷积的滑动窗口冲突。设成大于等于 stride 会直接报错。5. 转置卷积与反卷积名字之争的来龙去脉5.1 “反卷积”这个叫法是怎么来的在早期的深度学习文献和很多中文教程里转置卷积经常被叫做“反卷积”Deconvolution。这个叫法其实是从信号处理领域借来的。在信号处理里反卷积确实指的是卷积的逆运算——已知输出和卷积核反推输入。这个操作在数学上是良定义的也有成熟的求解方法。但深度学习里的转置卷积不是这个意思。它不反推输入只是做了一个形状上的放大。所以严格来说把它叫反卷积是错的。那为什么这个叫法流传这么广因为早期做分割的论文比如那篇经典的 FCN用了 deconvolution 这个词后来大家就跟着叫了约定俗成改不过来。5.2 为什么现在主流叫“转置卷积”现在学术界和主流框架基本都统一叫转置卷积Transposed Convolution了。原因很简单这个名字准确。它描述的就是“用卷积矩阵的转置来做运算”这个数学事实不会让人误以为它在求逆。PyTorch 里的类名是ConvTranspose2dTensorFlow 里是Conv2DTranspose都是这个思路。我的建议是在正式场合、写论文、写文档的时候一律用“转置卷积”。跟别人交流时如果对方说“反卷积”你心里知道他说的是转置卷积就行不用刻意纠正但自己别跟着叫错。5.3 一个容易踩的坑别把它当成真的求逆我见过有人真的拿转置卷积去尝试还原普通卷积的输入结果发现还原出来的东西和原图差很远然后怀疑自己代码写错了。其实没错是理解错了。普通卷积丢的信息比如边缘被卷积核覆盖不到的部分在转置卷积里是补不回来的它只能补零或者补学出来的值。所以如果你要做的是“精确还原”转置卷积帮不了你如果你要做的是“合理放大”它才是对的工具。6. 转置卷积的实操从零实现一个上采样模块6.1 PyTorch 里的基本用法先看最基本的调用方式import torch import torch.nn as nn # 输入batch1, channel3, H4, W4 x torch.randn(1, 3, 4, 4) # 转置卷积层输入通道3输出通道8核3x3stride2padding1output_padding1 deconv nn.ConvTranspose2d( in_channels3, out_channels8, kernel_size3, stride2, padding1, output_padding1 ) y deconv(x) print(y.shape) # torch.Size([1, 8, 8, 8])输入 4×4输出 8×8正好放大两倍。这个配置是分割网络里最常用的“双倍上采样”模板你可以直接抄。6.2 参数选择的计算过程上面那组参数不是随便写的我们倒推一下。目标是 4→8放大两倍所以 stride 取 2。核大小取 3 是最常见的因为 3×3 的感受野和参数量平衡得最好。然后代入公式$$H_{out} (4-1)\times2 - 2P 3 \text{op}$$要让它等于 8先算 $(4-1)\times2 3 9$。所以 $-2P \text{op} -1$。如果 $P1$那么 $\text{op}1$。如果 $P0$那么 $\text{op}-1$不合法。所以 $P1, \text{op}1$ 是这组目标下最自然的选择。这个倒推过程在实际搭网络时非常有用。你先定好输入输出尺寸和放大倍率然后反推 padding 和 output_padding比瞎试快得多。6.3 用转置卷积搭一个完整的解码器下面是一个简化的解码器片段展示转置卷积怎么和普通卷积配合class DecoderBlock(nn.Module): def __init__(self, in_ch, out_ch): super().__init__() self.up nn.ConvTranspose2d( in_ch, out_ch, kernel_size3, stride2, padding1, output_padding1 ) self.conv nn.Sequential( nn.Conv2d(out_ch, out_ch, 3, padding1), nn.BatchNorm2d(out_ch), nn.ReLU(inplaceTrue) ) def forward(self, x): x self.up(x) x self.conv(x) return x这个结构里转置卷积负责放大后面的普通卷积负责在放大后的特征图上做一次平滑和特征重组。为什么要加后面那个卷积因为转置卷积的输出容易出现“棋盘格伪影”checkerboard artifact加一层普通卷积能有效缓解。这是实战里非常常用的一招。6.4 棋盘格伪影的成因与规避棋盘格伪影是转置卷积最出名的问题。现象是输出图像上出现规律的网格状明暗条纹。成因是当 stride 大于 1 时卷积核在输入上滑动时不同输出位置被覆盖的次数不均匀。有些位置被覆盖多次有些只被覆盖一次导致输出值忽大忽小形成条纹。规避方法有几个。第一把 kernel_size 设成 stride 的整数倍比如 stride2 时用 4×4 的核覆盖更均匀。第二在转置卷积后面接一层普通卷积做平滑。第三干脆用“插值上采样 普通卷积”替代转置卷积很多现代网络比如一些分割模型就是这么做的效果更稳。我个人在项目里更倾向第三种虽然多了一步但省心。7. 常见问题与排查技巧实录7.1 尺寸对不上怎么办这是最高频的问题。现象是转置卷积的输出和下一层期望的输入尺寸差 1 或 2。排查步骤先手算一遍公式确认理论输出尺寸。打印实际输出尺寸和理论值对比。如果差 1优先调 output_padding。如果差得多检查 stride 和 padding 是不是配错了。我整理了一个速查表现象可能原因解决输出比预期小 1output_padding 没设设为 1输出比预期大很多stride 设大了检查放大倍率输出尺寸不变padding 太大减小 padding报错 output_padding 非法op stride把 op 改小7.2 训练不收敛的几个隐藏原因转置卷积本身不会导致不收敛但它的参数配置会间接影响。我踩过的坑里有两个特别典型。第一个是 output_padding 设错导致尺寸错位网络在拼接 skip connection 时形状对不上报错或者静默广播训练直接崩。第二个是转置卷积的初始化。默认初始化在放大倍率大时容易让输出值爆炸建议用较小的初始化或者在转置卷积后加 BatchNorm。提示如果你的网络里有 skip connection转置卷积的输出尺寸必须和对应编码器层的尺寸严格一致。差一个像素都会导致拼接失败。这时候 output_padding 就是你的救命参数。7.3 转置卷积 vs 插值上采样怎么选这个问题我被问过无数次。直接给结论追求效果、算力充足、任务对细节要求高用转置卷积让它自己学。追求稳定、怕棋盘格、想省事用插值上采样 普通卷积。生成模型比如 GAN 的生成器转置卷积用得多但要注意伪影。语义分割两者都有现代网络更偏向插值方案。我个人的经验是新手先用插值方案把流程跑通等有精力调优了再换转置卷积对比效果。不要一上来就纠结用哪个先把网络跑起来最重要。8. 我在实际项目里总结的几条经验转置卷积这个操作我前后在好几个项目里用过从分割到超分都碰过。最大的体会是它的参数不是调出来的是算出来的。你把输入输出尺寸和放大倍率定死stride、padding、output_padding 就基本确定了剩下的空间很小。所以与其反复试参数不如先把公式吃透一次算对。另一个体会是关于名字的。刚入行的时候我也跟着叫“反卷积”后来写文档被同事指出来才去查了来龙去脉。现在我在团队里要求所有人写代码注释和文档时统一用“转置卷积”避免新人被误导。这个习惯看起来小但能省掉很多沟通成本。最后分享一个实用技巧如果你不确定一组参数对不对写个三行的小脚本随机生成一个输入跑一遍转置卷积打印输出尺寸和你期望的对比。这比在完整网络里调试快得多也不会被其他层的报错干扰。这个习惯我保持了几年帮我省下了大量排查时间。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑