赞
踩
DCGAN(深度卷积对抗生成网络,Deep Convolutional Generative Adversarial Networks)是GAN的直接扩展。不同之处在于,DCGAN会分别在判别器和生成器中使用卷积和转置卷积层。
- 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超参数
数据处理和增强:
- 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')
将数据转换成字典迭代器,并可视化部分训练数据:
- 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)
该功能是通过一系列 Conv2dTranspose 转置卷积层来完成的,每个层都与 BatchNorm2d 层和 ReLu 激活层配对,输出数据会经过 tanh 函数,使其返回 [-1,1] 的数据范围内。
DCGAN生成结构如下:
代码实现:
- 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()
使用卷积而不是通过池化来进行下采样是一个好方法,因为它可以让网络学习自己的池化特征。
代码实现如下:
- 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()
定义交叉熵损失函数BCELoss
- # 定义损失函数
- adversarial_loss = nn.BCELoss(reduction='mean')
- # 为生成器和判别器设置优化器
- 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.')
训练判别器
训练判别器的目的是最大程度地提高判别图像真伪的概率。通过提高其随机梯度来更新判别器,所以我们要最大化
训练生成器
需要最小化
模型训练正向逻辑:
- 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")
得到生成器和判别器训练迭代的损失函数:
- 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()
显示生成的图像
- 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)
可见随着训练次数的增加,图像质量也越来越好。
加载生成器网络模型参数文件来生成图像:
- # 从文件中获取模型参数并加载到网络中
- 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()
DCGAN在判别器和生成器中加入了卷积和转置卷积层,随着迭代次数的增加,生成图像的质量也随之提高。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。