GAN,DCGAN

GAN

介绍

这个框架可以针对多种模型和优化算法提供特定的训练算法。在这篇文章中,我们探讨了生成模型通过将随机噪声传输到多层感知机来生成样本的特例,同时判别模型也是通过多层感知机实现的。我们称这个特例为对抗网络。在这种情况下,我们可以仅使用非常成熟的反向传播和丢弃算法训练两个模型,生成模型在生成样本时只使用前向传播算法。并且不需要近似推理和马尔可夫链作为前题。

相关工作

含隐变量的有向图模型可以由含隐变量的无向图模型替代,例如受限制波兹曼机(RBM),深度波兹曼机(DBM)和它们很多的变种。这些模型之间的相互影响可以被表达为非标准化的势函数的乘积,再通过随机变量的所有状态的全局整合来标准化。这个数量(配分函数)和它的梯度的估算是很棘手的,尽管他们能够依靠马尔可夫链和蒙特卡罗(MCMC)算法来估计,同时依靠MCMC算法的混合也会引发一个严重的问题。

深度信念网络(DBN)是一个包含一个无向层和若干有向层的混合模型。当使用一个快速逐层训练法则时,DBNS 会引发无向模型和有向模型相关的计算难题。

不是利用似然函数的估计或约数的选择准则已经被提出来了,例如分数匹配和噪音压缩评估(NCE)。他们都需要知道先验概率密度知识用来分析指定一个规范化的常量。请注意,许多有趣的带有一些隐层变量的生成模型(如DBN和DBM),它们甚至不需要一些难以处理的非标准化的概率密度先验知识。一些模型如自动编码降噪机和压缩编码的学习准则与分数匹配在RBM上的应用非常相似。在NCE中,使用一个判别训练准则来拟合一个生成模型。然而,生成模型常常被用来判别从一个固定噪音分布中抽样生成的数据,而不是拟合一个独立的判别模型。由于NCE使用一个固定的噪音分布,仅仅是从观测变量的一个小子集中学习到一个大致正确的分布后,模型的学习便急剧减慢。

最后,一些技术并没有用来明确定义概率分布,而是用来训练一个生成器来从期望的分布中拟合出样本。这个方法优势在于这些机器学习算法能够设计使用反向传播算法训练。这个领域最近比较突出的工作包含生成随机网络(GSN),它扩展了广义的除噪自动编码器:两者都可以看作是定义了一个参数化的马尔可夫链,即一个通过执行生成马尔科夫链的一个步骤来学习机器参数的算法。同GSNs相比,对抗网络不需要使用马尔可夫链来采样。由于对抗网络在生成阶段不需要循环反馈信息,它们能够更好的利用分段线性单元,这可以提高反向传播的效率。大部分利用反向传播算法来训练生成器的例子包括贝叶斯变分自动编码和随机反向传播。

GAN细节介绍

GAN是由两部分主成:生成模型G(generative model)和判别模型D(discriminative model)。生成模型捕捉样本数据的分布,判别模型是一个二分类器,判别输入是真实数据还是生成的样本。

GAN,DCGAN_第1张图片

X是真实数据,真实数据符合Pdata(x)分布。z是噪声数据,噪声数据符合Pz(z)分布,比如高斯分布或者均匀分布。然后从噪声z进行抽样,通过G之后生成数据x=G(z)。然后真实数据与生成数据一起送入分类器D,后面接一个sigmoid函数,输出判定类别。

 

GAN,DCGAN_第2张图片

这里,z是噪声数据,从z中采样作为x,形成绿色的高耸的部分,原始数据Xdata是不变的。蓝色虚线是分类器(sigmoid),黑色虚线是原始数据,绿色实线是生成数据。最初的时候D可以很好的区分开真实数据和生成数据,看图(b),对于蓝色虚线而言,单纯的绿色部分可以很明确的划分为0,黑色虚线的部分可以很明确的划分成1,二者相交的部分划分不是很明确。看图(c)绿色实现生成数据更新,与原始数据相似度增加。最后一张图,经过多次更新与对抗生成之后,生成数据已经和原始数据非常相像的了,这时分类器已经无法判断到底是输出1还是0,于是就变成了0.5一条水平线。

GAN,DCGAN_第3张图片

这张图形象的说明了一下G和D的优化方向。优化D的时候需要很好的画出黑色虚线,使它能够区分开真实数据和生成数据。优化G的时候,生成数据更加接近原始数据的样子,使得D难以区分数据真假。如此反复直到最后再也画不出区分的黑色虚线。

 

主要特点和应用场景

(1)GAN可以用来产生data。

(2)根据GAN的组成结构我们可以知道,GAN 整个的过程就是,G产生一个自创的假数据和真数据放在一起让D来区分,在这种不停的较量中G就模拟出来了跟真实数据十分相近的数据。所以GAN主要的应用场景就是能够学习出这样模拟分布的数据,并且可以用模拟分布代替原始数据的地方!

重要公式

GAN,DCGAN_第4张图片

GAN优化目标函数:

GAN,DCGAN_第5张图片

D想办法增加V的值,G想办法减小V的值,两人在相互的对抗。

下面讲这个式子的数学意义。

首先固定G训练D :

1)训练D的目的是希望这个式子的值越大越好。真实数据希望被D分成1,生成数据希望被分成0。

第一项,如果有一个真实数据被分错,那么log(D(x))<<0,期望会变成负无穷大。

第二项,如果被分错成1的话,第二项也会是负无穷大。

很多被分错的话,就会出现很多负无穷,那样可以优化的空间还有很多。可以修正参数,使V的数值增大。

2)训练G ,它是希望V的值越小越好,让D分不开真假数据。

因为目标函数的第一项不包含G,是常数,所以可以直接忽略 不受影响。

对于G来说 它希望D在划分他的时候能够越大越好,他希望被D划分1(真实数据)。

GAN的优势和缺陷


优势

  1. 根据实际的结果,它们看上去可以比其它模型产生了更好的样本(图像更锐利、清晰)。
  2. 生成对抗式网络框架能训练任何一种生成器网络(理论上-实践中,用 REINFORCE 来训练带有离散输出的生成网络非常困难)。大部分其他的框架需要该生成器网络有一些特定的函数形式,比如输出层是高斯的。重要的是所有其他的框架需要生成器网络遍布非零质量(non-zero mass)。生成对抗式网络能学习可以仅在与数据接近的细流形(thin manifold)上生成点。
  3. 不需要设计遵循任何种类的因式分解的模型,任何生成器网络和任何鉴别器都会有用。
  4. 无需利用马尔科夫链反复采样,无需在学习过程中进行推断(Inference),回避了近似计算棘手的概率的难题。

与其他生成式模型相比较,生成式对抗网络有以下四个优势:

  1. 与PixelRNN相比,生成一个样本的运行时间更小。GAN 每次能产生一个样本,而 PixelRNN 需要一次产生一个像素来生成样本。 
  2. 与VAE 相比,它没有变化的下限。如果鉴别器网络能完美适合,那么这个生成器网络会完美地恢复训练分布。换句话说,各种对抗式生成网络会渐进一致(asymptotically consistent),而 VAE 有一定偏置。 
  3. 与深度玻尔兹曼机相比,既没有一个变化的下限,也没有棘手的分区函数。它的样本可以一次性生成,而不是通过反复应用马尔可夫链运算器(Markov chain operator)。 
  4. 与 GSN 相比,它的样本可以一次生成,而不是通过反复应用马尔可夫链运算器。 
  5. 与NICE 和 Real NVE 相比,在 latent code 的大小上没有限制。

 
缺陷或存在的问题

①解决不收敛(non-convergence)的问题。 
目前面临的基本问题是:所有的理论都认为 GAN 应该在纳什均衡(Nash equilibrium)上有卓越的表现,但梯度下降只有在凸函数的情况下才能保证实现纳什均衡。当博弈双方都由神经网络表示时,在没有实际达到均衡的情况下,让它们永远保持对自己策略的调整是可能的。

②难以训练:崩溃问题(collapse problem) 
GAN模型被定义为极小极大问题,没有损失函数,在训练过程中很难区分是否正在取得进展。GAN的学习过程可能发生崩溃问题(collapse problem),生成器开始退化,总是生成同样的样本点,无法继续学习。当生成模型崩溃时,判别模型也会对相似的样本点指向相似的方向,训练无法继续。当然Goodfellow在【Improved Techniques for Training GANs】文章中也有一些相应的改进方法例如:特征映射等。


③无需预先建模,模型过于自由不可控。 
与其他生成式模型相比,GAN这种竞争的方式不再要求一个假设的数据分布,即不需要formulate p(x),而是使用一种分布直接进行采样sampling,从而真正达到理论上可以完全逼近真实数据,这也是GAN最大的优势。然而,这种不需要预先建模的方法缺点是太过自由了,对于较大的图片,较多的 pixel的情形,基于简单 GAN 的方式就不太可控了(超高维)。在GAN[Goodfellow Ian, Pouget-Abadie J] 中,每次学习参数的更新过程,被设为D更新k回,G才更新1回,也是出于类似的考虑。

import matplotlib.pyplot as plt
from torch.utils.data import DataLoader
from torch import nn
import numpy as np
from torch.autograd import Variable
import torch

batch_size=8
data_iter=DataLoader(data,batch_size=batch_size)
#定义生成器
class net_G(nn.Module):
    def __init__(self):
        super(net_G,self).__init__()
        self.model=nn.Sequential(
            nn.Linear(2,2),
        )
        self._initialize_weights()
    def forward(self,x):
        x=self.model(x)
        return x
    def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m,nn.Linear):
                m.weight.data.normal_(0,0.02)
                m.bias.data.zero_()
#定义识别器
class net_D(nn.Module):
    def __init__(self):
        super(net_D,self).__init__()
        self.model=nn.Sequential(
            nn.Linear(2,5),
            nn.Tanh(),
            nn.Linear(5,3),
            nn.Tanh(),
            nn.Linear(3,1),
            nn.Sigmoid()
        )
        self._initialize_weights()
    def forward(self,x):
        x=self.model(x)
        return x
    def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m,nn.Linear):
                m.weight.data.normal_(0,0.02)
                m.bias.data.zero_()
#训练
# Saved in the d2l package for later use
def update_D(X,Z,net_D,net_G,loss,trainer_D):
    batch_size=X.shape[0]
    Tensor=torch.FloatTensor
    ones=Variable(Tensor(np.ones(batch_size))).view(batch_size,1)
    zeros = Variable(Tensor(np.zeros(batch_size))).view(batch_size,1)
    real_Y=net_D(X.float())
    fake_X=net_G(Z)
    fake_Y=net_D(fake_X)
    loss_D=(loss(real_Y,ones)+loss(fake_Y,zeros))/2
    loss_D.backward()
    trainer_D.step()
    return float(loss_D.sum())
# Saved in the d2l package for later use
def update_G(Z,net_D,net_G,loss,trainer_G):
    batch_size=Z.shape[0]
    Tensor=torch.FloatTensor
    ones=Variable(Tensor(np.ones((batch_size,)))).view(batch_size,1)
    fake_X=net_G(Z)
    fake_Y=net_D(fake_X)
    loss_G=loss(fake_Y,ones)
    loss_G.backward()
    trainer_G.step()
    return float(loss_G.sum())
def train(net_D,net_G,data_iter,num_epochs,lr_D,lr_G,latent_dim,data):
    loss=nn.BCELoss()
    Tensor=torch.FloatTensor
    trainer_D=torch.optim.Adam(net_D.parameters(),lr=lr_D)
    trainer_G=torch.optim.Adam(net_G.parameters(),lr=lr_G)
    plt.figure(figsize=(7,4))
    d_loss_point=[]
    g_loss_point=[]
    d_loss=0
    g_loss=0
    for epoch in range(1,num_epochs+1):
        d_loss_sum=0
        g_loss_sum=0
        batch=0
        for X in data_iter:
            batch+=1
            X=Variable(X)
            batch_size=X.shape[0]
            Z=Variable(Tensor(np.random.normal(0,1,(batch_size,latent_dim))))
            trainer_D.zero_grad()
            d_loss = update_D(X, Z, net_D, net_G, loss, trainer_D)
            d_loss_sum+=d_loss
            trainer_G.zero_grad()
            g_loss = update_G(Z, net_D, net_G, loss, trainer_G)
            g_loss_sum+=g_loss
        d_loss_point.append(d_loss_sum/batch)
        g_loss_point.append(g_loss_sum/batch)
    plt.ylabel('Loss', fontdict={'size': 14})
    plt.xlabel('epoch', fontdict={'size': 14})
    plt.xticks(range(0,num_epochs+1,3))
    plt.plot(range(1,num_epochs+1),d_loss_point,color='orange',label='discriminator')
    plt.plot(range(1,num_epochs+1),g_loss_point,color='blue',label='generator')
    plt.legend()
    plt.show()
    print(d_loss,g_loss)
    
    Z =Variable(Tensor( np.random.normal(0, 1, size=(100, latent_dim))))
    fake_X=net_G(Z).detach().numpy()
    plt.figure(figsize=(3.5,2.5))
    plt.scatter(data[:,0],data[:,1],color='blue',label='real')
    plt.scatter(fake_X[:,0],fake_X[:,1],color='orange',label='generated')
    plt.legend()
    plt.show()
if __name__ == '__main__':
    lr_D,lr_G,latent_dim,num_epochs=0.05,0.005,2,20
    generator=net_G()
    discriminator=net_D()
    train(discriminator,generator,data_iter,num_epochs,lr_D,lr_G,latent_dim,data)

参考:https://zhuanlan.zhihu.com/p/28853704

DCGAN

我们提出,要建立图像的良好特征,训练GAN是一种方法,之后,我们会把判别器和生成器都作为可再用的特征提取器,用到监督学习的任务中。GAN实际上为最大似然估计的相关技术提供了一种颇具吸引力的替代方案。更进一步,GAN的学习过程,和对启发式损失函数要求不高,这两点对表征学习具有吸引力。GAN出了名的训练不稳定,这经常导致生成器会产出很多荒谬的结果。对于GAN中到底学习到了什么样的中间表征,在当前出版的研究里也并不多见。

In this paper, we make the following contributions:

在这篇文章里,我们做出如下贡献:

  • 我们提出并评价了这样一件事情:什么样的GAN体系拓扑能让训练更加稳定。 我们将这一类架构称作是DCGAN

  • 我们使用图像分类任务上训练出来的判别器和其他的非监督算法做了比较。

  • 我们对GAN学习到的特征做出了可视化,并经验性的证明了特殊的特征表征了特殊的对象。

  • 针对生成器,我们提出了一个很有趣的算法向量,这个向量能很简单的在语义层面上操作生成样例的质量。

对图像上下文的表征:一个经典的非监督表征学习手段是做出数据聚类(例如使用k-means),之后利用聚类结果来改善分类结果。在图像这一类场景下,可以对图像进行批处理,利用多个图像的聚类来学习到更有效的图像表征,另一个很流行的理论是训练自编码器(卷积式的自编码器),主流存在两种方式:一种是分离编码中向量的意义和位置,另一种是分析编码的梯度结构,这两种方式都能将图像作成紧编码,并且尽可能的通过解码器还原图像。这些方法已经被证明能很好的通过图像像素来学习表征。深度置信网络同样也能学习到表征的连续表达。

 生成自然图像

图像的生成模型划分为两个领域:参数化领域和非参数化领域 。非参数领域通常是在图像数据库下做匹配,经常对成批的图像做匹配,它在纹理合成,超分辨率重建和in-paiting中用的较多。参数模型已经被广泛研究过(例如,MNIST中手写数字的纹理合成)。尽管生成真实世界的自然图像这一点在当前并没有很大成功。尽管其中的一些变种已经取得了一定成功,但是这种采样通常十分模糊。其他的,页游诸如面向扩散过程的生成方法。GAN在图像生成方面,具有不可思议的抗噪特性。这种方法中,一种添加拉普拉斯金字塔的方法展示出了较高质量的图像,但是由于在链式乘法模型中引入了噪声,导致生成的对象看上去是摇摆的。循环网络和反卷积网络似乎在自然图像的生成上取得了一定成功,但它们并没有应用到监督任务上。

方法和模型架构 

对现行CNN架构三个改进的学习和纠正。

  1. 所有的卷积网络,凡是自卷积开始,使用了确定性池化函数的,都能学习到自己空间上的降采样。我们在生成器中使用了这种方法,允许生成器学习到它自己的空间降采样,也包括判别器。 
  2. 消除卷积特征顶部的全连接层已经成为一种趋势。最有力的证据是在顶级表现的分类模型中使用了全局平均池化(global average pooling).我们发现,全局平均池化增强了模型稳定性,但减缓了收敛速度。一个折中的方法,是把最高层的卷积特征和输入连接起来,生成器和判别其各自做自己的输出,实测效果不错。GAN的第一层,输入了一个均匀分布的噪声Z,仅仅只是一个矩阵乘法,可以视作一个全连接层,但是结果被转化为一个4维张量并被用作卷积栈的开始。对于判别器而言,最后一层被平展开,然后输入了一个sigmoid函数,图1中对这种模型架构做了一个可视化。
  3. 第三个是BN,这种方法将每一层的输入都正则化为期望0方差1。它改进了训练问题,也缓解了深层网络中的梯度溢出问题。但实际上,这种方法在深层的生成器中被证明是不适用的,它会导致生成器反复震荡生成单点数据,这在GANs中往往是失败的。对于直接将BN使用在所有层上的方法,同样会引起震荡并导致模型不稳定,所以,不要再生成器的输入层上使用BN,也不要在判别器的输出层上使用BN。

 在生成器中,使用Relu来做激活函数,并在输出层上使用Tanh。我们发现,使用有界的函数更有助于模型迅速在训练分布中覆盖颜色空间。在判别器中,尤其是对高分辨率模型的时候,我们发现Weak Relu更好用。 这是与原始GAN论文的对比,在那篇论文中,它使用Maxout来激活。

稳定DCGAN的架构指导: 

  • 判别器中,使用带步长的卷基层来替换所有pooling层,生成器中使用小步长卷积来代替pooling层。 
  • 在生成器和判别器中使用BN。 
  • 去除深度架构中的全连接隐藏层。 
  • 生成器中,除去最后一层使用Tanh之外,每一层都使用ReLU来激活。 
  • 判别器中,每一层都使用LeakReLU来激活。

对抗式训练的细节

所有的图像,都缩放到Tanh激活函数的定义域[-1,1]之内,除此之外没有做任何预处理。所有的模型都使用小批量SGD,一批是128张图。所有的权重都使用正态分布初始化,期望为1,方差为0.02。在LeakReLU中,负向权重全部设置为0.1。有鉴于之前的GAN中使用了动量,我们使用Adam来优化超参数。学习率中发现0.001太大了,使用0.0002。此外,我们发现动量参数β1=0.9β1=0.9的时候,训练波动大也不稳定,所以设置为0.5使训练稳定。

GAN,DCGAN_第6张图片

图1:用于LSUN场景的DCGAN的生成器。一个100维,服从均匀分布的噪声Z在一个小范围卷积表征空间中投影为许多特征映射,接着连续4个小步长卷积,将这个噪声作成一个64*64的像素图像,毫无疑问,没有全连接层或者pooling层。

通过训练我们得到如下结论:

  1. 生成模型中采样的视觉质量改善了对过拟合的关注和对训练样本的记忆。生成表现和模型的学习速度之间有显著关系。就像在线学习那样,在收敛之后又继续添加了样例。我们的模型并不是因为过拟合或者记住了训练样本才表现好的。图像中的数据量并没有任何增加。 
  2. 多个样本上的噪声导致欠拟合。
  3. 模型是可以记住训练样本的,但是在小学习率和小批量SGD下这并不是一个经验事实,SGD和小学习率下并没有先验的经验证据。

GAN,DCGAN_第7张图片

Summary

  • DCGAN architecture has four convolutional layers for the Discriminator and four "fractionally-strided" convolutional layers for the Generator.
  • The Discriminator is a 4-layer strided convolutions with batch normalization (except its input layer) and leaky ReLU activations.
  • Leaky ReLU is a nonlinear function that give a non-zero output for a negative input. It aims to fix the “dying ReLU” problem and helps the gradients flow easier through the architecture.
import matplotlib.pyplot as plt
from torch.utils.data import DataLoader
from torch import nn
import numpy as np
from torch.autograd import Variable
import torch
from torchvision.datasets import ImageFolder
from torchvision.transforms import transforms
import zipfile
cuda = True if torch.cuda.is_available() else False
print(cuda)
#数据预处理
data_dir='/home/kesci/input/pokemon8600/'
batch_size=256
transform=transforms.Compose([
    transforms.Resize((64,64)),
    transforms.ToTensor(),
    transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))
])
pokemon=ImageFolder(data_dir+'pokemon',transform)
data_iter=DataLoader(pokemon,batch_size=batch_size,shuffle=True)
#定义生成器
class G_block(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size=4,strides=2, padding=1):
        super(G_block,self).__init__()
        self.conv2d_trans=nn.ConvTranspose2d(in_channels, out_channels, kernel_size=kernel_size,
                                             stride=strides, padding=padding, bias=False)
        self.batch_norm=nn.BatchNorm2d(out_channels,0.8)
        self.activation=nn.ReLU()
    def forward(self,x):
        return self.activation(self.batch_norm(self.conv2d_trans(x)))
Tensor=torch.cuda.FloatTensor
x=Variable(Tensor(np.zeros((2,3,16,16))))
g_blk=G_block(3,20)
g_blk.cuda()
print(g_blk(x).shape)
class net_G(nn.Module):
    def __init__(self,in_channels):
        super(net_G,self).__init__()

        n_G=64
        self.model=nn.Sequential(
            G_block(in_channels,n_G*8,strides=1,padding=0),
            G_block(n_G*8,n_G*4),
            G_block(n_G*4,n_G*2),
            G_block(n_G*2,n_G),
            nn.ConvTranspose2d(
                n_G,3,kernel_size=4,stride=2,padding=1,bias=False
            ),
            nn.Tanh()
        )
    def forward(self,x):
        x=self.model(x)
        return x

def weights_init_normal(m):
    classname = m.__class__.__name__
    if classname.find("Conv") != -1:
        torch.nn.init.normal_(m.weight.data, mean=0, std=0.02)
    elif classname.find("BatchNorm2d") != -1:
        torch.nn.init.normal_(m.weight.data, mean=1.0, std=0.02)
        torch.nn.init.constant_(m.bias.data, 0.0)
#定义识别器
class D_block(nn.Module):
    def __init__(self,in_channels,out_channels,kernel_size=4,strides=2,
                 padding=1,alpha=0.2):
        super(D_block,self).__init__()
        self.conv2d=nn.Conv2d(in_channels,out_channels,kernel_size,strides,padding,bias=False)
        self.batch_norm=nn.BatchNorm2d(out_channels,0.8)
        self.activation=nn.LeakyReLU(alpha)
    def forward(self,X):
        return self.activation(self.batch_norm(self.conv2d(X)))
class net_D(nn.Module):
    def __init__(self,in_channels):
        super(net_D,self).__init__()
        n_D=64
        self.model=nn.Sequential(
            D_block(in_channels,n_D),
            D_block(n_D,n_D*2),
            D_block(n_D*2,n_D*4),
            D_block(n_D*4,n_D*8)
        )
        self.conv=nn.Conv2d(n_D*8,1,kernel_size=4,bias=False)
        self.activation=nn.Sigmoid()
        # self._initialize_weights()
    def forward(self,x):
        x=self.model(x)
        x=self.conv(x)
        x=self.activation(x)
        return x
#训练
def update_D(X,Z,net_D,net_G,loss,trainer_D):
    batch_size=X.shape[0]
    Tensor=torch.cuda.FloatTensor
    ones=Variable(Tensor(np.ones(batch_size,)),requires_grad=False).view(batch_size,1)
    zeros = Variable(Tensor(np.zeros(batch_size,)),requires_grad=False).view(batch_size,1)
    real_Y=net_D(X).view(batch_size,-1)
    fake_X=net_G(Z)
    fake_Y=net_D(fake_X).view(batch_size,-1)
    loss_D=(loss(real_Y,ones)+loss(fake_Y,zeros))/2
    loss_D.backward()
    trainer_D.step()
    return float(loss_D.sum())

def update_G(Z,net_D,net_G,loss,trainer_G):
    batch_size=Z.shape[0]
    Tensor=torch.cuda.FloatTensor
    ones=Variable(Tensor(np.ones((batch_size,))),requires_grad=False).view(batch_size,1)
    fake_X=net_G(Z)
    fake_Y=net_D(fake_X).view(batch_size,-1)
    loss_G=loss(fake_Y,ones)
    loss_G.backward()
    trainer_G.step()
    return float(loss_G.sum())


def train(net_D,net_G,data_iter,num_epochs,lr,latent_dim):
    loss=nn.BCELoss()
    Tensor=torch.cuda.FloatTensor
    trainer_D=torch.optim.Adam(net_D.parameters(),lr=lr,betas=(0.5,0.999))
    trainer_G=torch.optim.Adam(net_G.parameters(),lr=lr,betas=(0.5,0.999))
    plt.figure(figsize=(7,4))
    d_loss_point=[]
    g_loss_point=[]
    d_loss=0
    g_loss=0
    for epoch in range(1,num_epochs+1):
        d_loss_sum=0
        g_loss_sum=0
        batch=0
        for X in data_iter:
            X=X[:][0]
            batch+=1
            X=Variable(X.type(Tensor))
            batch_size=X.shape[0]
            Z=Variable(Tensor(np.random.normal(0,1,(batch_size,latent_dim,1,1))))

            trainer_D.zero_grad()
            d_loss = update_D(X, Z, net_D, net_G, loss, trainer_D)
            d_loss_sum+=d_loss
            trainer_G.zero_grad()
            g_loss = update_G(Z, net_D, net_G, loss, trainer_G)
            g_loss_sum+=g_loss

        d_loss_point.append(d_loss_sum/batch)
        g_loss_point.append(g_loss_sum/batch)
        print(
            "[Epoch %d/%d]  [D loss: %f] [G loss: %f]"
            % (epoch, num_epochs,  d_loss_sum/batch_size,  g_loss_sum/batch_size)
        )


    plt.ylabel('Loss', fontdict={ 'size': 14})
    plt.xlabel('epoch', fontdict={ 'size': 14})
    plt.xticks(range(0,num_epochs+1,3))
    plt.plot(range(1,num_epochs+1),d_loss_point,color='orange',label='discriminator')
    plt.plot(range(1,num_epochs+1),g_loss_point,color='blue',label='generator')
    plt.legend()
    plt.show()
    print(d_loss,g_loss)

    Z = Variable(Tensor(np.random.normal(0, 1, size=(21, latent_dim, 1, 1))),requires_grad=False)
    fake_x = generator(Z)
    fake_x=fake_x.cpu().detach().numpy()
    plt.figure(figsize=(14,6))
    for i in range(21):
        im=np.transpose(fake_x[i])
        plt.subplot(3,7,i+1)
        plt.imshow(im)
    plt.show()
if __name__ == '__main__':
    lr,latent_dim,num_epochs=0.005,100,50
    train(discriminator,generator,data_iter,num_epochs,lr,latent_dim)

参考:https://blog.csdn.net/xiening0618/article/details/79417734 

你可能感兴趣的:(GAN,DCGAN)