PyTorch深度学习实战(32)——DCGAN详解与实现

2024-01-25 14:04

本文主要是介绍PyTorch深度学习实战(32)——DCGAN详解与实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

PyTorch深度学习实战(32)——DCGAN详解与实现

    • 0. 前言
    • 1. 模型与数据集分析
      • 1.1 模型分析
      • 1.2 数据集介绍
    • 2. 构建 DCGAN 生成人脸图像
    • 小结
    • 系列链接

0. 前言

DCGAN (Deep Convolutional Generative Adversarial Networks) 是基于生成对抗网络 (Convolutional Generative Adversarial Networks, GAN) 的深度学习模型,相比传统的 GAN 模型,DCGAN 通过引入卷积神经网络 (Convolutional Neural Networks, CNN) 架构来提升生成网络和判别网络的性能。DCGAN 中的生成网络和判别网络都是使用卷积层和反卷积层构建的深度神经网络。生成网络接收一个随机噪声向量作为输入,并通过反卷积层将其逐渐转化为与训练数据相似的输出图像,判别网络则是一个用于分类真实和生成图像的卷积神经网络。

1. 模型与数据集分析

1.1 模型分析

我们已经学习了 GAN 的基本原理并并使用 PyTorch 实现了 GAN 模型用于生成 MNIST 手写数字图像。同时,我们已经知道,与普通神经网络相比,卷积神经网络 (Convolutional Neural Networks, CNN) 架构能够更好地学习图像中的特征。在本节中,我们将学习使用深度卷积生成对抗网络生成图像,在模型中使用卷积和池化操作替换全连接层。
首先,介绍如何使用随机噪声( 100 维向量)生成图像,将噪声形状转换为 batch size x 100 x 1 x 1,其中 batch size 表示批大小,由于在 DCGAN 使用 CNN,因此需要添加额外的通道信息,即 batch size x channel x height x width 的形式,channel 表示通道数,heightwidth 分别表示高度和宽度。
接下来,利用 ConvTranspose2d 将生成的噪声向量转换为图像,ConvTranspose2d 与卷积操作相反,将输入的小特征图通过预定义的核大小、步幅和填充上上采样到较大的尺寸。利用上采样逐渐将向量形状从 batch size x 100 x 1 x 1 转换为 batch size x 3 x 64 x 64,即将 100 维的随机噪声向量转换成一张 64 x 64 的图像。

1.2 数据集介绍

为了训练对抗生成网络,我们需要了解本节所用的数据集,数据集取自 Celeb A,可以自行构建数据集,也可以下载本文所用数据集,下载地址:https://pan.baidu.com/s/1dvDCBLSGwblg57p9RDBEJQ,提取码:y9fiCelebA 是一个大规模的人脸属性数据集,其中包含超过 20 万张名人图像,每张图像有 40 个属性注释。CelebA 数据集的图像来源于互联网上的名人照片,包括电影、音乐和体育界等各个领域。这些图像具有多样的姿势、表情、背景和装扮,涵盖了各种真实世界的场景。

2. 构建 DCGAN 生成人脸图像

接下来,我们使用 PyTorch 构建 DCGAN 模型生成人脸图像。

(1) 下载并获取人脸图像,示例图像如下所示:

示例图像
(2) 导入相关库:

from torchvision import transforms
import torchvision.utils as vutils
import cv2, numpy as np
import torch
import os
from glob import glob
from PIL import Image
from torch import nn, optim
from torch.utils.data import DataLoader, Dataset
from matplotlib import pyplot as plt
device = "cuda" if torch.cuda.is_available() else "cpu"

(3) 定义数据集和数据加载器。

裁剪图像,只保留面部区域并丢弃图像中的其他部分。首先,使用级联滤波器识别图像中的人脸:

face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')

OpenCV 提供了 4 个级联分类器用于人脸检测,可以从 OpenCV 官方下载这些级联分类器文件:

  • haarcascade_frontalface_alt.xml (FA1)
  • haarcascade_frontalface_alt2.xml (FA2)
  • haarcascade_frontalface_alt_tree.xml (FAT)
  • haarcascade_frontalface_default.xml (FD)

可以使用不同的数据集评估这些级联分类器的性能,总的来说这些分类器具有相似的准确率。

创建一个新文件夹,并将所有裁剪后的人脸图像转储到新文件夹中:

if not os.path.exists('cropped_faces'):os.mkdir('cropped_faces')images = glob('male_female_face_images/females/*.jpg')+glob('male_female_face_images/males/*.jpg')
for i in range(len(images)):img = cv2.imread(images[i],1)gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)faces = face_cascade.detectMultiScale(gray, 1.3, 5)for (x,y,w,h) in faces:img2 = img[y:(y+h),x:(x+w),:]cv2.imwrite('cropped_faces/'+str(i)+'.jpg', img2)

裁剪后的面部示例图像如下:

面部裁剪图像
定义要对每个图像执行的转换:

transform=transforms.Compose([transforms.Resize(64),transforms.CenterCrop(64),transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

定义 Faces 数据集类:

class Faces(Dataset):def __init__(self, folder):super().__init__()self.folder = folderself.images = sorted(glob(folder))def __len__(self):return len(self.images)def __getitem__(self, ix):image_path = self.images[ix]image = Image.open(image_path)image = transform(image)return image

创建数据集对象 ds

ds = Faces(folder='cropped_faces/*.jpg')

定义数据加载器类:

dataloader = DataLoader(ds, batch_size=64, shuffle=True, num_workers=8)

(4) 定义权重初始化函数,使权重的分布较小:

def weights_init(m):classname = m.__class__.__name__if classname.find('Conv') != -1:nn.init.normal_(m.weight.data, 0.0, 0.02)elif classname.find('BatchNorm') != -1:nn.init.normal_(m.weight.data, 1.0, 0.02)nn.init.constant_(m.bias.data, 0)

(5) 定义判别网络模型类 Discriminator,接收形状为 batch size x 3 x 64 x 64 的图像,并预测输入图像是真实图像还是生成图像:

class Discriminator(nn.Module):def __init__(self):super(Discriminator, self).__init__()self.model = nn.Sequential(nn.Conv2d(3,64,4,2,1,bias=False),nn.LeakyReLU(0.2,inplace=True),nn.Conv2d(64,64*2,4,2,1,bias=False),nn.BatchNorm2d(64*2),nn.LeakyReLU(0.2,inplace=True),nn.Conv2d(64*2,64*4,4,2,1,bias=False),nn.BatchNorm2d(64*4),nn.LeakyReLU(0.2,inplace=True),nn.Conv2d(64*4,64*8,4,2,1,bias=False),nn.BatchNorm2d(64*8),nn.LeakyReLU(0.2,inplace=True),nn.Conv2d(64*8,1,4,1,0,bias=False),nn.Sigmoid())self.apply(weights_init)def forward(self, input):return self.model(input)

打印模型的摘要信息:

from torchsummary import summary
discriminator = Discriminator().to(device)
print(summary(discriminator, (3,64,64)))

模型摘要输出结果如下所示:

----------------------------------------------------------------Layer (type)               Output Shape         Param #
================================================================Conv2d-1           [-1, 64, 32, 32]           3,072LeakyReLU-2           [-1, 64, 32, 32]               0Conv2d-3          [-1, 128, 16, 16]         131,072BatchNorm2d-4          [-1, 128, 16, 16]             256LeakyReLU-5          [-1, 128, 16, 16]               0Conv2d-6            [-1, 256, 8, 8]         524,288BatchNorm2d-7            [-1, 256, 8, 8]             512LeakyReLU-8            [-1, 256, 8, 8]               0Conv2d-9            [-1, 512, 4, 4]       2,097,152BatchNorm2d-10            [-1, 512, 4, 4]           1,024LeakyReLU-11            [-1, 512, 4, 4]               0Conv2d-12              [-1, 1, 1, 1]           8,192Sigmoid-13              [-1, 1, 1, 1]               0
================================================================
Total params: 2,765,568
Trainable params: 2,765,568
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.05
Forward/backward pass size (MB): 2.31
Params size (MB): 10.55
Estimated Total Size (MB): 12.91
----------------------------------------------------------------

(6) 定义生成网络模型类,使用形状为 batch size x 100 x 1 x 1 的输入生成图像:

class Generator(nn.Module):def __init__(self):super(Generator,self).__init__()self.model = nn.Sequential(nn.ConvTranspose2d(100,64*8,4,1,0,bias=False,),nn.BatchNorm2d(64*8),nn.ReLU(True),nn.ConvTranspose2d(64*8,64*4,4,2,1,bias=False),nn.BatchNorm2d(64*4),nn.ReLU(True),nn.ConvTranspose2d( 64*4,64*2,4,2,1,bias=False),nn.BatchNorm2d(64*2),nn.ReLU(True),nn.ConvTranspose2d( 64*2,64,4,2,1,bias=False),nn.BatchNorm2d(64),nn.ReLU(True),nn.ConvTranspose2d( 64,3,4,2,1,bias=False),nn.Tanh())self.apply(weights_init)def forward(self,input):return self.model(input)

打印模型的摘要信息:

generator = Generator().to(device)
print(summary(generator, (100,1,1)))

代码输出结果如下所示:

----------------------------------------------------------------Layer (type)               Output Shape         Param #
================================================================ConvTranspose2d-1            [-1, 512, 4, 4]         819,200BatchNorm2d-2            [-1, 512, 4, 4]           1,024ReLU-3            [-1, 512, 4, 4]               0ConvTranspose2d-4            [-1, 256, 8, 8]       2,097,152BatchNorm2d-5            [-1, 256, 8, 8]             512ReLU-6            [-1, 256, 8, 8]               0ConvTranspose2d-7          [-1, 128, 16, 16]         524,288BatchNorm2d-8          [-1, 128, 16, 16]             256ReLU-9          [-1, 128, 16, 16]               0ConvTranspose2d-10           [-1, 64, 32, 32]         131,072BatchNorm2d-11           [-1, 64, 32, 32]             128ReLU-12           [-1, 64, 32, 32]               0ConvTranspose2d-13            [-1, 3, 64, 64]           3,072Tanh-14            [-1, 3, 64, 64]               0
================================================================
Total params: 3,576,704
Trainable params: 3,576,704
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.00
Forward/backward pass size (MB): 3.00
Params size (MB): 13.64
Estimated Total Size (MB): 16.64
----------------------------------------------------------------

(7) 定义训练生成网络 (generator_train_step) 和判别网络 (discriminator_train_step) 的函数:

def discriminator_train_step(real_data, fake_data, loss, d_optimizer):d_optimizer.zero_grad()prediction_real = discriminator(real_data)error_real = loss(prediction_real.squeeze(), torch.ones(len(real_data)).to(device))error_real.backward()prediction_fake = discriminator(fake_data)error_fake = loss(prediction_fake.squeeze(), torch.zeros(len(fake_data)).to(device))error_fake.backward()d_optimizer.step()return error_real + error_fakedef generator_train_step(real_data, fake_data, loss, g_optimizer):g_optimizer.zero_grad()prediction = discriminator(fake_data)error = loss(prediction.squeeze(), torch.ones(len(real_data)).to(device))error.backward()g_optimizer.step()return error

在以上代码中,在判别网络预测结果上执行 .squeeze 操作,因为模型的输出形状为 batch size x 1 x 1 x 1,而预测结果需要与形状为 batch size x 1 的张量进行比较。

(8) 创建生成网络和判别网络模型对象、优化器以及损失函数:

discriminator = Discriminator().to(device)
generator = Generator().to(device)
loss = nn.BCELoss()
d_optimizer = optim.Adam(discriminator.parameters(), lr=0.0002, betas=(0.5, 0.999))
g_optimizer = optim.Adam(generator.parameters(), lr=0.0002, betas=(0.5, 0.999))

(9) 训练模型。

加载真实数据 (real_data) 并通过生成网络生成图像 (fake_data):

num_epochs = 100
d_loss_epoch = []
g_loss_epoch = []
for epoch in range(num_epochs):N = len(dataloader)d_loss_items = []g_loss_items = []for i, images in enumerate(dataloader):real_data = images.to(device)fake_data = generator(torch.randn(len(real_data), 100, 1, 1).to(device)).to(device)fake_data = fake_data.detach()

原始 GANDCGAN 的主要区别在于,在 DCGAN 模型中,由于使用了 CNN,因此不必展平 real_data

使用 discriminator_train_step 函数训练判别网络:

        d_loss = discriminator_train_step(real_data, fake_data, loss, d_optimizer)

利用噪声数据 (torch.randn(len(real_data))) 生成新图像 (fake_data) 并使用 generator_train_step 函数训练生成网络:

        fake_data = generator(torch.randn(len(real_data), 100, 1, 1).to(device)).to(device)g_loss = generator_train_step(real_data, fake_data, loss, g_optimizer)

记录损失变化:

        d_loss_items.append(d_loss.item())g_loss_items.append(g_loss.item())d_loss_epoch.append(np.average(d_loss_items))
g_loss_epoch.append(np.average(g_loss_items))

(10) 绘制模型训练期间,判别网络和生成网络损失变化情况:

epochs = np.arange(num_epochs)+1
plt.plot(epochs, d_loss_epoch, 'bo', label='Discriminator Training loss')
plt.plot(epochs, g_loss_epoch, 'r-', label='Generator Training loss')
plt.title('Training and Test loss over increasing epochs')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.grid('off')

损失变化
从上图中可以看出,生成网络和判别网络损失的变化与手写数字生成模型的损失变化模式并不相同,原因如下:

  • 人脸图像的尺寸相比手写数字更大,手写数字图像形状为 28 x 28 x 1,人脸图像形状为 64 x 64 x 3
  • 与人脸图像中的特征相比,手写数字图像中的特征较少
  • 与人脸图像中的信息相比,手写数字图像中仅少数像素中存在可用信息

(11) 训练过程完成后,生成图像样本:

generator.eval()
noise = torch.randn(64, 100, 1, 1, device=device)
sample_images = generator(noise).detach().cpu()
grid = vutils.make_grid(sample_images, nrow=8, normalize=True)
plt.imshow(grid.cpu().detach().permute(1,2,0))
plt.show()

生成图像样本

小结

DCGAN 是优秀的图像生成模型,其生成网路和判别网络都是使用卷积层和反卷积层构建的深度神经网络。生成网络接收一个随机噪声向量作为输入,并通过逐渐减小的反卷积层将其逐渐转化为与训练数据相似的输出图像;判别网络则是一个用于分类真实和生成图像的卷积神经网络。在本节中,我们学习了如何构建并训练 DCGAN 生成人脸图像。

系列链接

PyTorch深度学习实战(1)——神经网络与模型训练过程详解
PyTorch深度学习实战(2)——PyTorch基础
PyTorch深度学习实战(3)——使用PyTorch构建神经网络
PyTorch深度学习实战(4)——常用激活函数和损失函数详解
PyTorch深度学习实战(5)——计算机视觉基础
PyTorch深度学习实战(6)——神经网络性能优化技术
PyTorch深度学习实战(7)——批大小对神经网络训练的影响
PyTorch深度学习实战(8)——批归一化
PyTorch深度学习实战(9)——学习率优化
PyTorch深度学习实战(10)——过拟合及其解决方法
PyTorch深度学习实战(11)——卷积神经网络
PyTorch深度学习实战(12)——数据增强
PyTorch深度学习实战(13)——可视化神经网络中间层输出
PyTorch深度学习实战(14)——类激活图
PyTorch深度学习实战(15)——迁移学习
PyTorch深度学习实战(16)——面部关键点检测
PyTorch深度学习实战(17)——多任务学习
PyTorch深度学习实战(18)——目标检测基础
PyTorch深度学习实战(19)——从零开始实现R-CNN目标检测
PyTorch深度学习实战(20)——从零开始实现Fast R-CNN目标检测
PyTorch深度学习实战(21)——从零开始实现Faster R-CNN目标检测
PyTorch深度学习实战(22)——从零开始实现YOLO目标检测
PyTorch深度学习实战(23)——使用U-Net架构进行图像分割
PyTorch深度学习实战(24)——从零开始实现Mask R-CNN实例分割
PyTorch深度学习实战(25)——自编码器(Autoencoder)
PyTorch深度学习实战(26)——卷积自编码器(Convolutional Autoencoder)
PyTorch深度学习实战(27)——变分自编码器(Variational Autoencoder, VAE)
PyTorch深度学习实战(28)——对抗攻击(Adversarial Attack)
PyTorch深度学习实战(29)——神经风格迁移
PyTorch深度学习实战(30)——Deepfakes
PyTorch深度学习实战(31)——生成对抗网络(Generative Adversarial Network, GAN)

这篇关于PyTorch深度学习实战(32)——DCGAN详解与实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/643498

相关文章

使用Python实现IP地址和端口状态检测与监控

《使用Python实现IP地址和端口状态检测与监控》在网络运维和服务器管理中,IP地址和端口的可用性监控是保障业务连续性的基础需求,本文将带你用Python从零打造一个高可用IP监控系统,感兴趣的小伙... 目录概述:为什么需要IP监控系统使用步骤说明1. 环境准备2. 系统部署3. 核心功能配置系统效果展

MySQL中的分组和多表连接详解

《MySQL中的分组和多表连接详解》:本文主要介绍MySQL中的分组和多表连接的相关操作,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录mysql中的分组和多表连接一、MySQL的分组(group javascriptby )二、多表连接(表连接会产生大量的数据垃圾)MySQL中的

Java 实用工具类Spring 的 AnnotationUtils详解

《Java实用工具类Spring的AnnotationUtils详解》Spring框架提供了一个强大的注解工具类org.springframework.core.annotation.Annot... 目录前言一、AnnotationUtils 的常用方法二、常见应用场景三、与 JDK 原生注解 API 的

Python实现微信自动锁定工具

《Python实现微信自动锁定工具》在数字化办公时代,微信已成为职场沟通的重要工具,但临时离开时忘记锁屏可能导致敏感信息泄露,下面我们就来看看如何使用Python打造一个微信自动锁定工具吧... 目录引言:当微信隐私遇到自动化守护效果展示核心功能全景图技术亮点深度解析1. 无操作检测引擎2. 微信路径智能获

redis中使用lua脚本的原理与基本使用详解

《redis中使用lua脚本的原理与基本使用详解》在Redis中使用Lua脚本可以实现原子性操作、减少网络开销以及提高执行效率,下面小编就来和大家详细介绍一下在redis中使用lua脚本的原理... 目录Redis 执行 Lua 脚本的原理基本使用方法使用EVAL命令执行 Lua 脚本使用EVALSHA命令

Python中pywin32 常用窗口操作的实现

《Python中pywin32常用窗口操作的实现》本文主要介绍了Python中pywin32常用窗口操作的实现,pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个... 目录获取窗口句柄获取最前端窗口句柄获取指定坐标处的窗口根据窗口的完整标题匹配获取句柄根据窗口的类别匹配获取句

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B

SpringBoot3.4配置校验新特性的用法详解

《SpringBoot3.4配置校验新特性的用法详解》SpringBoot3.4对配置校验支持进行了全面升级,这篇文章为大家详细介绍了一下它们的具体使用,文中的示例代码讲解详细,感兴趣的小伙伴可以参考... 目录基本用法示例定义配置类配置 application.yml注入使用嵌套对象与集合元素深度校验开发

Python中的Walrus运算符分析示例详解

《Python中的Walrus运算符分析示例详解》Python中的Walrus运算符(:=)是Python3.8引入的一个新特性,允许在表达式中同时赋值和返回值,它的核心作用是减少重复计算,提升代码简... 目录1. 在循环中避免重复计算2. 在条件判断中同时赋值变量3. 在列表推导式或字典推导式中简化逻辑

判断PyTorch是GPU版还是CPU版的方法小结

《判断PyTorch是GPU版还是CPU版的方法小结》PyTorch作为当前最流行的深度学习框架之一,支持在CPU和GPU(NVIDIACUDA)上运行,所以对于深度学习开发者来说,正确识别PyTor... 目录前言为什么需要区分GPU和CPU版本?性能差异硬件要求如何检查PyTorch版本?方法1:使用命