资讯动态

Pytorch实现SRGAN:4倍图像超分辨率重建原理与实战

发布时间:2026/10/20 21:55:07 来源:尧图企业网站定制
把一张模糊到五官快认不出的旧图片丢进训练好的模型几秒后出来一张边缘锐利、纹理清晰的放大图——图片超分辨率大概是计算机视觉里最有“魔法感”的方向之一。这次“GAN重制版4”折腾的核心就是用Pytorch搭建SRGAN平台实现4倍图片超分辨率提升。这篇文章会把原理、核心代码、训练过程和踩坑记录全部摊开适合有一定Pytorch基础但没怎么训过GAN或者想亲手复现一个超分模型的人参考。我先说结论SRGAN不算难难的是让生成器和判别器好好配合。网上能搜到的复现代码很多但跟着跑完能出好效果的不多大多数情况下训练中期就崩了或者生成出来的图细节是有了、颜色却怪怪的。这篇文章更多是想把“为什么这么做”讲清楚你才能在自己机器上排查问题而不是无脑抄参数。1. 原理先行SRGAN到底解决了超分任务里的什么问题1.1 传统超分为什么不够用图片超分辨率的目标很直白给一张低分辨率图生成一张高分辨率图。传统做法无非是最近邻、双线性、双三次插值这一类方法核心思想都在“猜”——根据周围像素值算出中间位置的像素。双三次插值效果最好但也只是让边缘更平滑一点细节是真的补不出来。放大4倍之后照片看起来还是“虚”的。后来深度学习介入主流思路变成先用插值把低分辨率图放大到目标尺寸再丢进卷积网络让网络去学习“从模糊到清晰”的映射。代表工作是SRCNN只用三层卷积就能跑赢传统插值。再到SRResNet引入残差结构网络深度上去了PSNR指标能刷得很高。但这类模型有个通病训练时用像素间误差MSE作为损失网络学出来的是所有可能高清图的“平均值”结果就是输出图噪声少、PSNR高但放大看纹理糊成一片脸像打了磨皮。这种“平均效果”问题正是SRGAN要解决的。1.2 生成对抗机制怎么落到超分上SRGAN引入GAN的思路一个生成器负责把低分辨率图变成高分辨率图一个判别器负责判断输入图是真高清还是生成器造出来的假高清。生成器的目标就是骗过判别器让判别器分辨不出真伪。这个过程很像一个人学画画开始画得粗糙被老师判别器一眼识破为了不被识破就得把纹理、颜色、边缘都学得更接近原作。老师也在不断进步学生就被逼着越画越细。最后生成器输出的图不是“像素平均值”而是一种在统计分布上和真实高清图难以区分的输出观感自然好得多。这里有个容易混淆的点GAN不是让生成网络输出任意图案它的前提是生成器本身已经具备一定超分能力。如果生成器基础太弱判别器很容易学会“你输出的都是模糊图”然后快速碾压生成器导致训练崩掉。所以训练SRGAN时普遍采用两阶段策略先用像素损失把生成器训练到“基本能看”再加上对抗损失去打磨细节。1.3 感知损失SRGAN画质提升的关键按钮SRGAN论文里最核心的改动其实是损失函数。它没有只用GAN那一套对抗损失而是把损失拆成两部分内容损失和对抗损失。内容损失选的是“感知损失”做法是把生成图和真实高清图同时送入预训练好的VGG19网络取出某一层特征图然后计算特征图之间的L1距离。为什么要这么做因为VGG的特征图对应的是人眼关心的内容结构。如果两张图在VGG特征空间里很接近说明它们在语义内容、边缘轮廓、细节纹理上也接近。相比MSE逐像素比较感知损失更宽容像素位置的微小偏移同时更强调视觉结构。你可以理解为MSE是在问“每个点颜色差多少”感知损失是在问“这幅画的内容和结构像不像”。后者更贴近人的视觉判断。我最初复现时直接照搬论文公式但没注意VGG输入的范围结果生成图偏色严重。后面才搞明白VGG预训练权重是按ImageNet的均值和标准差归一化过的输入感知损失网络之前图像得先做同样的减均值除以标准差否则特征分布完全对不上。2. 实操准备跑SRGAN这活儿环境、数据、指标一次配齐2.1 硬件和运行环境建议SRGAN的模型规模放在今天不算大生成器主体是16个残差块判别器也就是一组卷积加两个全连接。真正常驻显存的主要是数据批次和中间特征图。我实测下来一张8GB显存级别的消费级显卡就能训练图像裁剪尺寸96×96、batch为16时显存占用大概7GB左右。如果你手里只有4GB显存也能跑无非是把batch降到8甚至4图像裁剪尺寸降到64×64训练时间变长而已。软件环境方面Pytorch 2.x配合CUDA 11.8是我最常用的组合。需要装的依赖不多核心是torch和torchvision外加opencv-python处理图像、pillow辅助读写、tqdm显示进度。torchvision主要用来加载VGG19做感知损失这个环节也可以自己单独下载VGG权重但直接用torchvision更省事。有一点要提醒训练时把数据加载的num_workers调高一些配合pin_memoryTrue能把数据读取等待时间压下来。CPU瓶颈比GPU瓶颈更容易被忽略很多人明明显卡不错训练速度却很慢多半是数据管线没跟上。2.2 训练数据从高清图造出低分辨样本SRGAN属于有监督学习我们需要成对的低分辨率和高分辨率图片。公开的超分数据集不难找一般以自然图像为主包含大量高清照片。但直接拿整张图喂进去不现实显存放不下收敛也慢。标准做法是先从训练集高清图里随机裁剪一块固定尺寸的小图比如96×96再用双三次插值把它降采样到24×24作为低分辨率输入。模型要做的事情就是输入24×24输出96×96。裁剪操作要注意一点随机裁剪一定要加固定随机种子或者在同一分支里同步生成裁剪坐标确保低分辨率图和高分辨率图是从同一个位置裁出来的。否则数据对完全错位模型根本无法学习。降采样操作我习惯用PyTorch的F.interpolate或者OpenCV的cv2.resize配INTER_CUBIC。两种方式效果接近但注意数值范围一致性Pytorch张量通常范围是0到1OpenCV读图后范围是0到255混用前一定先统一。我自己写Dataset类时会同时返回低分辨率图和高分辨率图尺寸分别是24×24和96×96并顺手把数据归一化到0到1区间。验证集的选择也有讲究。我一般从训练集之外另留一小组高清图固定裁剪若干位置做成成对样本每个epoch结束用这组样本生成超分结果并保存图片。这样做的好处是方便肉眼对比每个epoch的变化。只能看训练loss曲线的话很难判断模型到底有没有变好。2.3 评价指标别让PSNR骗了你超分任务最常见的客观指标是PSNR和SSIM。PSNR主要衡量像素误差值越高说明重建图和原图越接近但PSNR高不代表视觉好SSIM侧重结构相似性对亮度、对比度、结构变化更敏感相对靠谱一些。更贴近人眼感受的是LPIPS它计算的是深度特征空间的距离与主观视觉一致性较高。LPIPS数值越低越好。我建议训练阶段用PSNR和肉眼观察做主要参考因为LPIPS计算相对耗时最终评估时才把三个指标放在一起看。还有个大坑很多人训练完只盯着PSNR看发现GAN训练后PSNR反而比MSE预训练时低了就以为模型退化了。实际上GAN本来就会牺牲一定像素精度来换取视觉纹理的真实感这是预期行为。判断模型好坏截图放大看纹理细节是最直接的指标只能辅助参考。3. 代码落地生成器、判别器和损失函数手写全记录3.1 生成器代码残差块加亚像素上采样SRGAN的生成器结构并不复杂输入一层大卷积核卷积中间串联16个残差块再经过两个亚像素卷积层完成4倍上采样最后输出3通道高清图。我习惯把结构拆成三部分head、body、upsample这样代码调整起来方便。残差块用经典的convBNReLU结构但注意SRGAN里中间激活函数用的是PReLU而不是ReLU这是原论文的设计。PReLU在负区间有个可学习斜率能减少死神经元让梯度流动更顺畅。亚像素卷积也叫PixelShuffle核心思想是先通过卷积把通道数扩展成原来的r²倍再把通道重排成空间像素。以2倍上采样为例输入64通道特征图经过卷积变成256通道再调用nn.PixelShuffle(2)重排成64通道但宽高各翻倍的图。两次PixelShuffle就是4倍上采样。这个操作相比转置卷积的优点是几乎不产生棋盘格伪影训练也更稳。下面是生成器完整代码import torch import torch.nn as nn class ResidualBlock(nn.Module): def __init__(self, channels64): super().__init__() self.conv1 nn.Conv2d(channels, channels, kernel_size3, stride1, padding1) self.bn1 nn.BatchNorm2d(channels) self.relu nn.PReLU() self.conv2 nn.Conv2d(channels, channels, kernel_size3, stride1, padding1) self.bn2 nn.BatchNorm2d(channels) def forward(self, x): identity x out self.relu(self.bn1(self.conv1(x))) out self.bn2(self.conv2(out)) return out identity class GeneratorSRGAN(nn.Module): def __init__(self, in_channels3, out_channels3, num_res_blocks16, base_channels64): super().__init__() self.head nn.Sequential( nn.Conv2d(in_channels, base_channels, kernel_size9, stride1, padding4), nn.PReLU() ) body [ResidualBlock(base_channels) for _ in range(num_res_blocks)] body [ nn.Conv2d(base_channels, base_channels, kernel_size3, stride1, padding1), nn.BatchNorm2d(base_channels) ] self.body nn.Sequential(*body) self.upsample nn.Sequential( nn.Conv2d(base_channels, base_channels * 4, kernel_size3, stride1, padding1), nn.PixelShuffle(upscale_factor2), nn.PReLU(), nn.Conv2d(base_channels, base_channels * 4, kernel_size3, stride1, padding1), nn.PixelShuffle(upscale_factor2), nn.PReLU() ) self.tail nn.Conv2d(base_channels, out_channels, kernel_size9, stride1, padding4) def forward(self, x): x self.head(x) x self.body(x) x x self.upsample(x) return self.tail(x)这里head用9×9大卷积核原因是输入通道少大核能扩大初始感受野tail同样用9×9卷积把特征映射回RGB空间。需要4倍上采样时两个PixelShuffle串起来即可你要做2倍超分删掉一个上采样块就能直接跑。我实际测试下来这个生成器结构在超分任务上很稳也没有出现转置卷积常见的棋盘格。3.2 判别器代码判断真假高分辨率图像判别器可以理解成一个二分类网络输入是三通道图像输出是“真”的概率。SRGAN原版判别器由一组卷积组成卷积核都是3×3步长交替设为1和2通道数从64逐步增加到512中间插入BatchNorm和LeakyReLU。LeakyReLU的负斜率设为0.2它对小负数也保留梯度比ReLU更好训。这里需要特别注意全连接层的输入维度。如果训练时HR裁剪尺寸是96×96那么经过下采样后特征图是6×6512个通道全连接第一层就要接收512×6×6个数字也就是计算公式里的512 * 6 * 6。如果你把裁剪尺寸改了这个数字要跟着改。class DiscriminatorSRGAN(nn.Module): def __init__(self, in_channels3): super().__init__() def conv_block(in_ch, out_ch, stride, use_normTrue): layers [nn.Conv2d(in_ch, out_ch, kernel_size3, stridestride, padding1)] if use_norm: layers.append(nn.BatchNorm2d(out_ch)) layers.append(nn.LeakyReLU(0.2, inplaceTrue)) return nn.Sequential(*layers) self.conv nn.Sequential( conv_block(in_channels, 64, stride1, use_normFalse), conv_block(64, 64, stride2), conv_block(64, 128, stride1), conv_block(128, 128, stride2), conv_block(128, 256, stride1), conv_block(256, 256, stride2), conv_block(256, 512, stride1), conv_block(512, 512, stride2), ) self.fc nn.Sequential( nn.Linear(512 * 6 * 6, 1024), nn.LeakyReLU(0.2, inplaceTrue), nn.Linear(1024, 1) ) def forward(self, x): x self.conv(x) x torch.flatten(x, start_dim1) return self.fc(x)我最终没有在最后一层加Sigmoid训练时搭配nn.BCEWithLogitsLoss更稳。因为Sigmoid加BCE在数值上容易出现极端饱和区域而BCEWithLogitsLoss直接把Sigmoid和BCE合并内部做了数值稳定性处理。判别器输出logits而不是概率判断真假时大于0视为真小于0视为假就行。3.3 损失函数内容、感知、对抗三合一SRGAN的损失函数有三个组件感知损失、对抗损失、以及可选的像素损失。原始论文的生成器损失主要是感知损失加对抗损失但实际复现时我保留了一个权重很低的L1像素损失用来防止生成器在训练早期跑太偏。感知损失这块直接用torchvision加载VGG19的features层取到第36层也就是常说的edge特征层之后输出。这些预训练参数必须冻结不需要梯度。具体实现时把生成图和目标图都减ImageNet均值、除以标准差分别提取特征再算L1距离。import torch import torch.nn as nn import torchvision.models as models class PerceptualLoss(nn.Module): def __init__(self, devicecuda): super().__init__() vgg models.vgg19(pretrainedTrue).features.eval().to(device) self.loss_network nn.Sequential(*list(vgg.children())[:36]).eval() for p in self.loss_network.parameters(): p.requires_grad False self.criterion nn.L1Loss() self.mean torch.tensor([0.485, 0.456, 0.406]).view(1, 3, 1, 1).to(device) self.std torch.tensor([0.229, 0.224, 0.225]).view(1, 3, 1, 1).to(device) def forward(self, sr, hr): # 输入范围为0~1 sr (sr - self.mean) / self.std hr (hr - self.mean) / self.std return self.criterion(self.loss_network(sr), self.loss_network(hr))对抗损失按经典GAN写法生成器要尽量让判别器认为超分图是真的也就是让D(G(LR))接近1。如果把判别器输出当作logit生成器的对抗损失就可以用BCEWithLogitsLoss标签全设为1。注意区分两套输入范围训练时给生成器的图是0到1的浮点张量但ImageNet平均像素值是按0到1范围计算存储的这一点很容易被弄混。有人直接拿0到255的图去减0.485结果几乎全黑或全白。只要保持输入范围一致这个坑就能避开。3.4 训练主流程两阶段递进更稳SRGAN训练最忌讳直接从头开始端到端跑判别器开局就把生成器碾压生成器很快学废。正确姿势是分两个阶段先用L1或MSE损失预训练生成器让生成器具备基础超分能力再加载预训练权重把判别器加进来联合训练。预训练阶段比较简单就是把低分辨率图送入生成器和高分辨率图算逐像素损失更新生成器参数。我一般预训练80到100个epoch具体看损失下降情况PSNR稳定在合理区间就停。第二阶段联合训练时每轮迭代分两步先更新判别器用真实高清图当正样本生成器当前输出当负样本再更新生成器让生成器的输出去骗过判别器同时保持感知损失。下面是最小可运行的训练循环框架# 第一阶段预训练生成器 for epoch in range(pretrain_epochs): for lr_img, hr_img in train_loader: lr_img, hr_img lr_img.to(device), hr_img.to(device) sr_img generator(lr_img) loss_pix l1_loss(sr_img, hr_img) optimizer_G.zero_grad() loss_pix.backward() optimizer_G.step() # 第二阶段对抗训练 for epoch in range(gan_epochs): for lr_img, hr_img in train_loader: lr_img, hr_img lr_img.to(device), hr_img.to(device) sr_img generator(lr_img) batch_size hr_img.size(0) # 更新判别器 real_logits discriminator(hr_img) fake_logits discriminator(sr_img.detach()) d_loss bce_loss(real_logits, torch.ones_like(real_logits)) \ bce_loss(fake_logits, torch.zeros_like(fake_logits)) optimizer_D.zero_grad() d_loss.backward() optimizer_D.step() # 更新生成器 fake_logits discriminator(sr_img) adv_loss bce_loss(fake_logits, torch.ones_like(fake_logits)) percep_loss perceptual_loss(sr_img, hr_img) g_loss percep_loss * lambda_p adv_loss * lambda_a optimizer_G.zero_grad() g_loss.backward() optimizer_G.step()这段代码里lr_img是24×24的低分辨率图hr_img是96×96的高分辨率图。每次更新判别器之后生成器的输出图已经更新过一轮sr_img.detach()就是为了切断生成器梯度只让判别器更新。生成器阶段的对抗损失用真实标签1意思就是让生成器学会“骗过当前版本的判别器”。3.5 超参数速查表一套能直接套用的默认配置超参数设置直接决定训练是否稳定我这里贴出一套在8GB显存上验证过能跑的配置。不同数据集光照分布不同参数不需要照抄但量级和比例可以参考。参数推荐值说明HR裁剪尺寸96×96越大细节越好但显存占用线性增加放大倍数4对应两个PixelShuffle上采样块低分辨率输入尺寸24×24由96×96双三次降采样得到batch size168GB显存可跑4GB显存建议降到8生成器学习率1e-4预训练和GAN阶段都可用这个值判别器学习率1e-4判别器过强时可降到1e-5Adam beta10.9默认值GAN训练中常用Adam beta20.999Pytorch默认感知损失权重1e-2我实测1e-2偏稳论文常用1e-3对抗损失权重1e-3权重太大容易颜色漂移预训练epoch数80~100观察PSNR稳定即可进入第二阶段GAN训练epoch数100~150及时存档防止后期训练崩掉感知损失和对抗损失的权重要量级匹配。感知损失算出来通常是一个几十上百的数字对抗损失则只有个位数甚至零点几。如果两者直接相加对抗损失完全被淹没生成器学不到对抗逼真度。把感知损失权重调到1e-2附近对抗损失调到1e-3附近能让两者大概在同一影响力水平。这个比例不是绝对的但依据是让两个分量在总loss中占的比例不要差距超过一个数量级。4. 训练翻车合集Loss震荡、伪影与显存不足怎么救4.1 生成图像模糊或训练崩坏我的第一次复现就翻车了。跳过预训练阶段直接跑GAN前20个epoch生成器还能输出一团模糊的色块之后判别器loss直接归零生成器loss变成NaN。原因是判别器太强把生成器所有输出都判为假生成器梯度爆炸。解决办法就是前面提过的两阶段训练。预训练后生成器已经有了一个基本合理的超分函数这时加入判别器判别器没法靠“模糊”这个特征一眼判定真伪两者才能慢慢博弈起来。如果GAN训练期间判别器loss还是掉得太快可以把判别器学习率降到生成器的十分之一比如生成器1e-4判别器1e-5。另外一个小技巧是给判别器的真实标签加一点平滑值比如真实图标签从1改成0.9到0.95。这能让判别器不至于过度自信给生成器留出成长空间。4.2 棋盘格伪影棋盘格伪影是超分模型里最让人头疼的视觉缺陷生成的图片上出现一格一格像马赛克的网纹。直接原因多数是上采样操作不当。如果是用转置卷积重叠区域会造成亮度不均匀如果用PixelShuffle生成通道分配不合理也可能出现类似问题。根因在于当卷积核大小和上采样倍数不匹配时卷积核感受野在图像不同位置的重叠程度不一样导致部分像素更新的次数多、部分次数少形成了明暗交替的网格。排查思路很直接确认上采样是否用了PixelShuffle如果用了检查PixelShuffle之前的卷积核大小和填充是否合适。我推荐3×3卷积配合padding1这样不会引入额外边界效应。还有一个隐藏因素VGG感知损失前如果不做归一化特征分布偏掉生成器被迫硬拟合一些不合理的特征也容易产生纹理异常。先把归一化修正再去调结构。4.3 损失量级失衡训练到中期另一个常见现象是总损失下降但生成图颜色越来越淡或者越来越艳本质是感知损失和对抗损失的平衡出了问题。想判断哪个成分占了主导日志里不能只打印总loss要把percep_loss、adv_loss、pix_loss分别打出来。感知损失动辄几十对抗损失只有0.5到2如果感知损失没有乘权重它几乎决定了梯度方向对抗损失名存实亡。反过来如果对抗损失权重大到十几生成器会为了骗过判别器而忽略内容结构输出图可能细节很丰富但长得完全不像原图。我一般按这个思路调先固定感知损失权重把对抗损失打印出来看量级如果对抗损失比感知损失除以权重后还小十倍说明对抗影响力不足反之则降权重。这组数字没有绝对标准让分量在总loss里占比大致在同一数量级最重要。4.4 显存不足问题8GB显存跑SRGAN最大的瓶颈反而不是网络本身而是中间特征图和batch。一旦显存溢出Pytorch报的CUDA out of memory错误通常带着一串显存分布看不懂也没关系优先降低batch size这是最有效的一拳。如果batch降到4还爆就降HR裁剪尺寸从96×96降到64×64显存占用会按平方比例掉下来。不要轻易砍网络通道数改动结构之后效果变化很难归因。还有一个实用手段是开自动混合精度也就是AMP。只需要把梯度缩放器接进训练循环生成器和判别器的forward都用with torch.cuda.amp.autocast():包住显存能省下约三分之一速度还略有提升。我自己的经验是先固定裁剪尺寸只调batchbatch降到8还不行就把裁剪尺寸降到80甚至64。先保证训练能跑通再谈画质。4.5 客观指标与主观观感冲突训练结束时我常被一个现象迷惑某个checkpoint的PSNR和SSIM是历史最高但生成图看起来莫名平滑另一个checkpoint指标低一些肉眼看却纹理更细致。原因在于PSNR是逐像素RMSE的对数换算它对像素位置的微小偏移非常敏感而人眼其实不敏感这一点。比如你把一张图整体平移一个像素人眼几乎察觉不到但PSNR会剧烈下降。GAN训练中生成器为了让边缘更锐利会在局部位置做像素级别的重排PSNR因此下降视觉上反而更清晰。所以评估SRGAN效果时我会固定一组验证图每个epoch结束后保存生成结果训练完再按时间顺序排列逐张看变化。肉眼观察比单看数字可靠得多。客观指标记录起来也不亏作为训练崩溃的预警信号如果PSNR连续多个epoch断崖下跌多半是生成器开始放飞自我了。4.6 问题排查速查表训练SRGAN过程中各种问题以肉眼可见的速度出现是常态。常见的坑我整理成速查表照着排查能省很多时间。现象可能原因解决办法loss变成NaN学习率过高或输入存在异常值降低学习率检查输入范围是否在0~1判别器loss快速归零判别器过强降低判别器学习率或使用标签平滑生成器输出整体灰蒙蒙感知损失权重过低提高感知损失权重或加入L1像素损失生成图颜色偏色VGG归一化处理错误确认输入为0~1范围且做了ImageNet的mean/std画面出现棋盘格上采样配置不当改用PixelShuffle并检查卷积核paddingPSNR高但纹理模糊只用像素损失训练进入GAN阶段联合训练显存溢出batch或裁剪尺寸过大先降batch再降crop尺寸最后尝试AMP训练后期图像出现色斑对抗损失权重过大降低对抗损失权重或提前停止训练5. 效果评估与进阶改造跑通之后还能怎么玩5.1 让超分模型真正落到真实图片上训练结束后的测试阶段最常见的误区是拿网上随便一张低分辨率图进来就测。实验环境里构造的低分辨率图是双三次插值降采样得到的干净、无噪声、无压缩伪影真实场景的模糊图则是压缩、运动模糊、传感器噪声混合的结果。分布不匹配模型的超分效果会大打折扣。想让模型在真实图片上有可用效果可以在数据增强阶段给降采样后的低分辨率图加一点高斯噪声或JPEG压缩伪影让训练分布更接近真实场景。这一丁点改动对实际观感的提升往往比换一个更大更复杂的网络明显得多。另外超分模型本质是学习低分辨率到高分辨率的条件分布它对输入图像的尺寸没有严格限制。测试时整图如果太大可以切成重叠块分别超分再拼回去拼接缝处做一下羽化融合能避免接缝痕迹。这个技巧我在处理大图时经常用效果立竿见影。5.2 从SRGAN到新一代超分模型的升级路径跑通SRGAN之后进阶方向其实很清晰。先是ESRGAN它把残差块换成密集连接的RRDB块并且去掉了BatchNorm原因是BN在生成器里容易引入伪影感知损失从VGG54层改成了激活前的特征纹理重建质量又上了一个台阶。RNAN注重注意力机制SwinIR把Transformer搬进超分任务这些模型在指标上都能碾压SRGAN但训练复杂度和显存需求也成倍增加。想继续做应用还有一条路是Real-ESRGAN这类面向真实降质的模型它把降质过程做成了可以学习的模型专门处理老照片修复、动漫放大这类场景。从SRGAN起步最大的价值是理解对抗训练在图像生成里的核心逻辑生成器负责结构重建判别器负责逼真度门禁感知损失负责对齐内容。这套方法论往后迁移到色彩修复、去噪、去模糊思路完全通用。我个人觉得先别急着追新模型。把SRGAN从头到尾训一遍把训练过程中的每个坑都亲手踩平你对GAN训练的掌控感会质变。后续跑ESRGAN、SwinIR无非是换生成器主干、调损失权重的事。最后说点个人体会。这一版SRGAN前后跑了大概两周真正写网络结构的时间很少大部分精力都花在排查训练不稳定和颜色漂移上。如果你准备复现建议先把感知损失的归一化环节和两阶段训练策略想明白再动手。跑通之后找几张自己拍的模糊照片试试看到原本糊成一团的区域被重新补上纹理你大概就理解标题里那句“好像还挺好玩”是从哪来的了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑