【图像增强】Restormer 模型详解 笔记 CVPR2022 【参考[2111.09881] Restormer: Efficient Transformer for High-Resolution Image Restoration】注意点所有橙色 Transformer Block 都包含有 MDTA 和 GDFN。注意力多头每个头学习一个特征多个头学习多个特征学习点MDTA根据全图信息动态组合不同特征通道。怎么做通过 1 × 1 卷积和 3 × 3 深度卷积生成 Q、K、V再利用全部空间位置的响应计算通道注意力A softmax(t · Q̄ · K̄ᵀ)最后用O A · V加权组合特征。主要作用建立通道之间的依赖关系让特征组合方式随输入内容变化同时结合局部邻域信息和全图统计信息。复用场景希望网络利用全图信息又不想建立巨大的像素 × 像素注意力矩阵时。注意点每头注意力矩阵是d × d不是HW × HW输入通道数必须能被头数整除。GDFN通过局部处理和乘法门控进一步变换特征。怎么做先扩张通道并执行深度卷积再拆成两条分支计算G GELU(Z₁) ⊙ Z₂最后将通道投影回原大小。主要作用引入局部空间信息和非线性让一条分支调制另一条分支对特征进行抑制、放大或其他调整。复用场景需要增强普通前馈网络或卷积模块的特征变换能力时可以用它替换简单的“两层投影 激活”结构。注意点门控没有 sigmoid数值不限于[0,1]因此不是概率开关。模块方便记忆的作用核心操作MDTA决定不同通道如何协同全图响应计算通道关系再加权混合GDFN对混合后的特征进一步加工局部卷积、非线性、逐元素门控复用接口两者都能保持[B,C,H,W] → [B,C,H,W]。在你的可读版代码中它们本身不包含 LayerNorm 和残差相加组合成完整 Block 时使用X₁ X MDTA(LN₁(X))再使用X₂ X₁ GDFN(LN₂(X₁))。Restormer 模型图中的Restormer 是一种用于图像恢复的四级编码器—解码器网络。它将退化图像转换为特征通过不同分辨率的 Transformer Block 提取信息再逐级恢复分辨率预测图像残差得到清晰图像。它的主要特点是使用 MDTA 建立由全图信息决定的通道注意力使用 GDFN 对特征进行门控变换同时通过多尺度结构与跳跃连接保留图像细节。下面按图中的数据流详细解释。公式使用行内代码和 Unicode 符号避免 LaTeX 渲染问题。具体计算对应项目中的 …/basicsr/models/archs/restormer_arch.py第 1 步先找到输入和输出确定读图方向图左上角的照片下面写着DegradedI是输入图像。“Degraded”表示图像存在退化例如模糊、噪声或者雨纹。I 是这张输入图像的符号。图右上角的照片旁边写着RestoredÎ是网络输出的恢复图像。Î 表示网络对清晰图像的预测。中间的大部分结构就是将左边的退化图像转换为右边恢复图像的处理过程。整张图的主要路线是从左上角进入沿左侧向下到达底部再沿中间偏右的位置向上最后向右输出。你可以先把它想成一条 U 形路线。左边向下的部分负责提取特征右边向上的部分负责恢复图像。第 2 步明确哪里是编码器哪里是解码器你问的“哪里是解码器”先直接定位编码器在图的左侧。从最上方第一个橙色Transformer Block × L₁开始沿红色向下箭头经过Transformer Block × L₂、Transformer Block × L₃最后到图底部的Transformer Block × L₄。解码器在图的中间偏右沿绿色向上箭头排列。从底部的 L₄ 模块输出开始经过绿色上采样箭头、圆圈 C、1 × 1 卷积和橙色 Block逐级向上直到最上方中间的Transformer Block × L₁。具体来说解码器的三个处理层从下往上是中间偏下的Transformer Block × L₃。中间位置被展开为MDTA GDFN的橙色 Block。它代表二级解码器中的 Transformer Block内部结构被画出来了。最上方中间的Transformer Block × L₁它是一级解码器。最上方更靠右、下面写着Refinement的 Block 是后续精炼阶段。图底部的Transformer Block × L₄是连接编码器和解码器的最低分辨率部分通常叫作瓶颈层。项目代码将它命名为latent。所以读这张图时可以先划出四块左侧编码器、底部瓶颈层、中间偏右解码器、右上方精炼与输出。第 3 步理解“编码”和“解码”在这里是什么意思这里的“编码”不是把图片压缩成 JPEG 文件也不是加密。编码器做的是将图片转换成网络内部的特征表示并逐步在更低分辨率上处理这些特征。解码器做的是将低分辨率特征逐步恢复到原始分辨率并融合编码器保留下来的信息为生成恢复图像做准备。还有一点很重要解码器的中间输出通常仍然是“特征”不是可以直接显示的 RGB 图片。直到最后一个输出卷积网络才把这些特征转换成 3 通道图像。第 4 步先搞懂 H、W、C后面才能看懂每条箭头图中反复出现H × W × CH特征图的高度。W特征图的宽度。C特征图的通道数。输入 RGB 图像有三个通道即红、绿、蓝所以图中的输入和输出都是H × W × 3。经过网络卷积后通道数可以变成 48、96、192、384。这些通道已经不是红、绿、蓝了而是网络学习得到的不同特征响应。例如一些通道可能对边缘变化比较敏感一些可能对某种纹理或颜色组合比较敏感。不过每个通道的意义由训练决定并没有人为规定“第一个通道必须检测边缘”。你可以把一个通道想成一张二维数值图。48 个通道就是 48 张高度为 H、宽度为 W 的数值图叠在一起。图中采用H × W × C的写法代码采用[B,C,H,W]。其中 B 是一次同时输入多少张图像。如果只输入一张B 1。比如一张 256 × 256 的 RGB 图片在代码中就是[1,3,256,256]。后面我们一直用这张图作为例子。第 5 步看懂图左侧的图例图中的符号分别表示图中符号含义对数据做什么3 × 3方框普通卷积从局部邻域计算新特征1 × 1方框点卷积在每个位置混合不同通道3 × 3 Dconv深度卷积分别处理每个通道的局部邻域红色向下箭头下采样降低空间分辨率绿色向上箭头上采样提高空间分辨率圆圈 CConcatenation拼接将两份特征沿通道接起来圆圈 RReshape重排改变数据的维度组织方式圆圈加号逐元素相加对应位置的数值相加实心点乘号逐元素相乘对应位置的数值相乘圆圈叉号矩阵乘法按矩阵规则进行加权组合NormLayer Normalization归一化特征弯曲符号GELU 激活对数值进行非线性变换先记住两个容易混淆的操作拼接会增加通道数。两份[1,48,256,256]特征沿通道拼接得到[1,96,256,256]。相加不会增加通道数。两份[1,48,256,256]特征逐元素相加结果仍是[1,48,256,256]。第 6 步输入先经过第一个 3 × 3 卷积从左上角的输入照片出发向右遇到一个绿色的3 × 3方框。这个卷积负责生成浅层特征 F₀。什么是卷积可以先理解为在图像上取一个局部窗口使用一组可学习的权重进行加权求和计算出一个新的数值再移动窗口继续计算。3 × 3 表示窗口的空间大小。对于 RGB 输入实际计算还会使用输入的三个通道。这个模块默认生成 48 个输出通道。因此输入[1,3,256,256]经过它后变成[1,48,256,256]。计算可以写成F₀ Conv₃×₃(I)。这里高度和宽度没有变化。代码中卷积的步长为 1并在边缘进行 padding所以输出空间尺寸仍为 256 × 256。代码将这个模块叫作OverlapPatchEmbed。它先把原始像素转换成后续网络可以处理的特征。第 7 步进入第一级编码器F₀ 向右进入图左上方第一个橙色方框Transformer Block × L₁。这里的“× L₁”表示连续执行 L₁ 个 Transformer Block。默认 L₁ 4所以这个方框实际上包含四个连续的 Block。这里的 L₁ 表示 Block 数量不是 L1 损失。每个 Block 都会改变特征中的数值但保持高度、宽度、通道数不变。所以一级编码器输入是[1,48,256,256]输出仍是[1,48,256,256]。把它的输出叫作 E₁计算为E₁ Encoder₁(F₀)。E₁ 的输出分成两条路线一条沿红色箭头向下继续进入更深的编码器。另一条沿横向黑线向右保留给最上层解码器使用这条横向路线就是跳跃连接后面会详细讲。第 8 步第一次下采样进入二级编码器从一级编码器向下遇到第一个红色箭头。这个箭头表示下采样。默认情况下这一步把[1,48,256,256]变成[1,96,128,128]。可以分开看高度256 → 128。宽度256 → 128。通道48 → 96。因此图中写的是H/2 × W/2 × 2C。代码里的下采样不是直接缩放图片而是两步操作。第一步用普通 3 × 3 卷积将通道从 48 减少到 24得到[1,24,256,256]。第二步使用PixelUnshuffle(2)把每个 2 × 2 空间块中的四个位置搬到通道维。空间尺寸减半通道乘以 4因此得到[1,96,128,128]。整个过程是[1,48,256,256] → [1,24,256,256] → [1,96,128,128]。PixelUnshuffle 只是重排元素没有可训练参数前面的卷积负责学习特征变换。随后特征进入Transformer Block × L₂。默认 L₂ 6连续处理六个 Block输出仍为[1,96,128,128]。把这份输出叫作 E₂。E₂ 同样分成两路一路继续向下一路横向保留给二级解码器。第 9 步第二次下采样进入三级编码器从二级编码器继续沿红色箭头向下。这次输入为[1,96,128,128]经过下采样得到[1,192,64,64]。变化规律和上一步一致空间尺寸减半通道数翻倍。图中对应H/4 × W/4 × 4C。因为已经连续下采样两次所以高度和宽度都变成最初的四分之一。随后进入Transformer Block × L₃。默认 L₃ 6经过六个 Block 后shape 仍为[1,192,64,64]。把输出叫作 E₃。E₃ 也保留一条横向跳跃连接供三级解码器使用。第 10 步第三次下采样到达底部瓶颈层继续沿红色箭头向下输入[1,192,64,64]变成[1,384,32,32]。图中对应H/8 × W/8 × 8C。接下来进入图底部的Transformer Block × L₄。默认 L₄ 8所以这里连续执行八个 Block。输出叫作 Fₗ代码将这组 Block 命名为latent。它的 shape 为[1,384,32,32]。到这里编码路径已经完成。原始图像有 256 × 256 个空间位置现在只有 32 × 32 个空间位置但每个位置拥有更多通道。网络在这样的特征表示上继续进行信息处理。需要注意低分辨率特征并不是一张简单缩小的照片它是经过多层卷积、注意力和前馈变换得到的数值表示。第 11 步从瓶颈层向上正式进入解码器现在从图底部的 Fₗ 出发沿线向右再沿第一个绿色箭头向上。这就是解码器的起点。绿色箭头表示上采样。第一次上采样将[1,384,32,32]变成[1,192,64,64]。空间尺寸翻倍通道数减半。代码里的上采样也有两步。第一步用普通 3 × 3 卷积将通道从 384 扩展到 768得到[1,768,32,32]。第二步使用PixelShuffle(2)将每四个通道重新组织成一个 2 × 2 空间区域得到[1,192,64,64]。完整过程是[1,384,32,32] → [1,768,32,32] → [1,192,64,64]。PixelShuffle 本身是重排操作不是凭空生成新信息。上采样前的卷积会学习如何生成适合重排的通道特征。第 12 步在圆圈 C 处与三级编码器特征拼接第一次上采样后向上会遇到一个圆圈 C。这里有两条输入一条从下面来是刚上采样得到的[1,192,64,64]。另一条从左边来是三级编码器之前保留的 E₃shape 同样为[1,192,64,64]。圆圈 C 将它们沿通道拼接得到[1,384,64,64]。可以写成Z₃ Concat(Up(Fₗ), E₃)。为什么要把编码器的特征拿过来因为编码器在这个分辨率上已经提取过信息。解码器恢复到相同分辨率时可以直接使用这些保留下来的特征不必完全依赖底部特征重新构造所有细节。这条横向路线叫作skip connection跳跃连接。它跨过了更深的处理路径将某一级的信息直接送到对应的解码级。第 13 步通过 1 × 1 卷积再进入三级解码器拼接后向上会遇到一个蓝色的1 × 1方框。这是一个 1 × 1 卷积负责将通道从 384 压缩回 192shape 从[1,384,64,64]变成[1,192,64,64]。1 × 1 卷积虽然不直接查看周围像素但会在每个位置混合全部输入通道。可以把它理解为在一个位置上将 384 个特征数值重新组合成 192 个数值。随后进入橙色Transformer Block × L₃。这就是三级解码器默认包含六个 Block。经过处理后输出 D₃ 为[1,192,64,64]。把刚才三个操作连起来就是上采样 → 与编码特征拼接 → 1 × 1 压缩通道 → Transformer Block。第 14 步继续上采样进入二级解码器D₃ 向上经过第二个绿色箭头。shape 从[1,192,64,64]变成[1,96,128,128]。随后在第二个圆圈 C 处与二级编码器保留的 E₂ 拼接。E₂ 的 shape 为[1,96,128,128]因此拼接结果为[1,192,128,128]。再通过上面的 1 × 1 卷积将通道从 192 压缩到 96得到[1,96,128,128]。随后进入图中间那个内部写着MDTA 和 GDFN的橙色方框。这个方框属于二级解码路径。画图时作者把一个 Transformer Block 展开让你看到里面的两个核心模块。并不是只有这里才有 MDTA 和 GDFN。前面所有橙色 Transformer Block 都包含它们。项目实际的二级解码器默认仍然堆叠六个 Block输出 D₂ 为[1,96,128,128]。第 15 步最后一次上采样进入一级解码器D₂ 继续沿第三个绿色箭头向上。shape 从[1,96,128,128]变成[1,48,256,256]恢复到原始图像的空间尺寸。随后在最上方圆圈 C 处与一级编码器保留的 E₁ 拼接。两份特征都是[1,48,256,256]拼接后得到[1,96,256,256]。这里与前面两级不同拼接后没有再通过 1 × 1 卷积将通道压回 48。网络直接使用 96 个通道进入最上方中间的Transformer Block × L₁。这就是一级解码器默认包含四个 Block。输出是图中标记的 Fᵈshape 为[1,96,256,256]。这时解码器已经完成了三次上采样。空间尺寸回到了原始的 256 × 256但数据仍然是 96 通道的特征不是最终图片。第 16 步进入右上方的 RefinementFᵈF d F_dFd​向右进入下方写着Refinement的橙色方框。Refinement 可以理解为“精炼阶段”在已经恢复到原始分辨率的特征上继续进行处理。默认包含四个 Transformer Block。它不再上采样也不再下采样输入输出都是[1,96,256,256]。输出叫作 Fʳ可以写成Fʳ Refinement(Fᵈ)。这一阶段处理的是已经融合浅层编码信息和深层解码信息的特征。第 17 步将特征转换成三通道残差图像Fʳ 继续向右通过最后一个绿色的3 × 3方框。这个普通卷积将 96 个特征通道转换为 3 个输出通道shape 从[1,96,256,256]变成[1,3,256,256]。图中把这份三通道输出叫作 R可以写成R Conv₃×₃(Fʳ)。R 是网络预测的图像残差也就是“输入图像需要怎样修改”。它还不是右侧最终的恢复图像因为后面还要进行一次相加。第 18 步与原始输入相加得到恢复结果注意图最上方有一条很长的黑线。它从输入 I 出发跨过几乎整个网络最终进入输出前的圆圈加号。这个圆圈加号有两个输入一个是原始退化图像 I。另一个是刚才预测的残差 R。它们逐元素相加得到Î I R。例如某个像素的输入数值是 0.4网络预测该位置的修正量是 0.1那么输出就是 0.5如果修正量是 −0.1输出就是 0.3。这表示网络学习在原图基础上进行调整。R 可以为正也可以为负。这里的输入残差相加与编码器和解码器之间的通道拼接不同。最后相加不会改变 shape所以恢复结果仍为[1,3,256,256]。到这里整张图的外部路线已经走完。第 19 步现在再打开橙色 Transformer Block前面我们把 Transformer Block 当作一个“输入输出尺寸不变、但会处理特征”的盒子。现在打开这个盒子。每个 Block 按顺序包含两个主要处理阶段LayerNorm → MDTA → 加回输入。LayerNorm → GDFN → 加回该阶段输入。对于输入 X第一个阶段计算X₁ X MDTA(LN₁(X))。第二个阶段接着计算X₂ X₁ GDFN(LN₂(X₁))。这里的 X、X₁、X₂ shape 都相同。为什么要“加回输入”因为模块输出可以作为对原特征的修正而输入本身能够直接保留下来。这就是特征层面的残差连接。它与最终的图像残差连接原理相似但这里相加的是网络内部特征而不是 RGB 图像。第 20 步先理解 LayerNormMDTA 和 GDFN 前面都有 Norm它表示 Layer Normalization。在这个项目中LayerNorm 对每个像素位置的通道向量进行处理。假设某一层有 48 个通道那么在一个空间位置上就有 48 个特征数值。LayerNorm 根据这 48 个数值计算均值和方差再进行归一化。它不是把整张图所有位置混在一起归一化。代码先将[B,Cᵢ,Hᵢ,Wᵢ]重排成[B,N,Cᵢ]其中 N Hᵢ × Wᵢ再沿最后的通道维处理。普通WithBias版本的计算是y γ ⊙ (x−μ)/√(σ²ε) β。这里μ 是当前位置的通道均值。σ² 是当前位置的通道方差。ε 是一个很小的数用来保持数值稳定。γ 是可学习的缩放参数。β 是可学习的平移参数。项目还提供BiasFree版本计算为y γ ⊙ x/√(σ²ε)。它没有 β并且分子不减均值但仍然计算方差。Block 中前后两次 LayerNorm 使用各自独立的参数。第 21 步找到右下角的 MDTA 展开图右下角浅黄色区域标记为(a)就是 MDTA 的内部结构。从左到右看它的主线是输入 X → Norm → 生成 Q、K、V → reshape → 计算注意力 → 与 V 做矩阵乘法 → reshape → 1 × 1 卷积 → 加回 X。MDTA 的全称是 Multi-DConv Head Transposed Attention。可以先不记全称先记它要做的事情根据整幅特征图的响应决定不同特征通道之间如何相互组合。第 22 步Q、K、V 是什么从哪里来Norm 的输出在图中叫作 Y。Y 分成三条路线每条路线都有一个 1 × 1 卷积和一个 3 × 3 深度卷积分别生成 Q、K、V。Q 是 Query通常翻译为查询K 是 Key通常翻译为键V 是 Value通常翻译为值。它们不是额外输入的图片也不是人为指定的数据。它们都是同一份输入特征 Y经过三组不同的可学习变换生成的。可以写成Q DWConvQ(PWConvQ(Y))K、V 的生成方式相同但使用不同参数。Q 和 K 用来计算通道之间的关系V 提供后面被加权组合的特征数值。为什么先用 1 × 1 卷积因为它在每个空间位置混合通道把已有通道转换成适合 Q、K、V 的表示。为什么再用 3 × 3 深度卷积因为它让每个通道的响应包含附近像素的信息。“深度卷积”与普通卷积的区别是深度卷积分别处理各个通道不在这一步混合不同通道。通道间的混合主要由前后的 1 × 1 卷积完成。代码为了方便将三条路线合并计算先生成 3Cᵢ 个通道再进行深度卷积最后拆成三份。因此 Q、K、V 各自都有 Cᵢ 个通道。第 23 步理解“多头”假设当前特征有 96 个通道设置两个注意力头。网络就把通道分成两组每组 48 个通道各自计算自己的注意力矩阵。这里 a 2d 96/2 48。多头不是把图片切成左右两半也不是每个头负责图像中的一个区域。这里是沿通道维分组每个头仍然使用当前特征图的全部空间位置。不同头可以在不同通道子空间中学习不同的组合关系。最后将各头输出重新合并并用输出卷积继续混合信息。因此要求 Cᵢ 能够被 a 整除。第 24 步理解 reshape 后的数据长什么样Q、K、V 最初都是[B,Cᵢ,Hᵢ,Wᵢ]。代码将通道分成 a 个头并把二维空间展开变成[B,a,d,N]。例如在二级编码器中shape 为[1,96,128,128]头数为 2则 reshape 后得到[1,2,48,16384]因为 128 × 128 16,384。对于一个头中的某个通道现在可以把它看成一个长度为 16,384 的向量。这个向量包含了该通道在所有空间位置上的响应。Reshape 没有学习新权重也没有改变这些数值本身只是换一种方式组织它们方便后面的矩阵运算。随后代码还会对 Q 和 K 的每个空间响应向量进行 L2 归一化即Q̄ᵢ Qᵢ/max(‖Qᵢ‖₂,ε)K̄ 同理。这一步与前面的 LayerNorm 不同LayerNorm 在每个像素位置沿通道处理这里沿每个通道的全部空间位置处理。第 25 步计算通道之间的关系接下来Q̄ 与转置后的 K̄ 做矩阵乘法计算S t · Q̄ · K̄ᵀ。shape 变化是[B,a,d,N] [B,a,N,d] → [B,a,d,d]。这里 K̄ᵀ 表示交换最后两个维度。这样 Q̄ 和 K̄ 相乘时空间位置维 N 被求和留下两个通道维。对于矩阵中的一个元素计算为Sᵢⱼ t · Σn(Q̄ᵢₙK̄ⱼₙ)。它的含义是取第 i 个查询通道和第 j 个键通道比较它们在全部空间位置上的响应再把比较结果汇总成一个分数。因此S 中的每一个元素描述的是两个通道之间的相关关系。t 是可学习的温度乘子每个头有自己的 t。它调整 softmax 前分数的幅度。第 26 步Softmax 将关系分数变成权重图中 Q、K 矩阵乘法之后有 Softmax。它将每一行的分数转换成权重计算为Aᵢⱼ exp(Sᵢⱼ)/Σk exp(Sᵢₖ)。同一行的所有权重都为正并且总和为 1。例如某一行最后得到[0.1,0.7,0.2]可以理解为这一输出通道在组合 value 特征时对三个通道分别使用 0.1、0.7、0.2 的权重。图中的灰色方格就是注意力矩阵 A。这个矩阵的大小是每头 d × d不是像素数量 N × N。第 27 步用注意力权重组合 V图中注意力矩阵 A 向下与 V 在圆圈叉号处进行矩阵乘法得到O A · V。shape 为[B,a,d,d] [B,a,d,N] → [B,a,d,N]。对于空间位置 n输出通道 i 的计算是Oᵢₙ Σj(AᵢⱼVⱼₙ)。也就是说在同一个空间位置把不同 V 通道的响应按权重组合起来生成新的通道响应。注意力矩阵 A 是根据整幅特征图计算得到的所以它包含当前图像的全局信息随后这组权重应用于各个空间位置的通道组合。这也解释了它的特点权重的生成使用全图响应而输出阶段主要进行通道混合。最后O 经过 reshape 合并各个头恢复成[B,Cᵢ,Hᵢ,Wᵢ]再通过 1 × 1 输出卷积。图最右侧的加号将这份变换结果与原始 X 相加得到第一个残差子层的输出 X₁。第 28 步为什么 MDTA 没有建立巨大的像素关系矩阵如果对每个像素与其他全部像素建立关系那么 N 个位置需要 N × N 的注意力矩阵。对于 256 × 256 的特征图N 65,536N × N 约有 42.9 亿个元素。MDTA 改为建立通道关系。如果 Cᵢ 48、a 1那么注意力矩阵只有 48 × 48共 2,304 个元素。这只是在比较注意力矩阵的规模不代表整个模型只需要这么少的计算或显存。Q、K、V 仍然包含全部空间位置计算它们的相关性也需要遍历这些位置。但它避免了显式保存一个巨大 N × N 矩阵。这是其能够处理高分辨率特征的重要原因。第 29 步接着进入右上角的 GDFNMDTA 子层得到 X₁ 后接下来执行 GDFN 子层。图右上角浅蓝色区域标记为(b)就是 GDFN 的展开结构。主线是输入 → Norm → 两条卷积分支 → 一条分支执行 GELU → 两条分支逐元素相乘 → 1 × 1 输出卷积 → 加回输入。GDFN 的全称是 Gated-DConv Feed-Forward Network可以理解为“包含深度卷积和门控操作的前馈网络”。这里的“前馈”表示特征继续向前经过一组变换。“门控”则表示一条特征分支的数值会调制另一条分支。第 30 步GDFN 先增加内部通道设 GDFN 的输入通道为 Cᵢ扩张因子为 r内部每条分支的通道数为D int(Cᵢ·r)。默认 r 2.66。比如 Cᵢ 48 时D int(127.68) 127。代码先使用一个 1 × 1 卷积将输入通道从 Cᵢ 扩展到 2D。因此对于[B,48,Hᵢ,Wᵢ]的输入这一步得到[B,254,Hᵢ,Wᵢ]。接着执行 3 × 3 深度卷积shape 保持不变。再沿通道拆成两份 Z₁ 和 Z₂每份都有 127 个通道即[B,127,Hᵢ,Wᵢ]。图中把这两份数据画成两条并行路线。代码用一次扩张卷积、一次深度卷积和一次通道拆分完成它们。第 31 步GELU 和逐元素乘法形成门控在图中的两条路线里一条经过 GELU另一条不经过激活。随后两条路线在实心点乘号处相乘。计算为G GELU(Z₁) ⊙ Z₂。GELU 是一种非线性函数其形式为GELU(z) z·Φ(z)Φ 是标准正态分布的累积分布函数。学习这张结构图时先把它理解为“对输入数值进行平滑的非线性调整”即可。⊙ 表示逐元素乘法。例如两条分支在某个相同位置的数值分别为 0.5 和 2那么乘积就是 1如果其中一条接近零乘积也会接近零。因此一条分支的响应可以抑制、放大或改变另一条分支的响应这就是“门控”的含义。这里没有 sigmoid所以门控数值不限定在[0,1]。它不是只能“打开或关闭”的开关。乘法前后 shape 不变两份[B,D,Hᵢ,Wᵢ]相乘得到一份[B,D,Hᵢ,Wᵢ]。第 32 步GDFN 恢复通道并完成第二次残差相加乘法得到的 G 经过最后一个 1 × 1 卷积将通道从 D 压回 Cᵢ。对于刚才的例子就是[B,127,Hᵢ,Wᵢ] → [B,48,Hᵢ,Wᵢ]。于是 GDFN 的变换结果与输入 shape 相同可以进行残差相加。第二个子层的输出为X₂ X₁ GDFN(LN₂(X₁))。到这里一个完整 Transformer Block 执行结束。前面所有橙色方框中的每个 Block都会执行这两次特征更新先用 MDTA 处理通道关系再用 GDFN 进行门控特征变换。第 33 步将所有位置与默认代码参数对应起来默认网络的各层配置如下。这里“每头通道数”决定了注意力矩阵的大小。位置通道数注意力头数每头通道数Block 数量一级编码器481484二级编码器962486三级编码器1924486底部瓶颈层3848488三级解码器1924486二级解码器962486一级解码器961964Refinement961964一级解码器有 96 个通道是因为它与一级编码特征拼接后没有再压缩通道。所以虽然四级编码器每头都是 48 个通道但一级解码器和 refinement 每头是 96 个通道。第 34 步把一张图的完整 shape 路线再走一遍对于输入[1,3,256,256]每个关键位置如下顺序图中位置shape1左上角退化图像 I[1,3,256,256]2第一个 3 × 3 卷积输出 F₀[1,48,256,256]3左上方一级编码器 E₁[1,48,256,256]4第一次红色箭头下采样[1,96,128,128]5左侧二级编码器 E₂[1,96,128,128]6第二次红色箭头下采样[1,192,64,64]7左侧三级编码器 E₃[1,192,64,64]8第三次红色箭头下采样[1,384,32,32]9底部瓶颈层 Fₗ[1,384,32,32]10第一次绿色箭头上采样[1,192,64,64]11与 E₃ 在圆圈 C 处拼接[1,384,64,64]121 × 1 卷积压缩[1,192,64,64]13三级解码器 D₃[1,192,64,64]14第二次绿色箭头上采样[1,96,128,128]15与 E₂ 在圆圈 C 处拼接[1,192,128,128]161 × 1 卷积压缩[1,96,128,128]17二级解码器 D₂[1,96,128,128]18第三次绿色箭头上采样[1,48,256,256]19与 E₁ 在圆圈 C 处拼接[1,96,256,256]20一级解码器输出 Fᵈ[1,96,256,256]21Refinement 输出 Fʳ[1,96,256,256]22最后的 3 × 3 卷积输出 R[1,3,256,256]23与输入 I 相加得到 Î[1,3,256,256]这张表对应的就是图中从左上进入、向下编码、向上解码、向右输出的完整路线。第 35 步这些卷积和注意力为什么能学会恢复图像图中卷积的权重、LayerNorm 的缩放和平移参数、注意力的温度参数等都是通过训练学习的。训练时网络接收退化图像 I生成恢复结果 Î再与对应的清晰图像 GT 比较。项目常用 L1 损失可以理解为Loss mean(|Î−GT|)即计算预测图像与清晰目标在所有像素和通道上的平均绝对误差。通过反向传播程序计算哪些参数影响了误差再由优化器调整这些参数。经过大量退化图像和清晰图像对的训练网络逐渐学会合适的特征提取、通道组合、门控变换和残差预测方式。图中没有人为指定“这一层删除雨滴”或者“那个通道补充边缘”。这些处理方式由训练数据与损失共同决定。第 36 步图中的输出路线与双像素任务有什么不同图中展示的是普通单图 RGB 恢复输入是 3 通道输出残差也是 3 通道所以能够执行Î I R。项目中的双像素去散焦任务输入不同。它将左右两张 RGB 图像沿通道拼接形成 6 通道输入最终仍生成 3 通道恢复图像。6 通道输入不能直接与 3 通道输出逐元素相加。因此代码在这个任务中改为使用浅层特征跳跃连接先将 F₀ 从 C 通道投影到 2C 通道与 refinement 特征 Fʳ 相加再通过输出卷积生成 RGB 图像计算为Î Convout(Fʳ Convskip(F₀))。它仍然使用前面讲过的编码器、瓶颈、解码器、MDTA 和 GDFN只是输入通道与最后的跳跃连接方式发生了变化。