- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
本文分享自华为云社区《【昇思25天学习打卡营打卡指南-第二十天】DCGAN生成漫画头像》,作者:JeffDing.
在下面的教程中,我们将通过示例代码说明DCGAN网络如何设置网络、优化器、如何计算损失函数以及如何初始化模型权重。在本教程中,使用的动漫头像数据集共有70,171张动漫头像图片,图片大小均为96*96.
这部分原理介绍参考GAN图像生成.
DCGAN(深度卷积对抗生成网络,Deep Convolutional Generative Adversarial Networks)是GAN的直接扩展。不同之处在于,DCGAN会分别在判别器和生成器中使用卷积和转置卷积层.
它最早由Radford等人在论文Unsupervised Representation Learning With Deep Convolutional Generative Adversarial Networks中进行描述。判别器由分层的卷积层、BatchNorm层和LeakyReLU激活层组成。输入是3x64x64的图像,输出是该图像为真图像的概率。生成器则是由转置卷积层、BatchNorm层和ReLU激活层组成。输入是标准正态分布中提取出的隐向量𝑧,输出是3x64x64的RGB图像.
。
本教程将使用动漫头像数据集来训练一个生成式对抗网络,接着使用该网络生成动漫头像图片.
首先我们将数据集下载到指定目录下并解压。示例代码如下:
from download import download url = "https://download.mindspore.cn/dataset/Faces/faces.zip" path = download(url, "./faces", kind="zip", replace=True)
首先为执行过程定义一些输入:
batch_size = 128 # 批量大小 image_size = 64 # 训练图像空间大小 nc = 3 # 图像彩色通道数 nz = 100 # 隐向量的长度 ngf = 64 # 特征图在生成器中的大小 ndf = 64 # 特征图在判别器中的大小 num_epochs = 3 # 训练周期数 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 def create_dataset_imagenet(dataset_path): """数据加载""" dataset = ds.ImageFolderDataset(dataset_path, num_parallel_workers=4, shuffle=True, decode=True) # 数据增强操作 transforms = [ vision.Resize(image_size), vision.CenterCrop(image_size), vision.HWC2CHW(), lambda x: ((x / 255).astype("float32")) ] # 数据映射操作 dataset = dataset.project('image') dataset = dataset.map(transforms, 'image') # 批量操作 dataset = dataset.batch(batch_size) return dataset dataset = create_dataset_imagenet('./faces')
通过create_dict_iterator函数将数据转换成字典迭代器,然后使用matplotlib模块可视化部分训练数据.
import matplotlib.pyplot as plt def plot_data(data): # 可视化部分训练数据 plt.figure(figsize=(10, 3), dpi=140) for i, image in enumerate(data[0][:30], 1): plt.subplot(3, 10, i) plt.axis("off") plt.imshow(image.transpose(1, 2, 0)) plt.show() sample_data = next(dataset.create_tuple_iterator(output_numpy=True)) plot_data(sample_data)
当处理完数据后,就可以来进行网络的搭建了。按照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是输出图像中的通道数.
以下是生成器的代码实现:
import mindspore as ms from mindspore import nn, ops from mindspore.common.initializer import Normal weight_init = Normal(mean=0, sigma=0.02) gamma_init = Normal(mean=1, sigma=0.02) class Generator(nn.Cell): """DCGAN网络生成器""" def __init__(self): super(Generator, self).__init__() self.generator = nn.SequentialCell( nn.Conv2dTranspose(nz, ngf * 8, 4, 1, 'valid', weight_init=weight_init), nn.BatchNorm2d(ngf * 8, gamma_init=gamma_init), nn.ReLU(), nn.Conv2dTranspose(ngf * 8, ngf * 4, 4, 2, 'pad', 1, weight_init=weight_init), nn.BatchNorm2d(ngf * 4, gamma_init=gamma_init), nn.ReLU(), nn.Conv2dTranspose(ngf * 4, ngf * 2, 4, 2, 'pad', 1, weight_init=weight_init), nn.BatchNorm2d(ngf * 2, gamma_init=gamma_init), nn.ReLU(), nn.Conv2dTranspose(ngf * 2, ngf, 4, 2, 'pad', 1, weight_init=weight_init), nn.BatchNorm2d(ngf, gamma_init=gamma_init), nn.ReLU(), nn.Conv2dTranspose(ngf, nc, 4, 2, 'pad', 1, weight_init=weight_init), nn.Tanh() ) def construct(self, x): return self.generator(x) generator = Generator()
如前所述,判别器D是一个二分类网络模型,输出判定该图像为真实图的概率。通过一系列的Conv2d、BatchNorm2d和LeakyReLU层对其进行处理,最后通过Sigmoid激活函数得到最终概率.
DCGAN论文提到,使用卷积而不是通过池化来进行下采样是一个好方法,因为它可以让网络学习自己的池化特征.
判别器的代码实现如下:
class Discriminator(nn.Cell): """DCGAN网络判别器""" def __init__(self): super(Discriminator, self).__init__() self.discriminator = nn.SequentialCell( nn.Conv2d(nc, ndf, 4, 2, 'pad', 1, weight_init=weight_init), nn.LeakyReLU(0.2), nn.Conv2d(ndf, ndf * 2, 4, 2, 'pad', 1, weight_init=weight_init), nn.BatchNorm2d(ngf * 2, gamma_init=gamma_init), nn.LeakyReLU(0.2), nn.Conv2d(ndf * 2, ndf * 4, 4, 2, 'pad', 1, weight_init=weight_init), nn.BatchNorm2d(ngf * 4, gamma_init=gamma_init), nn.LeakyReLU(0.2), nn.Conv2d(ndf * 4, ndf * 8, 4, 2, 'pad', 1, weight_init=weight_init), nn.BatchNorm2d(ngf * 8, gamma_init=gamma_init), nn.LeakyReLU(0.2), nn.Conv2d(ndf * 8, 1, 4, 1, 'valid', weight_init=weight_init), ) self.adv_layer = nn.Sigmoid() def construct(self, x): out = self.discriminator(x) out = out.reshape(out.shape[0], -1) return self.adv_layer(out) discriminator = Discriminator()
当定义了D和G后,接下来将使用MindSpore中定义的二进制交叉熵损失函数BCELoss.
# 定义损失函数 adversarial_loss = nn.BCELoss(reduction='mean')
这里设置了两个单独的优化器,一个用于D,另一个用于G。这两个都是lr = 0.0002和beta1 = 0.5的Adam优化器.
# 为生成器和判别器设置优化器 optimizer_D = nn.Adam(discriminator.trainable_params(), learning_rate=lr, beta1=beta1) optimizer_G = nn.Adam(generator.trainable_params(), learning_rate=lr, beta1=beta1) optimizer_G.update_parameters_name('optim_g.') optimizer_D.update_parameters_name('optim_d.')
训练分为两个主要部分:训练判别器和训练生成器.
训练判别器 。
训练判别器的目的是最大程度地提高判别图像真伪的概率。按照Goodfellow的方法,是希望通过提高其随机梯度来更新判别器,所以我们要最大化logD(x)+log(1−D(G(z))的值.
训练生成器 。
如DCGAN论文所述,我们希望通过最小化log(1−D(G(z)))来训练生成器,以产生更好的虚假图像.
在这两个部分中,分别获取训练过程中的损失,并在每个周期结束时进行统计,将fixed_noise批量推送到生成器中,以直观地跟踪G的训练进度.
下面实现模型训练正向逻辑:
def generator_forward(real_imgs, valid): # 将噪声采样为发生器的输入 z = ops.standard_normal((real_imgs.shape[0], nz, 1, 1)) # 生成一批图像 gen_imgs = generator(z) # 损失衡量发生器绕过判别器的能力 g_loss = adversarial_loss(discriminator(gen_imgs), valid) return g_loss, gen_imgs def discriminator_forward(real_imgs, gen_imgs, valid, fake): # 衡量鉴别器从生成的样本中对真实样本进行分类的能力 real_loss = adversarial_loss(discriminator(real_imgs), valid) fake_loss = adversarial_loss(discriminator(gen_imgs), fake) d_loss = (real_loss + fake_loss) / 2 return d_loss grad_generator_fn = ms.value_and_grad(generator_forward, None, optimizer_G.parameters, has_aux=True) grad_discriminator_fn = ms.value_and_grad(discriminator_forward, None, optimizer_D.parameters) @ms.jit def train_step(imgs): valid = ops.ones((imgs.shape[0], 1), mindspore.float32) fake = ops.zeros((imgs.shape[0], 1), mindspore.float32) (g_loss, gen_imgs), g_grads = grad_generator_fn(imgs, valid) optimizer_G(g_grads) d_loss, d_grads = grad_discriminator_fn(imgs, gen_imgs, valid, fake) optimizer_D(d_grads) return g_loss, d_loss, gen_imgs
循环训练网络,每经过50次迭代,就收集生成器和判别器的损失,以便于后面绘制训练过程中损失函数的图像.
import mindspore G_losses = [] D_losses = [] image_list = [] total = dataset.get_dataset_size() for epoch in range(num_epochs): generator.set_train() discriminator.set_train() # 为每轮训练读入数据 for i, (imgs, ) in enumerate(dataset.create_tuple_iterator()): g_loss, d_loss, gen_imgs = train_step(imgs) if i % 100 == 0 or i == total - 1: # 输出训练记录 print('[%2d/%d][%3d/%d] Loss_D:%7.4f Loss_G:%7.4f' % ( epoch + 1, num_epochs, i + 1, total, d_loss.asnumpy(), g_loss.asnumpy())) D_losses.append(d_loss.asnumpy()) G_losses.append(g_loss.asnumpy()) # 每个epoch结束后,使用生成器生成一组图片 generator.set_train(False) fixed_noise = ops.standard_normal((batch_size, nz, 1, 1)) img = generator(fixed_noise) image_list.append(img.transpose(0, 2, 3, 1).asnumpy()) # 保存网络模型参数为ckpt文件 mindspore.save_checkpoint(generator, "./generator.ckpt") mindspore.save_checkpoint(discriminator, "./discriminator.ckpt")
运行下面代码,描绘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生成的图像.
import matplotlib.pyplot as plt import matplotlib.animation as animation def showGif(image_list): show_list = [] fig = plt.figure(figsize=(8, 3), dpi=120) for epoch in range(len(image_list)): images = [] for i in range(3): row = np.concatenate((image_list[epoch][i * 8:(i + 1) * 8]), axis=1) images.append(row) img = np.clip(np.concatenate((images[:]), axis=0), 0, 1) plt.axis("off") show_list.append([plt.imshow(img)]) ani = animation.ArtistAnimation(fig, show_list, interval=1000, repeat_delay=1000, blit=True) ani.save('./dcgan.gif', writer='pillow', fps=1) showGif(image_list)
从上面的图像可以看出,随着训练次数的增多,图像质量也越来越好。如果增大训练周期数,当num_epochs达到50以上时,生成的动漫头像图片与数据集中的较为相似,下面我们通过加载生成器网络模型参数文件来生成图像,代码如下:
# 从文件中获取模型参数并加载到网络中 mindspore.load_checkpoint("./generator.ckpt", generator) fixed_noise = ops.standard_normal((batch_size, nz, 1, 1)) img64 = generator(fixed_noise).transpose(0, 2, 3, 1).asnumpy() fig = plt.figure(figsize=(8, 3), dpi=120) images = [] for i in range(3): images.append(np.concatenate((img64[i * 8:(i + 1) * 8]), axis=1)) img = np.clip(np.concatenate((images[:]), axis=0), 0, 1) plt.axis("off") plt.imshow(img) plt.show()
。
点击关注,第一时间了解华为云新鲜技术~ 。
。
最后此篇关于教你基于MindSpore用DCGAN生成漫画头像的文章就讲到这里了,如果你想了解更多关于教你基于MindSpore用DCGAN生成漫画头像的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在尝试使用以下 keytool 命令为我的应用程序生成 keystore : keytool -genkey -alias tomcat -keystore tomcat.keystore -ke
编辑:在西里尔正确解决问题后,我注意到只需将生成轴的函数放在用于生成标签的函数下面就可以解决问题。 我几乎读完了 O'Reilly 书中关于 D3.js 的教程,并在倒数第二页上制作了散点图,但是当添
虽然使用 GraphiQL 效果很好,但我的老板要求我实现一个用户界面,用户可以在其中通过 UI 元素(例如复选框、映射关系)检查呈现给他们的元素并获取数据,这样做将为该人生成 graphql 输入,
我尝试在 Netbean 6.8 中使用 ws-import 生成 Java 类。我想重新生成 jax-ws,因为在 ebay.api.paypalapi 包中发现了一个错误(我认为该错误是由于 Pa
我有一个 perl 脚本,它获取系统日期并将该日期写入文件名。 系统日期被分配给 TRH1 变量,然后它被设置为一个文件名。 $TRH1 =`date + %Y%m%d%H%M`; print "TR
我是 Haskell 的新手,需要帮助。我正在尝试构建一种必须具有某种唯一性的新数据类型,因此我决定使用 UUID 作为唯一标识符: data MyType = MyType { uuid ::
我制作了一个脚本,它可以根据 Mysql 数据库中的一些表生成 XML。 该脚本在 PHP 中运行。 public function getRawMaterials($apiKey, $format
所以这是我的项目中的一个问题。 In this task, we will use OpenSSL to generate digital signatures. Please prepare a f
我在 SAS LIFEREG 中有一个加速故障时间模型,我想绘制它。因为 SAS 在绘图方面非常糟糕,我想实际重新生成 R 中曲线的数据并将它们绘制在那里。 SAS 提出了一个尺度(在指数分布固定为
我正在为 Django 后端制作一个样板,并且我需要能够使它到达下一个下载它的人显然无法访问我的 secret key 的地方,或者拥有不同的 key 。我一直在研究一些选项,并在这个过程中进行了实验
我正在创建一个生成采购订单的应用程序。我可以根据用户输入的详细信息创建文本文件。我想生成一个看起来比普通文本文件好得多的 Excel。有没有可以在我的应用程序中使用的开源库? 最佳答案 目前还没有任何
我正在尝试使用 ScalaCheck 为 BST 创建一个 Gen,但是当我调用 .sample 方法时,它给了我 java.lang.NullPointerException。我哪里错了? seal
已关闭。此问题需要 debugging details 。目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and the
我尝试编写一些代码,例如(在verilog中): parameter N = 128; if (encoder_in[0] == 1) begin 23 binary_out = 1;
我正忙于在 Grails 项目中进行从 MySQL 到 Postgres 的相当复杂的数据迁移。 我正在使用 GORM 在 PostGres 中生成模式,然后执行 MySQL -> mysqldump
如何使用纯 XSLT 生成 UUID?基本上是寻找一种使用 XSLT 创建独特序列的方法。该序列可以是任意长度。 我正在使用 XSLT 2.0。 最佳答案 这是一个good example 。基本上,
我尝试安装.app文件,但是当我安装并单击“同步”(在iTunes中)时,我开始在设备上开始安装,然后停止,这是一个问题,我不知道在哪里,但我看到了我无法解决的奇怪的事情: 最佳答案 似乎您没有在Xc
自从我生成 JavaDocs 以来已经有一段时间了,我确信这些选项在过去 10 年左右的时间里已经得到了改进。 我能否得到一些有关生成器的建议,该生成器将输出类似于 .Net 文档结构的 JavaDo
我想学习如何生成 PDF,我不想使用任何第三方工具,我想自己用代码创建它。到目前为止,我所看到的唯一示例是我通过在第 3 方 dll 上打开反射器查看的代码,以查看发生了什么。不幸的是,到目前为止我看
我正在从 Epplus 库生成 excel 条形图。 这是我成功生成的。 我的 table 是这样的 Mumbai Delhi Financial D
我是一名优秀的程序员,十分优秀!