068、超分与去噪联合:如何用单一模型处理噪声图像的超分辨率 068、超分与去噪联合如何用单一模型处理噪声图像的超分辨率上周调试一个监控视频增强项目甲方丢过来一段夜间停车场录像噪点跟雪花似的铺满画面。我习惯性把视频帧丢进训练好的EDSR模型结果输出图像不仅没变清晰反而把噪声结构放大了——超分模型对噪声极其敏感这是很多刚入坑的同学容易踩的坑。今天这篇笔记就聊聊怎么把去噪和超分塞进同一个模型里别让噪声毁了你的超分效果。噪声为什么会让超分模型翻车先讲个我踩过的坑。去年做遥感图像超分训练集是干净的航拍图测试时用户传了张带椒盐噪声的卫星图。模型输出结果里噪声点被放大成小方块边缘出现伪影。原因很简单传统超分模型假设输入是干净的低分辨率图像它学的是从低清到高清的映射。一旦输入带噪声模型会把噪声当成高频细节去放大——它分不清哪些是真实纹理哪些是噪声。更麻烦的是噪声和超分是相互耦合的。低分辨率图像本身已经丢失了高频信息噪声又额外引入了虚假的高频成分。如果先做去噪再做超分去噪过程会模糊边缘超分阶段又得重新恢复这些被抹掉的细节两步之间信息损失是叠加的。这就是为什么联合建模比pipeline方式靠谱。联合模型的三种主流思路我试过几种方案挑三个有代表性的说说。第一种共享编码器双头输出。编码器提取特征然后分两个分支一个分支做去噪输出干净的低分辨率图另一个分支做超分输出高分辨率图。训练时两个损失一起算。这个结构的问题是去噪分支和超分分支的特征未必能互相促进有时候去噪分支学到的平滑特征反而会拖累超分分支的锐度。我踩过这个坑后来发现加个特征融合模块会好一些。第二种噪声估计超分联合。模型先估计输入图像的噪声水平图noise map然后把噪声图和原始特征一起喂给超分模块。这种思路的好处是显式建模噪声分布模型能自适应不同强度的噪声。实现时注意噪声估计模块别太深否则梯度传播容易出问题。我习惯用3层卷积加一个sigmoid输出简单够用。第三种端到端的盲超分去噪。这是我现在项目里用的方案。模型不显式区分去噪和超分阶段而是让网络自己学习从噪声低分辨率到干净高分辨率的映射。关键在于训练数据的构造——用干净的高分辨率图先下采样再加噪声然后作为输入。损失函数用L1加感知损失再加一个边缘保持的梯度损失。这个方案对模型容量要求高我用的是改进版的RCAN加了通道注意力机制。代码实现里的几个关键点说个具体实现时容易翻车的地方。数据增强阶段很多人只做旋转翻转忽略了噪声增强。我建议训练时动态调整噪声类型和强度——高斯噪声、泊松噪声、椒盐噪声随机切换强度从低到高均匀采样。这样模型才能泛化到真实场景。损失函数的设计上别只盯着PSNR。我踩过的一个坑是只用L2损失结果模型输出虽然PSNR高但视觉上模糊得像油画。后来改成L1感知损失梯度损失的三合一组合。梯度损失用Sobel算子计算边缘让模型更关注结构信息。代码里这样写# 梯度损失别用torch.autograd.grad那个太慢defgradient_loss(pred,target):# 这里用Sobel核注意padding要samesobel_xtorch.tensor([[-1,0,1],[-2,0,2],[-1,0,1]],dtypetorch.float32).view(1,1,3,3)sobel_ytorch.tensor([[-1,-2,-1],[0,0,0],[1,2,1]],dtypetorch.float32).view(1,1,3,3)# 别忘记repeat到batch和channel维度pred_gxF.conv2d(pred,sobel_x.repeat(pred.size(1),1,1,1),padding1,groupspred.size(1))pred_gyF.conv2d(pred,sobel_y.repeat(pred.size(1),1,1,1),padding1,groupspred.size(1))target_gxF.conv2d(target,sobel_x.repeat(target.size(1),1,1,1),padding1,groupstarget.size(1))target_gyF.conv2d(target,sobel_y.repeat(target.size(1),1,1,1),padding1,groupstarget.size(1))returnF.l1_loss(pred_gx,target_gx)F.l1_loss(pred_gy,target_gy)训练策略上我推荐两阶段训练。第一阶段用干净的低分辨率图预训练超分能力第二阶段加入噪声数据微调。这样模型先学会超分的基本映射再适应噪声干扰比直接端到端训练收敛快得多。我试过直接端到端训练了200个epoch还没稳定两阶段训练80个epoch就出效果了。真实场景里的坑和应对说个实际项目里遇到的。监控视频的噪声不是均匀的——暗区噪声大亮区噪声小。如果用全局统一的噪声强度训练模型在暗区会过平滑亮区又保留太多噪声。解决办法是在输入层加一个亮度自适应模块根据像素亮度动态调整特征提取的权重。实现起来不复杂加个轻量级的注意力机制就行。另一个坑是推理速度。联合模型参数多在边缘设备上跑不动。我试过剪枝和量化效果还行。关键是把去噪相关的通道剪掉一部分——去噪任务对通道数不敏感但超分任务需要足够通道来恢复细节。剪枝时优先保留超分分支的通道去噪分支可以压缩到原来的1/3。个人经验总结做了两年联合去噪超分最大的体会是别追求一个模型解决所有噪声类型。真实场景的噪声分布太复杂单一模型很难面面俱到。我现在的做法是训练一个基座模型然后针对特定场景做微调。比如监控场景用夜间数据微调10个epoch就够了。另外评估指标别只看PSNR和SSIM。我遇到过PSNR很高但视觉上很假的情况——模型学会了平均化噪声但丢失了真实纹理。建议加上LPIPS感知相似度和NIQE无参考图像质量评估这两个指标更贴近人眼感受。最后说个玄学经验训练时batch size别太小我试过batch size4时模型不稳定改成16后收敛曲线平滑很多。可能是噪声数据方差大小batch的梯度方向太随机。下篇笔记聊聊视频超分里的时序一致性那个坑更多先预告一下。