019、BSRGAN盲超分:退化空间学习与无监督域适应的理论突破

发布时间:2026/7/1 20:10:32
019、BSRGAN盲超分:退化空间学习与无监督域适应的理论突破 019、BSRGAN盲超分退化空间学习与无监督域适应的理论突破从一张模糊到怀疑人生的照片说起去年帮朋友处理一批老照片他拿来的是一堆用诺基亚N95拍的、2008年北京奥运会的现场图。我心想不就是超分嘛SRGAN、EDSR、RCAN轮番上阵结果出来的效果让我差点把键盘摔了——纹理全是伪影人脸像蜡像天空出现莫名其妙的彩色条纹。问题出在哪这些模型训练时用的退化模型是双三次下采样而真实照片的退化过程复杂得多镜头像差、传感器噪声、压缩伪影、运动模糊、散焦模糊……这些因素叠加在一起根本不是一个简单的下采样能模拟的。这就是盲超分Blind Super-Resolution要解决的问题——在不知道退化核的情况下把低分辨率图像恢复成高分辨率。BSRGAN是2020年由Kai Zhang等人提出的它没有用花哨的网络结构而是在退化建模上做了两件极其聪明的事退化空间学习和无监督域适应。这篇文章我会把这两块掰开揉碎结合我踩过的坑给你讲明白。退化空间学习别再用单一退化核骗自己了传统超分模型为什么在真实图像上翻车因为它们训练时只用了一种退化方式比如双三次下采样。这相当于你只学会了在游泳池里游泳突然被扔进大海不淹死才怪。BSRGAN的思路是既然真实退化是多样的那我就模拟一个足够大的退化空间让模型见过各种“风浪”。具体怎么做BSRGAN的退化模型包含两个核心组件模糊核的随机采样。代码里是这样写的# 这里踩过坑模糊核大小不能固定要随机kernel_sizerandom.choice([7,9,11,13,15])# 别写死成11kernelgenerate_gaussian_kernel(kernel_size,sigma_range(0.2,4.0))# sigma范围要够宽不然模型学不到大模糊的情况注意这里的模糊核不是单一的而是从各向同性高斯、各向异性高斯、甚至广义高斯分布中随机采样。每个batch的模糊核都不同模型被迫学会适应各种模糊程度。我一开始偷懒只用了各向同性高斯结果模型对运动模糊各向异性完全没反应——这就是典型的“训练集偏差”。噪声的复合建模。真实噪声不是简单的高斯白噪声而是传感器噪声、量化噪声、压缩噪声的混合。BSRGAN用了一个噪声生成器# 别这样写noise np.random.randn(*img.shape) * sigma# 真实噪声是信号相关的亮度越高噪声越大noise_levelnp.random.uniform(1,30)# 噪声强度随机noisegenerate_poisson_gaussian_noise(img,noise_level)# 这里有个细节先加泊松噪声模拟光子计数再加高斯噪声模拟读出噪声这个复合噪声模型让BSRGAN在JPEG压缩图像上表现特别好。我试过用纯高斯噪声训练的模型处理微信压缩过的图片结果全是块效应——BSRGAN就不会因为它见过类似的压缩噪声。无监督域适应让模型自己学会“翻译”退化空间学习解决了“见过各种退化”的问题但还有一个更棘手的情况真实世界的退化可能完全不在你模拟的退化空间里。比如老照片的褪色、胶片颗粒、扫描仪的光学畸变——这些很难用数学公式精确建模。BSRGAN的解决方案是无监督域适应核心思想是让模型在真实低分辨率图像上做“自我校正”。具体分两步第一步退化核估计。给定一张真实低分辨率图像BSRGAN用一个轻量级的核估计网络KernelGAN来推断它的退化核。这个网络很小只有几层卷积但训练方式很巧妙——它用真实图像自己生成低分辨率版本然后比较两者的统计特性。# 这里踩过坑核估计网络不能太大否则过拟合classKernelEstimator(nn.Module):def__init__(self):super().__init__()# 只用4层卷积别加太多self.conv1nn.Conv2d(3,64,3,padding1)self.conv2nn.Conv2d(64,64,3,padding1)self.conv3nn.Conv2d(64,64,3,padding1)self.conv4nn.Conv2d(64,kernel_size*kernel_size,3,padding1)# 最后输出是模糊核的权重要保证和为1这个网络训练时用的损失函数是“判别器损失”——让估计的退化核生成的图像和真实图像在分布上无法区分。说白了就是让模型猜“这张图是怎么变模糊的”。第二步退化感知的微调。有了估计的退化核BSRGAN不是直接用它去反卷积而是用这个核去重新生成训练数据。具体来说从高分辨率图像库中取一张图用估计的退化核做下采样再加上估计的噪声水平生成一对新的训练样本。然后用这对样本去微调超分网络。# 别这样写直接用双三次下采样# 正确的做法用估计的核做卷积再下采样estimated_kernelkernel_estimator(lr_image)hr_patchcrop_random_patch(hr_database)lr_simulatedconvolve_and_downsample(hr_patch,estimated_kernel)# 加上估计的噪声noise_levelestimate_noise_level(lr_image)lr_simulatedgenerate_noise(lr_simulated,noise_level)# 用这对数据微调超分网络finetune_step(sr_model,lr_simulated,hr_patch)这个微调过程是迭代的每处理一批真实图像就更新一次退化核估计再用新的核生成训练数据。模型在真实图像上的表现会越来越好因为它在不断适应目标域的退化特性。训练技巧那些论文里没写但你必须知道的事BSRGAN的训练过程有很多细节我踩过的坑列出来你直接避雷学习率策略。BSRGAN用了余弦退火但初始学习率不能太大。我一开始设成2e-4结果loss直接炸了。后来改成1e-4配合warmup前500步线性增加到1e-4稳定多了。# 推荐的学习率设置optimizerAdam(sr_model.parameters(),lr1e-4)schedulerCosineAnnealingLR(optimizer,T_max500000,eta_min1e-7)# eta_min不能太小否则后期学不动数据增强。BSRGAN在训练时用了随机旋转和翻转但注意不要用颜色抖动——因为退化核估计对颜色敏感颜色抖动会干扰核的估计。Batch Size。BSRGAN的batch size建议设成16太小了核估计不稳定太大了显存不够。我用的是RTX 309016刚好。损失函数权重。BSRGAN用了L1损失、感知损失和GAN损失的组合。权重比例是L1:感知:GAN 1:0.1:0.01。感知损失权重不能太大否则纹理过于平滑GAN损失权重不能太小否则细节不够。实战效果从翻车到真香我拿BSRGAN处理了那批诺基亚老照片效果让我震惊。之前用SRGAN处理的人脸像打了马赛克BSRGAN恢复出了皮肤纹理和头发丝。天空的彩色条纹消失了取而代之的是自然的渐变。建筑物的边缘不再有锯齿而是清晰的直线。但BSRGAN也不是万能的。对于严重模糊的图像比如运动模糊超过20个像素它还是会翻车。这时候需要先做去模糊再做超分。另外BSRGAN对低分辨率图像的尺寸有要求——最好是64x64以上太小了核估计不准。个人经验性建议如果你要在自己的项目里用BSRGAN我给你三条建议第一别盲目照搬退化模型。BSRGAN的退化模型是针对自然图像的如果你处理的是医学影像或卫星图像需要重新设计退化空间。比如医学CT图像的噪声模型和自然图像完全不同你得先分析目标域的退化特性。第二核估计网络要轻量。很多人觉得核估计网络越复杂越好其实不是。核估计的本质是统计推断网络太深反而会过拟合到训练集的退化模式上。我试过把KernelGAN从4层加到8层结果在真实图像上的估计反而更差了。第三微调时要控制迭代次数。无监督域适应不是迭代越多越好。我观察到微调超过5000步后模型开始遗忘之前学到的通用超分能力只在当前数据集上过拟合。建议每处理1000张真实图像就做一次验证如果PSNR不再提升就停止。BSRGAN的核心贡献不是网络结构而是对退化建模的深刻理解。它告诉我们在真实世界中退化是复杂且多样的与其设计更复杂的网络不如先搞清楚数据是怎么变差的。这个思路不仅适用于超分也适用于去噪、去模糊、去雨等所有底层视觉任务。下次你遇到真实图像超分的问题别急着调网络结构先问问自己我理解这个图像的退化过程吗如果答案是否定的BSRGAN的退化空间学习和无监督域适应就是你最好的起点。