Pytorch使用MNIST数据集实现CGAN和生成指定的数字方式


Posted in Python onJanuary 10, 2020

CGAN的全拼是Conditional Generative Adversarial Networks,条件生成对抗网络,在初始GAN的基础上增加了图片的相应信息。

这里用传统的卷积方式实现CGAN。

import torch
from torch.utils.data import DataLoader
from torchvision.datasets import MNIST
from torchvision import transforms
from torch import optim
import torch.nn as nn
import matplotlib.pyplot as plt
import numpy as np
from torch.autograd import Variable
import pickle
import copy
 
import matplotlib.gridspec as gridspec
import os
 
def save_model(model, filename): #保存为CPU中可以打开的模型
 state = model.state_dict()
 x=state.copy()
 for key in x: 
  x[key] = x[key].clone().cpu()
 torch.save(x, filename)
 
def showimg(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)
 for i, img in enumerate(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')
 
def loadMNIST(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" if torch.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)
 return trainset,testset,trainloader,testloader
 
class discriminator(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()
  )
 def forward(self, x):
  x=self.dis(x)
  x=x.view(x.size(0),-1)
  x=self.fc(x)
  return x
 
class generator(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()
  )
 def forward(self, x):
  x=self.fc(x)
  x=x.view(x.size(0),1,56,56)
  x=self.br(x)
  x=self.gen(x)
  return x
 
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
 for i in range(epoch):
  for (img, label) in trainloader:
   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
 
   #compute loss of real_img
   real_out=D(img) #真实图片送入判别器D输出0~1
   d_loss_real=criterion(real_out,real_label)#得到loss
   real_scores=real_out#真实图片放入判别器输出越接近1越好
 
   #compute loss of fake_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越好
 
   #D bp and optimize
   d_loss=d_loss_real+d_loss_fake
   d_optimizer.zero_grad() #判别器D的梯度归零
   d_loss.backward() #反向传播
   d_optimizer.step() #更新判别器D参数
 
   #生成器G的训练compute loss of fake_img
   for j in range(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
    #bp and optimize
    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} '
     'D real: {:.6f}, D fake: {:.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

和基础GAN Pytorch使用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时训练的结果:

Pytorch使用MNIST数据集实现CGAN和生成指定的数字方式

可以看到训练到后面图像反而变模糊可能是训练过拟合

用模型生成指定的数字:

在训练的过程中保存了训练好的模型,根据输出图片的清晰度,用清晰度较高的模型,使用随机向量和10维类标签来指定生成的数字。

import torch
import torch.nn as nn
import pickle
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
 
num_img=9
class discriminator(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()
  )
 
 def forward(self, x):
  x = self.dis(x)
  x = x.view(x.size(0), -1)
  x = self.fc(x)
  return x
 
 
class generator(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()
  )
 
 def forward(self, x):
  x = self.fc(x)
  x = x.view(x.size(0), 1, 56, 56)
  x = self.br(x)
  x = self.gen(x)
  return x
 
 
def show(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)
 for i, img in enumerate(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')
 return width
 
def show_all(images_all):
 x=images_all[0]
 for i in range(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)
 for i, img in enumerate(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=[]
for i in range(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和生成指定的数字方式

以上这篇Pytorch使用MNIST数据集实现CGAN和生成指定的数字方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
在Django框架中运行Python应用全攻略
Jul 17 Python
使用PyCharm配合部署Python的Django框架的配置纪实
Nov 19 Python
PyQt5打开文件对话框QFileDialog实例代码
Feb 07 Python
查看django版本的方法分享
May 14 Python
Python实现快速计算词频功能示例
Jun 25 Python
pyqt5的QWebEngineView 使用模板的方法
Aug 18 Python
Python实现去除列表中重复元素的方法总结【7种方法】
Feb 16 Python
python提取log文件内容并画出图表
Jul 08 Python
python将字符串list写入excel和txt的实例
Jul 20 Python
python-序列解包(对可迭代元素的快速取值方法)
Aug 24 Python
Python的Django框架实现数据库查询(不返回QuerySet的方法)
May 19 Python
Python实现ElGamal加密算法的示例代码
Jun 19 Python
pytorch实现mnist分类的示例讲解
Jan 10 #Python
pytorch 准备、训练和测试自己的图片数据的方法
Jan 10 #Python
pytorch GAN伪造手写体mnist数据集方式
Jan 10 #Python
MNIST数据集转化为二维图片的实现示例
Jan 10 #Python
pytorch:实现简单的GAN示例(MNIST数据集)
Jan 10 #Python
pytorch GAN生成对抗网络实例
Jan 10 #Python
解决pytorch报错:AssertionError: Invalid device id的问题
Jan 10 #Python
You might like
PHP中英混合字符串截取函数代码
2011/07/17 PHP
php获取指定日期之间的各个周和月的起止时间
2014/11/24 PHP
javascript动画效果类封装代码
2007/08/28 Javascript
js 页面执行时间计算代码
2009/03/04 Javascript
jquery mobile的触控点击事件会多次触发问题的解决方法
2014/05/08 Javascript
javascript实现修改微信分享的标题内容等
2014/12/11 Javascript
javascript创建对象、对象继承的实用方式详解
2016/03/08 Javascript
JS延时器提示框的应用实例代码解析
2016/04/27 Javascript
浅谈js中调用函数时加不加括号的问题
2016/07/28 Javascript
微信小程序 数据封装,参数传值等经验分享
2017/01/09 Javascript
bootstrap的工具提示实例代码
2017/05/17 Javascript
nodejs密码加密中生成随机数的实例代码
2017/07/17 NodeJs
JavaScript登录验证基础教程
2017/11/01 Javascript
关于vue中watch检测到不到对象属性的变化的解决方法
2018/02/08 Javascript
js中的 || 与 && 运算符详解
2018/05/24 Javascript
基于vue v-for 多层循环嵌套获取行数的方法
2018/09/26 Javascript
对TypeScript库进行单元测试的方法
2019/07/18 Javascript
layui问题之渲染数据表格时,仅出现10条数据的解决方法
2019/09/12 Javascript
Python实现的石头剪子布代码分享
2014/08/22 Python
Python新手在作用域方面经常容易碰到的问题
2015/04/03 Python
解决Python中由于logging模块误用导致的内存泄露
2015/04/23 Python
Django ORM框架的定时任务如何使用详解
2017/10/19 Python
python+VTK环境搭建及第一个简单程序代码
2017/12/13 Python
Python用5行代码写一个自定义简单二维码
2018/10/21 Python
python实现剪切功能
2019/01/23 Python
Python 70行代码实现简单算式计算器解析
2019/08/30 Python
Pycharm激活方法及详细教程(详细且实用)
2020/05/12 Python
解决Python Matplotlib绘图数据点位置错乱问题
2020/05/16 Python
pip install命令安装扩展库整理
2021/03/02 Python
HTML5不支持标签和新增标签详解
2016/06/27 HTML / CSS
西班牙英格列斯百货法国官网:El Corte Inglés法国
2017/07/09 全球购物
优秀辅导员事迹材料
2014/02/16 职场文书
我的中国梦演讲稿初中篇
2014/08/19 职场文书
如何写股份合作协议书
2014/09/11 职场文书
常务副县长“三严三实”对照检查材料思想汇报
2014/10/05 职场文书
Spring Boot 启动、停止、重启、状态脚本
2021/06/26 Java/Android