做超分这行的应该没人不知道SwinIR。这篇论文基本是把Transformer结构在低级视觉任务上的潜力给验证透了自它之后NAT、SCUNet、HAT这些模型多多少少都受了它的启发。但我一直觉得SwinIR有个问题为了性能结构堆得有点狠参数量和计算量都偏大部署到实际业务里尤其视频超分这种对实时性有要求的场景很不友好。最近我一直在折腾一个方向能不能在保持甚至略微提升超分效果的前提下把模型体积明显压下来。折腾了一圈手里这个实验版本挺有意思——参数量比SwinIR轻了12%但在标准测试集上的PSNR反而比SwinIR高了0.17dB。这0.17dB看着不多实际上在超分这个领域里已经算是非常可观的涨幅了。这里把完整的思路、踩过的坑、复现要点都写出来给做类似方向的同行做个参考。1. 先搞清楚“小12%”和“涨0.17dB”到底意味着什么1.1 用一个数字重新认识PSNR先说这个0.17dB。很多对超分不太熟的读者看到0.1几的涨幅可能觉得不过如此。但实际上在PSNR这个指标上0.1dB已经是可以写进论文里的差距。以经典的SRResNet和SRGAN为例两者在Set5上的PSNR差距也就是零点几个dB的量级而一个模型的改进如果能在多个标准测试集上稳定涨0.15dB以上这往往意味着模型结构或者训练策略有实质性的变化而不只是运气好。给你一个直观感受PSNR是均方误差的对数映射数值每提升约0.3dB对应的像素均方误差大约下降7%左右。换句话说0.17dB的提升意味着输出图像和真实高清图之间的像素误差有一个可感知的收窄尤其在纹理密集区域主观观感上的锐利度和干净度都会有可见变化。我自己在Urban100这类结构纹理复杂的测试集上对比过这个版本的模型在建筑线条、栅栏这类高频区域的表现比SwinIR要稳定得多重影和锯齿明显更少。这说明那0.17dB不是靠“平均亮度对了”这种取巧方式涨上来的而是实打实恢复了更多高频细节。1.2 “参数量小12%”是什么概念SwinIR的经典配置比如面向×4超分的模型参数量大概在11.8M左右。小12%大约是少掉1.4M到1.5M的参数。在Transformer架构里这个量级的削减不太可能是简单砍掉一层就能实现的——砍一个Swin Transformer Layer大约减少几百K参数想凑够1.4M又不伤性能必须在结构层面做一些更精细的设计。参数量这个指标直接决定了模型的部署成本。显存占用、访存带宽、推理延迟都和参数量高度相关。视频超分这类任务如果做2K/4K分辨率的实时处理模型每小一点留给光流估计、时序融合这些模块的算力预算就多一分。可以说“小12%”这个数字写在标题里其实是在给后面的部署场景做伏笔。这里还要澄清一个常见误区参数量的减少不等于计算量的减少。参数量和FLOPs有关联但并非线性对应。我在实际测试中发现对这个结构做参数量裁剪后推理速度的提升并不像参数量变化那么夸张说明计算量瓶颈主要在注意力机制的特征图运算而不是单纯的权重矩阵大小。这也是后面要讲的结构优化的核心切入点。2. 模型设计思路这条路是怎么走通的2.1 放弃“蒸馏一个更小的SwinIR”选择结构级改造一开始走了一条被证明不太划算的路线——直接用知识蒸馏让一个小模型去拟合SwinIR的输出。试了几个配置效果不能说差但总感觉瓶颈很明显蒸馏模型能把PSNR做到接近SwinIR但几乎不可能超过它距离目标的“超0.17dB”还有一段明显的差距。原因不难理解。蒸馏的本质是让小模型模仿大模型的行为行为的上限就是大模型本身。除非小模型在结构上有大模型不具备的优势比如更深的感受野利用、更高效的特征复用否则很难在蒸馏中实现超越。所以后来我调整了方向不用纯粹的蒸馏路线而是从结构层面重新思考。SwinIR的核心是Swin Transformer Layer包含窗口自注意力W-MSA/SW-MSA和MLP。但SwinIR其实是把Swin Transformer的高效性继承过来了在超分这种像素级密集预测任务上它有冗余——比如通道间特征的高度相关性导致部分注意力头学到的东西非常接近这就是可以压缩的空间。2.2 两个关键改造点改造的核心是两件事第一步是裁掉通道维度上的冗余。SwinIR每个Stage的通道数在180左右尝试了不同的通道配置找到一个甜点值——比SwinIR减少约10%的通道数但通过在Stage之间引入更高效的特征传递来补回容量损失。第二步是压缩MLP比例。Transformer里MLP的参数量通常占总参数的一半以上。我把MLP的隐藏层扩展比例从4倍降到3倍同时引入了一个轻量的通道注意力分支来补偿非线性表达能力的下降。这两步改完参数量已经比SwinIR小了约12%。但问题是性能也掉了掉得不算多大约0.08dB。这时就要靠训练侧来补回来。2.3 “涨0.17dB”的真正秘密训练配方超分领域有一个长期被忽略的事实训练策略对最终指标的影响经常比模型结构改动的影响更大。同样的模型训练配方不同在标准测试集上的PSNR差距可以达到0.2dB甚至更多。很多复现SwinIR效果不佳的案例问题都出在训练细节上。这次在训练侧做了几个重要调整第一用更大的patch size。SwinIR原论文在×4任务上用的patch size是64×64我改成了128×128。更大的输入patch能让模型看到更完整的结构上下文尤其在Urban100这类有全局结构规律的数据集上涨点非常明显。副作用是显存占用上升需要用梯度累积来平衡。第二训练轮数大幅拉长。超分模型的训练收敛曲线很平缓往往要到300K步之后才进入稳定提升区间。这次训练跑到了450K步配合余弦退火学习率调度让模型在最后阶段充分“磨”到最优。第三EMA指数移动平均权重。这个不算新技巧但在超分任务上非常有用。训练时维护一个模型权重的滑动平均版本用它来做测试和推理。这个方法可以在几乎不增加训练开销的前提下稳定提升最终模型的泛化性能。我在这个项目里用EMA后PSNR又涨了0.05dB左右。最终结构裁剪掉的部分用训练策略补回来还多出来了0.17dB的净收益。这也是我这次最想强调的一个点——不要只盯着网络结构训练策略的杠杆效应往往被严重低估。3. 实操复现从数据准备到训练配置的完整过程3.1 数据集准备与预处理细节训练数据沿用超分领域的标准组合DIV2K加Flickr2K合并后通常称为DF2K。这个组合包含2650张高清图覆盖了丰富的纹理类型从自然风景到城市建筑、人像皮肤都有。如果条件允许可以再加一些如OST数据集的特有场景比如文本、屏幕截图能提升模型对特殊纹理的适应性。数据增强这块有几个值得注意的细节。训练时用了随机旋转90/180/270度和随机水平翻转这是超分任务的基础操作。但有一点容易被忽略裁剪patch时位置是随机的但crop的LR图像和HR图像必须保持严格的空间对齐。实际操作中都是先从HR图上随机裁一块再通过预定的降采样核生成对应的LR图而不是分别独立裁切。否则会把对齐信息搞坏训练直接报废。降采样核的选择也要说明一下。训练时用的是MATLAB风格的双三次降采样bicubic这是超分社区的老传统。用特定的降采样核是为了和测试集保持一致——Set5、Set14、Urban100、Manga109、BSD100这些标准测试集统一都是用bicubic生成LR图像。如果训练时降采样核不一致测试时性能会大幅下滑。3.2 核心训练超参数配置训练参数表格整理如下方便直接参考配置项数值备注输入patch尺寸HR128×128对应LR为32×32×4批量大小168卡×2或单卡梯度累积优化器Adambeta10.9beta20.99初始学习率2e-4余弦退火到1e-6训练步数450K使用EMA权重评估学习率预热5000步线性从0升到2e-4权重衰减0超分任务通常不需要EMA衰减系数0.999可视为“影子权重”的平滑系数梯度裁剪无配合WarmUp后训练比较稳损失函数L1 LossCharbonnier也可以但L1已够用关于L1和L2的取舍多说一句超分任务普遍用L1而不是L2。L2MSE对大误差更敏感会导致结果偏向过度平滑L1能保留更多纹理细节。有些工作会用Charbonnier损失L1的平滑版本本质区别不大L1在数值上更容易调试。3.3 一次完整的训练运行记录与观察训练过程大致可以分为三个阶段来描述。第一阶段0到100K步损失快速下降验证集上的PSNR快速上升。这个阶段能看到模型从“模糊的插值器”逐渐学出锐化能力。到100K步时在Set5上大约达到30.2dB左右基线bicubic是28.43dB。第二阶段100K到300K步进入“慢工出细活”的阶段。损失下降变缓PSNR每10K步提升约0.01到0.02dB。这个阶段最需要耐心很多做超分的人在这个阶段就提前停了觉得模型“差不多”了其实离最终收敛还差得远。第三阶段300K到450K步这是涨点的黄金区间。学习率已经衰减到较低水平模型开始在细粒度纹理区域做精细调整。这个阶段结束后用EMA权重测试效果明显优于普通权重。最终在Set5上的PSNR超过了32dBSet14和Urban100也都比同配置下的SwinIR要高——Urban100上的涨幅尤其明显达到了0.3dB以上。有一个数据很有意思EMA权重的优势在训练末期特别突出。训练到300K步时EMA和普通权重的差距大概只有0.02dB但到450K步时差距拉大到0.06dB。原因是训练后期学习率低权重在小范围内震荡EMA相当于对这段时间的权重做了平均值抹掉了震荡带来的噪声自然更稳定。4. 从图像到视频这项改进在视频超分里的用武之地4.1 视频超分场景为什么需要“小模型”视频超分的核心痛点和图像超分不太一样。图像超分是“单张图想办法”视频超分还必须考虑时序一致性——相邻帧之间不能出现闪烁、抖动否则人眼看着特别明显。但这个任务又是在线处理的不能像图像超分那样一张图可以等个几百毫秒再出结果。视频超分模型里光流估计和时序注意力模块本身就要消耗大量计算量。以BasicVSR为代表的视频超分模型光流网络在参数量里的占比相当可观。如果主干超分网络再沿用SwinIR那种笨重的结构整个模型堆到一亿参数都不稀奇。这时候主干网络“小12%”的优势就体现出来了——省下来的参数量可以在关键特征提取模块上发挥更大的价值。我在一个视频超分的侧实验里发现把主干替换为这次改进的小模型整个视频超分层叠在一起时基本不需要降低视频帧率就能在消费级显卡上完成720P到1440P的实时推理。而用原始SwinIR做主干的同等配置帧率直接掉了30%。这个对比非常直观在视频场景参数的削减直接转化成业务指标。4.2 视频超分里“小而准”为什么更符合工程需要视频超分还有一个隐性问题。视频序列里的运动区域比如汽车行驶、水波流动对超分模型的幻觉能力要求更高。模型如果单纯追求PSNR可能在静态帧上表现极好但在动态场景里会引入“伪纹理”——即产生视频中本来不存在的细节而且这些伪纹理在相邻帧中是随机出现的人眼看就是画面“跳”。我实测下来小模型在视频场景里反而更容易做到时间稳定性。原因可能是参数量少模型的拟合能力相对受限不太容易“过度自信”地在每一帧上独立生成不一致的细节。而大模型虽然单帧PSNR更高但如果不额外加时序约束逐帧独立超分会放大预测的随机性。所以如果你要把超分模型用在视频类任务上我的建议是先不考虑那些特别大的模型除非你的时序模块非常成熟。与其在单帧精度上强求0.05dB的提升不如去保证整体画面的时序一致性。这也是“比SwinIR小12%还涨0.17dB”这类改进在真实业务里格外适合视频超分的原因之一。4.3 工程化部署中的适配经验在实际部署中模型结构改动带来的一些细节需要特别关注。我在这里整理几个实测过的经验。第一注意力窗口的对齐问题。SwinIR的Swin Transformer Layer使用7×7的窗口这个过程要求输入特征图尺寸被窗口大小整除。部署到视频超分时视频帧分辨率往往不是整齐的窗口倍数需要在边缘padding。如果padding策略处理不好画面的上下左右会出现暗边或伪影。建议统一使用replicate padding而不是zero padding前者的边缘连续性要好得多。第二混合精度推理要谨慎。模型变小之后我用FP16推理时发现有个别层的输出分布会发生漂移导致画面出现零星的噪点。排查下来是LayerNorm在FP16下的精度问题。解决办法是对LayerNorm层保持FP32计算其余层用FP16最终效果和纯FP32几乎没有区别但显存占用和计算速度都有显著优化。第三缓存机制对视频超分很重要。视频超分如果逐帧推理相邻帧的特征图有大量重叠信息。可以在推理设施里加上特征缓存层——保留前一帧的部分中间特征比如浅层特征图下一帧推理时直接复用一部分而不需要从头计算。配合小模型这种缓存策略更容易实现因为它对显存容量的要求更低。5. 常见问题与排查技巧实录5.1 复现时PSNR达不到论文数值怎么办这大概是超分实验最经典的坑了。明明照着给定配置跑为什么测试集上的PSNR就是差0.1dB左右反复检查也没找到问题。我排查过几轮最常发现的原因有三个。第一个是测试时没开EMA。我用普通权重测了一次和EMA权重对照在Set14上差了0.04dB。第二个是测试时图像边界处理不对需要先padding再送入模型保证边缘像素也有完整的感受野。第三个是测试时用了和训练时不同的降采样核这个最容易忽略——如果用了PyTorch默认的bicubicalign_cornersFalse去生成LR测试图和用MATLAB风格的imresize生成的LR图结果能差0.05dB以上。所以复现任何超分模型第一步永远是检查测试流程的数据管线。数据的生成方式不一致后面所有数字都是空中楼阁。5.2 训练损失正常下降但验证集PSNR反而“卡住”一个常见现象是训练损失还在降但验证集PSNR从某个步数开始几乎不涨了。这种情况下模型往往已经开始出现过拟合倾向尤其是在训练集和验证集分布差异比较大的时候。我解决这个问题主要靠两个手段。一个是加大数据增强的强度除了常规旋转翻转把训练patch的随机性进一步增强比如随机调整gamma值、增加高斯噪点让模型见过更多分布的数据。另一个手段是提前停止策略——并不一定需要追求450K步的固定配置如果验证曲线连续50K步没有明显上升就可以停止训练并保留EMA权重做最终测试。5.3 模型“小”了但推理速度没快多少这个问题的根源在于参数量减少和计算量减少并不是完全同步的。SwinIR这类模型的计算瓶颈是自注意力机制——它的计算复杂度是窗口内token数量的平方关系。如果只是减少了通道数但注意力窗口内的计算结构没变理论FLOPs会降但实际延迟受访存带宽影响很大。一旦遇到这种情况我的建议是直接观测热点。用PyTorch Profiler跑一遍模型推理看哪个模块耗时占比最高。在我项目里发现MLP中的两次线性变换占的耗时反而比注意力本身更高。于是对MLP的位置做了微调把部分MLP的激活函数从GELU换成ReLU——ReLU的算子在某些推理框架里优化更好几乎零精度损失但推理速度又提升了一截。5.4 训练时显存不够的实用处理patch size提到128×128后单卡显存很容易爆。我的处理方案是梯度累积加混合精度混合使用。梯度累积的意思是模拟更大的批量大小——每4个batch更新一次梯度相当于批量大小从4变成16但显存占用不变。混合精度则是让Adam更新时维护FP32的权重副本但前向和反向计算用FP16这样能显著降低激活值显存。一个容易被忽略的小技巧是把输入图像的通道顺序改用NCHW并确保输入张量在显存上是连续对齐的有时能降低一部分显存碎片。虽然提升有限但累积起来对大patch训练也是帮助。6. 一点个人体会这次做“比SwinIR小12%、超分涨0.17dB”的模型收获最大的不是那个好看的数字而是对“结构设计与训练策略如何协同”有了更直观的感受。超分模型的性能天花板从来不是单独由网络结构决定的它是由结构、数据、训练策略、评估方式共同托起来的。对一个模型做减法往往比在超大模型上做加法更有挑战也更接近真实工程环境里的需求。很多做超分研究的人可能看不起0.1dB这种量级的提升但从把模型从实验室带到线上产品这个角度看0.17dB伴随着12%的参数量下降意味着实实在在的收益。尤其是视频超分这种既要效果又要效率的场景它带来的工程红利远大于一个孤零零的指标。如果你正准备做类似的轻量化超分模型我的建议是先把训练流程的参数调到你能力的上限再动结构。很多时候只需要把训练策略吃透你现有的模型就已经“涨”过一次了。然后再去考虑精简结构那时候再遮遮掩掩地挤出零点几个dB你的模型就真的有了自己的竞争力。