深度学习文献代码阅读-超分辨(ESRGAN)

摘要:
ESRGAN是在SRGAN基础上进行增强的网络,在2018年的比赛中获得了冠军Introduction介绍了基于PSNR指标获得的超分辨图像其结果会较为平滑,且与人们的主观有较大的差别作者针对SRGAN提出了3个改进的点第一点:使用了RDDB网络结构,这种层叠式的网络结构更容易表达效果第二点:使用RaGAN对抗网络,这种网络在优化生成器的时候,将判别真实图片的概率值考虑了进来第三点:对于VGG生成

ESRGAN是在SRGAN基础上进行增强的网络, 在2018年的比赛中获得了冠军

深度学习文献代码阅读-超分辨(ESRGAN)第1张

Introduction 介绍了基于PSNR指标获得的超分辨图像其结果会较为平滑,且与人们的主观有较大的差别

深度学习文献代码阅读-超分辨(ESRGAN)第2张

作者针对SRGAN提出了3个改进的点

第一点: 使用了RDDB网络结构, 这种层叠式的网络结构更容易表达效果

第二点: 使用RaGAN对抗网络, 这种网络在优化生成器的时候,将判别真实图片的概率值考虑了进来

第三点:对于VGG生成的语义纹理损失值,使用了relu之前的输出结果,进行比较

深度学习文献代码阅读-超分辨(ESRGAN)第3张

因为PSNR和SSIM的指标与人眼的视觉指标存在差异,因此作者使用了竞赛中的指标perceptual index

深度学习文献代码阅读-超分辨(ESRGAN)第4张

作者进行改进的点: 第一个在网络结构上的改进,使用了RRDB层

深度学习文献代码阅读-超分辨(ESRGAN)第5张

RRDB代码: 先进入class RRDBNet,然后调转到class RRDB,最后跳转到class ResidualDenseBlock

importfunctools
importtorch
importtorch.nn as nn
importtorch.nn.functional as F
importmodels.modules.module_util as mutil


classResidualDenseBlock_5C(nn.Module):
    def __init__(self, nf=64, gc=32, bias=True):
        super(ResidualDenseBlock_5C, self).__init__()
        #gc: growth channel, i.e. intermediate channels
        self.conv1 = nn.Conv2d(nf, gc, 3, 1, 1, bias=bias)
        self.conv2 = nn.Conv2d(nf + gc, gc, 3, 1, 1, bias=bias)
        self.conv3 = nn.Conv2d(nf + 2 * gc, gc, 3, 1, 1, bias=bias)
        self.conv4 = nn.Conv2d(nf + 3 * gc, gc, 3, 1, 1, bias=bias)
        self.conv5 = nn.Conv2d(nf + 4 * gc, nf, 3, 1, 1, bias=bias)
        self.lrelu = nn.LeakyReLU(negative_slope=0.2, inplace=True)

        #initialization
        mutil.initialize_weights([self.conv1, self.conv2, self.conv3, self.conv4, self.conv5], 0.1)

    defforward(self, x):
        x1 =self.lrelu(self.conv1(x))
        x2 = self.lrelu(self.conv2(torch.cat((x, x1), 1)))
        x3 = self.lrelu(self.conv3(torch.cat((x, x1, x2), 1)))
        x4 = self.lrelu(self.conv4(torch.cat((x, x1, x2, x3), 1)))
        x5 = self.conv5(torch.cat((x, x1, x2, x3, x4), 1))
        return x5 * 0.2 +x


classRRDB(nn.Module):
    '''Residual in Residual Dense Block'''

    def __init__(self, nf, gc=32):
        super(RRDB, self).__init__()
        self.RDB1 =ResidualDenseBlock_5C(nf, gc)
        self.RDB2 =ResidualDenseBlock_5C(nf, gc)
        self.RDB3 =ResidualDenseBlock_5C(nf, gc)

    defforward(self, x):
        out =self.RDB1(x)
        out =self.RDB2(out)
        out =self.RDB3(out)
        return out * 0.2 +x


classRRDBNet(nn.Module):
    def __init__(self, in_nc, out_nc, nf, nb, gc=32):
        super(RRDBNet, self).__init__()
        RRDB_block_f = functools.partial(RRDB, nf=nf, gc=gc)

        self.conv_first = nn.Conv2d(in_nc, nf, 3, 1, 1, bias=True) #进行第一次的卷积
        self.RRDB_trunk = mutil.make_layer(RRDB_block_f, nb) #添加RRDB残差块
        self.trunk_conv = nn.Conv2d(nf, nf, 3, 1, 1, bias=True) #再次进行卷积操作
        #### upsampling
        self.upconv1 = nn.Conv2d(nf, nf, 3, 1, 1, bias=True)
        self.upconv2 = nn.Conv2d(nf, nf, 3, 1, 1, bias=True)
        self.HRconv = nn.Conv2d(nf, nf, 3, 1, 1, bias=True)
        self.conv_last = nn.Conv2d(nf, out_nc, 3, 1, 1, bias=True)

        self.lrelu = nn.LeakyReLU(negative_slope=0.2, inplace=True)

    defforward(self, x):
        fea =self.conv_first(x)
        trunk =self.trunk_conv(self.RRDB_trunk(fea))
        fea = fea +trunk

        fea = self.lrelu(self.upconv1(F.interpolate(fea, scale_factor=2, mode='nearest')))
        fea = self.lrelu(self.upconv2(F.interpolate(fea, scale_factor=2, mode='nearest')))
        out =self.conv_last(self.lrelu(self.HRconv(fea)))

        return out

作者进行改进的点: 第二个在使用了RaGan对抗生成网络,对于判别器和生成器使用相对概率

深度学习文献代码阅读-超分辨(ESRGAN)第6张

对于生成器的ragan损失值,即

真实图片相对于虚假图片判断为假的损失值

虚假图片相对于真实图片判别为真的损失值

pred_g_fake = self.netD(self.fake_H) #判别生成的图片
if self.opt['train']['gan_type'] == 'gan':
   l_g_gan = self.l_gan_w *self.cri_gan(pred_g_fake, True)
elif self.opt['train']['gan_type'] == 'ragan':
   pred_d_real = self.netD(self.var_ref).detach() #判别真实的图片的概率值
   l_g_gan = self.l_gan_w *(
              self.cri_gan(pred_d_real - torch.mean(pred_g_fake), False) + #
              self.cri_gan(pred_g_fake - torch.mean(pred_d_real), True)) / 2 #生成的图片比真实图片更加的真实
l_g_total += l_g_gan

对于判别器的ragan损失值,即

真实图片相对于虚假图片判别为真的损失值

虚假图片相对于真实图片判别为假的损失值

   pred_d_real =self.netD(self.var_ref)
   pred_d_real =self.netD(self.var_ref)
   pred_d_fake = self.netD(self.fake_H.detach())  #detach to avoid BP to G
   if self.opt['train']['gan_type'] == 'gan':
            l_d_real =self.cri_gan(pred_d_real, True)
            l_d_fake =self.cri_gan(pred_d_fake, False)
            l_d_total = l_d_real +l_d_fake
   elif self.opt['train']['gan_type'] == 'ragan':
            l_d_real = self.cri_gan(pred_d_real -torch.mean(pred_d_fake), True)
            l_d_fake = self.cri_gan(pred_d_fake -torch.mean(pred_d_real), False)
            l_d_total = (l_d_real + l_d_fake) / 2

作者进行改进的点: 第二个使用vgg进行纹理细节提取时,使用最后一层conv的relu之前的输出结果

深度学习文献代码阅读-超分辨(ESRGAN)第7张

作者对最后一层的conv输出和relu输出做了可视化结果比对

深度学习文献代码阅读-超分辨(ESRGAN)第8张

将vgg损失值进行添加

 if self.cri_fea:  #feature loss
        real_fea = self.netF(self.var_H).detach() #表示真实图片的VGG损失值
        fake_fea = self.netF(self.fake_H) #
        l_g_fea = self.l_fea_w * self.cri_fea(fake_fea, real_fea) #构建L1损失值
        l_g_total += l_g_fea

这里使用的是vgg19的不带bn的输出

classVGGFeatureExtractor(nn.Module):
    def __init__(self, feature_layer=34, use_bn=False, use_input_norm=True,
                 device=torch.device('cpu')):
        super(VGGFeatureExtractor, self).__init__()
        self.use_input_norm =use_input_norm
        ifuse_bn:
            model = torchvision.models.vgg19_bn(pretrained=True)
        else:
            model = torchvision.models.vgg19(pretrained=False)
        ifself.use_input_norm:
            mean = torch.Tensor([0.485, 0.456, 0.406]).view(1, 3, 1, 1).to(device)
            #[0.485 - 1, 0.456 - 1, 0.406 - 1] if input in range [-1, 1]
            std = torch.Tensor([0.229, 0.224, 0.225]).view(1, 3, 1, 1).to(device)
            #[0.229 * 2, 0.224 * 2, 0.225 * 2] if input in range [-1, 1]
            self.register_buffer('mean', mean) #构建处理步骤的名字
            self.register_buffer('std', std)
        self.features = nn.Sequential(*list(model.features.children())[:(feature_layer + 1)])
        #No need to BP to variable
        for k, v inself.features.named_parameters():
            v.requires_grad = False #为了防止梯度进行更新

    defforward(self, x):
        #Assume input range is [0, 1]
        ifself.use_input_norm:
            x = (x - self.mean) /self.std
        output =self.features(x)
        return output

结果展示

ESRGAN网络在PSNR指标上表现的不是很好,但是在perceptual index上相当于其他方法有突出的表现

深度学习文献代码阅读-超分辨(ESRGAN)第9张

免责声明:文章转载自《深度学习文献代码阅读-超分辨(ESRGAN)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇git commit 关闭eslint校验并发下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

使用GAN 进行异常检测——anoGAN,TODO,待用于安全分析实验

先说实验成功的代码: git clone https://github.com/tkwoo/anogan-keras.git mkdir weights python main.py --mode train 即可看到效果了! 核心代码:main.py from __future__ import print_function import matp...

tfgan折腾笔记(二):核心函数详述——gan_model族

定义model的函数有: 1.gan_model 函数原型: defgan_model( #Lambdas defining models. generator_fn, discriminator_fn, #Real data and conditioning. real_data, generator_inputs,...

使用GAN进行异常检测——可以进行网络流量的自学习哇,哥哥,人家是半监督,无监督的话,还是要VAE,SAE。

实验了效果,下面的还是图像的异常检测居多。 https://github.com/LeeDoYup/AnoGAN https://github.com/tkwoo/anogan-keras 看了下,本质上是半监督学习,一开始是有分类模型的。代码如下,生产模型和判别模型: ### generator model define def generator_m...

开发者自述:我是这样学习 GAN 的

Generative Adversarial Network,就是大家耳熟能详的 GAN,由 Ian Goodfellow 首先提出,在这两年更是深度学习中最热门的东西,仿佛什么东西都能由 GAN 做出来。我最近刚入门 GAN,看了些资料,做一些笔记。 1.Generation 什么是生成(generation)?就是模型通过学习一些数据,然后生成类似的数...

GAN量化评估方法——IS(Inception Score)和FID(Frechet Inception Distance score)

  生成模型产生的是高维的复杂结构数据,它们不同于判别模型,很难用简单的指标来评估模型的好坏。下面介绍两种当前比较流行的评估生成模型的指标(仅判别图像):IS(Inception Score)和FID(Frechet Inception Distance score)。 IS   IS基于Google的预训练网络Inception Net-V3。Incep...

GAN训练技巧汇总

  GAN自推出以来就以训练困难著称,因为它的训练过程并不是寻找损失函数的最小值,而是寻找生成器和判别器之间的纳什均衡。前者可以直接通过梯度下降来完成,而后者除此之外,还需要其它的训练技巧。   下面对历年关于GAN的论文提出的训练技巧进行总结,这里仅记录技巧,具体原理请直接看论文原文。 WGAN和WGAN-GP   WGAN论文将GAN原文用来度量两个分...