Mindspore体验dcgan生成漫画头像

第一章 MindSpore框架的体验与部署

第二章Mindspore体验dcgan生成漫画头像

目录

前言

一、官方文档

二、使用体验

1.下载notebook并打开

GAN基础原理

DCGAN原理

2.实现生成式对抗网络的构建与实践

数据处理

创建网络

生成器

判别器

损失和优化器

损失函数

优化器

训练模型

结果展示

总结



前言

在第一篇中我们实现了昇思平台的安装与初体验,这一次我们可以进行对它深入的了解与尝试。想要了解安装部署的同学请去看我的第一篇哈。


一、官方文档

根据mindspore的官方文档,我们可以实现一个基于dcgan的漫画头像生成系统。

二、使用体验

1.下载notebook并打开

在昇思官网可以下载notebook源码。这里,笔者使用的是Windows系统的anaconda环境的jupyter notebook环境。读者可以根据自己的机器环境进行配置。

GAN基础原理

生成式对抗网络(Generative Adversarial Networks,GAN)是一种深度学习模型,是近年来复杂分布上无监督学习最具前景的方法之一。

最初,GAN由Ian J. Goodfellow于2014年发明,并在论文Generative Adversarial Nets中首次进行了描述,GAN由两个不同的模型组成——生成器判别器

  • 生成器的任务是生成看起来像训练图像的“假”图像;
  • 判别器需要判断从生成器输出的图像是真实的训练图像还是虚假的图像。

在训练过程中,生成器会不断尝试通过生成更好的假图像来骗过判别器,而判别器在这过程中也会逐步提升判别能力。这种博弈的平衡点是,当生成器生成的假图像和训练数据图像的分布完全一致时,判别器拥有50%的真假判断置信度。下面,我们首先定义一些在整个过程中需要用到的符号:

判别器的表示

  • 𝑥x:代表图像数据;
  • 𝐷(𝑥)D(x):判别器网络,给出图像判定为真实图像的概率;

在判别过程中,𝐷(𝑥)D(x)需要处理CHW格式且大小为3x64x64的图像数据。当𝑥x来自训练数据时,𝐷(𝑥)D(x)数值应该趋近于1,而当𝑥x来自生成器时,𝐷(𝑥)D(x)数值应该趋近于0。因此𝐷(𝑥)D(x)也可以被认为是传统的二分类器。

生成器的表示

  • 𝑧z:标准正态分布中提取出的隐向量;
  • 𝐺(𝑧)G(z):表示将隐向量𝑧z映射到数据空间的生成器函数;

函数𝐺(𝑧)G(z)的目标是将一个随机高斯噪声𝑧z通过一个生成网络生成一个和真实数据分布𝑝𝑑𝑎𝑡𝑎(𝑥)pdata(x)差不多的数据分布,其中θθ是网络参数,我们希望找到θθ使得𝑝𝐺(𝑥;θ)pG(x;θ)和𝑝𝑑𝑎𝑡𝑎(𝑥)pdata(x)尽可能的接近。

𝐷(𝐺(𝑧))D(G(z))是生成器𝐺G生成的假图像被判定为真实图像的概率,如Goodfellow 的论文中所述,DG在进行一场博弈,D想要最大程度的正确分类真图像与假图像,也就是参数𝑙𝑜𝑔𝐷(𝑥)logD(x);而G试图欺骗D来最小化假图像被识别到的概率,也就是参数𝑙𝑜𝑔(1−𝐷(𝐺(𝑧)))log(1−D(G(z)))。GAN的损失函数为:

min𝐺max𝐷𝑉(𝐷,𝐺)=𝐸𝑥∼𝑃𝑑𝑎𝑡𝑎(𝑥)[𝑙𝑜𝑔(𝐷(𝑥))]+𝐸𝑧∼𝑃𝑧(𝑧)[𝑙𝑜𝑔(1−𝐷(𝐺(𝑧)))]minGmaxDV(D,G)=Ex∼Pdata(x)[log(D(x))]+Ez∼Pz(z)[log(1−D(G(z)))]

从理论上讲,此博弈游戏的平衡点是𝑝𝐺(𝑥;θ)=𝑝𝑑𝑎𝑡𝑎(𝑥)pG(x;θ)=pdata(x),此时判别器会随机猜测输入是真图像还是假图像。下面我们简要说明生成器和判别器的博弈过程:

在上图中,蓝色虚线表示判别器,黑色虚线表示真实数据分布,绿色实线表示生成器生成的虚假数据分布,z表示隐向量,x表示生成的虚假图像G(z)。

  1. 在训练刚开始的时候,生成器和判别器的质量都比较差,生成器会随机生成一个数据分布。
  2. 判别器通过求取梯度和损失函数对网络进行优化,将靠近真实数据分布的数据判定为1,将靠近生成器生成出来数据分布的数据判定为0。
  3. 生成器通过优化,生成出更加贴近真实数据分布的数据。
  4. 生成器所生成的数据和真实数据达到相同的分布,此时判别器的输出为1/2。

DCGAN原理

DCGAN(深度卷积对抗生成网络,Deep Convolutional Generative Adversarial Networks)是GAN的直接扩展。不同之处在于,DCGAN会分别在判别器和生成器中使用卷积和转置卷积层。

它最早由Radford等人在论文Unsupervised Representation Learning With Deep Convolutional Generative Adversarial Networks中进行描述。判别器由分层的卷积层、BatchNorm层和LeakyReLU激活层组成。输入是3x64x64的图像,输出是该图像为真图像的概率。生成器则是由转置卷积层、BatchNorm层和ReLU激活层组成。输入是标准正态分布中提取出的隐向量𝑧z,输出是3x64x64的RGB图像。

2.实现生成式对抗网络的构建与实践

运行第一个模块,发现我们缺少mindvision库。

使用pip下载安装

先进入对应的虚拟python环境。

直接输入 pip install mindvision

成功安装

接下来的配置文档,我们根据我们的机器环境进行配置。

 安装完成后打开notebook

 简单运行官方的代码样例

import mindspore
from mindspore import nn
from mindspore import ops
from mindspore.dataset import vision, transforms
from mindspore.dataset import MnistDataset

导入成功 

继续运行,下载数据集。

from mindvision import dataset

dl_path = "./datasets"
dl_url = "https://download.mindspore.cn/dataset/Faces/faces.zip"

dl = dataset.DownLoad()  # 下载数据集
dl.download_and_extract_archive(url=dl_url, download_path=dl_path)

数据处理

首先为执行过程定义一些输入: 

import mindspore as ms
​
# 选择执行模式为图模式;指定训练使用的平台为"GPU",如需使用昇腾硬件可将其替换为"Ascend"
ms.set_context(mode=ms.GRAPH_MODE, device_target="CPU")
​
data_root = "./datasets"  # 数据集根目录
batch_size = 128          # 批量大小
image_size = 64           # 训练图像空间大小
nc = 3                    # 图像彩色通道数
nz = 100                  # 隐向量的长度
ngf = 64                  # 特征图在生成器中的大小
ndf = 64                  # 特征图在判别器中的大小
num_epochs = 10           # 训练周期数
lr = 0.0002               # 学习率
beta1 = 0.5               # Adam优化器的beta1超参数

定义create_dataset_imagenet函数对数据进行处理和增强操作。

import numpy as np
import mindspore.dataset as ds
import mindspore.dataset.vision as vision
​
from mindspore import nn, ops
​
def create_dataset_imagenet(dataset_path):
    """数据加载"""
    data_set = ds.ImageFolderDataset(dataset_path,
                                     num_parallel_workers=4,
                                     shuffle=True,
                                     decode=True)
​
    # 数据增强操作
    transform_img = [
        vision.Resize(image_size),
        vision.CenterCrop(image_size),
        vision.HWC2CHW(),
        lambda x: ((x / 255).astype("float32"), np.random.normal(size=(nz, 1, 1)).astype("float32"))]
​
    # 数据映射操作
    data_set = data_set.map(input_columns="image",
                            num_parallel_workers=4,
                            operations=transform_img,
                            output_columns=["image", "latent_code"],
                            column_order=["image", "latent_code"])
​
    # 批量操作
    data_set = data_set.batch(batch_size)
    return data_set
​
# 获取处理后的数据集
data = create_dataset_imagenet(data_root)
​
# 获取数据集大小
size = data.get_dataset_size()

[WARNING] ME(7140:14104,MainProcess):2022-11-26-00:35:05.353.374 [mindspore\dataset\engine\datasets.py:913] The parameter column_order will be deprecated in the future. Please use '.project' operation instead.

通过create_dict_iterator函数将数据转换成字典迭代器,然后使用matplotlib模块可视化部分训练数据。



import matplotlib.pyplot as plt
%matplotlib inline
​
data_iter = next(data.create_dict_iterator(output_numpy=True))
​
# 可视化部分训练数据
plt.figure(figsize=(10, 3), dpi=140)
for i, image in enumerate(data_iter['image'][:30], 1):
    plt.subplot(3, 10, i)
    plt.axis("off")
    plt.imshow(image.transpose(1, 2, 0))
plt.show()

创建网络

当处理完数据后,就可以来进行网络的搭建了。按照DCGAN论文中的描述,所有模型权重均应从mean为0,sigma为0.02的正态分布中随机初始化。

生成器

生成器G的功能是将隐向量z映射到数据空间。由于数据是图像,这一过程也会创建与真实图像大小相同的 RGB 图像。在实践场景中,该功能是通过一系列Conv2dTranspose转置卷积层来完成的,每个层都与BatchNorm2d层和ReLu激活层配对,输出数据会经过tanh函数,使其返回[-1,1]的数据范围内。

DCGAN论文生成图像如下所示:

图片来源:Unsupervised Representation Learning With Deep Convolutional Generative Adversarial Networks.

我们通过输入部分中设置的nzngfnc来影响代码中的生成器结构。nz是隐向量z的长度,ngf与通过生成器传播的特征图的大小有关,nc是输出图像中的通道数。

以下是生成器的代码实现:



from mindspore.common import initializer as init
​
def conv_t(in_channels, out_channels, kernel_size, stride=1, padding=0, pad_mode="pad"):
    """定义转置卷积层"""
    weight_init = init.Normal(mean=0, sigma=0.02)
    return nn.Conv2dTranspose(in_channels, out_channels,
                              kernel_size=kernel_size, stride=stride, padding=padding,
                              weight_init=weight_init, has_bias=False, pad_mode=pad_mode)
​
def bn(num_features):
    """定义BatchNorm2d层"""
    gamma_init = init.Normal(mean=1, sigma=0.02)
    return nn.BatchNorm2d(num_features=num_features, gamma_init=gamma_init)
​
class Generator(nn.Cell):
    """DCGAN网络生成器"""
​
    def __init__(self):
        super(Generator, self).__init__()
        self.generator = nn.SequentialCell()
        self.generator.append(conv_t(nz, ngf * 8, 4, 1, 0))
        self.generator.append(bn(ngf * 8))
        self.generator.append(nn.ReLU())
        self.generator.append(conv_t(ngf * 8, ngf * 4, 4, 2, 1))
        self.generator.append(bn(ngf * 4))
        self.generator.append(nn.ReLU())
        self.generator.append(conv_t(ngf * 4, ngf * 2, 4, 2, 1))
        self.generator.append(bn(ngf * 2))
        self.generator.append(nn.ReLU())
        self.generator.append(conv_t(ngf * 2, ngf, 4, 2, 1))
        self.generator.append(bn(ngf))
        self.generator.append(nn.ReLU())
        self.generator.append(conv_t(ngf, nc, 4, 2, 1))
        self.generator.append(nn.Tanh())
​
    def construct(self, x):
        return self.generator(x)
​
# 实例化生成器
netG = Generator()

判别器

如前所述,判别器D是一个二分类网络模型,输出判定该图像为真实图的概率。通过一系列的Conv2dBatchNorm2dLeakyReLU层对其进行处理,最后通过Sigmoid激活函数得到最终概率。

DCGAN论文提到,使用卷积而不是通过池化来进行下采样是一个好方法,因为它可以让网络学习自己的池化特征。

判别器的代码实现如下:



def conv(in_channels, out_channels, kernel_size, stride=1, padding=0, pad_mode="pad"):
    """定义卷积层"""
    weight_init = init.Normal(mean=0, sigma=0.02)
    return nn.Conv2d(in_channels, out_channels,
                     kernel_size=kernel_size, stride=stride, padding=padding,
                     weight_init=weight_init, has_bias=False, pad_mode=pad_mode)
​
class Discriminator(nn.Cell):
    """DCGAN网络判别器"""
​
    def __init__(self):
        super(Discriminator, self).__init__()
        self.discriminator = nn.SequentialCell()
        self.discriminator.append(conv(nc, ndf, 4, 2, 1))
        self.discriminator.append(nn.LeakyReLU(0.2))
        self.discriminator.append(conv(ndf, ndf * 2, 4, 2, 1))
        self.discriminator.append(bn(ndf * 2))
        self.discriminator.append(nn.LeakyReLU(0.2))
        self.discriminator.append(conv(ndf * 2, ndf * 4, 4, 2, 1))
        self.discriminator.append(bn(ndf * 4))
        self.discriminator.append(nn.LeakyReLU(0.2))
        self.discriminator.append(conv(ndf * 4, ndf * 8, 4, 2, 1))
        self.discriminator.append(bn(ndf * 8))
        self.discriminator.append(nn.LeakyReLU(0.2))
        self.discriminator.append(conv(ndf * 8, 1, 4, 1))
        self.discriminator.append(nn.Sigmoid())
​
    def construct(self, x):
        return self.discriminator(x)
​
# 实例化判别器
netD = Discriminator()

损失和优化器

MindSpore将损失函数、优化器等操作都封装到了Cell中,因为GAN结构上的特殊性,其损失是判别器和生成器的多输出形式,这就导致它和一般的分类网络不同。所以我们需要自定义WithLossCell类,将网络和Loss连接起来。

损失函数

当定义了DG后,接下来将使用MindSpore中定义的二进制交叉熵损失函数BCELoss ,为DG加上损失函数和优化器。

  • 连接生成器和损失函数,代码如下:

# 定义损失函数
loss = nn.BCELoss(reduction='mean')
​
class WithLossCellG(nn.Cell):
    """连接生成器和损失"""
​
    def __init__(self, netD, netG, loss_fn):
        super(WithLossCellG, self).__init__(auto_prefix=True)
        self.netD = netD
        self.netG = netG
        self.loss_fn = loss_fn
​
    def construct(self, latent_code):
        """构建生成器损失计算结构"""
        fake_data = self.netG(latent_code)
        out = self.netD(fake_data)
        label_real = ops.OnesLike()(out)
        loss = self.loss_fn(out, label_real)
        return loss
  • 连接判别器和损失函数,代码如下:


class WithLossCellD(nn.Cell):
    """连接判别器和损失"""
​
    def __init__(self, netD, netG, loss_fn):
        super(WithLossCellD, self).__init__(auto_prefix=True)
        self.netD = netD
        self.netG = netG
        self.loss_fn = loss_fn
​
    def construct(self, real_data, latent_code):
        """构建判别器损失计算结构"""
        out_real = self.netD(real_data)
        label_real = ops.OnesLike()(out_real)
        loss_real = self.loss_fn(out_real, label_real)
​
        fake_data = self.netG(latent_code)
        fake_data = ops.stop_gradient(fake_data)
        out_fake = self.netD(fake_data)
        label_fake = ops.ZerosLike()(out_fake)
        loss_fake = self.loss_fn(out_fake, label_fake)
        return loss_real + loss_fake

优化器

这里设置了两个单独的优化器,一个用于D,另一个用于G。这两个都是lr = 0.0002beta1 = 0.5的Adam优化器。

为了跟踪生成器的学习进度,在训练的过程中,我们定期将一批固定的遵循高斯分布的隐向量fixed_noise输入到G中,可以看到隐向量生成的图像。



# 创建一批隐向量用来观察G
np.random.seed(1)
fixed_noise = ms.Tensor(np.random.randn(64, nz, 1, 1), dtype=ms.float32)
​
# 为生成器和判别器设置优化器
optimizerD = nn.Adam(netD.trainable_params(), learning_rate=lr, beta1=beta1)
optimizerG = nn.Adam(netG.trainable_params(), learning_rate=lr, beta1=beta1)

训练模型

训练分为两个主要部分:训练判别器和训练生成器。

  • 训练判别器

    训练判别器的目的是最大程度地提高判别图像真伪的概率。按照Goodfellow的方法,是希望通过提高其随机梯度来更新判别器,所以我们要最大化𝑙𝑜𝑔𝐷(𝑥)+𝑙𝑜𝑔(1−𝐷(𝐺(𝑧))logD(x)+log(1−D(G(z))的值。

  • 训练生成器

    如DCGAN论文所述,我们希望通过最小化𝑙𝑜𝑔(1−𝐷(𝐺(𝑧)))log(1−D(G(z)))来训练生成器,以产生更好的虚假图像。

在这两个部分中,分别获取训练过程中的损失,并在每个周期结束时进行统计,将fixed_noise批量推送到生成器中,以直观地跟踪G的训练进度。

下面进行训练:



class DCGAN(nn.Cell):
    """定义DCGAN网络"""
​
    def __init__(self, myTrainOneStepCellForD, myTrainOneStepCellForG):
        super(DCGAN, self).__init__(auto_prefix=True)
        self.myTrainOneStepCellForD = myTrainOneStepCellForD
        self.myTrainOneStepCellForG = myTrainOneStepCellForG
​
    def construct(self, real_data, latent_code):
        output_D = self.myTrainOneStepCellForD(real_data, latent_code).view(-1)
        netD_loss = output_D.mean()
        output_G = self.myTrainOneStepCellForG(latent_code).view(-1)
        netG_loss = output_G.mean()
        return netD_loss, netG_loss
实例化生成器和判别器的WithLossCell和TrainOneStepCell。

In [12]:



# 实例化WithLossCell
netD_with_criterion = WithLossCellD(netD, netG, loss)
netG_with_criterion = WithLossCellG(netD, netG, loss)
​
# 实例化TrainOneStepCell
myTrainOneStepCellForD = nn.TrainOneStepCell(netD_with_criterion, optimizerD)
myTrainOneStepCellForG = nn.TrainOneStepCell(netG_with_criterion, optimizerG)

循环训练网络,每经过50次迭代,就收集生成器和判别器的损失,以便于后面绘制训练过程中损失函数的图像。



# 实例化DCGAN网络
dcgan = DCGAN(myTrainOneStepCellForD, myTrainOneStepCellForG)
dcgan.set_train()
​
# 创建迭代器
data_loader = data.create_dict_iterator(output_numpy=True, num_epochs=num_epochs)
G_losses = []
D_losses = []
image_list = []
​
# 开始循环训练
print("Starting Training Loop...")
​
for epoch in range(num_epochs):
    # 为每轮训练读入数据
    for i, d in enumerate(data_loader):
        real_data = ms.Tensor(d['image'])
        latent_code = ms.Tensor(d["latent_code"])
        netD_loss, netG_loss = dcgan(real_data, latent_code)
        if i % 50 == 0 or i == size - 1:
            # 输出训练记录
            print('[%2d/%d][%3d/%d]   Loss_D:%7.4f  Loss_G:%7.4f' % (
                epoch + 1, num_epochs, i + 1, size, netD_loss.asnumpy(), netG_loss.asnumpy()))
        D_losses.append(netD_loss.asnumpy())
        G_losses.append(netG_loss.asnumpy())
​
    # 每个epoch结束后,使用生成器生成一组图片
    img = netG(fixed_noise)
    image_list.append(img.transpose(0, 2, 3, 1).asnumpy())
​
    # 保存网络模型参数为ckpt文件
    ms.save_checkpoint(netG, "Generator.ckpt")
    ms.save_checkpoint(netD, "Discriminator.ckpt")

 初次尝试,出现报错:

RuntimeError: Unexpected error. Invalid image, ./datasets\faces\41604.jpg decode failed, the image is broken or permission denied.
Line of code : 122
File         : mindspore\ccsrc\minddata\dataset\engine\datasetops\source\image_folder_op.cc

很明显,问题原因是图片损坏或权限问题。

我们打开文件夹去查看一下,的确是图片已损坏。那我们将数据集旁的压缩包进行解压覆盖。解压完成后,再次打开数据集,可以看到图片已经修复完成。

再次实验开始训练。这一次的对抗神经网络比第一篇的lenet很明显消耗算力要多了很多。

Starting Training Loop...
[ 1/10][  1/549]   Loss_D: 0.9487  Loss_G: 2.8116
[ 1/10][ 51/549]   Loss_D: 1.7577  Loss_G:10.9718
[ 1/10][101/549]   Loss_D: 0.4995  Loss_G: 3.4224
[ 1/10][151/549]   Loss_D: 0.5207  Loss_G: 4.7320
[ 1/10][201/549]   Loss_D: 0.5944  Loss_G: 6.1879
[ 1/10][251/549]   Loss_D: 0.7243  Loss_G: 5.6230
[ 1/10][301/549]   Loss_D: 1.0566  Loss_G: 8.1467
[ 1/10][351/549]   Loss_D: 0.8798  Loss_G: 6.8631
[ 1/10][401/549]   Loss_D: 1.9408  Loss_G: 2.4352
[ 1/10][451/549]   Loss_D: 1.1904  Loss_G: 8.0717
[ 1/10][501/549]   Loss_D: 0.5741  Loss_G: 5.1539
[ 1/10][549/549]   Loss_D: 0.7244  Loss_G: 6.8598
[ 2/10][  1/549]   Loss_D: 0.6800  Loss_G: 2.8094
[ 2/10][ 51/549]   Loss_D: 0.4741  Loss_G: 3.6057
[ 2/10][101/549]   Loss_D: 0.6971  Loss_G: 3.1635
[ 2/10][151/549]   Loss_D: 0.4821  Loss_G: 3.3885
[ 2/10][201/549]   Loss_D: 1.3610  Loss_G: 2.7418
[ 2/10][251/549]   Loss_D: 0.3119  Loss_G: 3.4965
[ 2/10][301/549]   Loss_D: 1.2650  Loss_G: 2.9397
[ 2/10][351/549]   Loss_D: 0.5933  Loss_G: 2.5890
[ 2/10][401/549]   Loss_D: 0.4977  Loss_G: 2.6506
[ 2/10][451/549]   Loss_D: 0.3647  Loss_G: 2.8786
[ 2/10][501/549]   Loss_D: 0.4899  Loss_G: 3.7978
[ 2/10][549/549]   Loss_D: 0.4216  Loss_G: 3.5123
[ 3/10][  1/549]   Loss_D: 0.4984  Loss_G: 4.4313
[ 3/10][ 51/549]   Loss_D: 0.8768  Loss_G: 7.0500
[ 3/10][101/549]   Loss_D: 0.5803  Loss_G: 5.0793
[ 3/10][151/549]   Loss_D: 0.6609  Loss_G: 2.2792
[ 3/10][201/549]   Loss_D: 0.4175  Loss_G: 4.7435
[ 3/10][251/549]   Loss_D: 0.3933  Loss_G: 4.2352
[ 3/10][301/549]   Loss_D: 0.5673  Loss_G: 2.7045
[ 3/10][351/549]   Loss_D: 0.6207  Loss_G: 2.3788
[ 3/10][401/549]   Loss_D: 0.5936  Loss_G: 2.6619
[ 3/10][451/549]   Loss_D: 0.6627  Loss_G: 5.0005
[ 3/10][501/549]   Loss_D: 0.8255  Loss_G: 1.6260
[ 3/10][549/549]   Loss_D: 0.4849  Loss_G: 4.6147
[ 4/10][  1/549]   Loss_D: 0.7955  Loss_G: 1.9926
[ 4/10][ 51/549]   Loss_D: 0.4734  Loss_G: 3.2014
[ 4/10][101/549]   Loss_D: 0.8793  Loss_G: 1.4053
[ 4/10][151/549]   Loss_D: 0.3582  Loss_G: 2.5979
[ 4/10][201/549]   Loss_D: 0.5387  Loss_G: 3.3358
[ 4/10][251/549]   Loss_D: 0.9358  Loss_G: 3.2012
[ 4/10][301/549]   Loss_D: 0.5707  Loss_G: 4.5730
[ 4/10][351/549]   Loss_D: 0.7776  Loss_G: 4.8124
[ 4/10][401/549]   Loss_D: 0.4092  Loss_G: 3.4990
[ 4/10][451/549]   Loss_D: 0.4135  Loss_G: 3.2599
[ 4/10][501/549]   Loss_D: 0.5648  Loss_G: 2.8526
[ 4/10][549/549]   Loss_D: 0.5565  Loss_G: 3.1748
[ 5/10][  1/549]   Loss_D: 0.6311  Loss_G: 4.0271
[ 5/10][ 51/549]   Loss_D: 0.4635  Loss_G: 3.6951
[ 5/10][101/549]   Loss_D: 0.7703  Loss_G: 1.9067
[ 5/10][151/549]   Loss_D: 0.6474  Loss_G: 1.3896
[ 5/10][201/549]   Loss_D: 1.4381  Loss_G: 1.1795
[ 5/10][251/549]   Loss_D: 0.5213  Loss_G: 2.5108
[ 5/10][301/549]   Loss_D: 0.6392  Loss_G: 2.6104
[ 5/10][351/549]   Loss_D: 0.4867  Loss_G: 2.3963
[ 5/10][401/549]   Loss_D: 0.6047  Loss_G: 2.4089
[ 5/10][451/549]   Loss_D: 0.5309  Loss_G: 2.8736
[ 5/10][501/549]   Loss_D: 0.5753  Loss_G: 3.6794
[ 5/10][549/549]   Loss_D: 1.0052  Loss_G: 1.2394
[ 6/10][  1/549]   Loss_D: 1.1906  Loss_G: 6.8362
[ 6/10][ 51/549]   Loss_D: 0.4155  Loss_G: 2.5607
[ 6/10][101/549]   Loss_D: 1.6138  Loss_G: 0.5080
[ 6/10][151/549]   Loss_D: 0.8172  Loss_G: 1.5014
[ 6/10][201/549]   Loss_D: 0.6967  Loss_G: 5.2143
[ 6/10][251/549]   Loss_D: 0.6850  Loss_G: 1.3772
[ 6/10][301/549]   Loss_D: 0.5450  Loss_G: 2.1229
[ 6/10][351/549]   Loss_D: 0.5056  Loss_G: 2.1068
[ 6/10][401/549]   Loss_D: 0.4739  Loss_G: 2.8684
[ 6/10][451/549]   Loss_D: 0.5366  Loss_G: 2.3096
[ 6/10][501/549]   Loss_D: 0.4508  Loss_G: 1.7802
[ 6/10][549/549]   Loss_D: 0.8342  Loss_G: 2.2548
[ 7/10][  1/549]   Loss_D: 0.5573  Loss_G: 4.0267
[ 7/10][ 51/549]   Loss_D: 0.7410  Loss_G: 2.3037
[ 7/10][101/549]   Loss_D: 0.6700  Loss_G: 1.9992
[ 7/10][151/549]   Loss_D: 0.8071  Loss_G: 5.1885
[ 7/10][201/549]   Loss_D: 0.5741  Loss_G: 1.5209
[ 7/10][251/549]   Loss_D: 0.5998  Loss_G: 1.9137
[ 7/10][301/549]   Loss_D: 1.2534  Loss_G: 5.8762
[ 7/10][351/549]   Loss_D: 1.7599  Loss_G: 1.1529
[ 7/10][401/549]   Loss_D: 0.5422  Loss_G: 1.9621
[ 7/10][451/549]   Loss_D: 0.4839  Loss_G: 2.9988
[ 7/10][501/549]   Loss_D: 0.7826  Loss_G: 5.5011
[ 7/10][549/549]   Loss_D: 0.5503  Loss_G: 2.3725
[ 8/10][  1/549]   Loss_D: 0.6691  Loss_G: 4.2466
[ 8/10][ 51/549]   Loss_D: 0.5461  Loss_G: 2.0987
[ 8/10][101/549]   Loss_D: 0.4201  Loss_G: 2.5834
[ 8/10][151/549]   Loss_D: 0.5920  Loss_G: 2.0090
[ 8/10][201/549]   Loss_D: 0.6428  Loss_G: 1.8949
[ 8/10][251/549]   Loss_D: 0.4933  Loss_G: 4.4112
[ 8/10][301/549]   Loss_D: 0.5574  Loss_G: 2.5720
[ 8/10][351/549]   Loss_D: 0.2877  Loss_G: 3.4134
[ 8/10][401/549]   Loss_D: 0.7567  Loss_G: 3.0611
[ 8/10][451/549]   Loss_D: 0.4393  Loss_G: 2.7309
[ 8/10][501/549]   Loss_D: 1.1448  Loss_G: 6.7999
[ 8/10][549/549]   Loss_D: 0.9303  Loss_G: 6.7643
[ 9/10][  1/549]   Loss_D: 0.9245  Loss_G: 1.7276
[ 9/10][ 51/549]   Loss_D: 0.3482  Loss_G: 2.7859
[ 9/10][101/549]   Loss_D: 0.3848  Loss_G: 2.7122
[ 9/10][151/549]   Loss_D: 0.7443  Loss_G: 2.3568
[ 9/10][201/549]   Loss_D: 0.5922  Loss_G: 4.1343
[ 9/10][251/549]   Loss_D: 0.6185  Loss_G: 4.4837
[ 9/10][301/549]   Loss_D: 0.5732  Loss_G: 4.1202
[ 9/10][351/549]   Loss_D: 1.1618  Loss_G: 6.8321
[ 9/10][401/549]   Loss_D: 0.7044  Loss_G: 4.2240
[ 9/10][451/549]   Loss_D: 0.3451  Loss_G: 3.6564
[ 9/10][501/549]   Loss_D: 0.6951  Loss_G: 4.1818
[ 9/10][549/549]   Loss_D: 0.7487  Loss_G: 1.5944
[10/10][  1/549]   Loss_D: 0.9374  Loss_G: 5.1160
[10/10][ 51/549]   Loss_D: 3.2007  Loss_G: 0.6091
[10/10][101/549]   Loss_D: 0.3892  Loss_G: 2.8658
[10/10][151/549]   Loss_D: 0.4722  Loss_G: 2.2726
[10/10][201/549]   Loss_D: 3.2437  Loss_G: 1.5150
[10/10][251/549]   Loss_D: 1.3150  Loss_G: 7.8126
[10/10][301/549]   Loss_D: 0.5530  Loss_G: 1.9683
[10/10][351/549]   Loss_D: 0.8319  Loss_G: 2.4234
[10/10][401/549]   Loss_D: 0.5502  Loss_G: 2.9019
[10/10][451/549]   Loss_D: 0.3378  Loss_G: 3.8130
[10/10][501/549]   Loss_D: 0.3802  Loss_G: 2.7914
[10/10][549/549]   Loss_D: 0.5493  Loss_G: 1.6474

结果展示

运行下面代码,描绘DG损失与训练迭代的关系图:

plt.figure(figsize=(10, 5))
plt.title("Generator and Discriminator Loss During Training")
plt.plot(G_losses, label="G", color='blue')
plt.plot(D_losses, label="D", color='orange')
plt.xlabel("iterations")
plt.ylabel("Loss")
plt.legend()
plt.show()

可视化训练过程中通过隐向量fixed_noise生成的图像。

plt.figure(figsize=(10, 5))
plt.title("Generator and Discriminator Loss During Training")
plt.plot(G_losses, label="G", color='blue')
plt.plot(D_losses, label="D", color='orange')
plt.xlabel("iterations")
plt.ylabel("Loss")
plt.legend()
plt.show()

从上面的图像可以看出,随着训练次数的增多,图像质量也越来越好。如果增大训练周期数,当num_epochs达到50以上时,生成的动漫头像图片与数据集中的较为相似,下面我们通过加载训练周期为50的生成器网络模型参数文件Generator.ckpt来生成图像,代码如下:

plt.figure(figsize=(10, 5))
plt.title("Generator and Discriminator Loss During Training")
plt.plot(G_losses, label="G", color='blue')
plt.plot(D_losses, label="D", color='orange')
plt.xlabel("iterations")
plt.ylabel("Loss")
plt.legend()
plt.show()
14316544B [00:00, 15985888.74B/s]                               

到此我们就完成了dcgan生成动漫头像的步骤了。 从上面的代码与运行结果,可以看出随着训练轮数的增加,我们图片的噪音不断减少,也不断变得更清晰。


总结

本文对通过昇思框架实现对抗神经网络实现动漫头像识别以及会遇到的问题进行了简单的介绍。最后自己生成的动漫头像也是非常的有意义,值得一试。

欢迎大家加入昇思社区,一起讨论昇思框架的许许多多,构建昇思大家庭!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值