Pytorch使用MNIST数据集实现CGAN和生成指定的数字方式
CGAN的全拼是ConditionalGenerativeAdversarialNetworks,条件生成对抗网络,在初始GAN的基础上增加了图片的相应信息。
这里用传统的卷积方式实现CGAN。
importtorch fromtorch.utils.dataimportDataLoader fromtorchvision.datasetsimportMNIST fromtorchvisionimporttransforms fromtorchimportoptim importtorch.nnasnn importmatplotlib.pyplotasplt importnumpyasnp fromtorch.autogradimportVariable importpickle importcopy importmatplotlib.gridspecasgridspec importos defsave_model(model,filename):#保存为CPU中可以打开的模型 state=model.state_dict() x=state.copy() forkeyinx: x[key]=x[key].clone().cpu() torch.save(x,filename) defshowimg(images,count): images=images.to('cpu') images=images.detach().numpy() images=images[[6,12,18,24,30,36,42,48,54,60,66,72,78,84,90,96]] images=255*(0.5*images+0.5) images=images.astype(np.uint8) grid_length=int(np.ceil(np.sqrt(images.shape[0]))) plt.figure(figsize=(4,4)) width=images.shape[2] gs=gridspec.GridSpec(grid_length,grid_length,wspace=0,hspace=0) fori,imginenumerate(images): ax=plt.subplot(gs[i]) ax.set_xticklabels([]) ax.set_yticklabels([]) ax.set_aspect('equal') plt.imshow(img.reshape(width,width),cmap=plt.cm.gray) plt.axis('off') plt.tight_layout() #plt.tight_layout() plt.savefig(r'./CGAN/images/%d.png'%count,bbox_inches='tight') defloadMNIST(batch_size):#MNIST图片的大小是28*28 trans_img=transforms.Compose([transforms.ToTensor()]) trainset=MNIST('./data',train=True,transform=trans_img,download=True) testset=MNIST('./data',train=False,transform=trans_img,download=True) #device=torch.device("cuda:0"iftorch.cuda.is_available()else"cpu") trainloader=DataLoader(trainset,batch_size=batch_size,shuffle=True,num_workers=10) testloader=DataLoader(testset,batch_size=batch_size,shuffle=False,num_workers=10) returntrainset,testset,trainloader,testloader classdiscriminator(nn.Module): def__init__(self): super(discriminator,self).__init__() self.dis=nn.Sequential( nn.Conv2d(1,32,5,stride=1,padding=2), nn.LeakyReLU(0.2,True), nn.MaxPool2d((2,2)), nn.Conv2d(32,64,5,stride=1,padding=2), nn.LeakyReLU(0.2,True), nn.MaxPool2d((2,2)) ) self.fc=nn.Sequential( nn.Linear(7*7*64,1024), nn.LeakyReLU(0.2,True), nn.Linear(1024,10), nn.Sigmoid() ) defforward(self,x): x=self.dis(x) x=x.view(x.size(0),-1) x=self.fc(x) returnx classgenerator(nn.Module): def__init__(self,input_size,num_feature): super(generator,self).__init__() self.fc=nn.Linear(input_size,num_feature)#1*56*56 self.br=nn.Sequential( nn.BatchNorm2d(1), nn.ReLU(True) ) self.gen=nn.Sequential( nn.Conv2d(1,50,3,stride=1,padding=1), nn.BatchNorm2d(50), nn.ReLU(True), nn.Conv2d(50,25,3,stride=1,padding=1), nn.BatchNorm2d(25), nn.ReLU(True), nn.Conv2d(25,1,2,stride=2), nn.Tanh() ) defforward(self,x): x=self.fc(x) x=x.view(x.size(0),1,56,56) x=self.br(x) x=self.gen(x) returnx if__name__=="__main__": criterion=nn.BCELoss() num_img=100 z_dimension=110 D=discriminator() G=generator(z_dimension,3136)#1*56*56 trainset,testset,trainloader,testloader=loadMNIST(num_img)#data D=D.cuda() G=G.cuda() d_optimizer=optim.Adam(D.parameters(),lr=0.0003) g_optimizer=optim.Adam(G.parameters(),lr=0.0003) ''' 交替训练的方式训练网络 先训练判别器网络D再训练生成器网络G 不同网络的训练次数是超参数 也可以两个网络训练相同的次数, 这样就可以不用分别训练两个网络 ''' count=0 #鉴别器D的训练,固定G的参数 epoch=119 gepoch=1 foriinrange(epoch): for(img,label)intrainloader: labels_onehot=np.zeros((num_img,10)) labels_onehot[np.arange(num_img),label.numpy()]=1 #img=img.view(num_img,-1) #img=np.concatenate((img.numpy(),labels_onehot)) #img=torch.from_numpy(img) img=Variable(img).cuda() real_label=Variable(torch.from_numpy(labels_onehot).float()).cuda()#真实label为1 fake_label=Variable(torch.zeros(num_img,10)).cuda()#假的label为0 #computelossofreal_img real_out=D(img)#真实图片送入判别器D输出0~1 d_loss_real=criterion(real_out,real_label)#得到loss real_scores=real_out#真实图片放入判别器输出越接近1越好 #computelossoffake_img z=Variable(torch.randn(num_img,z_dimension)).cuda()#随机生成向量 fake_img=G(z)#将向量放入生成网络G生成一张图片 fake_out=D(fake_img)#判别器判断假的图片 d_loss_fake=criterion(fake_out,fake_label)#假的图片的loss fake_scores=fake_out#假的图片放入判别器输出越接近0越好 #Dbpandoptimize d_loss=d_loss_real+d_loss_fake d_optimizer.zero_grad()#判别器D的梯度归零 d_loss.backward()#反向传播 d_optimizer.step()#更新判别器D参数 #生成器G的训练computelossoffake_img forjinrange(gepoch): z=torch.randn(num_img,100)#随机生成向量 z=np.concatenate((z.numpy(),labels_onehot),axis=1) z=Variable(torch.from_numpy(z).float()).cuda() fake_img=G(z)#将向量放入生成网络G生成一张图片 output=D(fake_img)#经过判别器得到结果 g_loss=criterion(output,real_label)#得到假的图片与真实标签的loss #bpandoptimize g_optimizer.zero_grad()#生成器G的梯度归零 g_loss.backward()#反向传播 g_optimizer.step()#更新生成器G参数 temp=real_label if(i%10==0)and(i!=0): print(i) torch.save(G.state_dict(),r'./CGAN/Generator_cuda_%d.pkl'%i) torch.save(D.state_dict(),r'./CGAN/Discriminator_cuda_%d.pkl'%i) save_model(G,r'./CGAN/Generator_cpu_%d.pkl'%i)#保存为CPU中可以打开的模型 save_model(D,r'./CGAN/Discriminator_cpu_%d.pkl'%i)#保存为CPU中可以打开的模型 print('Epoch[{}/{}],d_loss:{:.6f},g_loss:{:.6f}' 'Dreal:{:.6f},Dfake:{:.6f}'.format( i,epoch,d_loss.data[0],g_loss.data[0], real_scores.data.mean(),fake_scores.data.mean())) temp=temp.to('cpu') _,x=torch.max(temp,1) x=x.numpy() print(x[[6,12,18,24,30,36,42,48,54,60,66,72,78,84,90,96]]) showimg(fake_img,count) plt.show() count+=1
和基础GANPytorch使用MNIST数据集实现基础GAN里面的卷积版网络比较起来,这里修改的主要是这几个地方:
生成网络的输入值增加了真实图片的类标签,生成网络的初始向量z_dimension之前用的是100维,由于MNIST有10类,Onehot以后一张图片的类标签是10维,所以将类标签放在后面z_dimension=100+10=110维;
训练生成器的时候,由于生成网络的输入向量z_dimension=110维,而且是100维随机向量和10维真实图片标签拼接,需要做相应的拼接操作;
z=torch.randn(num_img,100)#随机生成向量 z=np.concatenate((z.numpy(),labels_onehot),axis=1) z=Variable(torch.from_numpy(z).float()).cuda()
由于计算Loss和生成网络的输入向量都需要用到真实图片的类标签,需要重新生成real_label,对label进行onehot。其中real_label就是真实图片的标签,当num_img=100时,real_label的维度是(100,10);
labels_onehot=np.zeros((num_img,10)) labels_onehot[np.arange(num_img),label.numpy()]=1 img=Variable(img).cuda() real_label=Variable(torch.from_numpy(labels_onehot).float()).cuda()#真实label为1 fake_label=Variable(torch.zeros(num_img,10)).cuda()#假的label为0
real_label的维度是(100,10),计算Loss的时候也要有对应的维度,判别网络的输出也不再是标量,而是要修改为10维;
nn.Linear(1024,10)
在输出图片的同时输出期望的类标签。
temp=temp.to('cpu') _,x=torch.max(temp,1)#返回值有两个,第一个是按列的最大值,第二个是相应最大值的列标号 x=x.numpy() print(x[[6,12,18,24,30,36,42,48,54,60,66,72,78,84,90,96]])
epoch等于0、25、50、75、100时训练的结果:
可以看到训练到后面图像反而变模糊可能是训练过拟合
用模型生成指定的数字:
在训练的过程中保存了训练好的模型,根据输出图片的清晰度,用清晰度较高的模型,使用随机向量和10维类标签来指定生成的数字。
importtorch importtorch.nnasnn importpickle importnumpyasnp importmatplotlib.pyplotasplt importmatplotlib.gridspecasgridspec num_img=9 classdiscriminator(nn.Module): def__init__(self): super(discriminator,self).__init__() self.dis=nn.Sequential( nn.Conv2d(1,32,5,stride=1,padding=2), nn.LeakyReLU(0.2,True), nn.MaxPool2d((2,2)), nn.Conv2d(32,64,5,stride=1,padding=2), nn.LeakyReLU(0.2,True), nn.MaxPool2d((2,2)) ) self.fc=nn.Sequential( nn.Linear(7*7*64,1024), nn.LeakyReLU(0.2,True), nn.Linear(1024,10), nn.Sigmoid() ) defforward(self,x): x=self.dis(x) x=x.view(x.size(0),-1) x=self.fc(x) returnx classgenerator(nn.Module): def__init__(self,input_size,num_feature): super(generator,self).__init__() self.fc=nn.Linear(input_size,num_feature)#1*56*56 self.br=nn.Sequential( nn.BatchNorm2d(1), nn.ReLU(True) ) self.gen=nn.Sequential( nn.Conv2d(1,50,3,stride=1,padding=1), nn.BatchNorm2d(50), nn.ReLU(True), nn.Conv2d(50,25,3,stride=1,padding=1), nn.BatchNorm2d(25), nn.ReLU(True), nn.Conv2d(25,1,2,stride=2), nn.Tanh() ) defforward(self,x): x=self.fc(x) x=x.view(x.size(0),1,56,56) x=self.br(x) x=self.gen(x) returnx defshow(images): images=images.detach().numpy() images=255*(0.5*images+0.5) images=images.astype(np.uint8) plt.figure(figsize=(4,4)) width=images.shape[2] gs=gridspec.GridSpec(1,num_img,wspace=0,hspace=0) fori,imginenumerate(images): ax=plt.subplot(gs[i]) ax.set_xticklabels([]) ax.set_yticklabels([]) ax.set_aspect('equal') plt.imshow(img.reshape(width,width),cmap=plt.cm.gray) plt.axis('off') plt.tight_layout() plt.tight_layout() #plt.savefig(r'drive/深度学习/DCGAN/images/%d.png'%count,bbox_inches='tight') returnwidth defshow_all(images_all): x=images_all[0] foriinrange(1,len(images_all),1): x=np.concatenate((x,images_all[i]),0) print(x.shape) x=255*(0.5*x+0.5) x=x.astype(np.uint8) plt.figure(figsize=(9,10)) width=x.shape[2] gs=gridspec.GridSpec(10,num_img,wspace=0,hspace=0) fori,imginenumerate(x): ax=plt.subplot(gs[i]) ax.set_xticklabels([]) ax.set_yticklabels([]) ax.set_aspect('equal') plt.imshow(img.reshape(width,width),cmap=plt.cm.gray) plt.axis('off') plt.tight_layout() #导入相应的模型 z_dimension=110 D=discriminator() G=generator(z_dimension,3136)#1*56*56 D.load_state_dict(torch.load(r'./CGAN/Discriminator.pkl')) G.load_state_dict(torch.load(r'./CGAN/Generator.pkl')) #依次生成0到9 lis=[] foriinrange(10): z=torch.randn((num_img,100))#随机生成向量 x=np.zeros((num_img,10)) x[:,i]=1 z=np.concatenate((z.numpy(),x),1) z=torch.from_numpy(z).float() fake_img=G(z)#将向量放入生成网络G生成一张图片 lis.append(fake_img.detach().numpy()) output=D(fake_img)#经过判别器得到结果 show(fake_img) plt.savefig('./CGAN/generator/%d.png'%i,bbox_inches='tight') show_all(lis) plt.savefig('./CGAN/generator/all.png',bbox_inches='tight') plt.show()
生成的结果是:
以上这篇Pytorch使用MNIST数据集实现CGAN和生成指定的数字方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。