有趣的图像生成——使用DCGAN与pytorch生成动漫头像

文章目录

  • 有趣的图像生成——使用DCGAN与pytorch生成动漫头像
    • 一、源码下载
    • 二、什么是DCGAN
    • 三、DCGAN的实现
      • 1、**数据集的选择**
      • 2、**生成器的构建**
      • 3、**判别器的构建**
      • 4、**DCGAN的训练**
    • 四、生成图片
    • 五、结论
    • 六、参考

一、源码下载

下载地址:https://gitee.com/yang_guo123/dcgan-pytorch

数据集下载地址:链接: https://pan.baidu.com/s/1PcZ4TLyqcN52096eIfbmCA 密码: auc5

二、什么是DCGAN

生成对抗网络(GAN)是由Ian Goodfellow在2014年提出的一种生成网络,它由生成器(Generator)与判别器(Discriminator)构成。

生成器:负责伪造假图片,试图以假乱真。

判别器:负责区分图片,希望能从图片中区分真实图片与假图片

在GAN的训练过程中,生成器通过凭空捏造出一幅图片,令判别器进行打分,并通过判别器的分数进行梯度更新,而判别器可以看到真实图片与生成器的伪造图片,通过区分伪造图片与真实图片进行梯度更新。

使用通俗的话来讲,生成器好比制作假冒伪劣手机的奸商,而判别器好比鉴定专家。在一开始,奸商与鉴定专家都是新手,奸商制作的山寨手机都是随机的形状,而鉴定专家也是随机判断手机的好坏;突然有一天奸商了解到手机是长方形的,由此制作的手机能够轻松骗过鉴定专家,这样一来,鉴定专家损失惨重;由于时间的积累,鉴定专家有了一定的经验,能够判定山寨手机的一些特征,则奸商损失惨重,由此这样多轮的较量,鉴定专家能够精确的判定手机是否为赝品,而奸商也可以制作可以以假乱真的赝品手机。

在传统的GAN中,通常使用全连接神经网络,并且其难以训练,于是,在2016年Alec Radford等人提出了DCGAN(论文详见:https://arxiv.org/pdf/1511.06434.pdf),通过改进CNN的模型,将深度卷积神经网络引入GAN,并且获得了很好的效果。

由于本文主要为实践方面,理论层面就不再赘述,有兴趣的网友可以自行下载论文阅读。

三、DCGAN的实现

1、数据集的选择

本文所采用的数据集为动漫头像数据集,图像大小为96x96,由下图所示:

2、生成器的构建

DCGAN的生成器器由全卷积神经网络构成,首先在网络中输入一个长度为100的随机向量,通过多次的反卷积运算,并使用tanh激活函数输出,将随机向量变为长宽为64x64三通道图像,具体结构由下图所示:

有图可见,在每一层反卷积时,图像的通道数都会缩小一半,并在最后一层将通道数目调整为3通道,输出一张RGB图像,构建的代码由下文所示:

class Generator(nn.Module):def __init__(self, nz, nc, ngf):super(Generator, self).__init__()self.net = Sequential(nn.ConvTranspose2d(nz, ngf * 8, 4, 1, 0, bias=False),nn.BatchNorm2d(ngf * 8),nn.ReLU(inplace=True),nn.ConvTranspose2d(ngf * 8, ngf * 4, 4, 2, 1, bias=False),nn.BatchNorm2d(ngf * 4),nn.ReLU(inplace=True),nn.ConvTranspose2d(ngf * 4, ngf * 2, 4, 2, 1, bias=False),nn.BatchNorm2d(ngf * 2),nn.ReLU(inplace=True),nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 1, bias=False),nn.BatchNorm2d(ngf),nn.ReLU(inplace=True),nn.ConvTranspose2d(ngf, nc, 4, 2, 1, bias=False),nn.Tanh())def forward(self, x):return self.net(x)

3、判别器的构建

DCGAN有趣的地方在于判别器的网络结构与生成器正好是对称的,唯一有所不同的是其激活函数换成了LeakyRelu,并且输出端使用的激活函数为sigmoid,下面是判别器的代码实现:

class Discriminator(nn.Module):def __init__(self, nc, ndf):super(Discriminator, self).__init__()self.net = Sequential(nn.Conv2d(nc, ndf, 4, 2, 1, bias=False),nn.BatchNorm2d(ndf),nn.LeakyReLU(0.2, inplace=True),nn.Conv2d(ndf, ndf*2, 4, 2, 1, bias=False),nn.BatchNorm2d(ndf*2),nn.LeakyReLU(0.2, inplace=True),nn.Conv2d(ndf*2, ndf*4, 4, 2, 1, bias=False),nn.BatchNorm2d(ndf*4),nn.LeakyReLU(0.2, inplace=True),nn.Conv2d(ndf*4, ndf*8, 4, 2, 1, bias=False),nn.BatchNorm2d(ndf*8),nn.LeakyReLU(0.2, inplace=True),nn.Conv2d(ndf*8, 1, 4, 1, 0, bias=False),nn.Sigmoid())def forward(self, x):return self.net(x)

4、DCGAN的训练

在训练的开始,使用pytorch自带的Detaset进行数据集的预处理与读取:

class DCGAN_dataloader(Dataset):def __init__(self, csv_path, transforms=None):super(DCGAN_dataloader, self).__init__()self.transforms = transformsself.data = pd.read_csv(csv_path)def __getitem__(self, item):img_path = self.data["img"][item]img = Image.open(img_path).convert("RGB")img = self.transforms(img)return imgdef __len__(self):return len(self.data["img"])

在这里,本文使用了一些数据增广的方法,例如随机翻转:

def transform():return transforms.Compose([transforms.Resize((64, 64)),transforms.RandomHorizontalFlip(0.3),transforms.ToTensor(),transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])])

最后通过DataLoader传入网络:

# 读取数据集
dataset = DCGAN_dataloader("./dataset/data.csv", transforms=transform())
data = DataLoader(dataset,batch_size=bach_size,shuffle=True,drop_last=True
)

在DCGAN的论文中,使用了Adam优化器,并且将β1设置为0.5(Adam的具体实现请看吴恩达深度学习教程):

# 设置生成器和判别器的优化器为Adam
optim_D = Adam(self.Discriminator.parameters(),lr=self.lr_d,betas=[0.5, 0.999]
)
optim_G = Adam(self.Generator.parameters(),lr=self.lr_g,betas=[0.5, 0.999]
)

在这里将生成器与判别器的损失函数设为二值交叉熵损失:

# 设置损失函数为二值交叉熵损失
loss_func = BCELoss()

接下来就到了正式的训练过程,由于比较复杂,就分开来讲了。

首先读取数据集,并且将真实数据喂入判别器,并将标签设置为1,令判别器通过观测真实数据进行梯度更新:

img = Variable(img)
if self.device == "cuda":img = img.cuda()# 将数据喂入Discriminator
self.Discriminator.zero_grad()
label = torch.ones((bach_size,), device=self.device)
out = self.Discriminator(img).view(-1)
errD_real = loss_func(out, label)
errD_real.backward()

然后通过生成器生成一个批次的假数据并喂入判别器,并将标签设置为0,令判别器知道这次喂入的数据为假数据:

# 使用Generator生成假数据喂入Discriminator进行判别
noise = torch.randn(bach_size, self.nz, 1, 1, device=self.device)
fake = self.Generator(noise)
label.fill_(0)
out = self.Discriminator(fake.detach()).view(-1)
errD_fake = loss_func(out, label)
errD_fake.backward()
D_G_z1 = out.mean().item()
errD = errD_fake + errD_real
loss_d += errD.item()
optim_D.step()

最后通过生成器生成一个批次的假数据并让判别器判断,通过设置标签为1,使用蒙骗过判别器的数据进行梯度更新:

# 通过Discriminator返回的数值更新Generator
self.Generator.zero_grad()
label.fill_(1)
out = self.Discriminator(fake).view(-1)
errG = loss_func(out, label)
errG.backward()
loss_g += errG.item()
optim_G.step()

以下为全部代码:

    def train(self, epoch=20, bach_size=64):"""进行训练:param epoch: epoch数值:param bach_size: batch的大小:return: None"""# 读取数据集dataset = DCGAN_dataloader("./dataset/data.csv", transforms=transform())data = DataLoader(dataset,batch_size=bach_size,shuffle=True,drop_last=True)# 设置生成器和判别器的优化器为Adamoptim_D = Adam(self.Discriminator.parameters(),lr=self.lr_d,betas=[0.5, 0.999])optim_G = Adam(self.Generator.parameters(),lr=self.lr_g,betas=[0.5, 0.999])# 设置损失函数为二值交叉熵损失loss_func = BCELoss()loss_g_log = []loss_d_log = []loss_d = 0loss_g = 0print("#" * 10 + " 开始训练 " + "#" * 10)# 开始训练with tqdm(total=epoch, desc="训练进度", postfix=dict, mininterval=0.3) as pbar:for i_epoch in range(epoch):loss_d = 0loss_g = 0for i, img in enumerate(data):img = Variable(img)if self.device == "cuda":img = img.cuda()# 将数据喂入Discriminatorself.Discriminator.zero_grad()label = torch.ones((bach_size,), device=self.device)out = self.Discriminator(img).view(-1)errD_real = loss_func(out, label)errD_real.backward()D_x = out.mean().item()# 使用Generator生成假数据喂入Discriminator进行判别noise = torch.randn(bach_size, self.nz, 1, 1, device=self.device)fake = self.Generator(noise)label.fill_(0)out = self.Discriminator(fake.detach()).view(-1)errD_fake = loss_func(out, label)errD_fake.backward()D_G_z1 = out.mean().item()errD = errD_fake + errD_realloss_d += errD.item()optim_D.step()# 通过Discriminator返回的数值更新Generatorself.Generator.zero_grad()label.fill_(1)out = self.Discriminator(fake).view(-1)errG = loss_func(out, label)errG.backward()loss_g += errG.item()optim_G.step()if i % 5 == 0:pbar.set_postfix(**{'loss_D': "{:.4f}".format(loss_d / (i + 1)),'loss_G': "{:.4f}".format(loss_g / (i + 1)),'D(x)': "{:.4f}".format(D_x),'D(G(z))': "{:.4f}".format(D_G_z1)})loss_g_log.append(loss_g / (i + 1))loss_d_log.append(loss_d / (i + 1))with torch.no_grad():img = self.Generator(torch.randn(20, self.nz, 1, 1, device=self.device)).cpu()img = (img + 1) * 127os.mkdir("./log/img_log/epoch{}".format(i_epoch))for j in range(20):img_ = np.array(img[j]).transpose((1, 2, 0))cv2.imwrite("./log/img_log/epoch{}/img{}.jpg".format(i_epoch, j), img_)pbar.update(1)torch.save(self.Generator.state_dict(),"./log/model_g/epoch{}_loss{}.pth".format(i_epoch, loss_g / len(loss_g_log)))torch.save(self.Discriminator.state_dict(),"./log/model_d/epoch{}_loss{}.pth".format(i_epoch, loss_d / len(loss_d_log)))# 清空缓存torch.cuda.empty_cache()# 保存loss日志文件loss_log = pd.DataFrame()loss_log["g_loss"] = loss_g_logloss_log["d_loss"] = loss_d_logloss_log.to_csv("./log/loss/loss.csv")

四、生成图片

在训练好GAN模型以后,需要生成图片时,只需调用生成器网络,并通过喂入一组随机数进行生成图片。值得注意的一点在于,由于生成器的最后一层通过tanh输出,输出的数据分布为[-1,1],而正常的图片像素值在0~255之间,所以要转换一下输出图片的分布:

    def generate(self, path="./img/generate.jpg"):"""生成图片:param path: 生成图片的路径:return: None"""param = torch.load(self.model_path)self.Generator.load_state_dict(param)with torch.no_grad():img = self.Generator(torch.randn(1, self.nz, 1, 1, device=self.device))img = np.array(img[0].cpu()).transpose((1, 2, 0))img = (img + 1) * 127cv2.imshow("generate", img.astype(np.uint8))cv2.waitKey(0)cv2.imwrite(path, img)

五、结论

以下为训练过程中生成的结果

epoch0:

epoch4:

epoch30:

可见,随着迭代次数的增加,生成的图像的质量越来越好了。

六、参考

  1. PyTorch教程之DCGAN_我的学习笔记-CSDN博客
  2. DCGAN Tutorial — PyTorch Tutorials 1.9.0+cu102 documentation

有趣的图像生成——使用DCGAN与pytorch生成动漫头像相关推荐

  1. DCGAN in Tensorflow生成动漫人物

    引自:GAN学习指南:从原理入门到制作生成Demo 生成式对抗网络(GAN)是近年来大热的深度学习模型.最近正好有空看了这方面的一些论文,跑了一个GAN的代码,于是写了这篇文章来介绍一下GAN. 本文 ...

  2. numpy,pytorch生成随机数,随机分布总结

    在我们的平时的项目中,经常会用到生成随机数的方法.比如交叉验证中,随机采集的设置.在本文中将主要基于numpy常见的生成随机数方法和pytorch生成的随机数方法进行总结,并会分析随机种子对结果的影响 ...

  3. AI一分钟就能生成个性动漫头像?分享一个超好用的AI卡通头像生成器

    你是否常常在社交媒体或短视频平台上看到一些精美的卡通风格头像,但是找遍全网都找不到完全相同的,其实这些动漫卡通风格的头像大多都是利用AI绘制的,不仅精美漂亮而且独一无二,不会与其他人的头像重复,所以今 ...

  4. vs2019 利用Pytorch和TensorFlow分别实现DCGAN生成动漫头像

    这是针对于博客vs2019安装和使用教程(详细)的DCGAN生成动漫头像项目新建示例 目录 一.DCGAN架构及原理 二.项目结构 1.TensorFlow 2.Pytorch 三.数据集下载(两种方 ...

  5. 【Pytorch】DCGAN实战(三):二次元动漫头像生成

    文章目录 1.实现效果 2.环境配置 2.1Python 2.2Pytorch.CUDA 2.3Python IDE 3.具体实现 3.1数据预处理(data.py) (1)导入包 (2)定义数据类 ...

  6. 深度有趣 | 08 DCGAN人脸图片生成

    简介 在人脸数据上训练DCGAN,并生成一些人脸图片 数据 使用两个数据集 LFW:http://vis-www.cs.umass.edu/lfw/,Labeled Faces in the Wild ...

  7. pytorch:DCGAN生成动漫头像

    动漫头像数据集下载地址:动漫头像数据集_百度云连接,DCGAN论文下载地址: https://arxiv.org/abs/1511.06434 数据集里面的图片是这个样子的: 这是DCGAN的主要改进 ...

  8. 通过PyTorch用DCGAN生成动漫头像

    数据集 数据集我们用AnimeFaces数据集,共5万多张动漫头像. 链接:https://pan.baidu.com/s/1cp-A8ZV74YBelkSuKxuM6A 提取码:face 要把所有的 ...

  9. DCGAN——深度卷积生成对抗网络

    译文 | 让深度卷积网络对抗:DCGAN--深度卷积生成对抗网络 原文: https://arxiv.org/pdf/1511.06434.pdf -- 前言:如何把CNN与GAN结合?DCGAN是这 ...

最新文章

  1. java日历教程_JAVA Calendar方法使用基础教程详解
  2. 【JAVASCRIPT】无刷新评论
  3. CF1200D-White Lines【二维前缀和】
  4. 29、jdbc操作数据库(6)
  5. 在应用程序级别以外使用注册为 allowDefinition='MachineToApplication' 的节是错误
  6. [密码学基础][每个信息安全博士生应该知道的52件事][Bristol52]43 为AES 对抗侧信道攻击的防御
  7. protel99se进阶视频教程(手把手教你画51单片机开发板)
  8. 后端使用thymeleaf模板生成页面转pdf,结果客户现场中文不显示
  9. 内存泄漏导致的浏览器崩溃
  10. 如何提高文字和配图的整体性?总监送你7个实用方法
  11. 渗透学习日记day15
  12. mysql left join含义_left join是什么意思
  13. 以网游服务端的网络接入层设计为例,理解实时通信的技术挑战
  14. 【Java】函数式接口
  15. 服务端渲染VUE_SSR
  16. 360和360极速浏览器无法打开vue项目的问题
  17. 浅谈我眼中的“服务意识”
  18. pdf 转 word 软件
  19. javascript原生—悬浮导航栏
  20. 智能集群理论优化控制_深度解析【智能集群控制技术】到底多硬核?

热门文章

  1. 康佳 android 电视,康佳Android智能电视面世
  2. 未来计算机在现实世界的应用,计算机图形学:虚拟和现实世界的融合
  3. 手保守教你使用All in one seo
  4. MRT115 热电堆温度传感器
  5. UI设计素材,聪明的设计师关注字体的运用
  6. Python爬虫:煎蛋网图片URL解密处理
  7. 社区智慧警务系统建设技术方案
  8. Kubernetes笔记(九) Kubernetes 应用封装与扩展
  9. 如果是你话,跳还是不跳?
  10. 石家庄铁道大学计算机专业好找工作吗,大学“最让人头痛”的9个专业,但毕业后含金量高,就业形势好...