成都可以做网站的公司,网站模板制作教程视频,云南建设厅网站备案厂家,徐州网站建设哪家好1 条件GAN前置知识
条件GAN也可以使GAN所生成的数据可控#xff0c;使模型变得实用#xff0c;
1.1 实验描述
搭建条件GAN模型#xff0c;实现向模型中输入标签#xff0c;并使其生成与标签类别对应的模拟数据的功能#xff0c;基于WGAN-gp模型改造实现带有条件的wGAN-…
1 条件GAN前置知识
条件GAN也可以使GAN所生成的数据可控使模型变得实用
1.1 实验描述
搭建条件GAN模型实现向模型中输入标签并使其生成与标签类别对应的模拟数据的功能基于WGAN-gp模型改造实现带有条件的wGAN-gp模型。
2 实例代码编写
条件GAN与条件自编码神经网络的做法几乎一样在GAN的基础之上为每个模型输入都添加一个标签向量。
2.1 代码实战引入模块并载入样本----WGAN_cond_237.py第1部分
import torch
import torchvision
from torchvision import transforms
from torch.utils.data import DataLoader
from torch import nn
import torch.autograd as autograd
import matplotlib.pyplot as plt
import numpy as np
import matplotlib
import os
os.environ[KMP_DUPLICATE_LIB_OK]TRUE# 1.1 引入模块并载入样本:定义基本函数加载FashionMNIST数据集
def to_img(x):x 0.5 * (x1)x x.clamp(0,1)x x.view(x.size(0),1,28,28)return xdef imshow(img,filename None):npimg img.numpy()plt.axis(off)array np.transpose(npimg,(1,2,0))if filename ! None:matplotlib.image.imsave(filename,array)else:plt.imshow(array)# plt.savefig(filename) # 保存图片 注释掉因为会报错暂时不知道什么原因 2022.3.26 15:20plt.show()img_transform transforms.Compose([transforms.ToTensor(),transforms.Normalize(mean[0.5],std[0.5])]
)data_dir ./fashion_mnisttrain_dataset torchvision.datasets.FashionMNIST(data_dir,trainTrue,transformimg_transform,downloadTrue)
train_loader DataLoader(train_dataset,batch_size1024,shuffleTrue)
# 测试数据集
val_dataset torchvision.datasets.FashionMNIST(data_dir,trainFalse,transformimg_transform)
test_loader DataLoader(val_dataset,batch_size10,shuffleFalse)
# 指定设备
device torch.device(cuda:0 if torch.cuda.is_available() else cpu)
print(device)
2.2 代码实战实现生成器和判别器----WGAN_cond_237.py第2部分
# 1.2 实现生成器和判别器 因为复杂部分都放在loss值的计算方面了所以生成器和判别器就会简单一些。
# 生成器和判别器各自有两个卷积和两个全连接层。生成器最终输出与输入图片相同维度的数据作为模拟样本。
# 判别器的输出不需要有激活函数并且输出维度为1的数值用来表示结果。
# 在GAN模型中因判别器的输入则是具体的样本数据要区分每个数据的分布特征所以判别器使用实例归一化
class WGAN_D(nn.Module): # 定义判别器类D 有两个卷积和两个全连接层def __init__(self,inputch1):super(WGAN_D, self).__init__()self.conv1 nn.Sequential(nn.Conv2d(inputch,64,4,2,1), # 输出形状为[batch,64,28,28]nn.LeakyReLU(0.2,True),nn.InstanceNorm2d(64,affineTrue))self.conv2 nn.Sequential(nn.Conv2d(64,128,4,2,1),# 输出形状为[batch,64,14,14]nn.LeakyReLU(0.2,True),nn.InstanceNorm2d(128,affineTrue))self.fc nn.Sequential(nn.Linear(128*7*7,1024),nn.LeakyReLU(0.2,True))self.fc2 nn.Sequential(nn.InstanceNorm1d(1,affineTrue),nn.Flatten(),nn.Linear(1024,1))def forward(self,x,*arg): # 正向传播x self.conv1(x)x self.conv2(x)x x.view(x.size(0),-1)x self.fc(x)x x.reshape(x.size(0),1,-1)x self.fc2(x)return x.view(-1,1).squeeze(1)# 在GAN模型中因生成器的初始输入是随机值所以生成器使用批量归一化。
class WGAN_G(nn.Module): # 定义生成器类G有两个卷积和两个全连接层def __init__(self,input_size,input_n1):super(WGAN_G, self).__init__()self.fc1 nn.Sequential(nn.Linear(input_size * input_n,1024),nn.ReLU(True),nn.BatchNorm1d(1024))self.fc2 nn.Sequential(nn.Linear(1024,7*7*128),nn.ReLU(True),nn.BatchNorm1d(7*7*128))self.upsample1 nn.Sequential(nn.ConvTranspose2d(128,64,4,2,padding1,biasFalse), # 输出形状为[batch,64,14,14]nn.ReLU(True),nn.BatchNorm2d(64))self.upsample2 nn.Sequential(nn.ConvTranspose2d(64,1,4,2,padding1,biasFalse), # 输出形状为[batch,64,28,28]nn.Tanh())def forward(self,x,*arg): # 正向传播x self.fc1(x)x self.fc2(x)x x.view(x.size(0),128,7,7)x self.upsample1(x)img self.upsample2(x)return img
2.3 代码实战定义函数完成梯度惩罚项----WGAN_cond_237.py第3部分
# 1.3 定义函数compute_gradient_penalty()完成梯度惩罚项
# 惩罚项的样本X_inter由一部分Pg分布和一部分Pr分布组成同时对D(X_inter)求梯度并计算梯度与1的平方差最终得到gradient_penalties
lambda_gp 10
# 计算梯度惩罚项
def compute_gradient_penalty(D,real_samples,fake_samples,y_one_hot):# 获取一个随机数作为真假样本的采样比例eps torch.FloatTensor(real_samples.size(0),1,1,1).uniform_(0,1).to(device)# 按照eps比例生成真假样本采样值X_interX_inter (eps * real_samples ((1-eps)*fake_samples)).requires_grad_(True)d_interpolates D(X_inter,y_one_hot)fake torch.full((real_samples.size(0),),1,devicedevice) # 计算梯度输出的掩码在本例中需要对所有梯度进行计算故需要按照样本个数生成全为1的张量。# 求梯度gradients autograd.grad(outputsd_interpolates, # 输出值outputs传入计算过的张量结果inputsX_inter,# 待求梯度的输入值inputs传入可导的张量即requires_gradTruegrad_outputsfake, # 传出梯度的掩码grad_outputs使用1和0组成的掩码在计算梯度之后会将求导结果与该掩码进行相乘得到最终结果。create_graphTrue,retain_graphTrue,only_inputsTrue)[0]gradients gradients.view(gradients.size(0),-1)gradient_penaltys ((gradients.norm(2, dim1) - 1) ** 2).mean() * lambda_gpreturn gradient_penaltys
2.4 代码实战定义模型的训练函数----WGAN_cond_237.py第4部分
# 1.4 定义模型的训练函数
# 定义函数train()实现模型的训练过程。
# 在函数train()中按照对抗神经网络专题一中的式8-24实现模型的损失函数。
# 判别器的loss为D(fake_samples)-D(real_samples)再加上联合分布样本的梯度惩罚项gradient_penalties其中fake_samples为生成的模拟数据real_Samples为真实数据
# 生成器的loss为-D(fake_samples)。
def train(D,G,outdir,z_dimension,num_epochs30):d_optimizer torch.optim.Adam(D.parameters(),lr0.001) # 定义优化器g_optimizer torch.optim.Adam(G.parameters(),lr0.001)os.makedirs(outdir,exist_okTrue) # 创建输出文件夹# 在函数train()中判别器和生成器是分开训练的。让判别器学习的次数多一些判别器每训练5次生成器优化1次。# WGAN_gp不会因为判别器准确率太高而引起生成器梯度消失的问题所以好的判别器会让生成器有更好的模拟效果。for epoch in range(num_epochs):for i,(img,lab) in enumerate(train_loader):num_img img.size(0)# 训练判别器real_img img.to(device)y_one_hot torch.zeros(lab.shape[0],10).scatter_(1,lab.view(lab.shape[0],1),1).to(device)for ii in range(5): # 循环训练5次d_optimizer.zero_grad() # 梯度清零# 对real_img进行判别real_out D(real_img,y_one_hot)# 生成随机值z torch.randn(num_img,z_dimension).to(device)fake_img G(z,y_one_hot) # 生成fake_imgfake_out D(fake_img,y_one_hot) # 对fake_img进行判别# 计算梯度惩罚项gradient_penalty compute_gradient_penalty(D,real_img.data,fake_img.data,y_one_hot)# 计算判别器的lossd_loss -torch.mean(real_out)torch.mean(fake_out)gradient_penaltyd_loss.backward()d_optimizer.step()# 训练生成器for ii in range(1): # 训练一次g_optimizer.zero_grad() # 梯度清0z torch.randn(num_img,z_dimension).to(device)fake_img G(z,y_one_hot)fake_out D(fake_img,y_one_hot)g_loss -torch.mean(fake_out)g_loss.backward()g_optimizer.step()# 输出可视化结果并将生成的结果以图片的形式存储在硬盘中fake_images to_img(fake_img.cpu().data)real_images to_img(real_img.cpu().data)rel torch.cat([to_img(real_images[:10]), fake_images[:10]], axis0)imshow(torchvision.utils.make_grid(rel, nrow10),os.path.join(outdir, fake_images-{}.png.format(epoch 1)))# 输出训练结果print(Epoch [{}/{}], d_loss: {:.6f}, g_loss: {:.6f} D real: {:.6f}, D fake: {:.6f}.format(epoch, num_epochs, d_loss.data, g_loss.data,real_out.data.mean(), fake_out.data.mean()))# 保存训练模型torch.save(G.state_dict(), os.path.join(outdir, generator.pth))torch.save(D.state_dict(), os.path.join(outdir, discriminator.pth))
2.5 代码实战现可视化模型结果----WGAN_cond_237.py第5部分
# 1.5 定义函数实现可视化模型结果获取一部分测试数据显示由模型生成的模拟数据。
def displayAndTest(D,G,z_dimension): # 可视化结果sample iter(test_loader)images, labels sample.next()y_one_hot torch.zeros(labels.shape[0], 10).scatter_(1,labels.view(labels.shape[0], 1), 1).to(device)num_img images.size(0) # 获取样本个数with torch.no_grad():z torch.randn(num_img, z_dimension).to(device) # 生成随机数fake_img G(z, y_one_hot)fake_images to_img(fake_img.cpu().data) # 生成模拟样本rel torch.cat([to_img(images[:10]), fake_images[:10]], axis0)imshow(torchvision.utils.make_grid(rel, nrow10))print(labels[:10])
2.6 定义判别器类CondWGAN_D----WGAN_cond_237.py
第6部分
# 1.6 定义判别器类CondWGAN_D
# 在判别器和生成器类的正向结构中增加标签向量的输入并使用全连接网络对标签向量的维度进行扩展同时将其连接到输入数据。
class CondWGAN_D(WGAN_D): # 定义判别器类CondWGAN_D使其继承自WGAN_D类。def __init__(self, inputch2):super(CondWGAN_D, self).__init__(inputch)self.labfc1 nn.Linear(10, 28 * 28)def forward(self, x, lab): # 添加输入标签batch, width, height, channel1d_in torch.cat((x.view(x.size(0), -1), self.labfc1(lab)), -1)x d_in.view(d_in.size(0), 2, 28, 28)return super(CondWGAN_D, self).forward(x, lab)
2.7 定义生成器类CondWGAN_G----WGAN_cond_237.py第7部分
# 1.7 定义生成器类CondWGAN_G
# 在判别器和生成器类的正向结构中增加标签向量的输入并使用全连接网络对标签向量的维度进行扩展同时将其连接到输入数据。
class CondWGAN_G(WGAN_G): # 定义生成器类CondWGAN_G使其继承自WGAN_G类。def __init__(self, input_size, input_n2):super(CondWGAN_G, self).__init__(input_size, input_n)self.labfc1 nn.Linear(10, input_size)def forward(self, x, lab): # 添加输入标签batch, width, height, channel1d_in torch.cat((x, self.labfc1(lab)), -1)return super(CondWGAN_G, self).forward(d_in, lab)
2.8 调用函数并训练模型----WGAN_cond_237.py第6部分
# 1.8 调用函数并训练模型:实例化判别器和生成器模型并调用函数进行训练
if __name__ __main__:z_dimension 40 # 设置输入随机数的维度D CondWGAN_D().to(device) # 实例化判别器G CondWGAN_G(z_dimension).to(device) # 实例化生成器train(D, G, ./condw_img, z_dimension) # 训练模型displayAndTest(D, G, z_dimension) # 输出可视化
在训练之后模型输出了可视化结果如图所示第1行是原始样本第2行是输出的模拟样本。 同时程序也输出了图8-20中样本对应的类标签如下 tensor([9,2,1,1,6,1,4,6,5,7]) 从输出的样本中可以看到输出的模拟样本与原始样本的类别一致这表明生成器可以按照指定的标签生成模拟数据。 3 代码汇总WGAN_cond_237.py
import torch
import torchvision
from torchvision import transforms
from torch.utils.data import DataLoader
from torch import nn
import torch.autograd as autograd
import matplotlib.pyplot as plt
import numpy as np
import matplotlib
import os
os.environ[KMP_DUPLICATE_LIB_OK]TRUE# 1.1 引入模块并载入样本:定义基本函数加载FashionMNIST数据集
def to_img(x):x 0.5 * (x1)x x.clamp(0,1)x x.view(x.size(0),1,28,28)return xdef imshow(img,filename None):npimg img.numpy()plt.axis(off)array np.transpose(npimg,(1,2,0))if filename ! None:matplotlib.image.imsave(filename,array)else:plt.imshow(array)# plt.savefig(filename) # 保存图片 注释掉因为会报错暂时不知道什么原因 2022.3.26 15:20plt.show()img_transform transforms.Compose([transforms.ToTensor(),transforms.Normalize(mean[0.5],std[0.5])]
)data_dir ./fashion_mnisttrain_dataset torchvision.datasets.FashionMNIST(data_dir,trainTrue,transformimg_transform,downloadTrue)
train_loader DataLoader(train_dataset,batch_size1024,shuffleTrue)
# 测试数据集
val_dataset torchvision.datasets.FashionMNIST(data_dir,trainFalse,transformimg_transform)
test_loader DataLoader(val_dataset,batch_size10,shuffleFalse)
# 指定设备
device torch.device(cuda:0 if torch.cuda.is_available() else cpu)
print(device)# 1.2 实现生成器和判别器 因为复杂部分都放在loss值的计算方面了所以生成器和判别器就会简单一些。
# 生成器和判别器各自有两个卷积和两个全连接层。生成器最终输出与输入图片相同维度的数据作为模拟样本。
# 判别器的输出不需要有激活函数并且输出维度为1的数值用来表示结果。
# 在GAN模型中因判别器的输入则是具体的样本数据要区分每个数据的分布特征所以判别器使用实例归一化
class WGAN_D(nn.Module): # 定义判别器类D 有两个卷积和两个全连接层def __init__(self,inputch1):super(WGAN_D, self).__init__()self.conv1 nn.Sequential(nn.Conv2d(inputch,64,4,2,1), # 输出形状为[batch,64,28,28]nn.LeakyReLU(0.2,True),nn.InstanceNorm2d(64,affineTrue))self.conv2 nn.Sequential(nn.Conv2d(64,128,4,2,1),# 输出形状为[batch,64,14,14]nn.LeakyReLU(0.2,True),nn.InstanceNorm2d(128,affineTrue))self.fc nn.Sequential(nn.Linear(128*7*7,1024),nn.LeakyReLU(0.2,True))self.fc2 nn.Sequential(nn.InstanceNorm1d(1,affineTrue),nn.Flatten(),nn.Linear(1024,1))def forward(self,x,*arg): # 正向传播x self.conv1(x)x self.conv2(x)x x.view(x.size(0),-1)x self.fc(x)x x.reshape(x.size(0),1,-1)x self.fc2(x)return x.view(-1,1).squeeze(1)# 在GAN模型中因生成器的初始输入是随机值所以生成器使用批量归一化。
class WGAN_G(nn.Module): # 定义生成器类G有两个卷积和两个全连接层def __init__(self,input_size,input_n1):super(WGAN_G, self).__init__()self.fc1 nn.Sequential(nn.Linear(input_size * input_n,1024),nn.ReLU(True),nn.BatchNorm1d(1024))self.fc2 nn.Sequential(nn.Linear(1024,7*7*128),nn.ReLU(True),nn.BatchNorm1d(7*7*128))self.upsample1 nn.Sequential(nn.ConvTranspose2d(128,64,4,2,padding1,biasFalse), # 输出形状为[batch,64,14,14]nn.ReLU(True),nn.BatchNorm2d(64))self.upsample2 nn.Sequential(nn.ConvTranspose2d(64,1,4,2,padding1,biasFalse), # 输出形状为[batch,64,28,28]nn.Tanh())def forward(self,x,*arg): # 正向传播x self.fc1(x)x self.fc2(x)x x.view(x.size(0),128,7,7)x self.upsample1(x)img self.upsample2(x)return img# 1.3 定义函数compute_gradient_penalty()完成梯度惩罚项
# 惩罚项的样本X_inter由一部分Pg分布和一部分Pr分布组成同时对D(X_inter)求梯度并计算梯度与1的平方差最终得到gradient_penalties
lambda_gp 10
# 计算梯度惩罚项
def compute_gradient_penalty(D,real_samples,fake_samples,y_one_hot):# 获取一个随机数作为真假样本的采样比例eps torch.FloatTensor(real_samples.size(0),1,1,1).uniform_(0,1).to(device)# 按照eps比例生成真假样本采样值X_interX_inter (eps * real_samples ((1-eps)*fake_samples)).requires_grad_(True)d_interpolates D(X_inter,y_one_hot)fake torch.full((real_samples.size(0),),1,devicedevice) # 计算梯度输出的掩码在本例中需要对所有梯度进行计算故需要按照样本个数生成全为1的张量。# 求梯度gradients autograd.grad(outputsd_interpolates, # 输出值outputs传入计算过的张量结果inputsX_inter,# 待求梯度的输入值inputs传入可导的张量即requires_gradTruegrad_outputsfake, # 传出梯度的掩码grad_outputs使用1和0组成的掩码在计算梯度之后会将求导结果与该掩码进行相乘得到最终结果。create_graphTrue,retain_graphTrue,only_inputsTrue)[0]gradients gradients.view(gradients.size(0),-1)gradient_penaltys ((gradients.norm(2, dim1) - 1) ** 2).mean() * lambda_gpreturn gradient_penaltys# 1.4 定义模型的训练函数
# 定义函数train()实现模型的训练过程。
# 在函数train()中按照对抗神经网络专题一中的式8-24实现模型的损失函数。
# 判别器的loss为D(fake_samples)-D(real_samples)再加上联合分布样本的梯度惩罚项gradient_penalties其中fake_samples为生成的模拟数据real_Samples为真实数据
# 生成器的loss为-D(fake_samples)。
def train(D,G,outdir,z_dimension,num_epochs30):d_optimizer torch.optim.Adam(D.parameters(),lr0.001) # 定义优化器g_optimizer torch.optim.Adam(G.parameters(),lr0.001)os.makedirs(outdir,exist_okTrue) # 创建输出文件夹# 在函数train()中判别器和生成器是分开训练的。让判别器学习的次数多一些判别器每训练5次生成器优化1次。# WGAN_gp不会因为判别器准确率太高而引起生成器梯度消失的问题所以好的判别器会让生成器有更好的模拟效果。for epoch in range(num_epochs):for i,(img,lab) in enumerate(train_loader):num_img img.size(0)# 训练判别器real_img img.to(device)y_one_hot torch.zeros(lab.shape[0],10).scatter_(1,lab.view(lab.shape[0],1),1).to(device)for ii in range(5): # 循环训练5次d_optimizer.zero_grad() # 梯度清零# 对real_img进行判别real_out D(real_img,y_one_hot)# 生成随机值z torch.randn(num_img,z_dimension).to(device)fake_img G(z,y_one_hot) # 生成fake_imgfake_out D(fake_img,y_one_hot) # 对fake_img进行判别# 计算梯度惩罚项gradient_penalty compute_gradient_penalty(D,real_img.data,fake_img.data,y_one_hot)# 计算判别器的lossd_loss -torch.mean(real_out)torch.mean(fake_out)gradient_penaltyd_loss.backward()d_optimizer.step()# 训练生成器for ii in range(1): # 训练一次g_optimizer.zero_grad() # 梯度清0z torch.randn(num_img,z_dimension).to(device)fake_img G(z,y_one_hot)fake_out D(fake_img,y_one_hot)g_loss -torch.mean(fake_out)g_loss.backward()g_optimizer.step()# 输出可视化结果并将生成的结果以图片的形式存储在硬盘中fake_images to_img(fake_img.cpu().data)real_images to_img(real_img.cpu().data)rel torch.cat([to_img(real_images[:10]), fake_images[:10]], axis0)imshow(torchvision.utils.make_grid(rel, nrow10),os.path.join(outdir, fake_images-{}.png.format(epoch 1)))# 输出训练结果print(Epoch [{}/{}], d_loss: {:.6f}, g_loss: {:.6f} D real: {:.6f}, D fake: {:.6f}.format(epoch, num_epochs, d_loss.data, g_loss.data,real_out.data.mean(), fake_out.data.mean()))# 保存训练模型torch.save(G.state_dict(), os.path.join(outdir, cond_generator.pth))torch.save(D.state_dict(), os.path.join(outdir, cond_discriminator.pth))# 1.5 定义函数实现可视化模型结果获取一部分测试数据显示由模型生成的模拟数据。
def displayAndTest(D,G,z_dimension): # 可视化结果sample iter(test_loader)images, labels sample.next()y_one_hot torch.zeros(labels.shape[0], 10).scatter_(1,labels.view(labels.shape[0], 1), 1).to(device)num_img images.size(0) # 获取样本个数with torch.no_grad():z torch.randn(num_img, z_dimension).to(device) # 生成随机数fake_img G(z, y_one_hot)fake_images to_img(fake_img.cpu().data) # 生成模拟样本rel torch.cat([to_img(images[:10]), fake_images[:10]], axis0)imshow(torchvision.utils.make_grid(rel, nrow10))print(labels[:10])# 1.6 定义判别器类CondWGAN_D
# 在判别器和生成器类的正向结构中增加标签向量的输入并使用全连接网络对标签向量的维度进行扩展同时将其连接到输入数据。
class CondWGAN_D(WGAN_D): # 定义判别器类CondWGAN_D使其继承自WGAN_D类。def __init__(self, inputch2):super(CondWGAN_D, self).__init__(inputch)self.labfc1 nn.Linear(10, 28 * 28)def forward(self, x, lab): # 添加输入标签batch, width, height, channel1d_in torch.cat((x.view(x.size(0), -1), self.labfc1(lab)), -1)x d_in.view(d_in.size(0), 2, 28, 28)return super(CondWGAN_D, self).forward(x, lab)# 1.7 定义生成器类CondWGAN_G
# 在判别器和生成器类的正向结构中增加标签向量的输入并使用全连接网络对标签向量的维度进行扩展同时将其连接到输入数据。
class CondWGAN_G(WGAN_G): # 定义生成器类CondWGAN_G使其继承自WGAN_G类。def __init__(self, input_size, input_n2):super(CondWGAN_G, self).__init__(input_size, input_n)self.labfc1 nn.Linear(10, input_size)def forward(self, x, lab): # 添加输入标签batch, width, height, channel1d_in torch.cat((x, self.labfc1(lab)), -1)return super(CondWGAN_G, self).forward(d_in, lab)# 1.8 调用函数并训练模型:实例化判别器和生成器模型并调用函数进行训练
if __name__ __main__:z_dimension 40 # 设置输入随机数的维度D CondWGAN_D().to(device) # 实例化判别器G CondWGAN_G(z_dimension).to(device) # 实例化生成器train(D, G, ./condw_img, z_dimension) # 训练模型displayAndTest(D, G, z_dimension) # 输出可视化