DCGAN 源码解析

article/2025/8/26 22:25:48

为什么写Blog现在还没找到理由。不过用心看下去你会觉得更有意义。

我们以生成图片为例子:

  1. G就是一个生成图片的网络,它接受一个随机的噪声z,然后通过这个噪声生成图片,生成的数据记做G(z)
  2. D是一个判别网络,判别一张图片是不是“真实的”(是否是捏造的)。它的输入参数是xx代表一张图片,输出D(x)代表x为真实图片的概率,如果为1,就代表绝逼是真实的图片,而输出为0,就代表不可能是真实的图片。

在训练的过程中,生成网络G的目标就是生成假的图片去骗过判别网络D,而判别网络D的目标就是能够分辨出某一张图片是不是由G生成的。这就变成了一个博弈的过程。同时GD的能力也在训练的过程中逐渐提高。在最理想的情况下, 则就是D(G(z))=0.5

一、实现 Implementation

1.权重初始化

在DCGAN的论文中,作者指定所有模型的初始化权重是一个均值为0,标准差为0.02的正态分布。weights_init函数的输入是一个初始化的模型,然后按此标准重新初始化模型的卷积层、卷积转置层和BN层的权重。模型初始化后应立即应用此函数。

# custom(自定义) initial weight,called on netG and netD
def weights_init(m):classname = m.__class__.__name__  # return m's nameif classname.find('Conv') != -1:  # find():find 'classname' whether contains "Conv" character,if not,return -1;otherwise,return 0torch.nn.init.normal_(m.weight, 0.0, 0.02)  # nn.init.normal_():the initialization weigts used Normally Distributed,mean=0.0,std=0.02elif classname.find('BatchNorm') != -1:torch.nn.init.normal_(m.weight, 1.0, 0.02)torch.nn.init.zeros_(m.bias)

2. 生成器Generator

生成器G, 用于将隐向量 (z)映射到数据空间。 由于我们的数据是图片,也就是通过隐向量z生成一张与训练图片大小相同的RGB图片 (比如 3x64x64). 在实践中,这是通过一系列的ConvTranspose2d,BatchNorm2d,ReLU完成的。 生成器的输出,通过tanh激活函数把数据映射到[−1,1]。需要注意的是,在卷积转置层之后紧跟BN层,这是DCGAN论文的重要贡献。这些层(即BN层)有助于训练过程中梯度的流动。DCGAN论文中的生成器如下图所示:

生成器代码如下:

class Generator(nn.Module):  # father:nn.Module   son:Generatordef __init__(self, ngpu):  # initialize the properties of the fathersuper(Generator, self).__init__()  # jointly father and son,call the method of father's __init__(),let son include all the properties of fatherself.ngpu = ngpuself.main = nn.Sequential(  # construct neural layers in order# input is Z, going into a convolution;state size:4 x 4 x (ngf*8)nn.ConvTranspose2d(nz, ngf * 8, 4, 1, 0, bias=False),  # in_channels=nz, out_channels=ngf*8, kernel_size=4, stride=1, padding=0nn.BatchNorm2d(ngf * 8),nn.ReLU(True),# state size: 8 x 8 x (ngf*4)nn.ConvTranspose2d(ngf * 8, ngf * 4, 4, 2, 1, bias=False),nn.BatchNorm2d(ngf * 4),nn.ReLU(True),# state size: 16 x 16 x (ngf*2)nn.ConvTranspose2d(ngf * 4, ngf * 2, 4, 2, 1, bias=False),nn.BatchNorm2d(ngf * 2),nn.ReLU(True),# state size: 32 x 32 x (ngf)nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 1, bias=False),nn.BatchNorm2d(ngf),nn.ReLU(True),# state size: 64 x 64 x (nc)nn.ConvTranspose2d(ngf, nc, 4, 2, 1, bias=False),nn.Tanh())def forward(self, input):if input.is_cuda and self.ngpu > 1:output = nn.parallel.data_parallel(self.main, input, range(self.ngpu))else:output = self.main(input)return output

然后,我们可以实例化生成器,并应用weights_init方法,代码如下:

netG = Generator(ngpu).to(device)  # create the generator
netG.apply(weights_init)  # apply the weight_init function,randomly initialize all weights to means=0,std=0.2
if opt.netG != '':netG.load_state_dict(torch.load(opt.netG))
print(netG)

3.判别器Discriminator 

 如前所述,判别器D是一个二分类网络,它将图片作为输入,输出其为真的标量概率。这里,D的输入是一个3*64*64的图片,通过一系列的 Conv2d, BatchNorm2d,和 LeakyReLU 层对其进行处理,最后通过Sigmoid 激活函数输出最终概率。如有必要,你可以使用更多层对其扩展。DCGAN 论文提到使用跨步卷积而不是池化进行降采样是一个很好的实践,因为它可以让网络自己学习池化方法。BatchNorm2d层和LeakyReLU层也促进了梯度的健康流动,这对生成器G和判别器D的学习过程都是至关重要的。判别器代码如下:

class Discriminator(nn.Module):  # father:nn.Module   son:Discriminatordef __init__(self, ngpu):  # initialize the properties of the fathersuper(Discriminator, self).__init__()  # jointly father and son,call the method of father's __init__(),let son include all the properties of fatherself.ngpu = ngpuself.main = nn.Sequential(  # construct neural layers in order# input is 64 x 64 x (nc)nn.Conv2d(nc, ndf, 4, 2, 1, bias=False),  # in_channels=nz, out_channels=ngf, kernel_size=4, stride=2, padding=1nn.LeakyReLU(0.2, inplace=True),# state size. 32 x 32 x (ndf)nn.Conv2d(ndf, ndf * 2, 4, 2, 1, bias=False),nn.BatchNorm2d(ndf * 2),nn.LeakyReLU(0.2, inplace=True),# state size.  16 x 16 x (ndf*2)nn.Conv2d(ndf * 2, ndf * 4, 4, 2, 1, bias=False),nn.BatchNorm2d(ndf * 4),nn.LeakyReLU(0.2, inplace=True),# state size.  8 x 8 x (ndf*4)nn.Conv2d(ndf * 4, ndf * 8, 4, 2, 1, bias=False),nn.BatchNorm2d(ndf * 8),nn.LeakyReLU(0.2, inplace=True),# state size.   4 x 4 x (ndf*8)nn.Conv2d(ndf * 8, 1, 4, 1, 0, bias=False),nn.Sigmoid())def forward(self, input):if input.is_cuda and self.ngpu > 1:output = nn.parallel.data_parallel(self.main, input, range(self.ngpu))else:output = self.main(input)return output.view(-1, 1).squeeze(1)  # .view(-1,1):redefining the shape of the matrix;  .squeeze(1):remove the dimensions of 1 in the matrix

然后,我们同样可以实例化判别器,并应用weights_init方法,代码如下: 

netD = Discriminator(ngpu).to(device)  # # create the discriminator
netD.apply(weights_init)  # apply the weight_init function,randomly initialize all weights to means=0,std=0.2
if opt.netD != '':netD.load_state_dict(torch.load(opt.netD))
print(netD)

 4.损失函数和优化器

有了生成器D和判别器G,我们可以为其指定损失函数和优化器来进行学习。这里将使用Binary Cross Entropy损失函数 (BCELoss)。其在PyTorch中的定义为:

其中,y_i是标签,p_yi是样本为positive的概率,我们约定1代表positive points,0代表negative points。我们来分析一下这个公式:

①对于positive样本,y=1,loss=-logp_yi,当p_yi越大,loss越小;理想情况下,p_yi=1,loss=0;

②对于negative样本,y=0,loss=-log(1-p_yi) ,当p_yi越大,loss越大;理想情况下,p_yi=0,loss=0;

 DCGAN中咱们的损失函数为:

关于这个公式的含义,我在上篇博客已经讲过了,这里不再赘述。注意这个损失函数需要你提供两个log组件 (比如 log(D(x))和log(1−D(G(z))))。我们可以指定BCE的哪个部分使用输入y标签。但我们可以通过改变y标签来指定使用哪个log部分。

接下来,我们定义真实标签为1,假标签为0。这些标签用来计算生成器D和判别器G的损失,这也是原始GAN论文的惯例。最后,我们将设置两个独立的优化器,一个用于生成器G,另一个判别器D。如DCGAN 论文所述,两个Adam优化器学习率都为0.0002,Beta1都为0.5。为了记录生成器的学习过程,我们将会生成一批符合高斯分布的固定的隐向量(即fixed_noise)。在训练过程中,我们将周期性地把固定噪声作为生成器G的输入,通过输出看到由噪声生成的图像。

# Initialize BCELoss Function
criterion = nn.BCELoss()fixed_noise = torch.randn(opt.batchSize, nz, 1, 1, device=device)  # torch.randn(*size):return a tensor containing a set of random numbers drawn from the standard Normal Distribution
real_label = 1
fake_label = 0# set up optimizer for both netG and netD
optimizerD = optim.Adam(netD.parameters(), lr=opt.lr, betas=(opt.beta1, 0.999))
optimizerG = optim.Adam(netG.parameters(), lr=opt.lr, betas=(opt.beta1, 0.999))

5.训练Training 

最后,我们已经定义了GAN网络的所有结构,可以开始训练它了。请注意,训练GAN有点像一种艺术形式,因为不正确的超参数会导致模式崩溃,却不会提示超参数错误的信息。接下来,我们将会“为真假数据构造不同的mini-batches数据”,同时调整判别器G的目标函数以最大化logD(G(z))。训练分为两个部分。第一部分更新判别器,第二部分更新生成器。

第一部分——训练判别器(Part 1 - Train the Discriminator)

回想一下,判别器的训练目的是最大化输入正确分类的概率。实际上,我们想要最大化log(D(x))+log(1−D(G(z)))。为了区别mini-batches,分两步计算。第一步,我们将会构造一个来自训练数据的真图片batch,作为判别器D的输入,计算其损失loss(log(D(x)),调用backward方法计算梯度。第二步,我们将会构造一个来自生成器G的假图片batch,作为判别器D的输入,计算其损失loss(log(1−D(G(z))),调用backward方法累计梯度。最后,调用判别器D优化器的step方法更新一次模型(即判别器D)的参数。

第二部分——训练生成器(Part 2 - Train the Generator) 

如原论文所述,我们希望通过最小化log(1−D(G(z)))训练生成器G来创造更好的假图片。作为解决方案,我们希望最大化log(D(G(z)))。通过以下方法来实现这一点:使用判别器D来分类在第一部分G的输出图片,计算损失函数的时候用真实标签(记做GT),调用backward方法更新生成器G的梯度,最后调用生成器G优化器的step方法更新一次模型(即生成器G)的参数。使用真实标签作为GT来计算损失函数看起来有悖常理,但是这允许我们可以使用BCELoss的log(x)部分而不是log(1−x)部分,这正是我们想要的。 

for epoch in range(opt.niter):  # For each epochfor i, data in enumerate(dataloader, 0):  # For each batch in the dataloader############################# (1) Update D network: maximize log(D(x)) + log(1 - D(G(z)))############################ train with all-real batchnetD.zero_grad()# format batchreal_cpu = data[0].to(device)  # data[a,b]:a means to take all the data in row a, b means take all data in column bbatch_size = real_cpu.size(0)label = torch.full((batch_size,), real_label,dtype=real_cpu.dtype, device=device)#############################output = netD(real_cpu)  # Forward,pass all-real batch through netDerrD_real = criterion(output, label)  # calculate loss on all-real batcherrD_real.backward()  # calculate gradient for netD in backward propagationD_x = output.mean().item()  # .item():return a float point data when output loss# train with fakenoise = torch.randn(batch_size, nz, 1, 1, device=device)  # generate batch of z-vectorsfake = netG(noise)  # generate fake image batch with netGlabel.fill_(fake_label)output = netD(fake.detach())  # Forward,pass all-fake image batch through netDerrD_fake = criterion(output, label)  # calculate loss on all-fake image batcherrD_fake.backward()  # calculate gradient for this batch(all-fake image)D_G_z1 = output.mean().item()errD = errD_real + errD_fake  # add the lossoptimizerD.step()  # update the netD model by update discriminator's optimizer's step() method############################# (2) Update G network: maximize log(D(G(z)))###########################netG.zero_grad()label.fill_(real_label)  # fill real_labeloutput = netD(fake)  # Forward,pass fake images through netDerrG = criterion(output, label)  # calculate the loss between output and real_lable,why?because we want use BECLOSS's logP_y parterrG.backward()D_G_z2 = output.mean().item()optimizerG.step()

参考:https://www.codetd.com/article/13228021

 

 

 

 


http://chatgpt.dhexx.cn/article/rSD83A34.shtml

相关文章

pytorch搭建DCGAN

我们知道gan的过程是对生成分布拟合真实分布的一个过程,理想目标是让判别器无法识别输入数据到底是来源于生成器生成的数据还是真实的数据。 当然这是一个博弈的过程并且相互促进的过程,其真实的过程在于首先判别器会先拟合真实数据的分布,然…

tensorflow实现DCGAN

1、DCGAN的简单总结 【Paper】 : http://arxiv.org/abs/1511.06434 【github】 : https://github.com/Newmu/dcgan_code theano https://github.com/carpedm20/DCGAN-tensorflow tensorflow https://github.com/jacobgil/keras-dcgan keras https://github.c…

DCGAN TUTORIAL

Introduction 本教程将通过一个示例对DCGAN进行介绍。在向其展示许多真实名人的照片之后,我们将训练一个生成对抗网络(GAN)来产生新名人。此处的大多数代码来自pytorch / examples中的dcgan实现 ,并且本文档将对该实现进行详尽的…

DCGAN原文讲解

DCGAN的全称是Deep Convolution Generative Adversarial Networks(深度卷积生成对抗网络)。是2014年Ian J.Goodfellow 的那篇开创性的GAN论文之后一个新的提出将GAN和卷积网络结合起来,以解决GAN训练不稳定的问题的一篇paper. 关于基本的GAN的原理,可以…

DCGAN

转自:https://blog.csdn.net/liuxiao214/article/details/74502975 首先是各种参考博客、链接等,表示感谢。 1、参考博客1:地址 ——以下,开始正文。 2017/12/12 更新 解决训练不收敛的问题。 更新在最后面部分。 1、DCGAN的…

深度学习之DCGAN

这一此的博客我给大家介绍一下DCGAN的原理以及DCGAN的实战代码,今天我用最简单的语言给大家介绍DCGAN。 相信大家现在对深度学习有了一定的了解,对GAN也有了认识,如果不知道什么是GAN的可以去看我以前的博客,接下来我给大家介绍一下DCGAN的原理。 DCGAN DCGAN的全称是Deep Conv…

对抗神经网络(二)——DCGAN

一、DCGAN介绍 DCGAN即使用卷积网络的对抗网络,其原理和GAN一样,只是把CNN卷积技术用于GAN模式的网络里,G(生成器)网在生成数据时,使用反卷积的重构技术来重构原始图片。D(判别器)网…

对抗生成网络GAN系列——DCGAN简介及人脸图像生成案例

🍊作者简介:秃头小苏,致力于用最通俗的语言描述问题 🍊往期回顾:对抗生成网络GAN系列——GAN原理及手写数字生成小案例 🍊近期目标:写好专栏的每一篇文章 🍊支持小苏:点赞…

DCGAN理论讲解及代码实现

目录 DCGAN理论讲解 DCGAN的改进: DCGAN的设计技巧 DCGAN纯代码实现 导入库 导入数据和归一化 定义生成器 定义鉴别器 初始化和 模型训练 运行结果 DCGAN理论讲解 DCGAN也叫深度卷积生成对抗网络,DCGAN就是将CNN与GAN结合在一起,生…

torch学习 (三十七):DCGAN详解

文章目录 引入1 生成器2 鉴别器3 模型训练:生成器与鉴别器的交互4 参数设置5 数据载入6 完整代码7 部分输出图像示意7.1 真实图像7.2 训练200个批次7.2 训练400个批次7.2 训练600个批次 引入 论文详解:Unsupervised representation learning with deep c…

GANs系列:DCGAN原理简介与基础GAN的区别对比

本文长期不定时更新最新知识,防止迷路记得收藏哦! 还未了解基础GAN的,可以先看下面两篇文章: GNA笔记--GAN生成式对抗网络原理以及数学表达式解剖 入门GAN实战---生成MNIST手写数据集代码实现pytorch 背景介绍 2016年&#…

Pix2Pix和CycleGAN

GAN的局限性 即便如此,传统的GAN也不是万能的,它有下面两个不足: 1. 没有**用户控制(user control)**能力 在传统的GAN里,输入一个随机噪声,就会输出一幅随机图像。 但用户是有想法滴&#xff…

PyTorch 实现Image to Image (pix2pix)

目录 一、前言 二、数据集 三、网络结构 四、代码 (一)net (二)dataset (三)train (四)test 五、结果 (一)128*128 (二)256*256 …

pix2pix、pix2pixHD 通过损失日志进行训练可视化

目录 背景 代码 结果 总结 背景 pix2pix(HD)代码在训练时会自动保存一个损失变化的txt文件,通过该文件能够对训练过程进行一个简单的可视化,代码如下。 训练的损失文件如图,对其进行可视化。 代码 #coding:utf-8 ## #author: QQ&#x…

Pix2Pix代码解析

参考链接:https://github.com/yenchenlin/pix2pix-tensorflow https://blog.csdn.net/stdcoutzyx/article/details/78820728 utils.py from __future__ import division import math import json import random import pprint import scipy.misc import numpy as…

pix2pix 与 pix2pixHD的大致分析

目录 pix2pix与pix2pixHD的生成器 判别器 PatchGAN(马尔科夫判别器) 1、pix2pix 简单粗暴的办法 如何解决模糊呢? 其他tricks 2、pix2pixHD 高分辨率图像生成 模型结构 Loss设计 使用Instance-map的图像进行训练 语义编辑 总结 …

Tensorflow2.0之Pix2pix

文章目录 Pix2pix介绍Pix2pix应用Pix2pix生成器及判别器网络结构代码实现1、导入需要的库2、下载数据包3、加载并展示数据包中的图片4、处理图片4.1 将图像调整为更大的高度和宽度4.2 随机裁剪到目标尺寸4.3 随机将图像做水平镜像处理4.4 图像归一化4.5 处理训练集图片4.6 处理…

pix2pix算法笔记

论文:Image-to-Image Translation with Conditional Adversarial Networks 论文链接:https://arxiv.org/abs/1611.07004 代码链接:https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix 这篇论文发表在CVPR2017,简称pix2pix,是将GAN应用于有监督的图像到图像翻译的经…

Pix2Pix原理解析以及代码流程

文章目录 1、网络搭建2、反向传播过程3、PatchGAN4.与CGAN的不同之处 1、网络搭建 class UnetGenerator(nn.Module):"""Create a Unet-based generator"""def __init__(self, input_nc, output_nc, num_downs, ngf64, norm_layernn.BatchNorm2d…

图像翻译网络模型Pix2Pix

Pix2pix算法(Image-to-Image Translation,图像翻译),它的核心技术有三点:基于条件GAN的损失函数,基于U-Net的生成器和基于PatchGAN的判别器。Pix2Pix能够在诸多图像翻译任务上取得令人惊艳的效果,但因为它的输入是图像对&#xff…