使用Pytorch从零开始构建WGAN

引言

在考虑生成对抗网络的文献时,Wasserstein GAN 因其与传统 GAN 相比的训练稳定性而成为关键概念之一。在本文中,我将介绍基于梯度惩罚的 WGAN 的概念。文章的结构安排如下:

  1. WGAN 背后的直觉;
  2. GAN 和 WGAN 的比较;
  3. 基于梯度惩罚的WGAN的数学背景;
  4. 使用 PyTorch 从头开始​​在;
  5. CelebA-Face 数据集上实现;
  6. WGAN 结果讨论。

WGAN 背后的直觉

GAN 最初由Ian J. Goodfellow 等人发明。在 GAN 中,有一个由生成器和判别器进行的双玩家最小最大游戏。早期 GAN 的主要问题是模式崩溃和梯度消失问题。为了克服这些问题,长期以来发明了许多技术。WGAN 是试图克服传统 GAN 的这些问题的方法之一。

GAN 与 WGAN

与传统的 GAN 相比,WGAN 有一些改进/变化。

  1. 评论家而非判别器;
  2. W-Loss 代替 BCE Loss;
  3. 使用梯度惩罚/权重剪裁进行权重正则化。

传统GAN的判别器被“Critic”取代。从实现的角度来看,这只不过是最后一层没有 Sigmoid 激活的判别器。

我们稍后将讨论 WGAN 损失函数和权重正则化。

数学背景

损失函数

这是基于梯度惩罚的 WGAN 的完整损失函数。

等式 1. 具有梯度惩罚的完整 WGAN 损失函数 — [3]
在这里插入图片描述
看起来很吓人吧?让我们分解一下这个方程。

第 1 部分:原始批评损失
在这里插入图片描述

该方程产生的值应由生成器正向最大化,同时由批评家负向最大化。请注意,这里的 x_CURL 是生成器 (G(z)) 生成的图像。

这里,D 在最后一层没有 Sigmoid 激活,因此 D(*) 可以是任何实数。这给出了地球移动器的真实分布和生成分布之间的距离的近似值 - [1]。我们在这里想做的是,

  1. 评论家的观点:通过最大化等式 2结果的负值/最小化正值,尽可能地将评论家对真实图像和生成图像的输出分布分开。这反映了评论家的目标,即为真实图像提供更高的分数,为更低的分数到生成的图像。
  2. 生成器的观点:尝试通过以相反的方向分离真实图像和生成图像的输出分布来抵消评论家的努力。这最终使式 2 的结果的正值最大化。这反映了生成器的目标是通过欺骗 Critic 来提高生成图像的 Critic 分数。
  • 在这里你可能已经注意到,Critic over Discriminator这个名字的出现是因为 Critic 不区分真假图像,只是给出一个无界的分数。

为了确保方程有效,我们需要确保 Critic 函数是 1-Lipschitz 连续的 — [1]。

1-Lipschitz连续性

函数 f(x) 是 1-L 连续的,梯度应始终小于或等于 1。

为了确保这种1-Lipschitz连续性,文献中主要提出了2种方法。

  1. Weight Clipping——这是 WGAN 论文 [2] 附带的初始方法;
  2. 梯度惩罚方法——这是在最初的论文之后作为改进提出的[3]。

在本文中,我们将重点关注基于梯度惩罚的 WGAN。

第二部分:梯度惩罚
在这里插入图片描述
这是 Gulrajani 等人提出的梯度惩罚。——[3]。这里我们通过减小 Critic 梯度的 L2 范数与 1 之间的平方距离来强制 Critic 的梯度为 1。注意,我们不能强制 Critic 的梯度为 0,因为这会导致梯度消失问题。

等等!x(^)是什么?

考虑到 1-Lipschitz 连续性的定义,所有 x 的梯度应≤1。但实际上,确保所有可能的图像都满足这种条件是很困难的。因此,我们使用 x(^) 表示使用真实图像和生成图像作为梯度惩罚的数据点的随机插值图像。这确保了 Critic 的梯度将通过查看训练期间遇到的一组公平的数据点/图像进行正则化。

Pytorch实现

在这里,我将介绍大家应该做的必要更改,以便将传统的 GAN 更改为 WGAN。

对于下面的实现,我将使用我在之前有关 DCGAN 的文章中详细解释的模型和训练原理。

数据集

Celeba-face 数据集用于训练。下载、预处理、制作数据加载器脚本如代码1所示。

import zipfile
import os
if not os.path.isfile('celeba.zip'):!mkdir data_faces && wget https://s3-us-west-1.amazonaws.com/udacity-dlnfd/datasets/celeba.zip with zipfile.ZipFile("celeba.zip","r") as zip_ref:zip_ref.extractall("data_faces/")from torch.utils.data import DataLoadertransform = transforms.Compose([transforms.Resize((img_size,img_size)),transforms.ToTensor(),transforms.Normalize((0.5,0.5, 0.5),(0.5, 0.5, 0.5))])dataset = datasets.ImageFolder('data_faces', transform=transform)
data_loader = DataLoader(dataset,batch_size=batch_size,shuffle=True)

生成器和评论家

Critic 与 Discriminator 相同,但不包含最后一层 Sigmoid 激活。

class Generator(nn.Module):def __init__(self,noise_channels,img_channels,hidden_G):super(Generator,self).__init__()self.G=nn.Sequential(conv_trans_block(noise_channels,hidden_G*16,kernal_size=4,stride=1,padding=0),conv_trans_block(hidden_G*16,hidden_G*8),conv_trans_block(hidden_G*8,hidden_G*4),conv_trans_block(hidden_G*4,hidden_G*2),nn.ConvTranspose2d(hidden_G*2,img_channels,kernel_size=4,stride=2,padding=1),nn.Tanh())def forward(self,x):return self.G(x)class Critic(nn.Module):def __init__(self,img_channels,hidden_D):super(Critic,self).__init__()self.D=nn.Sequential(conv_block(img_channels,hidden_G),conv_block(hidden_G,hidden_G*2),conv_block(hidden_G*2,hidden_G*4),conv_block(hidden_G*4,hidden_G*8),nn.Conv2d(hidden_G*8,1,kernel_size=4,stride=2,padding=0))def forward(self,x):return self.D(x)

Generator 和 Critic 的支持块如下面的代码 3 所示。

class conv_trans_block(nn.Module):def __init__(self,in_channels,out_channels,kernal_size=4,stride=2,padding=1):super(conv_trans_block,self).__init__()self.block=nn.Sequential(nn.ConvTranspose2d(in_channels,out_channels,kernal_size,stride,padding),nn.BatchNorm2d(out_channels),nn.ReLU())def forward(self,x):return self.block(x)class conv_block(nn.Module):def __init__(self,in_channels,out_channels,kernal_size=4,stride=2,padding=1):super(conv_block,self).__init__()self.block=nn.Sequential(nn.Conv2d(in_channels,out_channels,kernal_size,stride,padding),nn.BatchNorm2d(out_channels),nn.LeakyReLU(0.2))def forward(self,x):return self.block(x)

损失函数

与任何其他典型的损失函数不同,损失函数可能有点棘手,因为它包含梯度。在这里,我们将使用梯度惩罚来实现 W-loss,稍后可以将其插入 WGAN 模型中。

def get_gen_loss(crit_fake_pred):gen_loss= -torch.mean(crit_fake_pred)return gen_lossdef get_crit_loss(crit_fake_pred, crit_real_pred, gradient_penalty, c_lambda):crit_loss= torch.mean(crit_fake_pred)- torch.mean(crit_real_pred)+ c_lambda* gradient_penaltyreturn crit_loss

让我们分解一下代码 4 中所示的损失函数。

  1. 生成器损失 - 生成器损失不受梯度惩罚的影响。因此,它必须仅最大化 D(x_CURL)/ D(G(z)) 项,这意味着最小化 -D(G(z))。这是在第 2 行中实现的。
  2. 批评者损失 - 批评者损失包含等式 1 中所示损失的 2 个部分。在第 6 行中,前两项给出等式 2 中解释的原始批评者损失,而最后一项给出等式 3 中解释的梯度惩罚。

梯度惩罚可以按照下面的代码 5 来实现 - [1]。

def get_gradient(crit, real_imgs, fake_imgs, epsilon):mixed_imgs= real_imgs* epsilon + fake_imgs*(1- epsilon)mixed_scores= crit(mixed_imgs)gradient= torch.autograd.grad(outputs= mixed_scores,inputs= mixed_imgs,grad_outputs= torch.ones_like(mixed_scores),create_graph=True,retain_graph=True)[0]return gradientdef gradient_penalty(gradient):gradient= gradient.view(len(gradient), -1)gradient_norm= gradient.norm(2, dim=1)penalty = torch.nn.MSELoss()(gradient_norm, torch.ones_like(gradient_norm))return penalty

在代码 5 中,get_gradient()函数返回从x_hat (混合图像)开始到Critic 输出 (mixed_scores)结束的所有网络梯度。这将在gradient_penalty()函数中使用,它返回Critic梯度的1和L2范数之间的均方距离。

减少 Critic 的损失最终会减少这种梯度惩罚。这确保了 Critic 函数保留了 1-Lipschitz 连续性。

训练

训练将与上一篇文章中的几乎相同。但这里的损失与传统的 GAN 损失不同。我已经使用WANDB记录我的结果。如果您有兴趣记录结果,WANDB 是一个非常好的工具。

C=Critic(img_channels,hidden_C).to(device)
G=Generator(noise_channels,img_channels,hidden_G).to(device)#C=C.apply(init_weights)
#G=G.apply(init_weights)wandb.watch(G, log='all', log_freq=10)
wandb.watch(C, log='all', log_freq=10)opt_C=torch.optim.Adam(C.parameters(),lr=lr, betas=(0.5,0.999))
opt_G=torch.optim.Adam(G.parameters(),lr=lr, betas=(0.5,0.999))gen_repeats=1
crit_repeats=3noise_for_generate=torch.randn(batch_size,noise_channels,1,1).to(device)losses_C=[]
losses_G=[]for epoch in range(1,epochs+1):loss_C_epoch=[]loss_G_epoch=[]for idx,(x,_) in enumerate(data_loader):C.train()G.train()x=x.to(device)x_len=x.shape[0]### Train Closs_C_iter=0for _ in range(crit_repeats):opt_C.zero_grad()z=torch.randn(x_len,noise_channels,1,1).to(device)real_imgs=xfake_imgs=G(z).detach()real_C_out=C(real_imgs)fake_C_out=C(fake_imgs)epsilon= torch.rand(len(x),1,1,1, device= device, requires_grad=True)gradient= get_gradient(C, real_imgs, fake_imgs.detach(), epsilon)gp= gradient_penalty(gradient)loss_C= get_crit_loss(fake_C_out, real_C_out, gp, c_lambda=10)loss_C.backward()opt_C.step()loss_C_iter+=loss_C.item()/crit_repeats### Train Gloss_G_iter=0for _ in range(gen_repeats):opt_G.zero_grad()z=torch.randn(x_len,noise_channels,1,1).to(device)fake_C_out = C(G(z))loss_G= get_gen_loss(fake_C_out)loss_G.backward()opt_G.step()loss_G_iter+=loss_G.item()/gen_repeats

结果

这是经过 10 个 epoch 训练后获得的结果。与传统 GAN 一样,生成的图像随着时间的推移变得更加真实。WANDB 项目的所有结果都可以在这里找到。
在这里插入图片描述

结论

生成对抗网络一直是深度学习社区的热门话题。由于 GAN 传统训练方法的缺点,WGAN 随着时间的推移变得越来越流行。这主要是因为它对模式崩溃具有鲁棒性并且不存在梯度消失问题。在本文中,我们实现了一个能够生成人脸的简单 WGAN 模型。

请随意查看 GitHub 代码。如有任何意见、建议和意见,我们将不胜感激。

Reference

[1] GAN specialization on coursera

[2] Arjovsky, Martin et al. “Wasserstein GAN”

[3] Gulrajani, Ishaan et al. “Improved Training of Wasserstein GANs”

[4] Goodfellow, Ian et al. “Generative Adversarial Networks”

[5] Vincent Herrmann, “Wasserstein GAN and the Kantorovich-Rubinstein Duality”

[6] Karras, Tero et al. “A Style-Based Generator Architecture for Generative Adversarial Networks”

本文译自Udith Haputhanthri的博文。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/202205.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

求解Beamforming-SOCP(CVX求解)

时间:2023年11月23日14:00:16: 直接上代码(辛苦两天才改出来的) clear all; K 4; %user number N4; %base station number var1e-9; H []; %initialize H matrix for i1:Kh 1/sqrt(2*K)*mvnrnd(zeros(N,1),eye(N),1)1i/sqrt(2*…

探针台的发展趋势

随着半导体技术的不断发展和市场需求的增长,探针台也在不断进步和创新。以下是探针台的一些发展趋势: 自动化与智能化:为提高测试效率和减少人为误差,探针台正朝着更高程度的自动化和智能化发展。例如,通过引入机器视…

JS PromiseLike 的判定与使用

目录 一. $.ajax()返回值遇到的问题二. Promise A 规范三. 判断是否为PromiseLike3.1 判断ES6的new Promise()3.2 判断包含then方法的对象3.3 判断$.ajax()返回的对象 一. $.ajax()返回值遇到的问题 当我们执行如下js代码时,可以看到$.ajax()执行后,得到…

计算机网络的OSI七层模型

目录 1、OSI七层模型是什么 1.1 物理层(Physical Layer) 1.2 数据链路层(Data Link Layer) 1.3 网络层(Network Layer) 1.4 传输层(Transport Layer) 1.5 会话层(S…

杨传辉:从一体化架构,到一体化产品,为关键业务负载打造一体化数据库

在刚刚结束的年度发布会上,OceanBase正式推出一体化数据库的首个长期支持版本 4.2.1 LTS,这是面向 OLTP 核心场景的全功能里程碑版本,相比上一个 3.2.4 LTS 版本,新版本能力全面提升,适应场景更加丰富,有更…

一篇文章,教你看懂加密工具The Enigma Protector

The Enigma Protector作为一款专业的软件授权和保护工具,一直以来深受开发者喜爱,此次携手慧都合作上线,更加方便了国内用户的购买和使用,一起来看看这款工具都有哪些值得期待的地方↓↓↓ The Enigma Protector 是一款专门设计用…

机器学习第11天:降维

文章目录 机器学习专栏 主要思想 主流方法 1.投影 二维投射到一维 三维投射到二维 2.流形学习 一、PCA主成分分析 介绍 代码 二、三内核PCA 具体代码 三、LLE 结语 机器学习专栏 机器学习_Nowl的博客-CSDN博客 主要思想 介绍:当一个任务有很多特征…

CTF靶场搭建及Web赛题制作与终端docker环境部署

♥ ♡ ♥ ♡ ♥ ♡ ♥ ♡ ♥ ♡ ♥ ♡ ♥ ♡ ♥ ♡ ♥ ♡ ♥ ♡ ♥ ♡ ♥ ♡ ♥ ♡ ♥ ♡ ♥ ♡ ♥ ♡ ♥ ♡ ♥ ♡ ♥ ♡ ♥ ♡ ♥ ♡ ♥ ♡ ♥ ♡ ♥ 写在前面 ╔═══════════════════════════════════════════════════…

Python爬取京东商品销售数据进行数据分析示例代码,以口红为例

文章目录 一、准备工作驱动安装模块使用与介绍 二、流程解析三、完整代码四、效果展示关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包项目源码合集①Python工具包②Python实战案例③Python小游戏源码五、面试资…

【电路笔记】-电流源

电流源 文章目录 电流源1、概述1.1 理想电流源1.2 实际电流源1.3 连接规则 2、依赖电流2.1 压控电流源2.2 电流控制电流源 3、总结 本文为前面文章 电压源的延续,我们将在本文介绍电流源。 与电压源的情况类似,我们将首先介绍理想电流源的概念&#xff…

【数据结构】树的基本概念 | 入门树以及二叉树必熟知

树的学习过程中,二叉树比较重要,但是在学习二叉树之前,得先需要了解到一些数的概念。 树的定义 树是一种非线性的数据结构,它是由 n(n > 0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它…

BTS-GAN:基于MRI和条件对抗性网络的乳腺肿瘤计算机辅助分割系统

BTS-GAN: Computer-aided segmentation system for breast tumor using MRI and conditional adversarial networks BTS-GAN:基于MRI和条件对抗性网络的乳腺肿瘤计算机辅助分割系统背景贡献实验方法Parallel dilated convolution module(并行扩展卷积模块…

tp8 使用rabbitMQ(1)简单队列

php8.0 使用 rabbitmq 要使用 3.6版本以上的&#xff0c; 并且还要开启 php.ini中的 socket 扩展 php think make:command SimpleMQProduce //创建一个生产者命令行 php think make:command SimpleMQConsumer //创建一个消费者命令行 生产者代码 <?php declare (strict_ty…

为何设计师都在用这个原型样机资源网站?

谈论原型样机素材模板&#xff0c;这个话题对设计师来说如同老朋友一般熟悉。设计师们在创作完毕后&#xff0c;为了更淋漓尽致地展示他们的设计成果&#xff0c;通常会将其放置在真实的样机素材模板中。这种原型样机素材可以让设计作品迅速且清晰地呈现在真实环境中。找到一个…

java游戏制作-飞翔的鸟游戏

一.准备工作 首先创建一个新的Java项目命名为“飞翔的鸟”&#xff0c;并在src中创建一个包命名为“com.qiku.bird"&#xff0c;在这个包内分别创建4个类命名为“Bird”、“BirdGame”、“Column”、“Ground”&#xff0c;并向需要的图片素材导入到包内。 二.代码呈现 …

【每日一题】2216.美化数组的最少删除数-2023.11.21

题目&#xff1a; 2216. 美化数组的最少删除数 给你一个下标从 0 开始的整数数组 nums &#xff0c;如果满足下述条件&#xff0c;则认为数组 nums 是一个 美丽数组 &#xff1a; nums.length 为偶数对所有满足 i % 2 0 的下标 i &#xff0c;nums[i] ! nums[i 1] 均成立 …

【Vue】自定义指令

hello&#xff0c;我是小索奇&#xff0c;精心制作的Vue系列持续发放&#xff0c;涵盖大量的经验和示例&#xff0c;如果对您有用&#xff0c;可以点赞收藏哈~ 自定义指令 自定义指令就是自己定义的指令&#xff0c;是对 DOM 元素进行底层操作封装 ,程序化地控制 DOM&#xff…

【开源】基于Vue.js的高校实验室管理系统的设计和实现

项目编号&#xff1a; S 015 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S015&#xff0c;文末获取源码。} 项目编号&#xff1a;S015&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 实验室类型模块2.2 实验室模块2.3 实…

2023 最新 PDF.js 在 Vue3 中的使用(长期更新)

因为自己写业务要定制各种 pdf 预览情况&#xff08;可能&#xff09;&#xff0c;所以采用了 pdf.js 而不是各种第三方封装库&#xff0c;主要还是为了更好的自由度。 一、PDF.js 介绍 官方地址 中文文档 PDF.js 是一个使用 HTML5 构建的便携式文档格式查看器。 pdf.js 是社区…

ABB机 器 人 操 作 培 训

目 录 1 培训手册介绍 ---------------------------------------------2 2 系统安全与环境保护 ---------------------------------------------3 3 机器人综述 ---------------------------------------------5 4 机器人示教 --------------------------------------------12…