深度学习:DCGAN

news/2024/12/21 22:30:57/

目录

什么是DCGAN

DCGAN与GAN的区别

DCGAN生成器

DCGAN判别器

基于MindSpore框架实现DCGAN

数据集:

变量定义:

数据预处理:

生成器:

 判别器:

损失函数与优化器

训练模型

 模型推理


什么是DCGAN

CDGAN(Deep Convolutional Generative Adversarial Networks),是GAN(Generative Adversarial Networks)的一种变体,它特别使用了卷积神经网络(CNNs)作为生成器和判别器的构建模块。

DCGAN使用全卷积网络结构代替传统的池化层和全连接层。在生成器中采用转置卷积(也称为分数步长卷积或反卷积)来逐步增加图像的空间维度。

在判别器中使用卷积层来逐步减少空间维度并提取特征。

ReLU激活函数用于生成器的所有层(除输出层使用Tanh激活函数外),LeakyReLU激活函数用于判别器的所有层。

DCGAN与GAN的区别

  • 基础架构:传统GAN没有对生成器和判别器的具体结构做出严格规定;而DCGAN明确指定了使用深度卷积网络。
  • 稳定性:由于采用了上述改进措施,DCGAN相比原始GAN在训练过程中表现得更为稳定。
  • 应用领域:虽然两者都可以应用于多种类型的数据生成任务,但DCGAN因其特殊的网络结构,在处理图像数据方面尤为有效。

关于GAN网络,可参考:深度学习:GAN图像生成-CSDN博客

DCGAN生成器

按照DCGAN论文中的描述,所有模型权重均应从mean为0,sigma为0.02的正态分布中随机初始化。

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

DCGAN判别器

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

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

基于MindSpore框架实现DCGAN

数据集:

# 记载数据集
from download import downloadurl = "https://download.mindspore.cn/dataset/Faces/faces.zip"path = download(url, "./faces", kind="zip", replace=True)

变量定义:

# 变量定义
batch_size = 128 # 批量大小
image_size = 64 # 训练图像的空间大小
num_channels = 3 # 彩色图片的通道数
latent_size = 100 # 输入生成器的隐向量长度
generator_feature_size = 64 # 特征图在生成器中的大小
discriminator_feature_size = 64 # 特征图在判别器中的大小
num_epochs = 10 # 训练轮次
lr = 0.0002 # 学习率
beta1 = 0.5 # Adam优化器的beta1超参数

数据预处理:

# 对数据进行预处理并增强
import numpy as np
import mindspore as ms
import mindspore.dataset as ds
import mindspore.dataset.vision as vision
import timedef create_dataset_imagenet(dataset_path):dataset = ds.ImageFolderDataset(dataset_path, # 指定数据集所在的文件夹路径num_parallel_workers=4, # 并行工作线程为4shuffle=True, # 打乱数据集decode=True # 解码图片)# 数据增持transforms = [vision.Resize(image_size), # 将图像大小调整到指定的image_sizevision.CenterCrop(image_size),  # 从中心裁剪出指定大小的image_size的图像vision.HWC2CHW(), # 将图像的通道顺序从HWC(高宽通道)转换为CHW(通道高宽)lambda x:((x / 255).astype("float32"))  # 将像素值归一化到[0,1]区间,并转换为float32类型]# 数据映射操作dataset = dataset.project("image")dataset = dataset.map(transforms, "image") # 对'image'列应用上面定义的transforms变换# 批量操作dataset = dataset.batch(batch_size)return datasetdataset = create_dataset_imagenet('./faces')

 

生成器:

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):def __init__(self):super(Generator, self).__init__()self.generator = nn.SequentialCell(# (in_channels, out_channels, kernel_size, stride, pad_mode, padding)# pad_mode='valid':不对输入进行填充,返回输出可能的最大长度。nn.Conv2dTranspose(latent_size, generator_feature_size * 8, 4, 1, 'valid', weight_init=weight_init),nn.BatchNorm2d(generator_feature_size * 8, gamma_init=gamma_init),nn.ReLU(),# pad_mode='pad':对输入填充指定的量。nn.Conv2dTranspose(generator_feature_size * 8, generator_feature_size * 4, 4, 2, 'pad', 1, weight_init=weight_init),nn.BatchNorm2d(generator_feature_size * 4, gamma_init=gamma_init),nn.ReLU(),nn.Conv2dTranspose(generator_feature_size * 4, generator_feature_size * 2, 4, 2, 'pad', 1, weight_init=weight_init),nn.BatchNorm2d(generator_feature_size * 2, gamma_init=gamma_init),nn.ReLU(),nn.Conv2dTranspose(generator_feature_size * 2, generator_feature_size, 4, 2, 'pad', 1, weight_init=weight_init),nn.BatchNorm2d(generator_feature_size, gamma_init=gamma_init),nn.ReLU(),nn.Conv2dTranspose(generator_feature_size, num_channels, 4, 2, 'pad', 1, weight_init=weight_init),nn.Tanh())def construct(self, x):return self.generator(x)generator = Generator()

 判别器:

# 判别器
class Discriminator(nn.Cell):def __init__(self):super(Discriminator, self).__init__()self.discriminator = nn.SequentialCell(nn.Conv2d(num_channels, discriminator_feature_size, 4, 2, 'pad', 1, weight_init=weight_init),nn.LeakyReLU(0.2),nn.Conv2d(discriminator_feature_size, discriminator_feature_size * 2, 4, 2, 'pad', 1, weight_init=weight_init),# gamma_init: 参数的初始化方法nn.BatchNorm2d(discriminator_feature_size * 2, gamma_init=gamma_init),nn.LeakyReLU(0.2),nn.Conv2d(discriminator_feature_size * 2, discriminator_feature_size * 4, 4, 2, 'pad', 1, weight_init=weight_init),nn.BatchNorm2d(discriminator_feature_size * 4, gamma_init=gamma_init),nn.LeakyReLU(0.2),nn.Conv2d(discriminator_feature_size * 4, discriminator_feature_size * 8, 4, 2, 'pad', 1, weight_init=weight_init),nn.BatchNorm2d(discriminator_feature_size * 8, gamma_init=gamma_init),nn.LeakyReLU(0.2),nn.Conv2d(discriminator_feature_size * 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()

损失函数与优化器

loss = nn.BCELoss(reduction='mean')# beta1: 第一个动量矩阵的指数衰减率
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.update_parameters_name() 
方法用于更新优化器参数的名称前缀。
这通常在你想要为优化器中的参数添加一个特定的命名空间或前缀时使用,
这样可以更容易地管理和区分不同的优化器参数
'''
optimizer_G.update_parameters_name('optim_g.')
optimizer_D.update_parameters_name('optim_d.')

训练模型

# 生成器forward函数
def generator_forward(real_imgs, valid):# 这里使用标准正态分布来生成噪声z,其形状为(batch_size, latent_size, 1, 1)。z = ops.standard_normal((real_imgs.shape[0], latent_size, 1, 1))gen_imgs = generator(z)# valid是目标标签,通常是一批全1的张量,表示这些图像是真实的。# loss计算判别器输出与目标标签之间的差异,这个差异就是生成器试图最小化的损失。g_loss = loss(discriminator(gen_imgs), valid)return g_loss, gen_imgs# 判别器forward函数
def discriminator_forward(real_imgs, gen_imgs, valid, fake):real_loss = loss(discriminator(real_imgs), valid)fake_loss = loss(discriminator(gen_imgs), fake)d_loss = (real_loss + fake_loss) / 2return d_loss# 计算梯度
'''
has_aux (bool) - 是否返回辅助参数的标志。
若为 True , fn 输出数量必须超过一个,其中只有 fn 第一个输出参与求导,
其他输出值将直接返回。
'''
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)def train_step(imgs):# 为真实的图像创建全1的有效标签valid = ops.ones((imgs.shape[0], 1), ms.float32)# 为假的图像创建全0的无效标签fake = ops.zeros((imgs.shape[0], 1), ms.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)# 返回loss值和生成结果return g_loss, d_loss, gen_imgs# 生成器损失集合
G_losses = []
# 判别器损失集合
D_losses = []
# 生成图像集合
image_list = []total = dataset.get_dataset_size()for epoch in range(num_epochs):start = time.time()# 没轮训练前,将模型设为训练状态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, latent_size, 1, 1))img = generator(fixed_noise)image_list.append(img.transpose(0, 2, 3, 1).asnumpy())# 保存网络模型参数为ckpt文件ms.save_checkpoint(generator, "./generator.ckpt")ms.save_checkpoint(discriminator, "./discriminator.ckpt")end = time.time()print('time:',(start-end))

 模型推理

# 模型推理
ms.load_checkpoint("./generator.ckpt", generator)# 测试噪音数据
fixed_noise = ops.standard_normal((batch_size, latent_size, 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()


http://www.ppmy.cn/news/1534974.html

相关文章

Kafka和RabbitMQ区别

RabbitMQ的消息延迟是微秒级,Kafka是毫秒级(1毫秒1000微秒) 延迟消息是指生产者发送消息发送消息后,不能立刻被消费者消费,需要等待指定的时间后才可以被消费。 Kafka的单机呑吐量是十万级,RabbitMQ是万级…

安卓使用memtester进行内存压力测试

memteser简介 memtester 是一个用于测试内存可靠性的工具。 它可以对计算机的内存进行压力测试,以检测内存中的错误,例如位翻转、随机存取错误等。memtester 可以在不同的操作系统上运行,并且可以针对不同大小的内存进行测试。 下载源码 m…

408算法题leetcode--第24天

#378. 有序矩阵中第 K 小的元素 378. 有序矩阵中第 K 小的元素思路&#xff1a;值二分&#xff0c;如注释时间&#xff1a;O(log(r-l) * n)&#xff1b;空间&#xff1a;O(1) class Solution { public:int check(vector<vector<int>>& matrix, int target){/…

多用户网页聊天室(测试报告)

一、项目背景 随着现代互联网的快速发展&#xff0c;实时通信系统&#xff08;如聊天应用&#xff09;已成为人们日常交流的重要工具。多用户网页聊天室项目旨在为用户提供一个基于Web的实时聊天平台&#xff0c;支持用户之间的即时通信、好友管理和历史消息记录查看。为了提升…

C语言复习概要(二)

本文目录 C语言中的数组与函数详解1. 引言2. 数组2.1. 什么是数组&#xff1f;语法&#xff1a;示例&#xff1a; 2.2. 数组的初始化示例 1&#xff1a;在声明时初始化示例 2&#xff1a;部分初始化示例 3&#xff1a;运行时赋值 2.3. 数组的访问与修改示例&#xff1a; 2.4. 多…

第十八讲-布局管理QVBoxLayout

QVBoxLayout 是 PyQt5 中用于在垂直方向上排列小部件(widgets)的布局管理器。它将子小部件从上到下按顺序排列,可以通过添加、插入、设置间距和对齐方式等方法对布局进行控制。QVBoxLayout 主要用于创建简单且整洁的界面。 初步示例 下面是一个简单的示例,展示了如何使用 …

SLF4J报错log4j又报错

项目场景&#xff1a; 搭建一个spirngboot项目&#xff0c;启动运行时&#xff0c;SLF4J报错 解决后 ~ log4j又报错了。 问题描述 首先是SLF4J报错了&#xff0c;解决完SL4J报错问题后&#xff0c;再次启动项目&#xff0c;log4j又报错了 。。。 报错信息&#xff1a; SLF4J…

WaterCloud:一套基于.NET 8.0 + LayUI的快速开发框架,完全开源免费!

前言 今天大姚给大家分享一套基于.NET 8.0 LayUI的快速开发框架&#xff0c;项目完全开源、免费&#xff08;MIT License&#xff09;且开箱即用&#xff1a;WaterCloud。 可完全实现二次开发让开发更多关注业务逻辑。既能快速提高开发效率&#xff0c;帮助公司节省人力成本&…