点击上方“小白学视觉”,选择加"星标"或“置顶

重磅干货,第一时间送达

作者:Venkatesh Tata

编译:ronghuaiyang

生成对抗网络的一篇实践文章,使用PyTorch,用很简单的代码搭建了一个GANs,非常通俗易懂。

我们创建了一个生成对抗网络,可以生成显示世界中没有的鸟。

这些鸟都是通过GANs生成的。

在我们实际创建GAN之前,我们先看看GANs背后的思想。GANs是Ian Goodfellow发明的,他在斯坦福获得了本科和硕士学位,在蒙特利尔大学获得了博士学位。这是深度学习领域的一个新的大事。Yann LeCun说过:

"生成对抗网络是近年来机器学习领域最有趣的想法"

什么是GANs?我们为什么要创造GANs?

神经网络很擅长分类和预测事情,但是AI的研究者想要让神经网络更加像人类,通过创造东西而不仅仅是看见东西。 Ian Goodfellow成功的发明了这样一类深度学习模型,可以用来创造东西。

GANs是怎么工作的?

GANs有两个独立的神经网络。一个叫做“G”,代表了生成器,另外一个叫做“D”,代表了判别器。生成器首先随机的产生图像,判别器通过观察这些图像告诉生成器这些图片有多真实。

让我们考虑一个生成器

在开始的时候,生成器用一个随机噪声信号作为输入,产生一个随机图像作为输出,通过判别器的帮助,开始产生越来越真实的图像。

判别器

判别器是生成器的一个对手,它的输入即有真实的图像,同时也有生成器生成的图像,判别器输出这个图像的真实程度。

到了某个点的时候,判别器无法判断出这个图像是否是真实图像了,这时我们可以发现某个由生成器输出的图像是之前从没有存在过的了。

GANs的应用

  • 超分辨率

  • 艺术辅助

  • 元素抽取


开始写代码 !

注意:下面的代码并不适合深度学习的新手,我希望你有一些python深度学习的经验。

开始我们先导入一些GAN需要的包。首先需要确保PyTorch已安装。

#importing required librariesfrom __future__ import print_functionimport torchimport torch.nn as nnimport torch.nn.parallelimport torch.optim as optimimport torch.utils.dataimport torchvision.datasets as dsetimport torchvision.transforms as transformsimport torchvision.utils as vutilsfrom torch.autograd import Variable

设置一些超参数,batch-size和图像的尺寸:

# Setting hyperparametersbatchSize = 64 imageSize = 64

第一行我们设置了batchsize为64,第二行设置了输出图像的尺寸为64x64。


然后我们创建一个图像的转换器的对象,如下:

# Creating the transformationstransform = transforms.Compose([transforms.Scale(imageSize), transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),])

上面的转化器是将图像作为判别器的输入所必须的。


注意:如果需要获取数据集,点击这里:https://github.com/venkateshtata/GAN_Medium.git>,clone这个仓库,然后替换 “dcgan.py” 文件为你需要写入的python文件, “data” 文件夹存储的是数据集。


现在我们加载数据集。这里我们使用的是 CIFAR-10的数据集。我们批量加载,确保你的python文件和你导入的数据集在同一个文件夹。

# Loading the datasetdataset = dset.CIFAR10(root = './data', download = True, transform = transform)dataloader = torch.utils.data.DataLoader(dataset, batch_size = batchSize, shuffle = True, num_workers = 2)

我们将数据集下载后放在./data目录下,应用我们之前定义的转化器。然后使用dataLoader 来获取训练图像。其中‘num_workers’ 表示的是读取数据用的线程的数量,其他的参数可以从字面意思理解。


由于这里我们需要处理两个神经网络,我们会定义一个全局的函数来初始化给定的神经网络,只要将神经网络模型通过参数传给这个函数即可。

def weights_init(m):classname = m.__class__.__name__if classname.find('Conv') != -1:m.weight.data.normal_(0.0, 0.02)elif classname.find('BatchNorm') != -1:m.weight.data.normal_(1.0, 0.02)m.bias.data.fill_(0)

上面的函数获取神经网络的模型作为参数,初始化所有的参数。这个函数在训练开始时在每个迭代都会调用。

第一步就是定义我们的生成器神经网络。我们创建一个生成器的类,里面包含了一系列的层。

class G(nn.Module):def __init__(self):super(G, self).__init__()self.main = nn.Sequential(nn.ConvTranspose2d(100, 512, 4, 1, 0, bias = False),nn.BatchNorm2d(512),nn.ReLU(True),nn.ConvTranspose2d(512, 256, 4, 2, 1, bias = False),nn.BatchNorm2d(256),nn.ReLU(True),nn.ConvTranspose2d(256, 128, 4, 2, 1, bias = False),nn.BatchNorm2d(128),nn.ReLU(True),nn.ConvTranspose2d(128, 64, 4, 2, 1, bias = False),nn.BatchNorm2d(64),nn.ReLU(True),nn.ConvTranspose2d(64, 3, 4, 2, 1, bias = False),nn.Tanh())

分解上面的代码:

  • 我们创建了一个类‘G’,继承了 ‘nn.module’,这个类里有构建模型所需要的各种功能,只要将各种应用和连接放到神经网络里即可。

  • 然后我们创建了一个模型,包含了一系列的模块,如卷积,全连接等。

  • 这里从图中可以看大,生成器和判别器是相互倒着的。生成器的输入时一个向量,所以这里我们使用了转置卷积 ‘ConvTranspose2d’。

  • 然后我们在batch的维度上对所有的特征进行了归一化,然后使用ReLU进行了非线性变换。

  • 我们重复上面的操作,输入的节点从100变到了512,特征数从512变到了256,bias保持为False。

  • 在最后的 ‘ConvTranspose2d’ 中,我们输出了3个通道,因为输出的是‘RGB’的图像,使用了‘Tanh’作为激活函数。


现在我们创建一个forward函数来进行生成器信号的前向传播。

def forward(self, input):output = self.main(input)return output

上面的函数的输入时长度为100的随机向量。返回的是一个生成的图像。随机向量产生随机图像。


创建生成器:

netG = G() netG.apply(weights_init)

这里我们创建了一个生成器,然后进行了参数初始化。


现在我们再定义一个判别器类:

class D(nn.Module):def __init__(self):super(D, self).__init__()self.main = nn.Sequential(nn.Conv2d(3, 64, 4, 2, 1, bias = False),nn.LeakyReLU(0.2, inplace = True),nn.Conv2d(64, 128, 4, 2, 1, bias = False),nn.BatchNorm2d(128),nn.LeakyReLU(0.2, inplace = True),nn.Conv2d(128, 256, 4, 2, 1, bias = False),nn.BatchNorm2d(256),nn.LeakyReLU(0.2, inplace = True),nn.Conv2d(256, 512, 4, 2, 1, bias = False),nn.BatchNorm2d(512),nn.LeakyReLU(0.2, inplace = True),nn.Conv2d(512, 1, 4, 1, 0, bias = False),nn.Sigmoid())

判别器分解:

  • 和G类似,判别器也是继承了‘nn.module’,输入是生成器生成的图像,返回一个0~1之间的数字。

  • 由于用生成器的输出作为输入,第一个操作时卷积,我们的激活函数使用了LeakyReLU。

  • 可以看到,不同于生成器,我们这里使用了LeakyReLU,这个是经验得来的。

  • 我们使用了‘BatchNorm2d’ 来进行特征归一化。

  • 最后,我们使用了sigmoid函数,输入0~1之间的概率。


为了进行前向传播,我们定义一个forward函数,使用生成器的输出作为输入:

def forward(self, input):output = self.main(input)return output.view(-1)

最后一行,我们的输出值在0~1之间,由于我们需要把向量铺平,确保向量有相同的维度。


创建判别器 :

netD = D() netD.apply(weights_init)

上面我们创建了判别器,初始化所有的参数:


现在,我们开始训练生成对抗网络。开始之前,我们需要得到一个损失函数,用来评价判别器的损失。我们使用 BCE Loss,非常适合对抗网络。然后生成器和判别器我们都需要一个优化器。

criterion = nn.BCELoss()optimizerD = optim.Adam(netD.parameters(), lr = 0.0002, betas = (0.5, 0.999))optimizerG = optim.Adam(netG.parameters(), lr = 0.0002, betas = (0.5, 0.999))

我们创建了一个评价函数用来度量预测和目标之间的差别。我们为判别器和生成器各创建了一个优化器。

我们使用了 ‘Adam’ 优化器,这是个SGD的升级版。


我们训练神经网络25个epochs:

for epoch in range(25):

我们从数据集中循环读取图像 :

for i, data in enumerate(dataloader, 0):

第一步需要更新判别器中的参数,我们把判别器中所有的梯度清零。

netD.zero_grad()

我们知道,判别器需要用真实和虚假的图像同时训练。这里我们先用一个真实图像来训练

real, _ = datainput = Variable(real)target = Variable(torch.ones(input.size()[0]))output = netD(input)errD_real = criterion(output, target)

我们从数据集中获取一个真实图像训练判别器,然后包装成一个变量。然后前向传播,得到预测值,然后计算loss。


现在,使用生成器输出的虚假图像训练判别器:

noise = Variable(torch.randn(input.size()[0], 100, 1, 1))fake = netG(noise)target = Variable(torch.zeros(input.size()[0]))output = netD(fake.detach())errD_fake = criterion(output, target)

这里,我们先让一个随机向量通过生成器,得到一个虚假的图像。然后将这个虚假图像通过判别器,得到预测,计算损失。


误差反向传播:

errD = errD_real + errD_fakeerrD.backward()optimizerD.step()

这里我们计算判别器总的loss作为判别器的loss,更新判别器的时候,不更新生成器的权值。最后我们通过优化器来判别器更新权值。


下面我们更新生成器的权值:

netG.zero_grad()target = Variable(torch.ones(input.size()[0]))output = netD(fake)errG = criterion(output, target)errG.backward()optimizerG.step()

就像之前一样,我们先将所有的梯度清零。然后将loss是通过计算生成器的梯度来反向传播,然后通过生成器的优化器来更新生成器的权值。


现在,我们最后的步骤就是在每100个steps时打印loss,存储真实的图像和生成的图像,可以这么做:

print('[%d/%d][%d/%d] Loss_D: %.4f Loss_G: %.4f' % (epoch, 25, i, len(dataloader), errD.data[0], errG.data[0]))if i % 100 == 0:vutils.save_image(real, '%s/real_samples.png' % "./results", normalize = True)fake = netG(noise)vutils.save_image(fake.data, '%s/fake_samples_epoch_%03d.png' % ("./results", epoch), normalize = True)

完整代码 :

from __future__ import print_functionimport torchimport torch.nn as nnimport torch.nn.parallelimport torch.optim as optimimport torch.utils.dataimport torchvision.datasets as dsetimport torchvision.transforms as transformsimport torchvision.utils as vutilsfrom torch.autograd import VariablebatchSize = 64 imageSize = 64transform = transforms.Compose([transforms.Scale(imageSize), transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),]) # We create a list of transformations (scaling, tensor conversion, normalization) to apply to the input images.dataset = dset.CIFAR10(root = './data', download = True, transform = transform) dataloader = torch.utils.data.DataLoader(dataset, batch_size = batchSize, shuffle = True, num_workers = 2) def weights_init(m):classname = m.__class__.__name__if classname.find('Conv') != -1:m.weight.data.normal_(0.0, 0.02)elif classname.find('BatchNorm') != -1:m.weight.data.normal_(1.0, 0.02)m.bias.data.fill_(0)class G(nn.Module):def __init__(self):super(G, self).__init__()self.main = nn.Sequential(nn.ConvTranspose2d(100, 512, 4, 1, 0, bias = False),nn.BatchNorm2d(512),nn.ReLU(True),nn.ConvTranspose2d(512, 256, 4, 2, 1, bias = False),nn.BatchNorm2d(256),nn.ReLU(True),nn.ConvTranspose2d(256, 128, 4, 2, 1, bias = False),nn.BatchNorm2d(128),nn.ReLU(True),nn.ConvTranspose2d(128, 64, 4, 2, 1, bias = False),nn.BatchNorm2d(64),nn.ReLU(True),nn.ConvTranspose2d(64, 3, 4, 2, 1, bias = False),nn.Tanh())def forward(self, input):output = self.main(input)return outputnetG = G()netG.apply(weights_init)class D(nn.Module):def __init__(self):super(D, self).__init__()self.main = nn.Sequential(nn.Conv2d(3, 64, 4, 2, 1, bias = False),nn.LeakyReLU(0.2, inplace = True),nn.Conv2d(64, 128, 4, 2, 1, bias = False),nn.BatchNorm2d(128),nn.LeakyReLU(0.2, inplace = True),nn.Conv2d(128, 256, 4, 2, 1, bias = False),nn.BatchNorm2d(256),nn.LeakyReLU(0.2, inplace = True),nn.Conv2d(256, 512, 4, 2, 1, bias = False),nn.BatchNorm2d(512),nn.LeakyReLU(0.2, inplace = True),nn.Conv2d(512, 1, 4, 1, 0, bias = False),nn.Sigmoid())def forward(self, input):output = self.main(input)return output.view(-1)netD = D()netD.apply(weights_init)criterion = nn.BCELoss()optimizerD = optim.Adam(netD.parameters(), lr = 0.0002, betas = (0.5, 0.999))optimizerG = optim.Adam(netG.parameters(), lr = 0.0002, betas = (0.5, 0.999))for epoch in range(25):for i, data in enumerate(dataloader, 0):netD.zero_grad()real, _ = datainput = Variable(real)target = Variable(torch.ones(input.size()[0]))output = netD(input)errD_real = criterion(output, target)noise = Variable(torch.randn(input.size()[0], 100, 1, 1))fake = netG(noise)target = Variable(torch.zeros(input.size()[0]))output = netD(fake.detach())errD_fake = criterion(output, target)errD = errD_real + errD_fakeerrD.backward()optimizerD.step()netG.zero_grad()target = Variable(torch.ones(input.size()[0]))output = netD(fake)errG = criterion(output, target)errG.backward()optimizerG.step()print('[%d/%d][%d/%d] Loss_D: %.4f Loss_G: %.4f' % (epoch, 25, i, len(dataloader), errD.data[0], errG.data[0]))if i % 100 == 0:vutils.save_image(real, '%s/real_samples.png' % "./results", normalize = True)fake = netG(noise)vutils.save_image(fake.data, '%s/fake_samples_epoch_%03d.png' % ("./results", epoch), normalize = True)

你可以从我的GitHub仓库看到代码:

https://github.com/venkateshtata/GAN_Medium

如果有好的建议,可以随便fork或者拉代码,谢谢!

好消息!

小白学视觉知识星球

开始面向外开放啦

理解和创建GANs|使用PyTorch来做深度学习相关推荐

  1. 使用Pytorch实现NLP深度学习

    原文链接:https://pytorch.org/tutorials/beginner/deep_learning_nlp_tutorial.html 本文将会帮助你了解使用Pytorch进行深度学习 ...

  2. 人工智能AI:TensorFlow Keras PyTorch MXNet PaddlePaddle 深度学习实战 part1

    日萌社 人工智能AI:TensorFlow Keras PyTorch MXNet PaddlePaddle 深度学习实战 part1 人工智能AI:TensorFlow Keras PyTorch ...

  3. 【代码实现】最新PyTorch机器学习与深度学习技术方法

    近年来,随着AlphaGo.无人驾驶汽车.医学影像智慧辅助诊疗.ImageNet竞赛等热点事件的发生,人工智能迎来了新一轮的发展浪潮.尤其是深度学习技术,在许多行业都取得了颠覆性的成果.另外,近年来, ...

  4. 优化你的CPU来做深度学习

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 导读 对于想学习深度学习的同学们来说,学习资源网上有很多,但是计算 ...

  5. 亚马逊服务器怎么做系统,使用亚马逊云服务器EC2做深度学习(四)配置好的系统镜像...

    这是<使用亚马逊云服务器EC2做深度学习>系列的第四篇文章. 配置深度学习的环境是一个非常繁琐的过程.它要求你对Linux命令有一定地了解,与此同时各种深度学习库.驱动更新十分频繁,有可能 ...

  6. 云服务器做深度学习推荐+autoDL云服务器进行深度学习教程

    目录 主流云服务器 autoDL云服务器进行深度学习教程 1.购买autoDL云服务器 2.向服务器上传项目数据 3.解压服务器上的项目数据 4.终端训练 4.1 远程IDE 4.2  代码执行结束自 ...

  7. 官方推荐!用TensorFlow 2.0做深度学习入门教程

    最近,TensorFlow 2.0版的开发者预览版发布没多久,这不,又有一篇优质教程来了. 最近,前Youtube视频分类的产品经理.Hands-On MachineLearning with Sci ...

  8. Google首席科学家谈Google是怎么做深度学习的

    Google首席科学家谈Google是怎么做深度学习的 dongfeiwww  2016-03-26 10:17 收藏64 评论1 2016年3月7日,谷歌首席科学家,MapReduce.BigTab ...

  9. 人人都可以做深度学习应用:入门篇

    一.人工智能和新科技革命 2017年围棋界发生了一件比较重要事,Master(Alphago)以60连胜横扫天下,击败各路世界冠军,人工智能以气势如虹的姿态出现在我们人类的面前.围棋曾经一度被称为&q ...

最新文章

  1. 负载均衡技术中的真集群和伪集群
  2. A Comprehensive Analysis of Sequence Alignment Algorithms for LongRead Sequencing
  3. AOSP 设置编译输出目录
  4. VMSS上用Managed Disk和Data Disk进行自动扩展(1)
  5. JAVA-最常用的A题语法
  6. UNITY 内存问题资料收集
  7. 51nod 1448 二染色问题 (逆向考虑)
  8. 直流电机 步进电机 伺服电机
  9. android中如何执行java命令
  10. vue 侦听器侦听对象属性_SQL Server始终处于侦听器状态
  11. C1认证学习笔记(第一章)
  12. 夏普科学计算机标准差,夏普比率-标准差-贝他系数
  13. java 在某个时间段定时_Java 在某一个时间点定时执行任务(转载)
  14. 电子邮件营销的十大技巧
  15. 武汉市公积金提取流程
  16. Oracle 11g客户端网络服务名配置
  17. 构建一个 CLI 工具
  18. 今天,王坚正式把“杭州城市大脑”作为礼物献给世界
  19. 从零使用okhttp和gson解析聚合数据的新闻头条API
  20. mysql是大端小端_大端和小端 - HackerVirus - 博客园

热门文章

  1. python透明的桌面时钟_透明桌面时钟-透明桌面时钟下载 v2018.07.16免费版--pc6下载站...
  2. 如何将PDF转为Word使用?安利3个可以转换的软件
  3. React:真正理解虚拟DOM
  4. cadvisor如何采集数据
  5. FreeRTOS学习记录
  6. Linux特殊权限之umask,SBIT,SUID,SGID及ACL权限列表
  7. matlab-线性代数 齐次方程组 基础解系和通解
  8. 水滴石穿(1):Java序列化与反序列化
  9. 硕士女程序员相亲被拒,晒出征婚条件,网友:这是花钱娶祖宗?
  10. angular 内置管道和自定义管道