深度学习-DRGAN对抗神经网络生成动漫头像

mac2024-05-26  36

动漫头像素材,项目中新建data文件夹放进去

        具体思路是,生成器是将一个噪点生成一副假图片,然后将假图片传给判别器进行判断,如果判别器判断为真,则代码生成器性能很好,而判别器是从真实图片中学习模型,对生成的假图片进行判断,如果判断出来为假则代码判别器性能很好。

关于代码的具体注释已经写上,需要单独开博客讲的内容在前几篇博客里写了,直接上代码吧:

train.py主运行页面:

import argparse import torch import torchvision import torchvision.utils as vutils import torch.nn as nn from model import NetD, NetG # 定义是否使用GPU device = torch.device("cuda" if torch.cuda.is_available() else "cpu") #判断是否能用GPU # 图像读入与预处理 transforms = torchvision.transforms.Compose([ torchvision.transforms.Resize(96), #处理图像尺寸,短边变为96,长边对应比例缩放 torchvision.transforms.ToTensor(), #数据集加载时,默认的图片格式是 numpy,所以通过 transforms 转换成 Tensor,图像范围[0, 255] -> [0.0,1.0] torchvision.transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)), ]) #使用公式进行归一化channel=(channel-mean)/std,因为transforms.ToTensor()已经把数据处理成[0,1],那么(x-0.5)/0.5就是[-1.0, 1.0] dataset = torchvision.datasets.ImageFolder('data/', transform=transforms) dataloader = torch.utils.data.DataLoader( dataset=dataset, batch_size=64, #因为需要生成包含64张小图的大图片,所以把64定位一个批度 shuffle=True, drop_last=True, #如何处理数据集长度除于batch_size余下的数据。True就抛弃,否则保留 ) netG = NetG(64, 100).to(device) #操作过程中通道数都是64的倍数,最后由64一下子变为3,100是噪声维度,噪声用来生成假图片 netD = NetD(64).to(device) #操作过程中通道数都是64的倍数,最后由64一下子变为1 criterion = nn.BCELoss() #用于二分类 optimizerG = torch.optim.Adam(netG.parameters(), lr=0.0002, betas=(0.5, 0.999)) #生成器的优化器 optimizerD = torch.optim.Adam(netD.parameters(), lr=0.0002, betas=(0.5, 0.999)) #判别器的优化器 label = torch.FloatTensor(64) #创建一个元素个数为64的tensor标签,随机赋值 real_label = 1 #真图片标签为1 fake_label = 0 #假图片标签为0 for epoch in range(1, 25 + 1): for i, (imgs, _) in enumerate(dataloader): # 固定生成器G,训练鉴别器D(判别器的好坏要通过是否能判断出假图片来体现) optimizerD.zero_grad() #判别器优化器梯度全部降为0 ## 让D尽可能的把真图片判别为1 imgs = imgs.to(device) #将图片数据copy一份到device指定的GPU上去 output = netD(imgs) #判别器输出 label.data.fill_(real_label) #标签全部改为1,一开始判断真实图片 label = label.to(device) #将labelcopy放入GPU output=output.squeeze() #output.shape为(64,1,1,1)维度,label为(64),这一句是将output中所有维度为一的去掉,不加这一句运行不会出错,但是会有警告 errD_real = criterion(output, label) #计算判断真实图片的损失值 errD_real.backward() #反向传播 ## 让D尽可能把假图片判别为0 label.data.fill_(fake_label) #标签全部改为0,一开始假图片 noise = torch.randn(64, 100, 1, 1) #随机生成64个噪点,每个噪点维度为(100,1,1) noise = noise.to(device) #将噪点放入GPU fake = netG(noise) # 生成假图 output = netD(fake.detach()) # 使用判别器对一个批次假图片进行分类 output=output.squeeze() errD_fake = criterion(output, label) #计算判断假图片为假的损失值 errD_fake.backward() #反向传播 errD = errD_fake + errD_real #判断真图片和判断假图片的损失值加和作为总损失 optimizerD.step() #对判别器进行优化 # 固定鉴别器D,训练生成器G(生成器性能的好坏要通过判别器是否判断为真来体现) optimizerG.zero_grad() #生成器梯度全部降为0 # 让D尽可能把G生成的假图判别为1 label.data.fill_(real_label) #标签全部改为1,一开始判断真实图片 label = label.to(device) output = netD(fake) #判别刚才生成的假图片 output=output.squeeze() errG = criterion(output, label) #计算判断假图片为真的损失值 errG.backward() #反向传播 optimizerG.step() #对生成器进行优化 print('[%d/%d][%d/%d] Loss_D: %.3f Loss_G %.3f' % (epoch, 25, i, len(dataloader), errD.item(), errG.item())) vutils.save_image(fake.data, '%s/fake_samples_epoch_%03d.png' % ('imgs/', epoch), #保存图像 normalize=True)

model.py模型结构页面:

import torch.nn as nn # 定义生成器网络G,从噪声中生成一张彩色图片 class NetG(nn.Module): #注意这里图片都是四维,第一维都是批度64,为了方便将第一个省去 def __init__(self, ngf, nz): #操作过程中通道数都是ngf的倍数,最后由ngf一下子变为3,nz是噪点维度,噪声用来生成假图片 super(NetG, self).__init__() # layer1输入的是一个100x1x1的随机噪声, 输出尺寸(ngf*8)x4x4 self.layer1 = nn.Sequential( #(100,1,1)-->(64*8,4,4) nn.ConvTranspose2d(nz, ngf * 8, kernel_size=4, stride=1, padding=0, bias=False), #o=(i-1)*s-2*p+k nn.BatchNorm2d(ngf * 8), #参数为输出通道数 nn.ReLU(inplace=True) #implace=True是原地操作,直接替换掉以前的变量,比如x=x+5 ) # layer2输出尺寸(ngf*4)x8x8 self.layer2 = nn.Sequential( #(64*8,4,4)-->(64*4,8,8) nn.ConvTranspose2d(ngf * 8, ngf * 4, 4, 2, 1, bias=False), nn.BatchNorm2d(ngf * 4), nn.ReLU(inplace=True) ) # layer3输出尺寸(ngf*2)x16x16 self.layer3 = nn.Sequential( #(64*4,8,8)-->(64*2,16,16) nn.ConvTranspose2d(ngf * 4, ngf * 2, 4, 2, 1, bias=False), nn.BatchNorm2d(ngf * 2), nn.ReLU(inplace=True) ) # layer4输出尺寸(ngf)x32x32 self.layer4 = nn.Sequential( #(64*2,16,16)-->(64,32,32) nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 1, bias=False), nn.BatchNorm2d(ngf), nn.ReLU(inplace=True) ) # layer5输出尺寸 3x96x96 self.layer5 = nn.Sequential( #(64,32,32)-->(3,96,96) nn.ConvTranspose2d(ngf, 3, 5, 3, 1, bias=False), nn.Tanh() ) # 定义NetG的前向传播 def forward(self, x): out = self.layer1(x) out = self.layer2(out) out = self.layer3(out) out = self.layer4(out) out = self.layer5(out) return out # 定义鉴别器网络D class NetD(nn.Module): def __init__(self, ndf): #操作过程中图片的通道数一直是ndf的倍数 super(NetD, self).__init__() # layer1 输入 3 x 96 x 96, 输出 (ndf) x 32 x 32 self.layer1 = nn.Sequential( #(3,96,96)-->(64,32,32) nn.Conv2d(3, ndf, kernel_size=5, stride=3, padding=1, bias=False), nn.BatchNorm2d(ndf), nn.LeakyReLU(0.2, inplace=True) #relu中f=maxy(0,x),而leakyrelu中f=x>0?x:ax(a=栏目大) ) # layer2 输出 (ndf*2) x 16 x 16 self.layer2 = nn.Sequential( #(64,32,32)-->(128,16,16) nn.Conv2d(ndf, ndf * 2, 4, 2, 1, bias=False), nn.BatchNorm2d(ndf * 2), nn.LeakyReLU(0.2, inplace=True) ) # layer3 输出 (ndf*4) x 8 x 8 self.layer3 = nn.Sequential( #(128,16,16)-->(256,8,8) nn.Conv2d(ndf * 2, ndf * 4, 4, 2, 1, bias=False), nn.BatchNorm2d(ndf * 4), nn.LeakyReLU(0.2, inplace=True) ) # layer4 输出 (ndf*8) x 4 x 4 self.layer4 = nn.Sequential( #(256,8,8)-->(512,4,4) nn.Conv2d(ndf * 4, ndf * 8, 4, 2, 1, bias=False), nn.BatchNorm2d(ndf * 8), nn.LeakyReLU(0.2, inplace=True) ) # layer5 输出一个数(概率) self.layer5 = nn.Sequential( #(512,4,4)-->(1,1,1) nn.Conv2d(ndf * 8, 1, 4, 1, 0, bias=False), nn.Sigmoid() ) # 定义NetD的前向传播 def forward(self,x): out = self.layer1(x) out = self.layer2(out) out = self.layer3(out) out = self.layer4(out) out = self.layer5(out) return out

 

生成的假图片:

epoch=1:

epoch=10:

epoch=20:

最新回复(0)