超分中的GAN总结:常用的判别器类型和GAN loss类型

2024-08-25 08:28

本文主要是介绍超分中的GAN总结:常用的判别器类型和GAN loss类型,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 概述

在真实数据超分任务上,从SRGAN开始,Loss函数基本是Pixel loss + GAN loss + Perceptual loss的组合。

与生成任务不同,对于超分这种复原任务,如果只使用Gan loss或者GAN loss的权重比较大的话,效果就比较差。

SRGAN成功的两个关键点:1. 引入了感知损失函数(Perceptual Loss),它是让生成图像产生细节的关键,而不是对抗损失函数。2. 将对抗损失函数的权重调小,让它不能影响训练的方向,只会微调生成图像的清晰度,消除感知损失函数带来的噪声。参见底层视觉之美。

在实践中,一般gan loss的权重设置为Pixel loss的千分之一。

2. 超分中的判别器

判别器一般来说有三种:

  • 分类网络 vgg,resnet等
    最后一层输出输出一个数字,代表整张图的判别结果
  • Patch gan
    最后一层不再输出一个数字,而是输出1xnxn的特征图,其中的每一个数字代表了原图中一个patch的判别结果;最后的loss通过对这nxn个点求均值得到;
  • U-Net discriminator with spectral normalization (SN).
    在Real ESRGAN中提出的,因为unet的输入分辨率和输出分辨率一致,相当于unet判别器对每个像素进行了判别,最后的loss求均值得到;引入spectral normalization 是为了稳定训练,同时可以消除一些artifacts;

3. 超分中的几种 Gan loss

3.1 Vanilla GAN

最原始的gan loss,判别器做的是二分类任务,判别器的最后输出经过sigmoid后计算交叉熵;一般用
self.loss = nn.BCEWithLogitsLoss()实现,其相当于sigmoid + 交叉熵;

3.2 LSGAN (最小平方gan)

不去算sigmoid和交叉熵,而是直接算判别器预测输出与真实标签值的MSE;一般用self.loss = nn.MSELoss()

3.3 WGAN loss

WGAN是对原始的GAN的改进,优化了其会发生梯度消失训练不稳定的问题,原始的GAN最小化生成器loss等价于最小化真实分布P_r与生成分布P_g之间的JS散度 → WGAN最小化真实分布P_r与生成分布P_g之间的Wasserstein距离;
具体来说,WGAN去掉了sigmoid, 同时也不再计算交叉熵,而是直接返回D(x)的均值。因为一般来说,都是最小化loss,对于真实样本直接输出-input.mean();对于生成样本,如果是优化生成器的时候,wgan loss为-input.mean(),如果是优化判别器,则输出input.mean();代码如下;

def wgan_loss(input, target):# target is booleanreturn -1 * input.mean() if target else input.mean()

3.4 RAGAN (相对Gan)

衡量的是真实数据比生成数据真实的概率,也就是说原始的GAN是将判别器的输出直接计算loss,而RAGAN会先计算真实样本的判别器输出和生成样本的判别器输出,做差值后再进行loss计算;比如生成器loss如下:
D_loss = self.D_lossfn_weight * (
self.D_lossfn(pred_d_real - torch.mean(pred_g_fake, 0, True), False) +
self.D_lossfn(pred_g_fake - torch.mean(pred_d_real, 0, True), True)) / 2

3.5 代码(来自KAIR)

  • Loss函数定义代码
    class GANLoss(nn.Module):def __init__(self, gan_type, real_label_val=1.0, fake_label_val=0.0):super(GANLoss, self).__init__()self.gan_type = gan_type.lower()self.real_label_val = real_label_valself.fake_label_val = fake_label_val# 原始gan和ragan都是二分类if self.gan_type == 'gan' or self.gan_type == 'ragan':self.loss = nn.BCEWithLogitsLoss()elif self.gan_type == 'lsgan':self.loss = nn.MSELoss()elif self.gan_type == 'wgan':def wgan_loss(input, target):# target is booleanreturn -1 * input.mean() if target else input.mean()self.loss = wgan_losselif self.gan_type == 'softplusgan':def softplusgan_loss(input, target):# target is booleanreturn F.softplus(-input).mean() if target else F.softplus(input).mean()self.loss = softplusgan_losselse:raise NotImplementedError('GAN type [{:s}] is not found'.format(self.gan_type))def get_target_label(self, input, target_is_real):if self.gan_type in ['wgan', 'softplusgan']:return target_is_real# 返回标签,如果target_is_real为true,则返回全1的标签;如果为false则返回全0的标签if target_is_real:return torch.empty_like(input).fill_(self.real_label_val)else:return torch.empty_like(input).fill_(self.fake_label_val)def forward(self, input, target_is_real):target_label = self.get_target_label(input, target_is_real)loss = self.loss(input, target_label)return loss```
    
  • 判别器Loss计算代码
    if self.opt_train['gan_type'] in ['gan', 'lsgan', 'wgan', 'softplusgan']:# realpred_d_real = self.netD(self.H)                # 1) real datal_d_real = self.D_lossfn(pred_d_real, True)l_d_real.backward()# fakepred_d_fake = self.netD(self.E.detach().clone()) # 2) fake data, detach to avoid BP to Gl_d_fake = self.D_lossfn(pred_d_fake, False)l_d_fake.backward()
    elif self.opt_train['gan_type'] == 'ragan':# realpred_d_fake = self.netD(self.E).detach()       # 1) fake data, detach to avoid BP to Gpred_d_real = self.netD(self.H)                # 2) real datal_d_real = 0.5 * self.D_lossfn(pred_d_real - torch.mean(pred_d_fake, 0, True), True)l_d_real.backward()# fakepred_d_fake = self.netD(self.E.detach())l_d_fake = 0.5 * self.D_lossfn(pred_d_fake - torch.mean(pred_d_real.detach(), 0, True), False)l_d_fake.backward()```
    
  • 生成器loss计算代码
    if self.opt['train']['gan_type'] in ['gan', 'lsgan', 'wgan', 'softplusgan']:pred_g_fake = self.netD(self.E)D_loss = self.D_lossfn_weight * self.D_lossfn(pred_g_fake, True)
    elif self.opt['train']['gan_type'] == 'ragan':pred_d_real = self.netD(self.H).detach()pred_g_fake = self.netD(self.E)# 相对判别器D_loss = self.D_lossfn_weight * (self.D_lossfn(pred_d_real - torch.mean(pred_g_fake, 0, True), False) +self.D_lossfn(pred_g_fake - torch.mean(pred_d_real, 0, True), True)) / 2
    

这篇关于超分中的GAN总结:常用的判别器类型和GAN loss类型的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1105037

相关文章

Python中pywin32 常用窗口操作的实现

《Python中pywin32常用窗口操作的实现》本文主要介绍了Python中pywin32常用窗口操作的实现,pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个... 目录获取窗口句柄获取最前端窗口句柄获取指定坐标处的窗口根据窗口的完整标题匹配获取句柄根据窗口的类别匹配获取句

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

Python的time模块一些常用功能(各种与时间相关的函数)

《Python的time模块一些常用功能(各种与时间相关的函数)》Python的time模块提供了各种与时间相关的函数,包括获取当前时间、处理时间间隔、执行时间测量等,:本文主要介绍Python的... 目录1. 获取当前时间2. 时间格式化3. 延时执行4. 时间戳运算5. 计算代码执行时间6. 转换为指

Python正则表达式语法及re模块中的常用函数详解

《Python正则表达式语法及re模块中的常用函数详解》这篇文章主要给大家介绍了关于Python正则表达式语法及re模块中常用函数的相关资料,正则表达式是一种强大的字符串处理工具,可以用于匹配、切分、... 目录概念、作用和步骤语法re模块中的常用函数总结 概念、作用和步骤概念: 本身也是一个字符串,其中

usb接口驱动异常问题常用解决方案

《usb接口驱动异常问题常用解决方案》当遇到USB接口驱动异常时,可以通过多种方法来解决,其中主要就包括重装USB控制器、禁用USB选择性暂停设置、更新或安装新的主板驱动等... usb接口驱动异常怎么办,USB接口驱动异常是常见问题,通常由驱动损坏、系统更新冲突、硬件故障或电源管理设置导致。以下是常用解决

Python实现图片分割的多种方法总结

《Python实现图片分割的多种方法总结》图片分割是图像处理中的一个重要任务,它的目标是将图像划分为多个区域或者对象,本文为大家整理了一些常用的分割方法,大家可以根据需求自行选择... 目录1. 基于传统图像处理的分割方法(1) 使用固定阈值分割图片(2) 自适应阈值分割(3) 使用图像边缘检测分割(4)

Windows Docker端口占用错误及解决方案总结

《WindowsDocker端口占用错误及解决方案总结》在Windows环境下使用Docker容器时,端口占用错误是开发和运维中常见且棘手的问题,本文将深入剖析该问题的成因,介绍如何通过查看端口分配... 目录引言Windows docker 端口占用错误及解决方案汇总端口冲突形成原因解析诊断当前端口情况解

springboot项目中常用的工具类和api详解

《springboot项目中常用的工具类和api详解》在SpringBoot项目中,开发者通常会依赖一些工具类和API来简化开发、提高效率,以下是一些常用的工具类及其典型应用场景,涵盖Spring原生... 目录1. Spring Framework 自带工具类(1) StringUtils(2) Coll

MySQL 中查询 VARCHAR 类型 JSON 数据的问题记录

《MySQL中查询VARCHAR类型JSON数据的问题记录》在数据库设计中,有时我们会将JSON数据存储在VARCHAR或TEXT类型字段中,本文将详细介绍如何在MySQL中有效查询存储为V... 目录一、问题背景二、mysql jsON 函数2.1 常用 JSON 函数三、查询示例3.1 基本查询3.2

Java String字符串的常用使用方法

《JavaString字符串的常用使用方法》String是JDK提供的一个类,是引用类型,并不是基本的数据类型,String用于字符串操作,在之前学习c语言的时候,对于一些字符串,会初始化字符数组表... 目录一、什么是String二、如何定义一个String1. 用双引号定义2. 通过构造函数定义三、St