SRGAN超分实战:从原理到训练,用生成对抗网络重建真实感图像
简介针对图像超分辨率中大倍数重建缺乏高频纹理细节的问题这份zip压缩包提供了SRGAN的完整实现涵盖生成器与判别器结构、感知损失函数定义以及训练流程适合深度学习、计算机视觉方向的研究者与开发者复现论文或开展对比实验。压缩包共1198个文件以Python源码、PyTorch模型权重.pth和TensorBoard事件日志为主同时包含少量xml配置、jpg示例图片与pyc编译文件整体大小约156MB便于直接加载权重查看超分效果与训练曲线。目前已有2542人学习下载。借助预训练权重与日志可快速评估模型在4倍放大下的感知质量并结合代码理解对抗损失与内容损失如何平衡像素精度与纹理真实性为后续改进提供基线。 超分辨率重建这个方向我一直觉得是最贴近普通用户感知的CV任务之一。你给朋友解释图像分类、目标检测对方可能没什么感觉但你要说“我能把你十年前拍糊的老照片变清晰”基本都会来兴趣。SRGAN就是这么一项绕不开的工作2017年CVPR上的那篇Photo-Realistic Single Image Super-Resolution Using a Generative Adversarial Network算是给图像超分领域打开了一个新方向之前大家比的是谁PSNR高、谁重建误差小SRGAN直接换了个赛道比谁“看起来更真实”。这篇博客我就从实际做项目的角度把SRGAN的原理、结构、训练经验和后续演进一次讲透。1. 从“放大”到“重建”SRGAN要解决的痛点1.1 传统上采样为什么“看起来假”在深度学习普及之前图像超分基本靠插值算法。最常用的双三次插值Bicubic本质上就是根据周围像素点的灰度值做一个加权平均把已知信息“摊开”填到新增的像素位置。这个方法有它的优势计算量小、处理速度快、不依赖外部数据直到今天很多图像处理软件里的“放大图像”功能默认还是它。但问题也很明显。插值算法本质是在做猜测而且是最保守的那种猜测——它只能根据现有像素的局部关系来补新像素完全没有能力“无中生有”。你拿一张1920×1080的图放大到4K分辨率插值出来的画面就是一块被磨平了的、边缘发虚的图。在看视频或者打印大幅海报时这种模糊感非常明显。后来有一类基于重建的方法比如迭代反投影IBP、凸集投影POCS这类方法会建立降质模型模糊下采样然后反推一张高清图使得它降质之后能还原成输入的低清图。思路是对的但数学上这是个欠定问题ill-posed problem一张低清图可能对应无数张高清图单靠约束条件收敛一个唯一解结果通常偏平滑。1.2 深度学习SR路线从SRCNN到SRResNetSRCNN是2014年提出的开山之作结构很简单一个三层卷积网络中间一层做非线性映射端到端学习低分辨率到高分辨率的映射关系。当时的效果已经明显超过传统方法但SRCNN有个硬伤——它是在低分辨率空间或简单放大后的空间里做映射细节恢复能力有限感受野也不够。之后的FSRCNN、ESPCN在速度上做了很大优化开始引入亚像素卷积Sub-pixel Convolution也就是后来大家常说的PixelShuffle。ESPCN的思路是先在小分辨率图像上用卷积提取特征最后一步通过像素重排把多个通道的像素“揉”到一张大图上。这个思路对SRGAN影响很深SRGAN的上采样部分就沿用了这个设计。SRResNet则是把残差网络结构ResNet引入超分任务用了16个残差块堆叠配合PixelShuffle做上采样。在PSNR指标上SRResNet已经大幅超越传统方法。但注意一个细节SRResNet训练时用的还是MSE均方误差损失只是网络结构变深了重建结果在数值上“很准”视觉上依旧有塑料感、过度平滑的问题。1.3 一个反直觉的观察PSNR高分不等于“真实”我自己第一次复现完SRResNet之后有个很深的感触PSNR刷到30多dB比SRCNN高了不少但放大看纹理区域比如头发丝、树叶缝隙、衣服织物的纹路就是一团模糊的灰色。为什么会这样因为MSE损失衡量的只是像素级差异的平均值它会给每个位置的误差同样权重所以网络学到的“最优解”就是所有可能高清图的平均值——在数学上这是最小化期望误差的最优策略但视觉上就成了抹平高频细节的“钝化”结果。这就是SRGAN这篇论文的核心出发点如果我们想让超分结果“看起来像真的高清照片”就不能只用MSE这种像素空间的距离来衡量而应该让生成出的图在“语义层面”难以和真实高清图区分。这就顺理成章地引出了生成对抗网络GAN——用判别器来判断哪个是真图、哪个是生成图逼着生成器输出更自然、更符合真实图像分布的细节。这里插一句“深度学习的目的是拟合数据分布”这句话听着很玄但在超分任务里特别直观。传统SR学的是像素到像素的直接映射函数SRGAN学的是“低清图条件下的高清图条件分布”它不再是求一个平均解而是从这个分布里采样一个看起来合理的结果。这也解释了为什么SRGAN的结果有“纹理细节被凭空创造出来”的感觉。2. SRGAN网络结构拆解从生成器到判别器再到损失函数2.1 生成器16个残差块PixelShuffle上采样SRGAN生成器的主干是一个SRResNet结构具体来说是去掉BatchNorm的改进版。原始的SRResNet每个残差块里都有BatchNorm但作者在实际实验中发现去掉BatchNorm之后训练更稳定生成质量也更好。为什么因为超分任务中输入输出之间是有强关联的加上BatchNorm之后同一批数据里不同图像的统计量差异会被强行归一化导致网络丢失一些与绝对亮度、对比度相关的信息而这些信息对重建高频细节很重要。很多人复现时遇到训练不稳定的情况第一反应是调学习率其实把BatchNorm去掉往往立竿见影。结构上可以分成三块特征提取一个3×3卷积将输入图像从RGB空间映射到高维特征空间64维后面接ReLU激活。非线性映射16个残差块串联。每个残差块内部先经过一个3×3卷积、BatchNorm如果保留的话、ReLU再经过一个3×3卷积和BatchNorm最后和输入shortcut相加。残差块的作用是把低维特征逐步细化让网络可以学到更多高频残差信息。可以把这个过程类比成“细节修正”主干通道保留了整体结构每个残差块只负责补充当前特征图中缺失的细节。上采样与重建两个PixelShuffle模块每个先用3×3卷积把通道数扩展为原来的4倍再通过像素重排把通道维度折算成空间分辨率实现2倍上采样。两个级联就是4倍超分。最后经过一个3×3卷积输出RGB图。这里有一个特别容易忽略的细节PixelShuffle的操作本质很朴素就是把H×W×(r²C)的张量reshape成(H×r)×(W×r)×C但它让上采样过程变得可学习而不是像双三次插值那样固定权重。超分模型的上采样部分是整个系统的瓶颈如果用固定插值做上采样再卷积模型就失去了学习自己走细节的能力这也是早期方法效果上不去的另一个原因。2.2 判别器VGG风格的二分类器判别器结构沿用了GAN里的标准做法但有它自己的特点。整个网络没有全连接层全部是卷积层LeakyReLU最大池化或带步长卷积具体来说经过若干轮卷积后8个卷积块每两个翻倍通道数从64逐步增加到512最后接一个全连接层和sigmoid输出。训练时判别器的输入一半是真实高清图HR一半是生成器输出的假高清图SR目标是正确区分两者。生成器的对抗损失来自判别器的判断——判别器越难分辨说明生成器的输出越接近真实图像分布。这里需要注意一个细节SRGAN的判别器只在固定尺度比如128×128的高分辨率块上做判断并不对感知质量做逐像素的约束。换句话说判别器关注的是“图像整体的自然程度”——纹理是否真实、边缘是否有伪影、色彩是否协调而不是某一处的像素值是否对得上。这样的设计让生成器可以自由地“创造”纹理细节而不是被束缚在像素精确匹配的框架里。2.3 损失函数VGG感知损失才是SRGAN的精髓SRGAN的另一个核心贡献是感知损失Perceptual Loss。整条损失函数可以拆成三部分对抗损失Adversarial Loss生成器试图让判别器把生成图误判为真图的损失。SRGAN用的是最小化log(1-D(G(z)))的标准形式不过作者提到实际训练中用-log(D(G(z)))效果更好本质上是改变了对生成器的梯度信号强度。内容损失Content Loss: 论文没有直接用MSE做内容损失而是在预训练好的VGG16的某一层默认是relu5_4里计算生成图和真实高清图的特征表示之间的欧氏距离。像素损失在部分实现里会多加一项L2或L1像素损失帮助训练初期稳定。为什么用VGG特征空间的距离替代MSE因为VGG网络的深层特征编码的是图像的语义内容比如物体的类别、结构、轮廓而不是像素级的颜色偏移。两张图在像素上差很多比如纹理细节完全不同但在VGG特征空间里可能非常接近反过来两张图像素相差很小但在语义上完全就是两个东西比如一张是清晰的人脸、一张是磨皮过的假人脸。用感知损失训练生成器会更关注“看起来对不对”而不是“像素对不对”。我自己做实验时对比过MSE损失和感知损失下网络的中间输出感受非常直观用MSE训练时生成器倾向于把纹理区域输出成一片平滑的中等灰度值因为这是期望误差最小的解换到感知损失后网络开始“尝试”输出不同位置的纹理变化即使这些纹理和原始高清图不完全一样但结构上更加自然。感知损失的另一个理解角度它相当于一个“语义距离度量”告诉生成器哪些地方与真实高清图的语义差异大哪些地方可以容忍像素差异。这种细粒度的引导对稳定GAN训练有非常大的帮助。3. 训练SRGAN的关键实操细节坦白说SRGAN的结构不算复杂但想复现出论文的效果训练策略很关键。我实际上手跑过几轮这里说一些容易踩的坑。3.1 两阶段训练先预训练SRResNet再训练GAN这是整篇论文里最重要的一条工程经验。如果不先预训练生成器直接从头开始跑GAN判别器会非常容易地把生成器压死——因为生成器一开始输出的图跟真实高清图差距太大判别器可以轻松区分梯度信号就会变得极不稳定。正确的做法是先用MSE损失或L1损失预训练SRResNet让它先具备一定的重建能力。在这个阶段模型已经在学习低分辨率到高分辨率的基础映射生成的高清图在PSNR上已经相当不错了只是缺乏高频细节。这个预训练过程大概需要跑数十万步、几个epoch等到生成器的PSNR基本收敛再加载它的权重作为初始状态开始GAN训练阶段。这里有个小技巧GAN训练阶段的生成器学习率不要太大论文用的是1e-4判别器也是1e-4。我实际测试下来如果把生成器学习率降到5e-5判别器保持1e-4训练稳定性会更好但收敛速度会慢一些。可以根据任务自行权衡。3.2 损失权重怎么搭配SRGAN的完整损失是L L_content 1e-3 × L_adversarial 2e-8 × L_pixel这个权重配比是论文里给的参考值。其中内容损失用的是VGG特征空间的L2距离像素损失用的也是L2距离。注意对抗损失的权重系数非常小只有1e-3但它对最终视觉效果的影响却非常大。从这个权重就能看出感知损失占了绝对主导GAN训练只是在“最后推一把”让结果更贴近真实分布。我在实际调参中发现这个权重比并不是绝对的。数据集不同、分辨率不同对抗损失都可以在1e-3到1e-4之间浮动。如果发现生成的图片有色彩偏移或者出现奇怪伪影可以试着降低对抗损失的权重如果发现生成图太平滑、细节不够就稍微增大对抗损失权重。但一次调整幅度不要太大建议以2倍步长递增或递减。3.3 训练稳定性问题GAN训练本身就是猫鼠游戏超分任务里也不例外。常见的失败情况有三种模式崩塌、判别器过强、梯度消失。模式崩塌在超分任务里表现不明显因为输入始终是低分辨率图输出也被感知损失约束在很窄的范围不太容易出现“只产生一种图片”的情况。判别器过强是真正的问题。判别器如果太容易分类正确给生成器的梯度就会很快消失生成器就停在原地不动。解决办法是确保生成器预训练充分并且在GAN训练阶段对生成器采用更频繁的更新比如每更新2次生成器再更新1次判别器。梯度消失往往和激活函数有关。我在复现时把生成器末层的激活函数从tanh换成线性或恒等映射之后训练稳定性明显改善。除了调参还可以在生成器和判别器中加入谱归一化Spectral Normalization限制权重矩阵的谱范数可以缓解训练不稳定。原版SRGAN没有用谱归一化但后来的很多改进版比如Real-ESRGAN都加了这一项效果相当明显。3.4 数据处理与增强细节SRGAN的训练数据是DIV2K数据集800张2K分辨率高清图在实际项目中这个数据集在官网就可以申请到。训练时需要先生成对应的低分辨率图像做法是对高清图做高斯模糊可选然后双三次下采样4倍得到低分辨率输入。这里的关键是放大因子和模糊核的设置如果降质过程和实际应用场景不一致模型会严重水土不服。比如你训练时用的是理想双三次降采样但实际要处理的照片是手机随手拍的、带噪声和压缩伪影的低清图效果会大打折扣。这个问题我留在最后一节展开。数据增强上通常的做法是随机水平翻转和旋转90°。随机裁剪的patch大小建议选128×128高分辨率侧对应的低分辨率侧是32×32。Batch size不宜太大16就够用因为分辨率高的时候显存消耗非常快。我试过把Batch size提到32结果生成器特征提取部分的显存直接爆炸不大划算。4. SRGAN的效果评估PSNR、SSIM与只看分数会踩的坑4.1 保真度与感知质量是一对矛盾这是整个超分领域最核心的矛盾。PSNR和SSIM测量的是“像素层面的保真度”即生成的高清图与原始高清图之间的误差有多小。SRGAN在这两个指标上其实并不好看甚至不如SRResNet。但如果让人来做主观评测多数人会认为SRGAN生成的图像更自然、更清晰、更“像照片”。为什么我来做一个简单类比。假设你请一位画家根据一张素描重绘一幅油画。PSNR就像拿着一把尺子量重绘后的油画每一个像素的颜色和原图有多大差距——但画家根本不会一像素一像素地抠。SRGAN就像让一位经验丰富的画家根据素描补出光影、纹理和细节补出来的内容不一定和原图每个像素都一样但看上去是合理的、协调的、真实的。在超分任务里保真度和感知质量存在此消彼长的关系。最小化MSE会得到平滑的、均值化的结果在数值上偏差小但人类的视觉感知对高频细节边缘、纹理极其敏感反而觉得平滑化的图像“不真实”。SRGAN做的就是在保真度和感知质量之间找一个平衡点它放弃一点像素精度换来大幅提升的视觉自然度。4.2 主观评测与实际使用场景论文中用的是MOSMean Opinion Score评测法找一批评测者让他们给不同算法的超分结果打分分数从1极差到5极好。从MOS结果看SRGAN明显优于SRResNet和传统方法尤其在4倍超分时优势更明显。实际应用时你可能不会每次都组织一帮人做MOS评测。我的经验是选一些纹理丰富的测试图动物毛发、草地、砖墙、布料固定几个区域放大对比直接看细节上的差异。再配合一些实际“观众视角”的盲测把不同算法的结果随机打乱贴出来不告诉别人哪张是哪个算法让同事选“哪张看起来更像一张真照片”。这种直觉式认可比任何数值指标都更有说服力。不过要注意主观评测也有局限性。人的偏好往往受显示设备、距离、放大倍率影响同一组图在不同显示器上观感可能完全不同。所以看到论文里的MOS分数时也要考虑评测环境差异不能直接照搬。4.3 典型伪影与失败场景SRGAN输出的图像并不总是完美的。以下是最常见的几类问题过度锐化与纹理噪声当感知损失和对抗损失权重过高时生成器会把平坦区域比如皮肤、天空也当成纹理来创造产生类似“噪点”的颗粒感。我在调参时把对抗损失权重从1e-3调到2e-3后就遇到这个问题人物脸部的皮肤区域出现明显的粗糙感。边缘振铃效应在高对比度边缘附近比如建筑轮廓和天空交界处可能看到不太自然的亮暗条纹类似JPEG压缩伪影的放大版。语义失真在极小尺度下比如远处的人脸生成器“脑补”出来的细节可能与真实内容不符把眼睛位置画错、嘴巴形状画歪。这些问题其实都和SRGAN的底层假设有关——它假设低分辨率图像可以由一个固定降质过程模糊下采样退化而来。当这个假设成立时重建效果很好一旦实际降质过程偏离这个假设比如图像带了传感器噪声、运动模糊、压缩伪影生成器就会被迫用错误的方式去“脑补”结果就容易翻车。5. 从SRGAN到Real-ESRGAN超分模型走向实用的演进5.1 SRGAN的两大硬伤升维打击不存在的“细节”和训练不稳定SRGAN最大的硬伤是对降质模型的假设太理想化了。论文里默认低清图是由“双三次下采样”得到的但现实中的低清图有各种不可控因素原始图像的清晰度、拍摄时的对焦、手抖造成的运动模糊、后期压缩时的JPEG伪影、传感器噪点等等。你用做理想降质训练的SRGAN去处理这类真实图像输入数据的“分布”就已经偏离了训练数据的分布再强的模型也只是在错误的前提上强行找自己的理解。第二个硬伤是训练过程的“脆弱性”。GAN训练的核心难点在于对抗平衡判别器一旦压过生成器梯度信号就会消失生成器几乎停止学习。虽然两阶段训练能缓解这个问题但并不能根治。实际项目中要调出一组稳定的超参往往要花掉不少时间尤其在不同数据集间迁移时超参可能全部失效。5.2 Real-ESRGAN的改进思路降质模型更贴合真实世界Real-ESRGAN的核心思想很简单既然之前的模型都是在人工构造的数据上训练的那我先把降质过程做得更像“真实的降质过程”训练数据越接近真实模型就越实用。具体做法是引入“高阶降质模型”High-order Degradation Model把降质过程分解成多次合成的模糊、噪声、缩放、压缩伪影的组合。这个听起来只是数据增强的调整但实际效果是显著的。用Real-ESRGAN处理那些带噪声、带压缩痕迹的真实照片时重建效果明显比SRGAN干净许多不会强行创造不存在的纹理。但Real-ESRGAN也不是万能的。它依然依赖降质参数与真实图像匹配如果实际图像的模糊核超出它的假设范围同样会失效。做应用的时候还是需要先分析自己手里的图是怎么产生的再决定用哪种降质模型训练。5.3 扩展应用人脸超分、视频超分与移动端落地超分模型的价值不止在论文评测集上。人脸超分是热门的应用方向——专门针对人脸区域训练一个SRGAN变种可以恢复眼睛、嘴部细节常用于老照片修复、视频会议画质增强。另一个方向是视频超分但要注意的是视频超分与单张图像超分SISR有本质区别视频需要考虑时域一致性也就是前后帧的细节要连贯不能一帧一个样。直接拿SRGAN逐帧处理会引起闪烁问题需要结合光流对齐或者连续帧特征融合来稳定细节输出。移动端落地则碰到的完全是另一类问题显存够不够、推理速度能不能达到实时、功耗和发热能不能接受。SRGAN这类生成式模型的算力开销比SRCNN大得多想在移动端跑起来通常要配合剪枝和量化。如果只是做一次性的离线修复服务器端推理完全满足需要但如果是做实时预览就得考虑轻量化的方案。5.4 站在SRGAN肩膀上还能做什么SRGAN之后这个领域的发展速度非常快一些值得关注的演进方向ESRGAN把残差块升级为RRDBRelativistic Average GAN判别器从“绝对值判断”改成“相对值判断”效果进一步提升。GAN先验方法利用预训练GAN如StyleGAN的特征空间做先验约束在处理真实世界人脸修复时效果很好。扩散模型超分扩散模型天然适合生成高质量纹理目前SR3、Stable Diffusion Upscaler等方案已经在很多场景超过了基于GAN的方法但推理成本更高、速度更慢工业界落地还在探索中。从应用角度来看SRGAN之于超分问题的意义在于它打破了“像素保真度是唯一评价标准”这套框架让研究者和工程师真正开始关注人的视觉感知。哪怕今天你已经可以用上比它强大得多的模型回到SRGAN看问题理解问题的角度依然能给你做相关工作的启发——遇到一个“怎么都治不好”的任务时有时候不是方法不对而是根本衡量错了目标。如果你现在要复现或者自己动手搭一个SRGAN我的建议是不要急着堆机器、开大Batch先把数据做好、降质模型定对、SRResNet预处理训练扎实。这三个环节没做好后面GAN训练再花多少力气都白搭。等这三步走稳了再开始调对抗损失的权重、看不同纹理区域的主观效果你会发现SRGAN真正让人上瘾的地方是你亲眼看到了“像素被重新创造出来”的过程。本文还有配套的精品资源点击获取