(深度学习快速入门)第五章第三节:DCGAN人脸图像生成

news2024/11/18 17:39:29

文章目录

  • 一:CelebFaces Attribute(CelebA)数据集介绍
  • 二:模型结构
  • 三:代码编写
    • (1)参数配置
    • (2)数据集加载脚本
    • (3)模型脚本
    • (4)训练脚本

一:CelebFaces Attribute(CelebA)数据集介绍

CelebA数据集:CeleA是香港中文大学的开放数据,包含10177个名人身份的202599张图片,并且都做好了特征标记,这对人脸相关的训练是非常好用的数据集

  • 数据集官网
  • 百度网盘链接

这个数据集做了很多的标记,所以非常实用
在这里插入图片描述

有如下40种属性

  • 01 5_o_Clock_Shadow 胡子,(清晨刮脸的人傍晚已长出的短髭 ) -1
  • 02 Arched_Eyebrows 柳叶眉 1
  • 03 Attractive 有魅力的 1
  • 04 Bags_Under_Eyes 眼袋 -1
  • 05 Bald 秃头的 -1
  • 06 Bangs 刘海 -1
  • 07 Big_Lips 大嘴唇 -1
  • 08 Big_Nose 大鼻子 -1
  • 09 Black_Hair 黑发 -1
  • 10 Blond_Hair 金发 -1
  • 11 Blurry 睡眼惺松的 -1
  • 12 Brown_Hair 棕发 1
  • 13 Bushy_Eyebrows 浓眉 -1
  • 14 Chubby 丰满的 -1
  • 15 Double_Chin 双下巴 -1
  • 16 Eyeglasses 眼镜 -1
  • 17 Goatee 山羊胡子 -1
  • 18 Gray_Hair 白发,灰发 -1
  • 19 Heavy_Makeup 浓妆 1
  • 20 High_Cheekbones 高颧骨 1
  • 21 Male 男性 -1
  • 22 Mouth_Slightly_Open 嘴轻微的张开 1
  • 23 Mustache 胡子 -1
  • 24 Narrow_Eyes 窄眼 -1
  • 25 No_Beard 没有胡子 1
  • 26 Oval_Face 瓜子脸,鹅蛋脸 -1
  • 27 Pale_Skin 白皮肤 -1
  • 28 Pointy_Nose 尖鼻子 1
  • 29 Receding_Hairline 发际线; 向后梳得发际线 -1
  • 30 Rosy_Cheeks 玫瑰色的脸颊 -1
  • 31 Sideburns 连鬓胡子,鬓脚 -1
  • 32 Smiling 微笑的 1
  • 33 Straight_Hair 直发 1
  • 34 Wavy_Hair 卷发; 波浪发 -1
  • 35 Wearing_Earrings 戴耳环 1
  • 36 Wearing_Hat 带帽子 -1
  • 37 Wearing_Lipstick 涂口红 1
  • 38 Wearing_Necklace 带项链 -1
  • 39 Wearing_Necktie 戴领带 -1
  • 40 Young 年轻人 1

下载后你会看到下面三个文件夹及一个README.md文件

在这里插入图片描述

AnnoEval文件夹是关于图片特征描述的,这里不再介绍,因为这是无监督学习。Img文件夹存放图片。点进去之后它含有两个文件夹和一个压缩包,含义如下

img_celeba.7z纯“野生”文件,也就是从网络爬取的没有做裁剪的图片
img_align_celeba_png.7z把“野生”文件裁剪出人脸部分之后的图片,png格式
img_align_celeba.zipjpg格式的,比较小(推荐使用,直接解压即可)

zip解压后就是我们需要的图片,它是按照编号命名的,差不多20万张图片

在这里插入图片描述

二:模型结构

在这里插入图片描述

三:代码编写

(1)参数配置

import torch  
class Parameteres:  
    device = 'cuda' if torch.cuda.is_available() else 'cpu'  
    data_root = '~/autodl-tmp/dataset/celeba'  
  
    image_size = 64  # 生成人脸图片大小  
  
    z_dim = 100  # latent z dimension  
    data_channels = 3  
  
    batch_size = 64  # 8×8网格图片  
    beta = 0.5  # Adam参数1  
    init_lr = 0.0002  # Adam参数2  
    epochs = 1000  
    verbose_step = 250  # save image  
    save_step = 1000  # save model  
  
  
parameters = Parameteres()

(2)数据集加载脚本

  • GAN和以往的CNN等模型结构不同,因为是无监督学习,所以不需要标签,也没有验证集
import torchvision.utils  
from torchvision import transforms  
import torchvision.datasets as datasets  
from torch.utils.data import DataLoader  
  
from Parameteres import parameters  
import os  
  
# 环境变量(If use Windows)  
#  os.environ['KMP_DUPLICATE_LIB_OK'] = 'True'  
  
# 变换  
data_transform = transforms.Compose(  
    [  
        transforms.Resize(parameters.image_size),  # 64 × 3 × 3  
        transforms.CenterCrop(parameters.image_size),  #  
        transforms.ToTensor(),  
        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))  
    ]  
)  
  
# 反标准化,以便我们查看图片  
invtrans = transforms.Compose(  
    [  
        transforms.Normalize(mean=[0., 0., 0.], std=[1/0.5, 1/0.5, 1/0.5]),  
        transforms.Normalize(mean=[-0.5, -0.5, -0.5], std=[1., 1., 1.])  
    ]  
)  
  
# 数据集  
data_set = datasets.ImageFolder(  
    root=parameters.data_root,  
    transform=data_transform  
)  
  
# dataloader  
data_loader = DataLoader(dataset=data_set, batch_size=parameters.batch_size, shuffle=True, num_workers=8, drop_last=True)  
  
if __name__ == '__main__':  
  
    for data, _ in data_loader:  
        # NCHW  
        print(data.size())  
        data = invtrans(data)  
        torchvision.utils.save_image(data, "./test1.png", nrow=8)  
  
        break

上面代码中标准化的目的是为了进行训练,但是最终查看图片时一定要进行“反标准化”

  • 下图1是没有进行反标准化的图片
  • 下图2是进行了反标准化(也即恢复为正常显示)的图片

在这里插入图片描述

在这里插入图片描述

(3)模型脚本

生成器

import torch  
import torch.nn as nn  
  
from Parameteres import parameters  
  
class Generator(nn.Module):  
    def __init__(self):  
        super(Generator, self).__init__()  
        # 输入为100维高斯向量然后送入一个Linear,然后resahpe为(4×4×1024)  
        self.projectionlayer = nn.Linear(parameters.z_dim, 4*4*1024)  
  
        # 转置卷积堆叠  
        self.generator = nn.Sequential(  
            nn.ConvTranspose2d(  
                in_channels=1024,  # [N, 512, 8, 8]  
                out_channels=512,  
                kernel_size=(4, 4),  
                stride=(2, 2),  
                padding=(1,1),  
                bias=False),  
            nn.BatchNorm2d(512),  
            nn.ReLU(),  
  
            nn.ConvTranspose2d(  
                in_channels=512,  # [N, 256, 16, 16]  
                out_channels=256,  
                kernel_size=(4, 4),  
                stride=(2, 2),  
                padding=(1, 1),  
                bias=False),  
            nn.BatchNorm2d(256),  
            nn.ReLU(),  
  
            nn.ConvTranspose2d(  
                in_channels=256,  # [N, 128, 32, 32]  
                out_channels=128,  
                kernel_size=(4, 4),  
                stride=(2, 2),  
                padding=(1, 1),  
                bias=False),  
            nn.BatchNorm2d(128),  
            nn.ReLU(),  
  
            nn.ConvTranspose2d(  
                in_channels=128,  # [N, 3, 64, 64]  
                out_channels=parameters.data_channels,  
                kernel_size=(4, 4),  
                stride=(2, 2),  
                padding=(1, 1),  
                bias=False),  
            nn.Tanh()  # [0, 1]  
        )  
    def forward(self, latet_z):  
        z = self.projectionlayer(latet_z)  
        z_projected = z.view(-1, 1024, 4, 4)  # [N, 1024, 4, 4] NCHW  
        return self.generator(z_projected)  
  
    # 初始化参数  
    @staticmethod  
    def weights_init(layer):  
        layer_class_name = layer.__class__.__name__  
        if 'Conv' in layer_class_name:  # 卷积层初始化方法  
            nn.init.normal_(layer.weight.data, 0.0, 0.02)  
        elif 'BatchNorm' in layer_class_name:  # BatchNorm初始化方法  
            nn.init.normal_(layer.weight.data, 1.0, 0.02)  
            nn.init.normal_(layer.bias.data, 0.)  
  
  
if __name__ == '__main__':  
    z = torch.randn(size=(64, 100))  
    G = Generator()  
    g_out = G(z)  
    print(g_out.size())

判别器

import torch  
import torch.nn as nn  
  
from Parameteres import parameters  
  
class Discriminator(nn.Module):  
    def __init__(self):  
        super(Discriminator, self).__init__()  
        self.discriminator = nn.Sequential(  
            nn.Conv2d(  
                in_channels=parameters.data_channels,  # [N, 16, 32, 32]  
                out_channels=16,  
                kernel_size=(3, 3),  
                stride=(2, 2),  
                padding=(1, 1),  
                bias=False),  
            nn.LeakyReLU(0.2),  
  
            nn.Conv2d(  
                in_channels=16,  # [N, 32, 16, 16]  
                out_channels=32,  
                kernel_size=(3, 3),  
                stride=(2, 2),  
                padding=(1, 1),  
                bias=False),  
            nn.BatchNorm2d(32),  
            nn.LeakyReLU(0.2),  
  
            nn.Conv2d(  
                in_channels=32,  # [N, 64, 8, 8]  
                out_channels=64,  
                kernel_size=(3, 3),  
                stride=(2, 2),  
                padding=(1, 1),  
                bias=False),  
            nn.BatchNorm2d(64),  
            nn.LeakyReLU(0.2),  
  
            nn.Conv2d(  
                in_channels=64,  # [N, 128, 4, 4]  
                out_channels=128,  
                kernel_size=(3, 3),  
                stride=(2, 2),  
                padding=(1, 1),  
                bias=False),  
            nn.BatchNorm2d(128),  
            nn.LeakyReLU(0.2),  
  
            nn.Conv2d(  
                in_channels=128,  # [N, 256, 2, 2]  
                out_channels=256,  
                kernel_size=(3, 3),  
                stride=(2, 2),  
                padding=(1, 1),  
                bias=False),  
            nn.BatchNorm2d(256),  
            nn.LeakyReLU(0.2),  
        )  
        self.linear = nn.Linear(256*2*2, 1)  
        self.out_ac = nn.Sigmoid()  
  
    def forward(self, image):  
        out_d = self.discriminator(image)  
        out_d = out_d.view(-1, 256*2*2)  
        out_d = self.linear(out_d)  
        out = self.out_ac(out_d)  
  
        return out  
  
    # 初始化参数  
    @staticmethod  
    def weights_init(layer):  
        layer_class_name = layer.__class__.__name__  
        if 'Conv' in layer_class_name:  # 卷积层初始化方法  
            nn.init.normal_(layer.weight.data, 0.0, 0.02)  
        elif 'BatchNorm' in layer_class_name:  # BatchNorm初始化方法  
            nn.init.normal_(layer.weight.data, 1.0, 0.02)  
            nn.init.normal_(layer.bias.data, 0.)

(4)训练脚本

DCGAN训练过程和最原始的GAN一样,如下,先训练判别器再训练生成器

在这里插入图片描述

代码如下

import os  
import torch  
import numpy as np  
import torch.nn as nn  
from tensorboardX import SummaryWriter  
from model_generator import Generator  
from model_discriminator import Discriminator  
import torchvision  
  
from Parameteres import parameters  
from MyDataSet import data_loader, invtrans  
  
logger = SummaryWriter('./log')  
  
  
# 训练  
def train():  
    # 模型初始化  
    G = Generator()  # 生成器  
    G.apply(G.weights_init)  
    D = Discriminator()  # 判别器  
    D.apply(D.weights_init)  
    G.to(parameters.device)  
    D.to(parameters.device)  
  
    # BCE损失函数  
    loss_function = nn.BCELoss()  
  
    # 优化器(两个)  
    optimizer_g = torch.optim.Adam(G.parameters(), lr=parameters.init_lr, betas=(parameters.beta, 0.999))  
    optimizer_d = torch.optim.Adam(D.parameters(), lr=parameters.init_lr, betas=(parameters.beta, 0.999))  
  
    # 训练步数  
    step = 0  
  
    # 训练标志  
    G.train()  
    D.train()  
  
    # 生成64×100的高斯分布数据,用于最后生成图片  
    fixed_latent_z = torch.randn(size=(64, 100), device=parameters.device)  
  
    # 主循环  
    for epoch in range(0, parameters.epochs):  
        print("-----------当前epoch:{}-----------".format(epoch)) # [N, 3, 64, 64]  
        for batch, _ in data_loader:  
            """  
                先更新D:log(D(x)) + log(1-D(G(z)))  
            """            optimizer_d.zero_grad()  
            # 真实人脸鉴别  
            true_face = torch.full(size=(64, ), fill_value=0.9, dtype=torch.float, device=parameters.device)  
            predict_true_face = D(batch.to(parameters.device)).squeeze()  
            loss_d_of_true_face = loss_function(predict_true_face, true_face)  
  
            # 假人脸鉴别  
            fake_face = torch.full(size=(64, ), fill_value=0.1, dtype=torch.float, device=parameters.device)  
            latent_z = torch.randn(size=(64, 100), device=parameters.device)  
            predict_fake_face = D(G(latent_z)).squeeze()  # G生成假人脸  
            loss_d_of_fake_face = loss_function(predict_fake_face, fake_face)  
  
            # 两部分加和  
            loss_D = loss_d_of_true_face + loss_d_of_fake_face  
            loss_D.backward()  
            optimizer_d.step()  
  
            logger.add_scalar('loSS/D', loss_D.mean().item(), step)  # 有64个loss,使用均值  
  
            """  
                再更新G:log(1-D(G(z)))  
            """            optimizer_g.zero_grad()  
            latent_z = torch.randn(size=[64, 100], device=parameters.device)  
            # 生成器要生成“真”数据尽可能瞒过判别器  
            true_face_of_g = torch.full(size=(64, ), fill_value=0.9, dtype=torch.float, device=parameters.device)  
            predict_true_face_of_g = D(G(latent_z)).squeeze()  
  
            loss_G = loss_function(predict_true_face_of_g, true_face_of_g)  
            loss_G.backward()  
            optimizer_g.step()  
  
            logger.add_scalar('loss/G', loss_G.mean().item(), step)  
  
            if not step % parameters.verbose_step: #  每250步保存一张8×8图片  
                print("第{}步".format(step))  
                with torch.no_grad():  
                    fake_image = G(fixed_latent_z)  
                    fake_image = invtrans(fake_image)  
                    torchvision.utils.save_image(fake_image, "./img_save/face_step{}.png".format(step), nrow=8)  
  
  
            step += 1  
            logger.flush()  
  
    logger.close()  
  
  
if __name__ == '__main__':  
    if parameters.device == 'cuda':  
        print("GPU上训练")  
    else:  
        print("CPU上训练")  
    train()  
    # 训练完成后关机  
    os.system("shutdown")

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/338499.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kafka 副本

kafka 副本的基本信息 kafka副本作用提高数据可靠性kafka副本个数默认1个,生产环境中一般配置为2个,保证数据可靠性;但是过多的副本会增加磁盘存储空间、增加网络数据传输、降低kafka效率。kafka副本角色副本角色分为Leader和Follower。kafk…

【算法基础】前缀和与差分

😽PREFACE🎁欢迎各位→点赞👍 收藏⭐ 评论📝📢系列专栏:算法💪种一棵树最好是十年前其次是现在1.什么是前缀和前缀和指一个数组的某下标之前的所有数组元素的和(包含其自身&#x…

初学Docker

Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。 容器是完全使用沙箱机制&…

Linux内核启动(3,0.11版本)内核启动完成与进入内核main函数

这一部分是在讲解head.s代码,这个代码与bootsect.s和setup.s在同一目录下,但是head.s程序在被编译生成目标文件后会与内核其他程序一起被链接成system模块,位于system模块的最前面开始部分。system模块将被放置在磁盘上setup模块之后开始的扇…

论文阅读:《Evidence for a fundamental property of steering》

文章目录1 背景2 方法2.1 方向盘修正行为标识2.2 数据2.3 数据拟合3 结果3.1 速率曲线3.2 恒定的转向时间3.3 基本运动元素的叠加3.4 其他实验4 讨论5 总结(个人)1 背景 这篇短文的主要目的是去阐述“转方向盘”这一行为的基本性质:方向盘修正…

人大金仓数据库索引的应用与日常运维

索引的应用 一、常见索引及适应场景 BTREE索引 是KES默认索引,采用B树实现。 适用场景 范围查询和优化排序操作。 不支持特别长的字段。 HASH索引 先对索引列计算一个散列值(类似md5、sha1、crc32),然后对这个散列值以顺序…

SpringBoot+Vue实现师生健康信息管理系统

文末获取源码 开发语言:Java 框架:springboot JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7/8.0 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven包:Maven3.3.9 浏…

第二章-线程(3)

线程一、线程的定义二、线程的实现一、线程的定义 线程: 线程是进程中的一个实体,是系统独立调度和分派的基本单位。 进程是资源的拥有者,线程是系统独立调度和分配的基本单位。 进程与线程的比较: 调度:线程调度快…

Python 的Tkinter包系列之七:好例子补充2

Python 的Tkinter包系列之七:好例子补充2 英汉字典(使用文本文件记录英语单词和解释)、简单的通信录(使用SQLite数据库记录人员信息) 一、tkinter编写英汉字典 先看效果图: 词典文件是一个文本文件&…

python自动发送邮件实现

目录1 前言2 准备工作2.1 电子邮件的基础知识。2.2 python邮件库2.3 邮箱设置3 python实现邮件自动发送3.1 SMTP()和send()方法介绍3.2 python实现实例参考信息1 前言 python功能强大,可以实现我们日常办公的很多任务。诸如批量处理word,excel,pdf等等文件&#xf…

事务基础知识与执行计划

事务基础知识 数据库事务的概念 数据库事务是什么? 事务是一组原子性的SQL操作。事务由事务开始与事务结束之间执行的全部数据库操作组成。A(原子性)、(C一致性)、I(隔离性)、D(持久…

1625_MIT 6.828 stabs文档信息整理_下

全部学习汇总: GreyZhang/g_unix: some basic learning about unix operating system. (github.com) 继续之前的学习笔记,整理一下最近看过的一点stabs资料。 这一页中有一半的信息是Fortran专用的,直接跳过。参数的符号修饰符是p&#xff0c…

【webpack】webpack 中的插件安装与使用

一、webpack 插件的作用 通过安装和配置第三方的插件,可以拓展 webpack 的能力,从而让 webpack 用起来更方便。最常用的 的webpack 插件有如下两个: 1.webpack-dev-server(实时打包构建) 类似于 node.js 阶段用到的 no…

为什么说网络安全是风口行业?

前言 “没有网络安全就没有国家安全”。当前,网络安全已被提升到国家战略的高度,成为影响国家安全、社会稳定至关重要的因素之一。 网络安全行业特点 1、就业薪资非常高,涨薪快 2021年猎聘网发布网络安全行业就业薪资行业最高人均33.77万&…

Django框架之模型

模型 当前项目的开发, 都是数据驱动的。 以下为书籍信息管理的数据关系:书籍和人物是 :一对多关系 要先分析出项目中所需要的数据, 然后设计数据库表. 书籍信息表 字段名字段类型字段说明idAutoField主键nameCharField书名 idname1西游记2三国演义…

SpringMVC中遇到的错误

SpringMVC中遇到的错误1.web.xml中配置SpringMVC核心类: DispatcherServlet 报错解决方案:添加Tomcat包2. not declaration can be found for element--------‘mvc:annotation-driven‘通配符的匹配很全面, 但无法找到元素 mvc:annotation-driven 的声明解决方案&a…

雅思经验(9)之小作文常用词汇总结

写作:关于趋势的上升和下降在小作文中,真的是非常常见的,所以还是要积累一下。下面给出了很多词,但是在雅思写作中并不是词越丰富,分数就越高的。雅思写作强调的是准确性:在合适的地方用合适的词和句法。不…

Python+Go实践(电商架构三)

文章目录服务发现集成consul负载均衡负载均衡算法实现配置中心nacos服务发现 我们之前的架构是通过ipport来调用的python的API,这样做的弊端是 如果新加一个服务,就要到某个服务改web(go)层的调用代码,配置IP/Port并发…

8年软件测试工程师经验感悟

不知不觉在软件测试行业,野蛮生长了8年之久。这一路上拥有了非常多的感受。有迷茫,有踩过坑,有付出有收获, 有坚持! 我一直都在软件测试行业奋战, 毕业时一起入职的好友已经公司内部转岗,去选择…

理论七:为何说要多用组合少用继承?如何决定该用组合还是继承?

在面向对象编程中、有一条非常经典的设计原则,那就是:组合优于继承,多用组合少用继承。为什么不推荐使用继承?组合相比继承有哪些优势?如何判断该用组合还是继承?今天,我们就围绕着这三个问题,来…