第一章 MindSpore框架的体验与部署
第二章Mindspore体验dcgan生成漫画头像
前言
在第一篇中我们实现了昇思平台的安装与初体验,这一次我们可以进行对它深入的了解与尝试。想要了解安装部署的同学请去看我的第一篇哈。
一、官方文档
根据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 的论文中所述,
D
和
G
在进行一场博弈,
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,将靠近生成器生成出来数据分布的数据判定为0。
- 生成器通过优化,生成出更加贴近真实数据分布的数据。
- 生成器所生成的数据和真实数据达到相同的分布,此时判别器的输出为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.
我们通过输入部分中设置的
nz
、
ngf
和
nc
来影响代码中的生成器结构。
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
是一个二分类网络模型,输出判定该图像为真实图的概率。通过一系列的
Conv2d
、
BatchNorm2d
和
LeakyReLU
层对其进行处理,最后通过
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连接起来。
损失函数
当定义了
D
和
G
后,接下来将使用MindSpore中定义的二进制交叉熵损失函数BCELoss ,为
D
和
G
加上损失函数和优化器。
- 连接生成器和损失函数,代码如下:
# 定义损失函数 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.0002
和
beta1 = 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
结果展示
运行下面代码,描绘
D
和
G
损失与训练迭代的关系图:
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生成动漫头像的步骤了。 从上面的代码与运行结果,可以看出随着训练轮数的增加,我们图片的噪音不断减少,也不断变得更清晰。
总结
本文对通过昇思框架实现对抗神经网络实现动漫头像识别以及会遇到的问题进行了简单的介绍。最后自己生成的动漫头像也是非常的有意义,值得一试。
欢迎大家加入昇思社区,一起讨论昇思框架的许许多多,构建昇思大家庭!
版权归原作者 北冥 . 所有, 如有侵权,请联系我们删除。